[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: 2sic # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\nlfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG] \"\nlabels: ''\nassignees: ''\n\n---\n\n<!-- FILL OUT THE FOLLOWING INFORMATION OR WE MAY CLOSE YOUR ISSUE WITHOUT INVESTIGATING -->\n\n### Bug Affects...\n<!-- HINT: remove lines which don't apply  -->\n[x] edit experience / UI\n[x] admin experience UI\n[x] Razor templating\n[x] JS development\n[x] Content Types or data management\n[x] APIs like REST\n[x] Platform parts (Dnn/Oqtane)\n[x] other / unknown\n\n### Current Behavior / Expected Behavior\n<!-- HINT: Describe how the bug manifests. -->\n<!-- HINT: Describe what the behavior would be without the bug. -->\n<!-- HINT: Describe the motivation or the concrete use case for the change -->\n<!-- Anything you would like to add -->\n\n### To Reproduce (Steps, Videos, Screenshots, Apps)\n<!--\nIf you can illustrate your feature request better with an example, please provide \n* STEPS TO REPRODUCE\n* and/or a MINIMAL DEMO like a screenshot or screen cast.\n* A sample App to reproduce the issue is also great!\n-->\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n### Your environment\n\n* **2sxc version(s):** 16.0X.X  <!-- Check whether this is still an issue in the most recent version -->\n* **Browser:** all | Chrome XX | Firefox XX | Edge XX | IE XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari\n* **DNN / Oqtane:** all | Dnn 9.6.1 | Dnn 9.xx.xx | Dnn 10 beta | Oqtane 6.0.1 | ...\n* **Hosting platform:** all | IIS | azure | ...\n* **Ui Languages:** any/all | English | German | ...\n\n### Additional context\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[FEAT] \"\nlabels: ''\nassignees: ''\n\n---\n\n<!-- FILL OUT THE FOLLOWING INFORMATION WE MAY CLOSE YOUR ISSUE WITHOUT INVESTIGATING -->\n\n### This Feature is About\n<!-- HINT: remove lines which don't apply  -->\n[x] edit experience / UI\n[x] admin experience UI\n[x] Razor templating\n[x] JS development\n[x] Content Types or data management\n[x] APIs like REST\n[x] Platform parts (Dnn/Oqtane)\n[x] other / unknown\n\n### Feature request\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!-- FILL OUT THE FOLLOWING INFORMATION WE MAY CLOSE YOUR ISSUE WITHOUT INVESTIGATING -->\n\n### I'm submitting a\n<!-- HINT: remove lines which don't apply  -->\n[x] bug report => search github for a similar issue before submitting\n[x] feature request\n[x] support request => use stackoverflow and tag with 2sxc <https://stackoverflow.com/questions/tagged/2sxc>\n[x] security issue => do not submit here but on <https://2sxc.org/en/contact>\n[x] not sure\n\n### ...about\n<!-- HINT: remove lines which don't apply  -->\n[x] edit experience / UI\n[x] admin experience UI\n[x] Razor templating\n[x] JS development\n[x] Content Types or data management\n[x] APIs like REST\n[x] DNN parts\n[x] other / unknown\n\n### Current Behavior / Expected Behavior\n<!-- HINT: Describe how the bug manifests. -->\n\n<!-- HINT: Describe what the behavior would be without the bug. -->\n\n<!-- HINT: Describe the motivation or the concrete use case for the change -->\n\n<!-- Anything you would like to add -->\n\n### Instructions to Reproduce the Problem\n<!--\nIf the current behavior is a bug or you can illustrate your feature request better with an example, \nplease provide the *STEPS TO REPRODUCE* and/or a *MINIMAL DEMO* like a screenshot or screen cast.\n\nA sample App to reproduce the issue is also great!\n-->\n\n### Your environment\n<!-- HINT: Operating system, IDE, package manager, HTTP server, ... -->\n\n* **2sxc version(s):** 20.0X.X  <!-- Check whether this is still an issue in the most recent version -->\n* **Browser:** all | Chrome XX | Firefox XX | Edge XX | IE XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari\n* **DNN:** all | 9.6.1 | 9.xx.xx\n* **Hosting platform:** all | IIS | azure | other\n* **Language:** any/all | English | German | other\n"
  },
  {
    "path": ".gitignore",
    "content": "# Keep ToSic_SexyContent folder\r\n!ToSIC_SexyContent\r\n!ToSic.Sxc\r\n\r\n# other stuff in the DesktopModules Folder\r\n/2sxc-docs/*\r\n/InstallPackages/*\r\nSrc/Mvc/Website/wwwroot/adam/Blog App/*\r\nbin/\r\nSrc/Integration/SxcEdit01/wwwroot/adam/*\r\n\r\n# 2sxc assets\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/2sxc\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/Content\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc/assets\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc/dist\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc/extensions\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc/js\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc/system\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane/assets\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane/dist\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane/extensions\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane/js\r\n/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane/system\r\n*.lutconfig\r\n\r\n# Exclude 2sxc-build.config.json\r\n**/2sxc-build.config.json\r\n.vs/\r\n/Src/2sxc Multi-Target Oqt510.sln\r\n/Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/ToSic.Sxc.Dnn.dnn\r\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"files.associations\": {\n    \"app.json\": \"jsonc\"\n  },\n  \"cSpell.words\": [\n    \"Oqtane\"\n  ],\n  \"sarif-viewer.connectToGithubCodeScanning\": \"off\",\n  \"chat.promptFilesRecommendations\": {\n    \"speckit.constitution\": true,\n    \"speckit.specify\": true,\n    \"speckit.plan\": true,\n    \"speckit.tasks\": true,\n    \"speckit.implement\": true\n  },\n  \"chat.tools.terminal.autoApprove\": {\n    \".specify/scripts/bash/\": true,\n    \".specify/scripts/powershell/\": true\n  }\n}\n"
  },
  {
    "path": "2sxc-build-fallback.config.json",
    "content": "{\n  /* ----- for developers - please read this -----\n   - Do not modify this file, it's a fallback for the build process and should be configured to do nothing\n   - Read https://go.2sxc.org/build for more details\n  */\n  \"JsTargets\": [\n    // \"C:/Projects/2sxc/2sxc-dnn/Website/DesktopModules/ToSIC_SexyContent\",\n    // \"C:/Projects/2sxc/2sxc/Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane\",\n    // \"C:/Projects/2sxc/2sxc-ui/projects/$2sxc-jasmine-browser/src\"\n  ],\n  /*\n  \"DnnTargets\": [\n    // \"C:/Projects/2sxc/2sxc-dnn/Website\"\n  ],\n  \"OqtaneTargets\": [\n    // \"C:/Projects/2sxc/oqtane/oqtane.framework/Oqtane.Server\"\n  ],\n  */\n  \"Sources\": [\n    // \"C:/Projects/2sxc/2sxc-sources/_latest\"\n  ],\n  // \"DnnInstallPackage\": \"C:/Projects/2sxc/2sxc/InstallPackages/Dnn-Installer\",\n  // \"OqtaneInstallPackage\": \"C:/Projects/2sxc/2sxc/InstallPackages/OqtaneModule\",\n}"
  },
  {
    "path": "Dependencies/Imageflow/Dnn/ToSic.Imageflow.Dnn.xml",
    "content": "<?xml version=\"1.0\"?>\n<doc>\n    <assembly>\n        <name>ToSic.Imageflow.Dnn</name>\n    </assembly>\n    <members>\n        <member name=\"T:ToSic.Imageflow.Dnn.BusinessController\">\n            <summary>\n            BusinessController to support UpgradeModule\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.BusinessController.UpgradeModule(System.String)\">\n            <summary>\n            Executed on module upgrade.\n            This Library package have dnn manifest with simplified \"module\" component,\n            to specify this BusinessController that supports upgrade.\n            </summary>\n            <param name=\"version\"></param>\n            <returns></returns>\n        </member>\n        <member name=\"T:ToSic.Imageflow.Dnn.Cache.HybridCacheOptions\">\n            <summary>\n            Hybrid cache options\n            </summary>\n        </member>\n        <member name=\"P:ToSic.Imageflow.Dnn.Cache.HybridCacheOptions.DiskCacheDirectory\">\n            <summary>\n            Where to store the cached files and the database\n            </summary>\n        </member>\n        <member name=\"P:ToSic.Imageflow.Dnn.Cache.HybridCacheOptions.QueueSizeLimitInBytes\">\n            <summary>\n            How many RAM bytes to use when writing asynchronously to disk before we switch to writing synchronously.\n            Defaults to 100MiB. \n            </summary>\n        </member>\n        <member name=\"P:ToSic.Imageflow.Dnn.Cache.HybridCacheOptions.CacheSizeLimitInBytes\">\n            <summary>\n            Defaults to 1 GiB. Don't set below 9MB or no files will be cached, since 9MB is reserved just for empty directory entries.\n            </summary>\n        </member>\n        <member name=\"P:ToSic.Imageflow.Dnn.Cache.HybridCacheOptions.MinCleanupBytes\">\n            <summary>\n            The minimum number of bytes to free when running a cleanup task. Defaults to 1MiB;\n            </summary>\n        </member>\n        <member name=\"P:ToSic.Imageflow.Dnn.Cache.HybridCacheOptions.MinAgeToDelete\">\n            <summary>\n            The minimum age of files to delete. Defaults to 10 seconds.\n            </summary>\n        </member>\n        <member name=\"P:ToSic.Imageflow.Dnn.Cache.HybridCacheOptions.DatabaseShards\">\n            <summary>\n            The number of shards to split the metabase into. More shards means more open log files, slower shutdown.\n            But more shards also mean less lock contention and faster start time for individual cached requests.\n            Defaults to 8. You have to delete the database directory each time you change this number.\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Cache.HybridCacheOptions.#ctor(System.String)\">\n            <summary>\n            HybridCacheOptions with cache folder\n            </summary>\n            <param name=\"cacheDir\"></param>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Cache.HybridCacheService.#ctor(ToSic.Imageflow.Dnn.Cache.HybridCacheOptions,Microsoft.Extensions.Logging.ILogger{ToSic.Imageflow.Dnn.Cache.HybridCacheService})\">\n            <summary>\n            Constructor for the Hybrid Cache service.\n            </summary>\n            <param name=\"options\">Options for the Hybrid Cache service.</param>\n            <param name=\"logger\">Logger instance for logging events.</param>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Cache.HybridCacheService.GetIssues\">\n            <summary>\n            Get a list of issues within the Hybrid Cache.\n            </summary>\n            <returns>A list of issues within the cache.</returns>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Cache.HybridCacheService.StartAsync(System.Threading.CancellationToken)\">\n            <summary>\n            Start the Hybrid Cache.\n            </summary>\n            <param name=\"cancellationToken\">Cancellation token for the operation.</param>\n            <returns>A task representing the starting of the cache.</returns>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Cache.HybridCacheService.StopAsync(System.Threading.CancellationToken)\">\n            <summary>\n            Stop the Hybrid Cache.\n            </summary>\n            <param name=\"cancellationToken\">Cancellation token for the operation.</param>\n            <returns>A task representing the stopping of the cache.</returns>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Cache.HybridCacheService.GetOrCreateBytes(System.Byte[],Imazen.Common.Extensibility.StreamCache.AsyncBytesResult,System.Threading.CancellationToken,System.Boolean)\">\n            <summary>\n            Retrieve or create a new set of bytes within the cache.\n            </summary>\n            <param name=\"key\">The key to identify the cache entry.</param>\n            <param name=\"dataProviderCallback\">The function that retrieves missing data.</param>\n            <param name=\"cancellationToken\">Cancellation token for the operation.</param>\n            <param name=\"retrieveContentType\">Whether or not to retrieve the content type of the data.</param>\n            <returns>The result of the cache retrieval or creation.</returns>\n        </member>\n        <member name=\"T:ToSic.Imageflow.Dnn.Cache.HybridCacheServiceExtensions\">\n            <summary>\n            Extension method for adding hybrid cache service to the IServiceCollection.\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Cache.HybridCacheServiceExtensions.AddImageflowHybridCache(Microsoft.Extensions.DependencyInjection.IServiceCollection,ToSic.Imageflow.Dnn.Cache.HybridCacheOptions)\">\n            <summary>\n            Adds image flow hybrid cache service to the IServiceCollection.\n            </summary>\n            <param name=\"services\">The IServiceCollection instance.</param>\n            <param name=\"options\">The hybrid cache options.</param>\n            <returns>The updated IServiceCollection instance.</returns>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.DependencyInjection.Resolve``1\">\n            <summary>\n            Dependency Injection resolver with a known type as a parameter.\n            </summary>\n            <typeparam name=\"T\">The type / interface we need.</typeparam>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.DependencyInjection.Configure\">\n            <summary>\n            Configure IoC. If it's already configured, do nothing.\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.DependencyInjection.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)\">\n            <summary>\n            ConfigureServices for DI\n            </summary>\n            <param name=\"services\"></param>\n        </member>\n        <member name=\"T:ToSic.Imageflow.Dnn.Helpers.MagicBytes\">\n            <summary>\n            Identify common file formats and proxy streams to the HTTP response.\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Helpers.MagicBytes.GetContentTypeFromBytes(System.Byte[])\">\n            <summary>\n            Returns the MIME type based on the provided byte array data.\n            </summary>\n            <param name=\"data\">The byte array data to check for the MIME type.</param>\n            <returns>A string representing the MIME type of the provided data.</returns>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Helpers.MagicBytes.ProxyToStream(System.IO.Stream,System.Web.HttpResponse)\">\n            <summary>\n            Proxies the given stream to the provided HTTP response, while also setting the content length\n            and the content type based off the provided data if possible.\n            </summary>\n            <param name=\"sourceStream\">The source stream to proxy.</param>\n            <param name=\"response\">The HTTP response to write to.</param>\n            <exception cref=\"T:System.InvalidOperationException\"></exception>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Helpers.PathHelpers.Base64Hash(System.String)\">\n            <summary>\n            Return the Base64 encoded hash string\n            </summary>\n            <param name=\"data\"></param>\n            <returns></returns>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.Helpers.PathHelpers.ToQueryDictionary(System.Collections.Specialized.NameValueCollection)\">\n            <summary>\n            Create a dictionary from a name value collection.\n            </summary>\n            <returns>A dictionary containing all the key-value pairs from a NameValueCollection</returns>\n            <param name=\"requestQuery\">The NameValueCollection containing the input key-value pairs.</param>\n        </member>\n        <member name=\"T:ToSic.Imageflow.Dnn.ImageflowModule\">\n            <summary>\n            ImageflowModule\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.ImageflowModule.Init(System.Web.HttpApplication)\">\n            <summary>\n            Init Imageflow HttpModule\n            </summary>\n            <param name=\"application\"></param>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.ImageflowModule.Dispose\">\n            <summary>\n            Dispose Imageflow HttpModule\n            </summary>\n        </member>\n        <member name=\"T:ToSic.Imageflow.Dnn.Options.ImageflowModuleOptions\">\n            <summary>\n            ImageflowModuleOptions\n            </summary>\n        </member>\n        <member name=\"P:ToSic.Imageflow.Dnn.Options.ImageflowModuleOptions.DefaultCacheControlString\">\n            <summary>\n            Use \"public, max-age=2592000\" to cache for 30 days and cache on CDNs and proxies.\n            </summary>\n        </member>\n        <member name=\"T:ToSic.Imageflow.Dnn.StartUp\">\n            <summary>\n            StartUp is helper class to enable registration of QueryStringRewrite functionality from\n            main 2sxc dnn module\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.StartUp.RegisterQueryStringRewrite(System.Func{System.Collections.Specialized.NameValueCollection,System.Collections.Specialized.NameValueCollection})\">\n            <summary>\n            Register QueryStringRewrite function for use in ImageJobInfo.\n            This registration should be called from the main 2sxc dnn module\n            before we use dnn imageflow.\n            </summary>\n            <param name=\"queryStringRewrite\"></param>\n        </member>\n        <member name=\"T:ToSic.Imageflow.Dnn.StartupDnn\">\n            <summary>\n            This configures .net Dependency Injection\n            The StartUp is defined as an IServiceRouteMapper.\n            This way DNN will auto-run this code before anything else\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.StartupDnn.RegisterRoutes(DotNetNuke.Web.Api.IMapRoute)\">\n            <summary>\n            This will be called by DNN when loading the assemblies.\n            We just want to trigger the DependencyInjection-Configure\n            </summary>\n            <param name=\"mapRouteManager\"></param>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.UpgradeUtil.UpgradeNativeAssemblies\">\n            <summary>\n            Ensure that native assemblies are in place, before we start to use them.\n            </summary>\n        </member>\n        <member name=\"M:ToSic.Imageflow.Dnn.UpgradeUtil.ReplaceNativeAssemblies\">\n            <summary>\n            Replacing of native assemblies is only possible when this assemblies are not already locked,\n            because are in use and loaded.\n            This part is tricky and it is possible that it will be executed more times, until all work is done.\n            </summary>\n        </member>\n    </members>\n</doc>\n"
  },
  {
    "path": "Dependencies/Koi/net6.0/Connect.Koi.deps.json",
    "content": "{\n  \"runtimeTarget\": {\n    \"name\": \".NETCoreApp,Version=v6.0\",\n    \"signature\": \"\"\n  },\n  \"compilationOptions\": {},\n  \"targets\": {\n    \".NETCoreApp,Version=v6.0\": {\n      \"Connect.Koi/03.00.01\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Html.Abstractions\": \"2.0.0\",\n          \"Microsoft.AspNetCore.Http\": \"2.0.0\",\n          \"Microsoft.AspNetCore.Http.Abstractions\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"Connect.Koi.dll\": {}\n        }\n      },\n      \"Microsoft.AspNetCore.Html.Abstractions/2.0.0\": {\n        \"dependencies\": {\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Html.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Http.Abstractions\": \"2.0.0\",\n          \"Microsoft.AspNetCore.WebUtilities\": \"2.0.0\",\n          \"Microsoft.Extensions.ObjectPool\": \"2.0.0\",\n          \"Microsoft.Extensions.Options\": \"2.0.0\",\n          \"Microsoft.Net.Http.Headers\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http.Abstractions/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Http.Features\": \"2.0.0\",\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http.Features/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.WebUtilities/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Net.Http.Headers\": \"2.0.0\",\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection.Abstractions/2.0.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.ObjectPool/2.0.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.Options/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.DependencyInjection.Abstractions\": \"2.0.0\",\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.Options.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.Primitives/2.0.0\": {\n        \"dependencies\": {\n          \"System.Runtime.CompilerServices.Unsafe\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.Primitives.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Net.Http.Headers/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\",\n          \"System.Buffers\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Net.Http.Headers.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"System.Buffers/4.4.0\": {},\n      \"System.Runtime.CompilerServices.Unsafe/4.4.0\": {},\n      \"System.Text.Encodings.Web/4.4.0\": {}\n    }\n  },\n  \"libraries\": {\n    \"Connect.Koi/03.00.01\": {\n      \"type\": \"project\",\n      \"serviceable\": false,\n      \"sha512\": \"\"\n    },\n    \"Microsoft.AspNetCore.Html.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Tdy0VkAnSeynmnbqF1JLchyPg5iQwmxTTG16byenoD2SXn/W8DR6HagZOZxvDb7gc4IerjdhIwuY8aV8nm7FAA==\",\n      \"path\": \"microsoft.aspnetcore.html.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.html.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-2YNhcHrGxo2YufA8TYGyaEMIJwikyisZqEzHCRpIuI0D6ZXkA47U/3NJg2r/x5/gGHNM3TXO7DsqH88qRda+yg==\",\n      \"path\": \"microsoft.aspnetcore.http/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-pblZLY7IfNqhQ5wwGQ0vNq2mG6W5YgZI1fk7suEuwZsGxGEADNBAyNlTALM9L8nMXdvbp6aHP/t4wHrFpcL3Sw==\",\n      \"path\": \"microsoft.aspnetcore.http.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http.Features/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-yk62muzFTZTKCQuo3nmVPkPvGBlM2qbdSxbX62TufuONuKQrTGQ/SwhwBbYutk5/YY7u4HETu0n9BKOn7mMgmA==\",\n      \"path\": \"microsoft.aspnetcore.http.features/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.features.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.WebUtilities/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-RqDEwy7jdHJ0NunWydSzJrpODnsF7NPdB0KaRdG60H1bMEt4DbjcWkUb+XxjZ15uWCMi7clTQClpPuIFLwD1yQ==\",\n      \"path\": \"microsoft.aspnetcore.webutilities/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.webutilities.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-eUdJ0Q/GfVyUJc0Jal5L1QZLceL78pvEM9wEKcHeI24KorqMDoVX+gWsMGLulQMfOwsUaPtkpQM2pFERTzSfSg==\",\n      \"path\": \"microsoft.extensions.dependencyinjection.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.ObjectPool/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-drOmgNZCJiNEqFM/TvyqwtogS8wqoWGQCW5KB/CVGKL6VXHw8OOMdaHyspp8HPstP9UDnrnuq+8eaCaAcQg6tA==\",\n      \"path\": \"microsoft.extensions.objectpool/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.objectpool.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.Options/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-sAKBgjl2gWsECBLLR9K54T7/uZaP2n9GhMYHay/oOLfvpvX0+iNAlQ2NJgVE352C9Fs5CDV3VbNTK8T2aNKQFA==\",\n      \"path\": \"microsoft.extensions.options/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.options.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.Primitives/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-ukg53qNlqTrK38WA30b5qhw0GD7y3jdI9PHHASjdKyTcBHTevFM2o23tyk3pWCgAV27Bbkm+CPQ2zUe1ZOuYSA==\",\n      \"path\": \"microsoft.extensions.primitives/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.primitives.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Net.Http.Headers/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Rm9zeNCWyNrGnysHdRXJpNfeDVlPzzFuidSuRLRNvOrnw71vgNPlR4H9wHo2hG/oSaruukqNjK06MDQqb+eXhA==\",\n      \"path\": \"microsoft.net.http.headers/2.0.0\",\n      \"hashPath\": \"microsoft.net.http.headers.2.0.0.nupkg.sha512\"\n    },\n    \"System.Buffers/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-AwarXzzoDwX6BgrhjoJsk6tUezZEozOT5Y9QKF94Gl4JK91I4PIIBkBco9068Y9/Dra8Dkbie99kXB8+1BaYKw==\",\n      \"path\": \"system.buffers/4.4.0\",\n      \"hashPath\": \"system.buffers.4.4.0.nupkg.sha512\"\n    },\n    \"System.Runtime.CompilerServices.Unsafe/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-9dLLuBxr5GNmOfl2jSMcsHuteEg32BEfUotmmUkmZjpR3RpVHE8YQwt0ow3p6prwA1ME8WqDVZqrr8z6H8G+Kw==\",\n      \"path\": \"system.runtime.compilerservices.unsafe/4.4.0\",\n      \"hashPath\": \"system.runtime.compilerservices.unsafe.4.4.0.nupkg.sha512\"\n    },\n    \"System.Text.Encodings.Web/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-l/tYeikqMHX2MD2jzrHDfR9ejrpTTF7wvAEbR51AMvzip1wSJgiURbDik4iv/w7ZgytmTD/hlwpplEhF9bmFNw==\",\n      \"path\": \"system.text.encodings.web/4.4.0\",\n      \"hashPath\": \"system.text.encodings.web.4.4.0.nupkg.sha512\"\n    }\n  }\n}"
  },
  {
    "path": "Dependencies/Koi/net7.0/Connect.Koi.deps.json",
    "content": "{\n  \"runtimeTarget\": {\n    \"name\": \".NETCoreApp,Version=v7.0\",\n    \"signature\": \"\"\n  },\n  \"compilationOptions\": {},\n  \"targets\": {\n    \".NETCoreApp,Version=v7.0\": {\n      \"Connect.Koi/03.00.01\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Html.Abstractions\": \"2.0.0\",\n          \"Microsoft.AspNetCore.Http\": \"2.0.0\",\n          \"Microsoft.AspNetCore.Http.Abstractions\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"Connect.Koi.dll\": {}\n        }\n      },\n      \"Microsoft.AspNetCore.Html.Abstractions/2.0.0\": {\n        \"dependencies\": {\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Html.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Http.Abstractions\": \"2.0.0\",\n          \"Microsoft.AspNetCore.WebUtilities\": \"2.0.0\",\n          \"Microsoft.Extensions.ObjectPool\": \"2.0.0\",\n          \"Microsoft.Extensions.Options\": \"2.0.0\",\n          \"Microsoft.Net.Http.Headers\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http.Abstractions/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Http.Features\": \"2.0.0\",\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http.Features/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.WebUtilities/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Net.Http.Headers\": \"2.0.0\",\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection.Abstractions/2.0.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.ObjectPool/2.0.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.Options/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.DependencyInjection.Abstractions\": \"2.0.0\",\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.Options.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.Primitives/2.0.0\": {\n        \"dependencies\": {\n          \"System.Runtime.CompilerServices.Unsafe\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.Primitives.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Net.Http.Headers/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\",\n          \"System.Buffers\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Net.Http.Headers.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"System.Buffers/4.4.0\": {},\n      \"System.Runtime.CompilerServices.Unsafe/4.4.0\": {},\n      \"System.Text.Encodings.Web/4.4.0\": {}\n    }\n  },\n  \"libraries\": {\n    \"Connect.Koi/03.00.01\": {\n      \"type\": \"project\",\n      \"serviceable\": false,\n      \"sha512\": \"\"\n    },\n    \"Microsoft.AspNetCore.Html.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Tdy0VkAnSeynmnbqF1JLchyPg5iQwmxTTG16byenoD2SXn/W8DR6HagZOZxvDb7gc4IerjdhIwuY8aV8nm7FAA==\",\n      \"path\": \"microsoft.aspnetcore.html.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.html.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-2YNhcHrGxo2YufA8TYGyaEMIJwikyisZqEzHCRpIuI0D6ZXkA47U/3NJg2r/x5/gGHNM3TXO7DsqH88qRda+yg==\",\n      \"path\": \"microsoft.aspnetcore.http/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-pblZLY7IfNqhQ5wwGQ0vNq2mG6W5YgZI1fk7suEuwZsGxGEADNBAyNlTALM9L8nMXdvbp6aHP/t4wHrFpcL3Sw==\",\n      \"path\": \"microsoft.aspnetcore.http.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http.Features/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-yk62muzFTZTKCQuo3nmVPkPvGBlM2qbdSxbX62TufuONuKQrTGQ/SwhwBbYutk5/YY7u4HETu0n9BKOn7mMgmA==\",\n      \"path\": \"microsoft.aspnetcore.http.features/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.features.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.WebUtilities/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-RqDEwy7jdHJ0NunWydSzJrpODnsF7NPdB0KaRdG60H1bMEt4DbjcWkUb+XxjZ15uWCMi7clTQClpPuIFLwD1yQ==\",\n      \"path\": \"microsoft.aspnetcore.webutilities/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.webutilities.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-eUdJ0Q/GfVyUJc0Jal5L1QZLceL78pvEM9wEKcHeI24KorqMDoVX+gWsMGLulQMfOwsUaPtkpQM2pFERTzSfSg==\",\n      \"path\": \"microsoft.extensions.dependencyinjection.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.ObjectPool/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-drOmgNZCJiNEqFM/TvyqwtogS8wqoWGQCW5KB/CVGKL6VXHw8OOMdaHyspp8HPstP9UDnrnuq+8eaCaAcQg6tA==\",\n      \"path\": \"microsoft.extensions.objectpool/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.objectpool.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.Options/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-sAKBgjl2gWsECBLLR9K54T7/uZaP2n9GhMYHay/oOLfvpvX0+iNAlQ2NJgVE352C9Fs5CDV3VbNTK8T2aNKQFA==\",\n      \"path\": \"microsoft.extensions.options/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.options.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.Primitives/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-ukg53qNlqTrK38WA30b5qhw0GD7y3jdI9PHHASjdKyTcBHTevFM2o23tyk3pWCgAV27Bbkm+CPQ2zUe1ZOuYSA==\",\n      \"path\": \"microsoft.extensions.primitives/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.primitives.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Net.Http.Headers/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Rm9zeNCWyNrGnysHdRXJpNfeDVlPzzFuidSuRLRNvOrnw71vgNPlR4H9wHo2hG/oSaruukqNjK06MDQqb+eXhA==\",\n      \"path\": \"microsoft.net.http.headers/2.0.0\",\n      \"hashPath\": \"microsoft.net.http.headers.2.0.0.nupkg.sha512\"\n    },\n    \"System.Buffers/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-AwarXzzoDwX6BgrhjoJsk6tUezZEozOT5Y9QKF94Gl4JK91I4PIIBkBco9068Y9/Dra8Dkbie99kXB8+1BaYKw==\",\n      \"path\": \"system.buffers/4.4.0\",\n      \"hashPath\": \"system.buffers.4.4.0.nupkg.sha512\"\n    },\n    \"System.Runtime.CompilerServices.Unsafe/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-9dLLuBxr5GNmOfl2jSMcsHuteEg32BEfUotmmUkmZjpR3RpVHE8YQwt0ow3p6prwA1ME8WqDVZqrr8z6H8G+Kw==\",\n      \"path\": \"system.runtime.compilerservices.unsafe/4.4.0\",\n      \"hashPath\": \"system.runtime.compilerservices.unsafe.4.4.0.nupkg.sha512\"\n    },\n    \"System.Text.Encodings.Web/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-l/tYeikqMHX2MD2jzrHDfR9ejrpTTF7wvAEbR51AMvzip1wSJgiURbDik4iv/w7ZgytmTD/hlwpplEhF9bmFNw==\",\n      \"path\": \"system.text.encodings.web/4.4.0\",\n      \"hashPath\": \"system.text.encodings.web.4.4.0.nupkg.sha512\"\n    }\n  }\n}"
  },
  {
    "path": "Dependencies/Koi/netstandard2.0/Connect.Koi.deps.json",
    "content": "{\n  \"runtimeTarget\": {\n    \"name\": \".NETStandard,Version=v2.0/\",\n    \"signature\": \"\"\n  },\n  \"compilationOptions\": {},\n  \"targets\": {\n    \".NETStandard,Version=v2.0\": {},\n    \".NETStandard,Version=v2.0/\": {\n      \"Connect.Koi/03.00.01\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Html.Abstractions\": \"2.0.0\",\n          \"Microsoft.AspNetCore.Http\": \"2.0.0\",\n          \"Microsoft.AspNetCore.Http.Abstractions\": \"2.0.0\",\n          \"NETStandard.Library\": \"2.0.3\"\n        },\n        \"runtime\": {\n          \"Connect.Koi.dll\": {}\n        }\n      },\n      \"Microsoft.AspNetCore.Html.Abstractions/2.0.0\": {\n        \"dependencies\": {\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Html.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Http.Abstractions\": \"2.0.0\",\n          \"Microsoft.AspNetCore.WebUtilities\": \"2.0.0\",\n          \"Microsoft.Extensions.ObjectPool\": \"2.0.0\",\n          \"Microsoft.Extensions.Options\": \"2.0.0\",\n          \"Microsoft.Net.Http.Headers\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http.Abstractions/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Http.Features\": \"2.0.0\",\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.Http.Features/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Http.Features.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.AspNetCore.WebUtilities/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Net.Http.Headers\": \"2.0.0\",\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.WebUtilities.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection.Abstractions/2.0.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.ObjectPool/2.0.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.ObjectPool.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.Options/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.DependencyInjection.Abstractions\": \"2.0.0\",\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.Options.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.Primitives/2.0.0\": {\n        \"dependencies\": {\n          \"System.Runtime.CompilerServices.Unsafe\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Extensions.Primitives.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Net.Http.Headers/2.0.0\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.Primitives\": \"2.0.0\",\n          \"System.Buffers\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.Net.Http.Headers.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.NETCore.Platforms/1.1.0\": {},\n      \"NETStandard.Library/2.0.3\": {\n        \"dependencies\": {\n          \"Microsoft.NETCore.Platforms\": \"1.1.0\"\n        }\n      },\n      \"System.Buffers/4.4.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/System.Buffers.dll\": {\n            \"assemblyVersion\": \"4.0.2.0\",\n            \"fileVersion\": \"4.6.25519.3\"\n          }\n        }\n      },\n      \"System.Runtime.CompilerServices.Unsafe/4.4.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll\": {\n            \"assemblyVersion\": \"4.0.3.0\",\n            \"fileVersion\": \"0.0.0.0\"\n          }\n        }\n      },\n      \"System.Text.Encodings.Web/4.4.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/System.Text.Encodings.Web.dll\": {\n            \"assemblyVersion\": \"4.0.2.0\",\n            \"fileVersion\": \"4.6.25519.3\"\n          }\n        }\n      }\n    }\n  },\n  \"libraries\": {\n    \"Connect.Koi/03.00.01\": {\n      \"type\": \"project\",\n      \"serviceable\": false,\n      \"sha512\": \"\"\n    },\n    \"Microsoft.AspNetCore.Html.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Tdy0VkAnSeynmnbqF1JLchyPg5iQwmxTTG16byenoD2SXn/W8DR6HagZOZxvDb7gc4IerjdhIwuY8aV8nm7FAA==\",\n      \"path\": \"microsoft.aspnetcore.html.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.html.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-2YNhcHrGxo2YufA8TYGyaEMIJwikyisZqEzHCRpIuI0D6ZXkA47U/3NJg2r/x5/gGHNM3TXO7DsqH88qRda+yg==\",\n      \"path\": \"microsoft.aspnetcore.http/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-pblZLY7IfNqhQ5wwGQ0vNq2mG6W5YgZI1fk7suEuwZsGxGEADNBAyNlTALM9L8nMXdvbp6aHP/t4wHrFpcL3Sw==\",\n      \"path\": \"microsoft.aspnetcore.http.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.Http.Features/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-yk62muzFTZTKCQuo3nmVPkPvGBlM2qbdSxbX62TufuONuKQrTGQ/SwhwBbYutk5/YY7u4HETu0n9BKOn7mMgmA==\",\n      \"path\": \"microsoft.aspnetcore.http.features/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.http.features.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.AspNetCore.WebUtilities/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-RqDEwy7jdHJ0NunWydSzJrpODnsF7NPdB0KaRdG60H1bMEt4DbjcWkUb+XxjZ15uWCMi7clTQClpPuIFLwD1yQ==\",\n      \"path\": \"microsoft.aspnetcore.webutilities/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.webutilities.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-eUdJ0Q/GfVyUJc0Jal5L1QZLceL78pvEM9wEKcHeI24KorqMDoVX+gWsMGLulQMfOwsUaPtkpQM2pFERTzSfSg==\",\n      \"path\": \"microsoft.extensions.dependencyinjection.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.ObjectPool/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-drOmgNZCJiNEqFM/TvyqwtogS8wqoWGQCW5KB/CVGKL6VXHw8OOMdaHyspp8HPstP9UDnrnuq+8eaCaAcQg6tA==\",\n      \"path\": \"microsoft.extensions.objectpool/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.objectpool.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.Options/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-sAKBgjl2gWsECBLLR9K54T7/uZaP2n9GhMYHay/oOLfvpvX0+iNAlQ2NJgVE352C9Fs5CDV3VbNTK8T2aNKQFA==\",\n      \"path\": \"microsoft.extensions.options/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.options.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.Primitives/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-ukg53qNlqTrK38WA30b5qhw0GD7y3jdI9PHHASjdKyTcBHTevFM2o23tyk3pWCgAV27Bbkm+CPQ2zUe1ZOuYSA==\",\n      \"path\": \"microsoft.extensions.primitives/2.0.0\",\n      \"hashPath\": \"microsoft.extensions.primitives.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Net.Http.Headers/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Rm9zeNCWyNrGnysHdRXJpNfeDVlPzzFuidSuRLRNvOrnw71vgNPlR4H9wHo2hG/oSaruukqNjK06MDQqb+eXhA==\",\n      \"path\": \"microsoft.net.http.headers/2.0.0\",\n      \"hashPath\": \"microsoft.net.http.headers.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.NETCore.Platforms/1.1.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==\",\n      \"path\": \"microsoft.netcore.platforms/1.1.0\",\n      \"hashPath\": \"microsoft.netcore.platforms.1.1.0.nupkg.sha512\"\n    },\n    \"NETStandard.Library/2.0.3\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==\",\n      \"path\": \"netstandard.library/2.0.3\",\n      \"hashPath\": \"netstandard.library.2.0.3.nupkg.sha512\"\n    },\n    \"System.Buffers/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-AwarXzzoDwX6BgrhjoJsk6tUezZEozOT5Y9QKF94Gl4JK91I4PIIBkBco9068Y9/Dra8Dkbie99kXB8+1BaYKw==\",\n      \"path\": \"system.buffers/4.4.0\",\n      \"hashPath\": \"system.buffers.4.4.0.nupkg.sha512\"\n    },\n    \"System.Runtime.CompilerServices.Unsafe/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-9dLLuBxr5GNmOfl2jSMcsHuteEg32BEfUotmmUkmZjpR3RpVHE8YQwt0ow3p6prwA1ME8WqDVZqrr8z6H8G+Kw==\",\n      \"path\": \"system.runtime.compilerservices.unsafe/4.4.0\",\n      \"hashPath\": \"system.runtime.compilerservices.unsafe.4.4.0.nupkg.sha512\"\n    },\n    \"System.Text.Encodings.Web/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-l/tYeikqMHX2MD2jzrHDfR9ejrpTTF7wvAEbR51AMvzip1wSJgiURbDik4iv/w7ZgytmTD/hlwpplEhF9bmFNw==\",\n      \"path\": \"system.text.encodings.web/4.4.0\",\n      \"hashPath\": \"system.text.encodings.web.4.4.0.nupkg.sha512\"\n    }\n  }\n}"
  },
  {
    "path": "Dependencies/RazorBlade/Release/net6.0/ToSic.Razor.deps.json",
    "content": "{\n  \"runtimeTarget\": {\n    \"name\": \".NETCoreApp,Version=v6.0\",\n    \"signature\": \"\"\n  },\n  \"compilationOptions\": {},\n  \"targets\": {\n    \".NETCoreApp,Version=v6.0\": {\n      \"ToSic.Razor/04.04.01\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Html.Abstractions\": \"2.2.0\",\n          \"Microsoft.Extensions.DependencyInjection\": \"3.1.16\"\n        },\n        \"runtime\": {\n          \"ToSic.Razor.dll\": {}\n        }\n      },\n      \"Microsoft.AspNetCore.Html.Abstractions/2.2.0\": {\n        \"dependencies\": {\n          \"System.Text.Encodings.Web\": \"4.5.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Html.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.2.0.0\",\n            \"fileVersion\": \"2.2.0.18316\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection/3.1.16\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.DependencyInjection.Abstractions\": \"3.1.16\"\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection.Abstractions/3.1.16\": {},\n      \"System.Text.Encodings.Web/4.5.0\": {}\n    }\n  },\n  \"libraries\": {\n    \"ToSic.Razor/04.04.01\": {\n      \"type\": \"project\",\n      \"serviceable\": false,\n      \"sha512\": \"\"\n    },\n    \"Microsoft.AspNetCore.Html.Abstractions/2.2.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Y4rs5aMEXY8G7wJo5S3EEt6ltqyOTr/qOeZzfn+hw/fuQj5GppGckMY5psGLETo1U9hcT5MmAhaT5xtusM1b5g==\",\n      \"path\": \"microsoft.aspnetcore.html.abstractions/2.2.0\",\n      \"hashPath\": \"microsoft.aspnetcore.html.abstractions.2.2.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection/3.1.16\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-zgV27UpG5tc/oW23Gh4r6DA1biMvdPv/efcNVp25Cx7bDcdoP3/snrdH+dscaOyjXtiZtYXELN4cDlyIAvNO+g==\",\n      \"path\": \"microsoft.extensions.dependencyinjection/3.1.16\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.3.1.16.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection.Abstractions/3.1.16\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-pFCBSw5MJiuucZAG+IrJLcQd4c7JIgc/7t6Mm6Q31wjEeamKQ+r7p1Aw21IHJm5KHqLNG/UdeaIt6ffullkC0Q==\",\n      \"path\": \"microsoft.extensions.dependencyinjection.abstractions/3.1.16\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.abstractions.3.1.16.nupkg.sha512\"\n    },\n    \"System.Text.Encodings.Web/4.5.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==\",\n      \"path\": \"system.text.encodings.web/4.5.0\",\n      \"hashPath\": \"system.text.encodings.web.4.5.0.nupkg.sha512\"\n    }\n  }\n}"
  },
  {
    "path": "Dependencies/RazorBlade/Release/net7.0/ToSic.Razor.deps.json",
    "content": "{\n  \"runtimeTarget\": {\n    \"name\": \".NETCoreApp,Version=v7.0\",\n    \"signature\": \"\"\n  },\n  \"compilationOptions\": {},\n  \"targets\": {\n    \".NETCoreApp,Version=v7.0\": {\n      \"ToSic.Razor/04.04.01\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Html.Abstractions\": \"2.2.0\",\n          \"Microsoft.Extensions.DependencyInjection\": \"3.1.16\"\n        },\n        \"runtime\": {\n          \"ToSic.Razor.dll\": {}\n        }\n      },\n      \"Microsoft.AspNetCore.Html.Abstractions/2.2.0\": {\n        \"dependencies\": {\n          \"System.Text.Encodings.Web\": \"4.5.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Html.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.2.0.0\",\n            \"fileVersion\": \"2.2.0.18316\"\n          }\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection/3.1.16\": {\n        \"dependencies\": {\n          \"Microsoft.Extensions.DependencyInjection.Abstractions\": \"3.1.16\"\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection.Abstractions/3.1.16\": {},\n      \"System.Text.Encodings.Web/4.5.0\": {}\n    }\n  },\n  \"libraries\": {\n    \"ToSic.Razor/04.04.01\": {\n      \"type\": \"project\",\n      \"serviceable\": false,\n      \"sha512\": \"\"\n    },\n    \"Microsoft.AspNetCore.Html.Abstractions/2.2.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Y4rs5aMEXY8G7wJo5S3EEt6ltqyOTr/qOeZzfn+hw/fuQj5GppGckMY5psGLETo1U9hcT5MmAhaT5xtusM1b5g==\",\n      \"path\": \"microsoft.aspnetcore.html.abstractions/2.2.0\",\n      \"hashPath\": \"microsoft.aspnetcore.html.abstractions.2.2.0.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection/3.1.16\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-zgV27UpG5tc/oW23Gh4r6DA1biMvdPv/efcNVp25Cx7bDcdoP3/snrdH+dscaOyjXtiZtYXELN4cDlyIAvNO+g==\",\n      \"path\": \"microsoft.extensions.dependencyinjection/3.1.16\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.3.1.16.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection.Abstractions/3.1.16\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-pFCBSw5MJiuucZAG+IrJLcQd4c7JIgc/7t6Mm6Q31wjEeamKQ+r7p1Aw21IHJm5KHqLNG/UdeaIt6ffullkC0Q==\",\n      \"path\": \"microsoft.extensions.dependencyinjection.abstractions/3.1.16\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.abstractions.3.1.16.nupkg.sha512\"\n    },\n    \"System.Text.Encodings.Web/4.5.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==\",\n      \"path\": \"system.text.encodings.web/4.5.0\",\n      \"hashPath\": \"system.text.encodings.web.4.5.0.nupkg.sha512\"\n    }\n  }\n}"
  },
  {
    "path": "Dependencies/RazorBlade/Release/netstandard2.0/ToSic.Razor.deps.json",
    "content": "{\n  \"runtimeTarget\": {\n    \"name\": \".NETStandard,Version=v2.0/\",\n    \"signature\": \"\"\n  },\n  \"compilationOptions\": {},\n  \"targets\": {\n    \".NETStandard,Version=v2.0\": {},\n    \".NETStandard,Version=v2.0/\": {\n      \"ToSic.Razor/04.04.01\": {\n        \"dependencies\": {\n          \"Microsoft.AspNetCore.Html.Abstractions\": \"2.0.0\",\n          \"Microsoft.Extensions.DependencyInjection\": \"3.1.16\",\n          \"NETStandard.Library\": \"2.0.3\"\n        },\n        \"runtime\": {\n          \"ToSic.Razor.dll\": {}\n        }\n      },\n      \"Microsoft.AspNetCore.Html.Abstractions/2.0.0\": {\n        \"dependencies\": {\n          \"System.Text.Encodings.Web\": \"4.4.0\"\n        },\n        \"runtime\": {\n          \"lib/netstandard2.0/Microsoft.AspNetCore.Html.Abstractions.dll\": {\n            \"assemblyVersion\": \"2.0.0.0\",\n            \"fileVersion\": \"2.0.0.17205\"\n          }\n        }\n      },\n      \"Microsoft.Bcl.AsyncInterfaces/1.1.1\": {\n        \"dependencies\": {\n          \"System.Threading.Tasks.Extensions\": \"4.5.4\"\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection/3.1.16\": {\n        \"dependencies\": {\n          \"Microsoft.Bcl.AsyncInterfaces\": \"1.1.1\",\n          \"Microsoft.Extensions.DependencyInjection.Abstractions\": \"3.1.16\"\n        }\n      },\n      \"Microsoft.Extensions.DependencyInjection.Abstractions/3.1.16\": {},\n      \"Microsoft.NETCore.Platforms/1.1.0\": {},\n      \"NETStandard.Library/2.0.3\": {\n        \"dependencies\": {\n          \"Microsoft.NETCore.Platforms\": \"1.1.0\"\n        }\n      },\n      \"System.Runtime.CompilerServices.Unsafe/4.5.3\": {},\n      \"System.Text.Encodings.Web/4.4.0\": {\n        \"runtime\": {\n          \"lib/netstandard2.0/System.Text.Encodings.Web.dll\": {\n            \"assemblyVersion\": \"4.0.2.0\",\n            \"fileVersion\": \"4.6.25519.3\"\n          }\n        }\n      },\n      \"System.Threading.Tasks.Extensions/4.5.4\": {\n        \"dependencies\": {\n          \"System.Runtime.CompilerServices.Unsafe\": \"4.5.3\"\n        }\n      }\n    }\n  },\n  \"libraries\": {\n    \"ToSic.Razor/04.04.01\": {\n      \"type\": \"project\",\n      \"serviceable\": false,\n      \"sha512\": \"\"\n    },\n    \"Microsoft.AspNetCore.Html.Abstractions/2.0.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-Tdy0VkAnSeynmnbqF1JLchyPg5iQwmxTTG16byenoD2SXn/W8DR6HagZOZxvDb7gc4IerjdhIwuY8aV8nm7FAA==\",\n      \"path\": \"microsoft.aspnetcore.html.abstractions/2.0.0\",\n      \"hashPath\": \"microsoft.aspnetcore.html.abstractions.2.0.0.nupkg.sha512\"\n    },\n    \"Microsoft.Bcl.AsyncInterfaces/1.1.1\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-yuvf07qFWFqtK3P/MRkEKLhn5r2UbSpVueRziSqj0yJQIKFwG1pq9mOayK3zE5qZCTs0CbrwL9M6R8VwqyGy2w==\",\n      \"path\": \"microsoft.bcl.asyncinterfaces/1.1.1\",\n      \"hashPath\": \"microsoft.bcl.asyncinterfaces.1.1.1.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection/3.1.16\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-zgV27UpG5tc/oW23Gh4r6DA1biMvdPv/efcNVp25Cx7bDcdoP3/snrdH+dscaOyjXtiZtYXELN4cDlyIAvNO+g==\",\n      \"path\": \"microsoft.extensions.dependencyinjection/3.1.16\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.3.1.16.nupkg.sha512\"\n    },\n    \"Microsoft.Extensions.DependencyInjection.Abstractions/3.1.16\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-pFCBSw5MJiuucZAG+IrJLcQd4c7JIgc/7t6Mm6Q31wjEeamKQ+r7p1Aw21IHJm5KHqLNG/UdeaIt6ffullkC0Q==\",\n      \"path\": \"microsoft.extensions.dependencyinjection.abstractions/3.1.16\",\n      \"hashPath\": \"microsoft.extensions.dependencyinjection.abstractions.3.1.16.nupkg.sha512\"\n    },\n    \"Microsoft.NETCore.Platforms/1.1.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==\",\n      \"path\": \"microsoft.netcore.platforms/1.1.0\",\n      \"hashPath\": \"microsoft.netcore.platforms.1.1.0.nupkg.sha512\"\n    },\n    \"NETStandard.Library/2.0.3\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==\",\n      \"path\": \"netstandard.library/2.0.3\",\n      \"hashPath\": \"netstandard.library.2.0.3.nupkg.sha512\"\n    },\n    \"System.Runtime.CompilerServices.Unsafe/4.5.3\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-3TIsJhD1EiiT0w2CcDMN/iSSwnNnsrnbzeVHSKkaEgV85txMprmuO+Yq2AdSbeVGcg28pdNDTPK87tJhX7VFHw==\",\n      \"path\": \"system.runtime.compilerservices.unsafe/4.5.3\",\n      \"hashPath\": \"system.runtime.compilerservices.unsafe.4.5.3.nupkg.sha512\"\n    },\n    \"System.Text.Encodings.Web/4.4.0\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-l/tYeikqMHX2MD2jzrHDfR9ejrpTTF7wvAEbR51AMvzip1wSJgiURbDik4iv/w7ZgytmTD/hlwpplEhF9bmFNw==\",\n      \"path\": \"system.text.encodings.web/4.4.0\",\n      \"hashPath\": \"system.text.encodings.web.4.4.0.nupkg.sha512\"\n    },\n    \"System.Threading.Tasks.Extensions/4.5.4\": {\n      \"type\": \"package\",\n      \"serviceable\": true,\n      \"sha512\": \"sha512-zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==\",\n      \"path\": \"system.threading.tasks.extensions/4.5.4\",\n      \"hashPath\": \"system.threading.tasks.extensions.4.5.4.nupkg.sha512\"\n    }\n  }\n}"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 2sic Internet Solutions GmbH\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Src/.gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.sln.docstates\n.vs\n\n# Build results\n\n[Dd]ebug/\n[Rr]elease/\nx64/\nbuild/\n[Bb]in/\n[Oo]bj/\n\n# Enable \"build/\" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets\n!packages/*/build/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n*_i.c\n*_p.c\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.log\n*.scc\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n*.cachefile\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n\n# Windows Azure Build Output\ncsx\n*.build.csdef\n\n# Others\nClientBin/\n\n# =========================\n# Windows detritus\n# =========================\n\n# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# =========================\n# DNN Module\n# =========================\n\n# Ignore .manifest file created by DNN while installing the module\nResources.zip.manifest\n\n# Ignore ModulePackages\n/ModulePackages/\n\n/Upgrade/Log\n/Packages/\n/_/\n\n# include bin files from koi, razor blade, and old-razorblade\n!koi/bin/\n!razorblade/bin/\n!razorblade-old/bin/\n!Extensions/ImageResizer/bin/\n\n# Test data\n\\.data-custom/configurations/features.json\n.data-custom/contenttypes 2/\n\\.data-custom/configurations/**\n.data-custom/configurations/**\n\n\n\n# Assets\n# Normally we would place this in the assets folder, but then the .gitignore is included in the DNN bundle, so we have the rules here\n# exclude map files from dist and system\n# note that we want to keep the old angular maps\n# because they never change, and in case of emergencies they are only located here and not on sources\nAssets/dist/**/*.map\nAssets/system/**/*.map\nAssets/js/*.map\n"
  },
  {
    "path": "Src/2sxc Integration.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.28803.202\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Core\", \"..\\..\\eav-server\\ToSic.Eav.Core\\ToSic.Eav.Core.csproj\", \"{82F94588-269B-4CDD-98D1-D5CB14C39090}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Apps\", \"..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\", \"{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Tests\", \"Dnn.Tests\\ToSic.Sxc.Tests\\ToSic.Sxc.Tests.csproj\", \"{0EA1085A-D15F-4254-8A79-DE811C47EBF4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.DataSources\", \"..\\..\\eav-server\\ToSic.Eav.DataSources\\ToSic.Eav.DataSources.csproj\", \"{93149D23-E6CC-43AF-97D0-32D89D29D714}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Repository.Efc\", \"..\\..\\eav-server\\ToSic.Eav.Repository.Efc\\ToSic.Eav.Repository.Efc.csproj\", \"{CB322A0B-0C28-4165-87A8-7BBE78911451}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Persistence.Efc\", \"..\\..\\eav-server\\ToSic.Eav.Persistence.Efc\\ToSic.Eav.Persistence.Efc.csproj\", \"{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.ImportExport\", \"..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\", \"{1253087A-070D-4BF7-B3C2-841537489910}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav\", \"..\\..\\eav-server\\ToSic.Eav\\ToSic.Eav.csproj\", \"{892F9D3B-0578-46A1-A46A-B694A7E15669}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.WebApi\", \"..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\", \"{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc\", \"Sxc\\ToSic.Sxc\\ToSic.Sxc.csproj\", \"{5D87EB0C-BF67-4814-A0FF-D96256C9B852}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"2sxc Core\", \"2sxc Core\", \"{5CD8015A-76D8-4633-8469-53B62A6C1894}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Eav\", \"Eav\", \"{2DBCC960-1C0B-494F-9E21-8707A1D344C3}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.WebApi\", \"Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\", \"{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Mvc\", \"Mvc\", \"{F1366AA6-6508-47E4-AE39-CB39537CA220}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Mvc\", \"Mvc\\ToSic.Sxc.Mvc\\ToSic.Sxc.Mvc.csproj\", \"{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Website\", \"Mvc\\Website\\Website.csproj\", \"{28A58816-468A-44E0-85CA-0428F0D87E27}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Razor.Engine\", \"Razor\\ToSic.Sxc.Razor.Engine\\ToSic.Sxc.Razor.Engine.csproj\", \"{9269847A-20A1-4F72-9E14-36BFE0323632}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Hybrid\", \"Razor\\ToSic.Sxc.Hybrid\\ToSic.Sxc.Hybrid.csproj\", \"{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Razor\", \"Razor\", \"{DD59EAFD-02D1-4285-B8BE-D2DD40536304}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Integration\", \"Integration\", \"{783FE270-1D23-4B43-8B17-C87C0697DBD5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"BasicEav01\", \"Integration\\BasicEav01\\BasicEav01.csproj\", \"{7F370FB9-704B-400C-B907-F4D7B884006A}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SxcEdit01\", \"Integration\\SxcEdit01\\SxcEdit01.csproj\", \"{67672FFA-702D-423F-906E-5E6A6D6B9EFD}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|DNN = Debug|DNN\n\t\tDebug|Windows-x64 = Debug|Windows-x64\n\t\tDebug|Windows-x86 = Debug|Windows-x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|DNN = Release|DNN\n\t\tRelease|Windows-x64 = Release|Windows-x64\n\t\tRelease|Windows-x86 = Release|Windows-x86\n\t\tTesting|Any CPU = Testing|Any CPU\n\t\tTesting|DNN = Testing|DNN\n\t\tTesting|Windows-x64 = Testing|Windows-x64\n\t\tTesting|Windows-x86 = Testing|Windows-x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Any CPU.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|DNN.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|DNN.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Windows-x64.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Windows-x86.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Any CPU.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|DNN.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|DNN.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Windows-x64.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Windows-x86.Build.0 = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{1253087A-070D-4BF7-B3C2-841537489910} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E} = {F1366AA6-6508-47E4-AE39-CB39537CA220}\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27} = {F1366AA6-6508-47E4-AE39-CB39537CA220}\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632} = {DD59EAFD-02D1-4285-B8BE-D2DD40536304}\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A} = {DD59EAFD-02D1-4285-B8BE-D2DD40536304}\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A} = {783FE270-1D23-4B43-8B17-C87C0697DBD5}\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD} = {783FE270-1D23-4B43-8B17-C87C0697DBD5}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tEnterpriseLibraryConfigurationToolBinariesPath = packages\\Unity.2.1.505.2\\lib\\NET35;packages\\Unity.2.1.505.0\\lib\\NET35\n\t\tSolutionGuid = {705647E1-B5B1-4D94-888C-1D918095554C}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Src/2sxc Integration.sln.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=attrib/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=attribs/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Backends/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=desktopmodules/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=dont/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Guids/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=initializers/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Langs/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=polymorph/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Runtimes/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=sexycontent/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Storages/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=tosic/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=unsortable/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=versioning/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=wirings/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/2sxc Multi-Target Oqt510.sln.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Oqtane/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/2sxc Multi-Target.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 18\nVisualStudioVersion = 18.0.11217.181\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Apps\", \"..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\", \"{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Dnn.WebApi\", \"Dnn\\ToSic.Sxc.Dnn.WebApi\\ToSic.Sxc.Dnn.WebApi.csproj\", \"{8398FE44-7164-48CB-96CF-74BA9C270BD2}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Dnn.Razor\", \"Dnn\\ToSic.Sxc.Dnn.Razor\\ToSic.Sxc.Dnn.Razor.csproj\", \"{78A558AF-F274-4E3C-95FE-8DE9226E0EBC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Dnn\", \"Dnn\\ToSic.Sxc.Dnn\\ToSic.Sxc.Dnn.csproj\", \"{D4250011-B9BE-4326-9736-4F0122C79802}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Testing.Performance\", \"..\\..\\eav-server\\ToSic.Testing.Performance\\ToSic.Testing.Performance.csproj\", \"{6735DC37-2849-45DB-BA76-C5663B6FFB1F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Dnn.Core\", \"Dnn\\ToSic.Sxc.Dnn.Core\\ToSic.Sxc.Dnn.Core.csproj\", \"{A94DE6D7-D1E6-4BE2-B5B5-DC4A6A61CD80}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.WebApi.Tests\", \"Sxc\\ToSic.Sxc.WebApi.Tests\\ToSic.Sxc.WebApi.Tests.csproj\", \"{000D1ACB-7247-42CF-A86F-987A0AF68BA1}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.DataSources\", \"..\\..\\eav-server\\ToSic.Eav.DataSources\\ToSic.Eav.DataSources.csproj\", \"{93149D23-E6CC-43AF-97D0-32D89D29D714}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Repository.Efc\", \"..\\..\\eav-server\\ToSic.Eav.Repository.Efc\\ToSic.Eav.Repository.Efc.csproj\", \"{CB322A0B-0C28-4165-87A8-7BBE78911451}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Persistence.Efc\", \"..\\..\\eav-server\\ToSic.Eav.Persistence.Efc\\ToSic.Eav.Persistence.Efc.csproj\", \"{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.ImportExport\", \"..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\", \"{1253087A-070D-4BF7-B3C2-841537489910}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.WebApi\", \"..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\", \"{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Platform Dnn\", \"Platform Dnn\", \"{82831295-FA89-4F5A-9420-DB6E15A8AD99}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L3.3 Sxc.Services\", \"L3.3 Sxc.Services\", \"{5CD8015A-76D8-4633-8469-53B62A6C1894}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L2.1 Eav.Data\", \"L2.1 Eav.Data\", \"{2DBCC960-1C0B-494F-9E21-8707A1D344C3}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L2.4 Eav.DataSources\", \"L2.4 Eav.DataSources\", \"{6D320108-78ED-40E6-83F7-9CD423471DB3}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.WebApi\", \"Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\", \"{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Platform Mvc\", \"Platform Mvc\", \"{F1366AA6-6508-47E4-AE39-CB39537CA220}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Mvc\", \"Mvc\\ToSic.Sxc.Mvc\\ToSic.Sxc.Mvc.csproj\", \"{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Website\", \"Mvc\\Website\\Website.csproj\", \"{28A58816-468A-44E0-85CA-0428F0D87E27}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Platform Oqtane\", \"Platform Oqtane\", \"{C2BEB114-B1DB-404D-8442-A75809059619}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Oqt.Server\", \"Oqtane\\ToSic.Sxc.Oqt.Server\\ToSic.Sxc.Oqt.Server.csproj\", \"{8DDD9ECE-28B0-4714-AD1A-B24FEF0C6785}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Oqt.Client\", \"Oqtane\\ToSic.Sxc.Oqt.Client\\ToSic.Sxc.Oqt.Client.csproj\", \"{5D7BC881-21DD-4123-985E-BBFFD8D683F3}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Oqt.Shared\", \"Oqtane\\ToSic.Sxc.Oqt.Shared\\ToSic.Sxc.Oqt.Shared.csproj\", \"{4E24511B-CF81-4F93-AF8F-D41D306133E9}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Oqt.Package\", \"Oqtane\\ToSic.Sxc.Oqt.Package\\ToSic.Sxc.Oqt.Package.csproj\", \"{8885C3AD-A7D0-4725-BF28-23C55522083E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Oqtane.Server\", \"..\\..\\oqtane\\oqtane.framework\\Oqtane.Server\\Oqtane.Server.csproj\", \"{1F1C0F04-736D-4A4D-A324-8FCA8C373738}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Oqtane.Shared\", \"..\\..\\oqtane\\oqtane.framework\\Oqtane.Shared\\Oqtane.Shared.csproj\", \"{748C1FF5-D9A0-4F8D-A113-0D1C54791CE8}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Oqtane.Client\", \"..\\..\\oqtane\\oqtane.framework\\Oqtane.Client\\Oqtane.Client.csproj\", \"{62B0A822-C3ED-436E-A67B-8E99A7E89B24}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Razor\", \"Razor\\ToSic.Sxc.Razor\\ToSic.Sxc.Razor.csproj\", \"{9269847A-20A1-4F72-9E14-36BFE0323632}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Layer 4 - ToSic.Sxc.Razor (net core)\", \"Layer 4 - ToSic.Sxc.Razor (net core)\", \"{DD59EAFD-02D1-4285-B8BE-D2DD40536304}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Platform Integration Tests\", \"Platform Integration Tests\", \"{783FE270-1D23-4B43-8B17-C87C0697DBD5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"BasicEav01\", \"Integration\\BasicEav01\\BasicEav01.csproj\", \"{7F370FB9-704B-400C-B907-F4D7B884006A}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SxcEdit01\", \"Integration\\SxcEdit01\\SxcEdit01.csproj\", \"{67672FFA-702D-423F-906E-5E6A6D6B9EFD}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Oqt.Server.Tests\", \"Oqtane\\ToSic.Sxc.Oqt.Server.Tests\\ToSic.Sxc.Oqt.Server.Tests.csproj\", \"{4BCB31EB-A3F8-41A0-B8E9-FFF06CFDBBF0}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L1.1 Sys (Core)\", \"L1.1 Sys (Core)\", \"{32E45183-6A02-41A2-A4D5-6CB58A6D39A9}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sys.Core\", \"..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\", \"{BC93EFB1-D740-4617-9C90-D9167F9E4545}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L2.2 Eav.Persistence\", \"L2.2 Eav.Persistence\", \"{896200CD-54AF-462D-881C-0C7A43F0D6AF}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sys.Core.Tests\", \"..\\..\\eav-server\\ToSic.Sys.Core.Tests\\ToSic.Sys.Core.Tests.csproj\", \"{2B1FE78B-9BB5-4B7D-9409-B2B5A3BF85A8}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Oqtane (Framework)\", \"Oqtane (Framework)\", \"{C4B25918-A3FA-49E6-8CE1-BF2A41FC4F45}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"ZZ Build Tools for Visual Studio\", \"ZZ Build Tools for Visual Studio\", \"{B39F27D8-8D23-4FE4-8007-0A744BBD0645}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.BuildTasks\", \"Build\\ToSic.Sxc.BuildTasks\\ToSic.Sxc.BuildTasks.csproj\", \"{B8DC61F4-CA64-441E-8508-206F2432AADB}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Code.Generate\", \"Sxc\\ToSic.Sxc.Code.Generate\\ToSic.Sxc.Code.Generate.csproj\", \"{FB557EF7-8120-4B05-B250-7FA49916BBB4}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Core.Configuration.Tests\", \"Sxc\\ToSic.Sxc.Configuration.Tests\\ToSic.Sxc.Core.Configuration.Tests.csproj\", \"{FA7585D8-CF3A-4027-BAA8-88CB08F273BB}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.DI.Tests\", \"..\\..\\eav-server\\ToSic.Sys.DI.Tests\\ToSic.Sys.DI.Tests.csproj\", \"{1BAF0475-B349-44EC-907F-5F87E949D560}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Data.Tests\\ToSic.Eav.Data.Tests.csproj\", \"{AA955C7C-5D29-4125-85E3-557D254257C5}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.DataSource.TestHelpers\", \"..\\..\\eav-server\\ToSic.Eav.DataSource.TestHelpers\\ToSic.Eav.DataSource.TestHelpers.csproj\", \"{8F0F0A98-19C0-443A-9666-56F92A7B6BCE}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.DataSources.Tests\", \"..\\..\\eav-server\\ToSic.Eav.DataSources.Tests\\ToSic.Eav.DataSources.Tests.csproj\", \"{15640566-0ECA-4006-A55B-FDF53EAF7549}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.DataSource.DbTests\", \"..\\..\\eav-server\\ToSic.Eav.DataSource.DbTests\\ToSic.Eav.DataSource.DbTests.csproj\", \"{E221C1FB-CA6B-4B80-81BE-130F73D878AB}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Testing.FullDbFixtures\", \"..\\..\\eav-server\\ToSic.Eav.Testing.FullDbFixtures\\ToSic.Eav.Testing.FullDbFixtures.csproj\", \"{233738E3-515C-4EAD-BA80-D649BEF43255}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.StartupTests\", \"..\\..\\eav-server\\ToSic.Eav.StartupTests\\ToSic.Eav.StartupTests.csproj\", \"{8FA5D0CF-619F-4B2A-9BA7-0124B2C5F325}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Persistence.Efc.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Persistence.Efc.Tests\\ToSic.Eav.Persistence.Efc.Tests.csproj\", \"{DA2CF8DA-BD16-825E-CA43-EF69F2CBE95F}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Repository.Efc.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Repository.Efc.Tests\\ToSic.Eav.Repository.Efc.Tests.csproj\", \"{DBF7E808-4DB5-67DB-2D6B-A044BE3D81F1}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Apps.TestHelpers\", \"..\\..\\eav-server\\ToSic.Eav.Apps.TestsHelpers\\ToSic.Eav.Apps.TestHelpers.csproj\", \"{3D8DDAE5-E025-4917-8570-6B428A520B7D}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Apps.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Apps.Tests\\ToSic.Eav.Apps.Tests.csproj\", \"{F2582791-2A07-0F5F-836F-AA977F7A4169}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.ImportExport.Tests\", \"..\\..\\eav-server\\ToSic.Eav.ImportExport.Tests\\ToSic.Eav.ImportExport.Tests.csproj\", \"{DBD36AC0-D874-25CC-4618-2A848D5E6584}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Dnn.SystemTests\", \"Dnn\\ToSic.Sxc.Dnn.SystemTests\\ToSic.Sxc.Dnn.SystemTests.csproj\", \"{5CC076B6-F193-4954-8287-0B3DD547BB8C}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Oqt.Shared.Tests\", \"Oqtane\\ToSic.Sxc.Oqt.Shared.Tests\\ToSic.Sxc.Oqt.Shared.Tests.csproj\", \"{BE3193C4-61CC-479B-8B0E-604F22B7AFBC}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Utils\", \"..\\..\\eav-server\\ToSic.Sys.Utils\\ToSic.Sys.Utils.csproj\", \"{00E352CC-021D-4D44-8B64-D2574CABD949}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Code\", \"..\\..\\eav-server\\ToSic.Sys.Code\\ToSic.Sys.Code.csproj\", \"{918D4D29-AF04-47E6-8354-FA26B7CD50D1}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Features\", \"..\\..\\eav-server\\ToSic.Sys.Features\\ToSic.Sys.Features.csproj\", \"{21B6CF7B-9960-4565-A12C-410F87299621}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Features.Tests\", \"..\\..\\eav-server\\ToSic.Sys.Features.Tests\\ToSic.Sys.Features.Tests.csproj\", \"{B6FCFFF3-2832-4BEB-BB00-134F8F28B7F8}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Caching\", \"..\\..\\eav-server\\ToSic.Sys.Caching\\ToSic.Sys.Caching.csproj\", \"{F0B3DAEE-647E-4394-8493-B4436C988DA4}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L1.2 Sys.Abc and Lib.Xyz\", \"L1.2 Sys.Abc and Lib.Xyz\", \"{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Persistence\", \"..\\..\\eav-server\\ToSic.Eav.Persistence\\ToSic.Eav.Persistence.csproj\", \"{7F4F52EB-C9D8-4D80-BA3C-5C69C3531B73}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Security\", \"..\\..\\eav-server\\ToSic.Sys.Security\\ToSic.Sys.Security.csproj\", \"{D61F1F78-5B21-4123-9F95-6EF74BFD349B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data.Build\", \"..\\..\\eav-server\\ToSic.Eav.Data.Build\\ToSic.Eav.Data.Build.csproj\", \"{1A6E3BED-07A4-4FE7-868E-FDD322584559}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data.Build.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Data.BuildTests\\ToSic.Eav.Data.Build.Tests.csproj\", \"{67B8056E-542E-4236-B3C6-E5E2E97A7256}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Custom\", \"Sxc\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\", \"{E36C050F-0B20-D6DB-E59D-04E16BF967A2}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Code\", \"Sxc\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\", \"{7723AE83-8207-4689-94BC-FA3E6473C851}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Code.HotBuild\", \"Sxc\\ToSic.Sxc.Code.HotBuild\\ToSic.Sxc.Code.HotBuild.csproj\", \"{ED7E1D31-1124-4A9E-9FB2-FBCDA7928BA8}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Services\", \"Sxc\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\", \"{079C92D4-F250-4343-ACF0-4EBE567B0CBE}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Images\", \"Sxc\\ToSic.Sxc.Images\\ToSic.Sxc.Images.csproj\", \"{DA6E8814-3D50-485C-8687-ECD1C8D143A9}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Engines\", \"Sxc\\ToSic.Sxc.Engines\\ToSic.Sxc.Engines.csproj\", \"{238BADBB-E464-4865-A16B-89273C63193B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Blocks\", \"Sxc\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\", \"{ACA628BE-DD0B-41BE-B964-47DA6B1C8C36}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Cms\", \"Sxc\\ToSic.Sxc.Cms\\ToSic.Sxc.Cms.csproj\", \"{0938A266-FF63-459A-AFE7-FAFC3D0E4818}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Edit\", \"Sxc\\ToSic.Sxc.Edit\\ToSic.Sxc.Edit.csproj\", \"{5A485FF9-6DD9-4C3D-AB3F-41F0BA864853}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.LightSpeed\", \"Sxc\\ToSic.Sxc.LightSpeed\\ToSic.Sxc.LightSpeed.csproj\", \"{C8EFA3F1-A420-053C-3DF2-0E19B4781ECD}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Web\", \"Sxc\\ToSic.Sxc.Web\\ToSic.Sxc.Web.csproj\", \"{1755959F-9267-7500-91F3-72E0477F0532}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L3.1 Sxc (Core)\", \"L3.1 Sxc (Core)\", \"{94A758E0-FE77-4E90-8ACF-75DDDC6224B5}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Apps\", \"Sxc\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\", \"{06706A1F-6B97-5773-2786-48045DD25A9A}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Render\", \"Sxc\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\", \"{173D3C32-4964-3514-6733-7185517086AE}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Data\", \"Sxc\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\", \"{B7445FDD-EFFC-A31A-3437-E3F1A36B70E3}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Core\", \"Sxc\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\", \"{3C58BD36-EC9F-E653-B04E-50B6647E74D4}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Adam\", \"Sxc\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\", \"{52D56D1E-6F2F-0408-9BFD-0A910E39BEE9}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L3.2 Sxc (Data)\", \"L3.2 Sxc (Data)\", \"{8032CCCC-682E-45C3-8E4B-E2D91B63FEE5}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L3.4 Sxc.Code\", \"L3.4 Sxc.Code\", \"{EF5E7304-EC1C-456D-A2FD-B90E0299A6D1}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L3.4 Sxc.Web(Api)\", \"L3.4 Sxc.Web(Api)\", \"{2F9BC915-92B9-4973-A63E-59A05ADD4E88}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L2.9 Eav (Unified)\", \"L2.9 Eav (Unified)\", \"{25F1BD72-BA38-41C3-A24F-57110B544285}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L2.6 Eav.ImportExport and DB\", \"L2.6 Eav.ImportExport and DB\", \"{7A84A35D-E2AC-4A05-8751-B51B99EA0967}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Layer 1 - ToSic.Sys and ToSic.Lib\", \"Layer 1 - ToSic.Sys and ToSic.Lib\", \"{5F9A8C26-582F-445D-9D30-5ADAB64B92CB}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Platforms\", \"Platforms\", \"{336BFF22-E482-46F3-97EF-D8EEB07751AB}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Layer 2 - ToSic.Eav\", \"Layer 2 - ToSic.Eav\", \"{46C0FCB4-4589-42CA-8553-9647B1E58BED}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Layer 3 - ToSic.Sxc\", \"Layer 3 - ToSic.Sxc\", \"{1C7429F8-2815-4612-B5D0-3825E9A381E7}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L3.9 Sxc (Unified)\", \"L3.9 Sxc (Unified)\", \"{4A88BE0D-10C5-4CC0-9A43-C816F2AD752C}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Shared Imports (never build this)\", \"SharedImports\\Shared Imports (never build this).csproj\", \"{C7306F87-56EE-44C8-9D06-F4CBA43F08B2}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Various.UnitTests\", \"Sxc\\ToSic.Sxc.Various.UnitTests\\ToSic.Sxc.Various.UnitTests.csproj\", \"{DB0FC72C-CAE7-5A8A-7F3B-85110F241BAE}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Various.SystemTests\", \"Sxc\\ToSic.Sxc.Various.SystemTests\\ToSic.Sxc.Various.SystemTests.csproj\", \"{6448A662-EC17-8345-589E-0234EFF04CD8}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Core.TestHelpers\", \"Sxc\\ToSic.Sxc.Core.TestHelpers\\ToSic.Sxc.Core.TestHelpers.csproj\", \"{E4F112C9-2682-66B2-4B1E-39C3461377C6}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Shared Imports (never build this)\", \"..\\..\\eav-server\\SharedImports\\Shared Imports (never build this).csproj\", \"{DBAD0308-A4CB-4257-BC48-09C5C9CD389E}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L2.7 Eav.WebApi\", \"L2.7 Eav.WebApi\", \"{55799BAC-652D-4A04-96AC-FCD790A38260}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Work\", \"..\\..\\eav-server\\ToSic.Eav.Work\\ToSic.Eav.Work.csproj\", \"{857450DA-7712-16A6-71DD-79817FFD356D}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Utils.Tests\", \"..\\..\\eav-server\\ToSic.Sys.Utils.Tests\\ToSic.Sys.Utils.Tests.csproj\", \"{C87ACAFD-732A-FBC3-36FA-7038145AE3CD}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"L2.3 Eav.Apps\", \"L2.3 Eav.Apps\", \"{CC8DE3B4-BE02-45B9-BB26-30B4654DC5E2}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Apps.Persistence\", \"..\\..\\eav-server\\ToSic.Eav.Apps.Persistence\\ToSic.Eav.Apps.Persistence.csproj\", \"{167D5DF9-9712-4496-B00F-8E74AB5F8FA2}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Context\", \"..\\..\\eav-server\\ToSic.Eav.Context\\ToSic.Eav.Context.csproj\", \"{908DFB9A-8532-41CD-8153-D6BA5A209386}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Persistence.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Persistence.Tests\\ToSic.Eav.Persistence.Tests.csproj\", \"{2715DFC3-147E-4FF1-84FF-3413F945A3D2}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Apps.Persistence.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Apps.Persistence.Tests\\ToSic.Eav.Apps.Persistence.Tests.csproj\", \"{4974EA0B-2303-4BA4-B57E-EE69FA3F0089}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Work.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Work.Tests\\ToSic.Eav.Work.Tests.csproj\", \"{13865038-0CDD-4EDA-8573-45A14F71E50C}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Apps.Tests\", \"Sxc\\ToSic.Sxc.Apps.Tests\\ToSic.Sxc.Apps.Tests.csproj\", \"{BD2E35A4-6337-415E-A42F-C60BA90E3A04}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Insights\", \"..\\..\\eav-server\\ToSic.Eav.Insights\\ToSic.Eav.Insights.csproj\", \"{39C9141D-152F-4F73-AA4B-B7EBA876CA3B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data\", \"..\\..\\eav-server\\ToSic.Eav.Data\\ToSic.Eav.Data.csproj\", \"{13862C0A-B482-4DAB-8B63-B97E29A13566}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data.Stack\", \"..\\..\\eav-server\\ToSic.Eav.Data.Stack\\ToSic.Eav.Data.Stack.csproj\", \"{171AE0B3-0488-4500-97A2-8F4508CABE52}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data.Stack.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Data.Stack.Tests\\ToSic.Eav.Data.Stack.Tests.csproj\", \"{13515640-4870-4679-A7D1-185884ED26AF}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.DataSource\", \"..\\..\\eav-server\\ToSic.Eav.DataSource\\ToSic.Eav.DataSource.csproj\", \"{F036E03A-2A87-FC19-74E3-CCB015E2D619}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.LookUp\", \"..\\..\\eav-server\\ToSic.Eav.LookUp\\ToSic.Eav.LookUp.csproj\", \"{3ADABC34-DDE6-A2CB-77E8-49E888529E11}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.OData\", \"..\\..\\eav-server\\ToSic.Sys.OData\\ToSic.Sys.OData.csproj\", \"{6DA3B0B5-4EFD-4D9F-2352-757B776C17CF}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.OData.Tests\", \"..\\..\\eav-server\\ToSic.Sys.OData.Tests\\ToSic.Sys.OData.Tests.csproj\", \"{342A893E-B25F-628F-09C4-605EEFB3D879}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.WebApi.Tests\", \"..\\..\\eav-server\\ToSic.Eav.WebApi.Tests\\ToSic.Eav.WebApi.Tests.csproj\", \"{286F6C95-62FF-CCAB-EF67-DB6AADFB49E7}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.LookUp.Tests\", \"..\\..\\eav-server\\ToSic.Eav.LookUp.Tests\\ToSic.Eav.LookUp.Tests.csproj\", \"{DF78EFBE-9330-4DFE-9996-835147C6D609}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.LookUp.TestHelpers\", \"..\\..\\eav-server\\ToSic.Eav.LookUp.TestHelpers\\ToSic.Eav.LookUp.TestHelpers.csproj\", \"{6784F6B4-98EF-4476-B2A5-4CE6413BF086}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Caching.Tests\", \"..\\..\\eav-server\\ToSic.Sys.Caching.Tests\\ToSic.Sys.Caching.Tests.csproj\", \"{03B8F8AA-EA03-4A6E-8B58-C8A011A3900C}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data.TestHelpers\", \"..\\..\\eav-server\\ToSic.Eav.Data.TestHelpers\\ToSic.Eav.Data.TestHelpers.csproj\", \"{94D57C1A-C4E5-40AC-89E1-DE67D74E6750}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data.Build.TestHelpers\", \"..\\..\\eav-server\\ToSic.Eav.Data.Build.TestHelpers\\ToSic.Eav.Data.Build.TestHelpers.csproj\", \"{CDF835A4-766D-46CE-AD69-5A1D89A00A9C}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Features.TestHelpers\", \"..\\..\\eav-server\\ToSic.Sys.Features.TestHelpers\\ToSic.Sys.Features.TestHelpers.csproj\", \"{7B3BB702-5BEF-48EB-91A9-8E34D99F321E}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Data.TestsPostBuild\", \"..\\..\\eav-server\\ToSic.Eav.Data.TestsPostBuild\\ToSic.Eav.Data.TestsPostBuild.csproj\", \"{846B7A05-F8F0-48C1-8A17-28E9F2AD629B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.DataSource.Tests\", \"..\\..\\eav-server\\ToSic.Eav.DataSource.Tests\\ToSic.Eav.DataSource.Tests.csproj\", \"{679DA9D4-D38E-4F50-AA27-3A5F50A3ED58}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.TestHelpers\", \"..\\..\\eav-server\\ToSic.Sys.TestHelpers\\ToSic.Sys.TestHelpers.csproj\", \"{AA708E63-59DE-4677-B8ED-4E8549482B90}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sys.Security.TestHelpers\", \"..\\..\\eav-server\\ToSic.Sys.Security.TestHelpers\\ToSic.Sys.Security.TestHelpers.csproj\", \"{C386DA5C-248C-4B91-BB00-C083EC7914AA}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.RenderTests\", \"Sxc\\ToSic.Sxc.RenderTests\\ToSic.Sxc.RenderTests.csproj\", \"{82DC9B95-9015-4EF3-87A6-07848CB1D89E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tTesting|Any CPU = Testing|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8398FE44-7164-48CB-96CF-74BA9C270BD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8398FE44-7164-48CB-96CF-74BA9C270BD2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8398FE44-7164-48CB-96CF-74BA9C270BD2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8398FE44-7164-48CB-96CF-74BA9C270BD2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8398FE44-7164-48CB-96CF-74BA9C270BD2}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8398FE44-7164-48CB-96CF-74BA9C270BD2}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{78A558AF-F274-4E3C-95FE-8DE9226E0EBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{78A558AF-F274-4E3C-95FE-8DE9226E0EBC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{78A558AF-F274-4E3C-95FE-8DE9226E0EBC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{78A558AF-F274-4E3C-95FE-8DE9226E0EBC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{78A558AF-F274-4E3C-95FE-8DE9226E0EBC}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{78A558AF-F274-4E3C-95FE-8DE9226E0EBC}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D4250011-B9BE-4326-9736-4F0122C79802}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D4250011-B9BE-4326-9736-4F0122C79802}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D4250011-B9BE-4326-9736-4F0122C79802}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D4250011-B9BE-4326-9736-4F0122C79802}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{D4250011-B9BE-4326-9736-4F0122C79802}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D4250011-B9BE-4326-9736-4F0122C79802}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A94DE6D7-D1E6-4BE2-B5B5-DC4A6A61CD80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A94DE6D7-D1E6-4BE2-B5B5-DC4A6A61CD80}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A94DE6D7-D1E6-4BE2-B5B5-DC4A6A61CD80}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A94DE6D7-D1E6-4BE2-B5B5-DC4A6A61CD80}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A94DE6D7-D1E6-4BE2-B5B5-DC4A6A61CD80}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A94DE6D7-D1E6-4BE2-B5B5-DC4A6A61CD80}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{000D1ACB-7247-42CF-A86F-987A0AF68BA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{000D1ACB-7247-42CF-A86F-987A0AF68BA1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{000D1ACB-7247-42CF-A86F-987A0AF68BA1}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{000D1ACB-7247-42CF-A86F-987A0AF68BA1}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8DDD9ECE-28B0-4714-AD1A-B24FEF0C6785}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8DDD9ECE-28B0-4714-AD1A-B24FEF0C6785}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8DDD9ECE-28B0-4714-AD1A-B24FEF0C6785}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8DDD9ECE-28B0-4714-AD1A-B24FEF0C6785}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8DDD9ECE-28B0-4714-AD1A-B24FEF0C6785}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8DDD9ECE-28B0-4714-AD1A-B24FEF0C6785}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5D7BC881-21DD-4123-985E-BBFFD8D683F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5D7BC881-21DD-4123-985E-BBFFD8D683F3}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5D7BC881-21DD-4123-985E-BBFFD8D683F3}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5D7BC881-21DD-4123-985E-BBFFD8D683F3}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5D7BC881-21DD-4123-985E-BBFFD8D683F3}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5D7BC881-21DD-4123-985E-BBFFD8D683F3}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4E24511B-CF81-4F93-AF8F-D41D306133E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4E24511B-CF81-4F93-AF8F-D41D306133E9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4E24511B-CF81-4F93-AF8F-D41D306133E9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4E24511B-CF81-4F93-AF8F-D41D306133E9}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{4E24511B-CF81-4F93-AF8F-D41D306133E9}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4E24511B-CF81-4F93-AF8F-D41D306133E9}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8885C3AD-A7D0-4725-BF28-23C55522083E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8885C3AD-A7D0-4725-BF28-23C55522083E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8885C3AD-A7D0-4725-BF28-23C55522083E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8885C3AD-A7D0-4725-BF28-23C55522083E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8885C3AD-A7D0-4725-BF28-23C55522083E}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1F1C0F04-736D-4A4D-A324-8FCA8C373738}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1F1C0F04-736D-4A4D-A324-8FCA8C373738}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1F1C0F04-736D-4A4D-A324-8FCA8C373738}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{748C1FF5-D9A0-4F8D-A113-0D1C54791CE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{748C1FF5-D9A0-4F8D-A113-0D1C54791CE8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{748C1FF5-D9A0-4F8D-A113-0D1C54791CE8}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{62B0A822-C3ED-436E-A67B-8E99A7E89B24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{62B0A822-C3ED-436E-A67B-8E99A7E89B24}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{62B0A822-C3ED-436E-A67B-8E99A7E89B24}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4BCB31EB-A3F8-41A0-B8E9-FFF06CFDBBF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4BCB31EB-A3F8-41A0-B8E9-FFF06CFDBBF0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4BCB31EB-A3F8-41A0-B8E9-FFF06CFDBBF0}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4BCB31EB-A3F8-41A0-B8E9-FFF06CFDBBF0}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BC93EFB1-D740-4617-9C90-D9167F9E4545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BC93EFB1-D740-4617-9C90-D9167F9E4545}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BC93EFB1-D740-4617-9C90-D9167F9E4545}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BC93EFB1-D740-4617-9C90-D9167F9E4545}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{BC93EFB1-D740-4617-9C90-D9167F9E4545}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BC93EFB1-D740-4617-9C90-D9167F9E4545}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2B1FE78B-9BB5-4B7D-9409-B2B5A3BF85A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2B1FE78B-9BB5-4B7D-9409-B2B5A3BF85A8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2B1FE78B-9BB5-4B7D-9409-B2B5A3BF85A8}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2B1FE78B-9BB5-4B7D-9409-B2B5A3BF85A8}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B8DC61F4-CA64-441E-8508-206F2432AADB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B8DC61F4-CA64-441E-8508-206F2432AADB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B8DC61F4-CA64-441E-8508-206F2432AADB}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FB557EF7-8120-4B05-B250-7FA49916BBB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FB557EF7-8120-4B05-B250-7FA49916BBB4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FB557EF7-8120-4B05-B250-7FA49916BBB4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FB557EF7-8120-4B05-B250-7FA49916BBB4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{FB557EF7-8120-4B05-B250-7FA49916BBB4}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FB557EF7-8120-4B05-B250-7FA49916BBB4}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FA7585D8-CF3A-4027-BAA8-88CB08F273BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA7585D8-CF3A-4027-BAA8-88CB08F273BB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FA7585D8-CF3A-4027-BAA8-88CB08F273BB}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA7585D8-CF3A-4027-BAA8-88CB08F273BB}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1BAF0475-B349-44EC-907F-5F87E949D560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1BAF0475-B349-44EC-907F-5F87E949D560}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1BAF0475-B349-44EC-907F-5F87E949D560}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1BAF0475-B349-44EC-907F-5F87E949D560}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AA955C7C-5D29-4125-85E3-557D254257C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA955C7C-5D29-4125-85E3-557D254257C5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AA955C7C-5D29-4125-85E3-557D254257C5}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA955C7C-5D29-4125-85E3-557D254257C5}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8F0F0A98-19C0-443A-9666-56F92A7B6BCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8F0F0A98-19C0-443A-9666-56F92A7B6BCE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8F0F0A98-19C0-443A-9666-56F92A7B6BCE}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8F0F0A98-19C0-443A-9666-56F92A7B6BCE}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{15640566-0ECA-4006-A55B-FDF53EAF7549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{15640566-0ECA-4006-A55B-FDF53EAF7549}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{15640566-0ECA-4006-A55B-FDF53EAF7549}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{15640566-0ECA-4006-A55B-FDF53EAF7549}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E221C1FB-CA6B-4B80-81BE-130F73D878AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E221C1FB-CA6B-4B80-81BE-130F73D878AB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E221C1FB-CA6B-4B80-81BE-130F73D878AB}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E221C1FB-CA6B-4B80-81BE-130F73D878AB}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{233738E3-515C-4EAD-BA80-D649BEF43255}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{233738E3-515C-4EAD-BA80-D649BEF43255}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{233738E3-515C-4EAD-BA80-D649BEF43255}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{233738E3-515C-4EAD-BA80-D649BEF43255}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8FA5D0CF-619F-4B2A-9BA7-0124B2C5F325}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8FA5D0CF-619F-4B2A-9BA7-0124B2C5F325}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8FA5D0CF-619F-4B2A-9BA7-0124B2C5F325}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8FA5D0CF-619F-4B2A-9BA7-0124B2C5F325}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DA2CF8DA-BD16-825E-CA43-EF69F2CBE95F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DA2CF8DA-BD16-825E-CA43-EF69F2CBE95F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DA2CF8DA-BD16-825E-CA43-EF69F2CBE95F}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DA2CF8DA-BD16-825E-CA43-EF69F2CBE95F}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DBF7E808-4DB5-67DB-2D6B-A044BE3D81F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DBF7E808-4DB5-67DB-2D6B-A044BE3D81F1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DBF7E808-4DB5-67DB-2D6B-A044BE3D81F1}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DBF7E808-4DB5-67DB-2D6B-A044BE3D81F1}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3D8DDAE5-E025-4917-8570-6B428A520B7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3D8DDAE5-E025-4917-8570-6B428A520B7D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3D8DDAE5-E025-4917-8570-6B428A520B7D}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3D8DDAE5-E025-4917-8570-6B428A520B7D}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F2582791-2A07-0F5F-836F-AA977F7A4169}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F2582791-2A07-0F5F-836F-AA977F7A4169}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F2582791-2A07-0F5F-836F-AA977F7A4169}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F2582791-2A07-0F5F-836F-AA977F7A4169}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DBD36AC0-D874-25CC-4618-2A848D5E6584}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DBD36AC0-D874-25CC-4618-2A848D5E6584}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DBD36AC0-D874-25CC-4618-2A848D5E6584}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DBD36AC0-D874-25CC-4618-2A848D5E6584}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5CC076B6-F193-4954-8287-0B3DD547BB8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5CC076B6-F193-4954-8287-0B3DD547BB8C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5CC076B6-F193-4954-8287-0B3DD547BB8C}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5CC076B6-F193-4954-8287-0B3DD547BB8C}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BE3193C4-61CC-479B-8B0E-604F22B7AFBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BE3193C4-61CC-479B-8B0E-604F22B7AFBC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BE3193C4-61CC-479B-8B0E-604F22B7AFBC}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BE3193C4-61CC-479B-8B0E-604F22B7AFBC}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{00E352CC-021D-4D44-8B64-D2574CABD949}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{00E352CC-021D-4D44-8B64-D2574CABD949}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{00E352CC-021D-4D44-8B64-D2574CABD949}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{00E352CC-021D-4D44-8B64-D2574CABD949}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{00E352CC-021D-4D44-8B64-D2574CABD949}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{00E352CC-021D-4D44-8B64-D2574CABD949}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{918D4D29-AF04-47E6-8354-FA26B7CD50D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{918D4D29-AF04-47E6-8354-FA26B7CD50D1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{918D4D29-AF04-47E6-8354-FA26B7CD50D1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{918D4D29-AF04-47E6-8354-FA26B7CD50D1}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{918D4D29-AF04-47E6-8354-FA26B7CD50D1}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{918D4D29-AF04-47E6-8354-FA26B7CD50D1}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{21B6CF7B-9960-4565-A12C-410F87299621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{21B6CF7B-9960-4565-A12C-410F87299621}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{21B6CF7B-9960-4565-A12C-410F87299621}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{21B6CF7B-9960-4565-A12C-410F87299621}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{21B6CF7B-9960-4565-A12C-410F87299621}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{21B6CF7B-9960-4565-A12C-410F87299621}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B6FCFFF3-2832-4BEB-BB00-134F8F28B7F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B6FCFFF3-2832-4BEB-BB00-134F8F28B7F8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B6FCFFF3-2832-4BEB-BB00-134F8F28B7F8}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B6FCFFF3-2832-4BEB-BB00-134F8F28B7F8}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F0B3DAEE-647E-4394-8493-B4436C988DA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F0B3DAEE-647E-4394-8493-B4436C988DA4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F0B3DAEE-647E-4394-8493-B4436C988DA4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F0B3DAEE-647E-4394-8493-B4436C988DA4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F0B3DAEE-647E-4394-8493-B4436C988DA4}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F0B3DAEE-647E-4394-8493-B4436C988DA4}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7F4F52EB-C9D8-4D80-BA3C-5C69C3531B73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7F4F52EB-C9D8-4D80-BA3C-5C69C3531B73}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7F4F52EB-C9D8-4D80-BA3C-5C69C3531B73}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7F4F52EB-C9D8-4D80-BA3C-5C69C3531B73}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{7F4F52EB-C9D8-4D80-BA3C-5C69C3531B73}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7F4F52EB-C9D8-4D80-BA3C-5C69C3531B73}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D61F1F78-5B21-4123-9F95-6EF74BFD349B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D61F1F78-5B21-4123-9F95-6EF74BFD349B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D61F1F78-5B21-4123-9F95-6EF74BFD349B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D61F1F78-5B21-4123-9F95-6EF74BFD349B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{D61F1F78-5B21-4123-9F95-6EF74BFD349B}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D61F1F78-5B21-4123-9F95-6EF74BFD349B}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1A6E3BED-07A4-4FE7-868E-FDD322584559}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1A6E3BED-07A4-4FE7-868E-FDD322584559}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1A6E3BED-07A4-4FE7-868E-FDD322584559}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1A6E3BED-07A4-4FE7-868E-FDD322584559}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1A6E3BED-07A4-4FE7-868E-FDD322584559}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1A6E3BED-07A4-4FE7-868E-FDD322584559}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{67B8056E-542E-4236-B3C6-E5E2E97A7256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{67B8056E-542E-4236-B3C6-E5E2E97A7256}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{67B8056E-542E-4236-B3C6-E5E2E97A7256}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{67B8056E-542E-4236-B3C6-E5E2E97A7256}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E36C050F-0B20-D6DB-E59D-04E16BF967A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E36C050F-0B20-D6DB-E59D-04E16BF967A2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E36C050F-0B20-D6DB-E59D-04E16BF967A2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E36C050F-0B20-D6DB-E59D-04E16BF967A2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E36C050F-0B20-D6DB-E59D-04E16BF967A2}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E36C050F-0B20-D6DB-E59D-04E16BF967A2}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7723AE83-8207-4689-94BC-FA3E6473C851}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7723AE83-8207-4689-94BC-FA3E6473C851}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7723AE83-8207-4689-94BC-FA3E6473C851}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7723AE83-8207-4689-94BC-FA3E6473C851}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{7723AE83-8207-4689-94BC-FA3E6473C851}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7723AE83-8207-4689-94BC-FA3E6473C851}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ED7E1D31-1124-4A9E-9FB2-FBCDA7928BA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ED7E1D31-1124-4A9E-9FB2-FBCDA7928BA8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ED7E1D31-1124-4A9E-9FB2-FBCDA7928BA8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ED7E1D31-1124-4A9E-9FB2-FBCDA7928BA8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ED7E1D31-1124-4A9E-9FB2-FBCDA7928BA8}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ED7E1D31-1124-4A9E-9FB2-FBCDA7928BA8}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{079C92D4-F250-4343-ACF0-4EBE567B0CBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{079C92D4-F250-4343-ACF0-4EBE567B0CBE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{079C92D4-F250-4343-ACF0-4EBE567B0CBE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{079C92D4-F250-4343-ACF0-4EBE567B0CBE}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{079C92D4-F250-4343-ACF0-4EBE567B0CBE}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{079C92D4-F250-4343-ACF0-4EBE567B0CBE}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DA6E8814-3D50-485C-8687-ECD1C8D143A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DA6E8814-3D50-485C-8687-ECD1C8D143A9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DA6E8814-3D50-485C-8687-ECD1C8D143A9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DA6E8814-3D50-485C-8687-ECD1C8D143A9}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DA6E8814-3D50-485C-8687-ECD1C8D143A9}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DA6E8814-3D50-485C-8687-ECD1C8D143A9}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{238BADBB-E464-4865-A16B-89273C63193B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{238BADBB-E464-4865-A16B-89273C63193B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{238BADBB-E464-4865-A16B-89273C63193B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{238BADBB-E464-4865-A16B-89273C63193B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{238BADBB-E464-4865-A16B-89273C63193B}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{238BADBB-E464-4865-A16B-89273C63193B}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ACA628BE-DD0B-41BE-B964-47DA6B1C8C36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ACA628BE-DD0B-41BE-B964-47DA6B1C8C36}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ACA628BE-DD0B-41BE-B964-47DA6B1C8C36}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ACA628BE-DD0B-41BE-B964-47DA6B1C8C36}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ACA628BE-DD0B-41BE-B964-47DA6B1C8C36}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ACA628BE-DD0B-41BE-B964-47DA6B1C8C36}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0938A266-FF63-459A-AFE7-FAFC3D0E4818}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0938A266-FF63-459A-AFE7-FAFC3D0E4818}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0938A266-FF63-459A-AFE7-FAFC3D0E4818}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0938A266-FF63-459A-AFE7-FAFC3D0E4818}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0938A266-FF63-459A-AFE7-FAFC3D0E4818}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0938A266-FF63-459A-AFE7-FAFC3D0E4818}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5A485FF9-6DD9-4C3D-AB3F-41F0BA864853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5A485FF9-6DD9-4C3D-AB3F-41F0BA864853}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5A485FF9-6DD9-4C3D-AB3F-41F0BA864853}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5A485FF9-6DD9-4C3D-AB3F-41F0BA864853}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5A485FF9-6DD9-4C3D-AB3F-41F0BA864853}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5A485FF9-6DD9-4C3D-AB3F-41F0BA864853}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C8EFA3F1-A420-053C-3DF2-0E19B4781ECD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C8EFA3F1-A420-053C-3DF2-0E19B4781ECD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C8EFA3F1-A420-053C-3DF2-0E19B4781ECD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C8EFA3F1-A420-053C-3DF2-0E19B4781ECD}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C8EFA3F1-A420-053C-3DF2-0E19B4781ECD}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C8EFA3F1-A420-053C-3DF2-0E19B4781ECD}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1755959F-9267-7500-91F3-72E0477F0532}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1755959F-9267-7500-91F3-72E0477F0532}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1755959F-9267-7500-91F3-72E0477F0532}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1755959F-9267-7500-91F3-72E0477F0532}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1755959F-9267-7500-91F3-72E0477F0532}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1755959F-9267-7500-91F3-72E0477F0532}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{06706A1F-6B97-5773-2786-48045DD25A9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{06706A1F-6B97-5773-2786-48045DD25A9A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{06706A1F-6B97-5773-2786-48045DD25A9A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{06706A1F-6B97-5773-2786-48045DD25A9A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{06706A1F-6B97-5773-2786-48045DD25A9A}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{06706A1F-6B97-5773-2786-48045DD25A9A}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{173D3C32-4964-3514-6733-7185517086AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{173D3C32-4964-3514-6733-7185517086AE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{173D3C32-4964-3514-6733-7185517086AE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{173D3C32-4964-3514-6733-7185517086AE}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{173D3C32-4964-3514-6733-7185517086AE}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{173D3C32-4964-3514-6733-7185517086AE}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B7445FDD-EFFC-A31A-3437-E3F1A36B70E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B7445FDD-EFFC-A31A-3437-E3F1A36B70E3}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B7445FDD-EFFC-A31A-3437-E3F1A36B70E3}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B7445FDD-EFFC-A31A-3437-E3F1A36B70E3}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B7445FDD-EFFC-A31A-3437-E3F1A36B70E3}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B7445FDD-EFFC-A31A-3437-E3F1A36B70E3}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3C58BD36-EC9F-E653-B04E-50B6647E74D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3C58BD36-EC9F-E653-B04E-50B6647E74D4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3C58BD36-EC9F-E653-B04E-50B6647E74D4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3C58BD36-EC9F-E653-B04E-50B6647E74D4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3C58BD36-EC9F-E653-B04E-50B6647E74D4}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3C58BD36-EC9F-E653-B04E-50B6647E74D4}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{52D56D1E-6F2F-0408-9BFD-0A910E39BEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{52D56D1E-6F2F-0408-9BFD-0A910E39BEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{52D56D1E-6F2F-0408-9BFD-0A910E39BEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{52D56D1E-6F2F-0408-9BFD-0A910E39BEE9}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{52D56D1E-6F2F-0408-9BFD-0A910E39BEE9}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{52D56D1E-6F2F-0408-9BFD-0A910E39BEE9}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C7306F87-56EE-44C8-9D06-F4CBA43F08B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C7306F87-56EE-44C8-9D06-F4CBA43F08B2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C7306F87-56EE-44C8-9D06-F4CBA43F08B2}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DB0FC72C-CAE7-5A8A-7F3B-85110F241BAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DB0FC72C-CAE7-5A8A-7F3B-85110F241BAE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DB0FC72C-CAE7-5A8A-7F3B-85110F241BAE}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DB0FC72C-CAE7-5A8A-7F3B-85110F241BAE}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6448A662-EC17-8345-589E-0234EFF04CD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6448A662-EC17-8345-589E-0234EFF04CD8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6448A662-EC17-8345-589E-0234EFF04CD8}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6448A662-EC17-8345-589E-0234EFF04CD8}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E4F112C9-2682-66B2-4B1E-39C3461377C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E4F112C9-2682-66B2-4B1E-39C3461377C6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E4F112C9-2682-66B2-4B1E-39C3461377C6}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E4F112C9-2682-66B2-4B1E-39C3461377C6}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DBAD0308-A4CB-4257-BC48-09C5C9CD389E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DBAD0308-A4CB-4257-BC48-09C5C9CD389E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DBAD0308-A4CB-4257-BC48-09C5C9CD389E}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{857450DA-7712-16A6-71DD-79817FFD356D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{857450DA-7712-16A6-71DD-79817FFD356D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{857450DA-7712-16A6-71DD-79817FFD356D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{857450DA-7712-16A6-71DD-79817FFD356D}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{857450DA-7712-16A6-71DD-79817FFD356D}.Testing|Any CPU.ActiveCfg = Testing|Any CPU\n\t\t{857450DA-7712-16A6-71DD-79817FFD356D}.Testing|Any CPU.Build.0 = Testing|Any CPU\n\t\t{C87ACAFD-732A-FBC3-36FA-7038145AE3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C87ACAFD-732A-FBC3-36FA-7038145AE3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C87ACAFD-732A-FBC3-36FA-7038145AE3CD}.Testing|Any CPU.ActiveCfg = Testing|Any CPU\n\t\t{C87ACAFD-732A-FBC3-36FA-7038145AE3CD}.Testing|Any CPU.Build.0 = Testing|Any CPU\n\t\t{167D5DF9-9712-4496-B00F-8E74AB5F8FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{167D5DF9-9712-4496-B00F-8E74AB5F8FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{167D5DF9-9712-4496-B00F-8E74AB5F8FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{167D5DF9-9712-4496-B00F-8E74AB5F8FA2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{167D5DF9-9712-4496-B00F-8E74AB5F8FA2}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{167D5DF9-9712-4496-B00F-8E74AB5F8FA2}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{908DFB9A-8532-41CD-8153-D6BA5A209386}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{908DFB9A-8532-41CD-8153-D6BA5A209386}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{908DFB9A-8532-41CD-8153-D6BA5A209386}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{908DFB9A-8532-41CD-8153-D6BA5A209386}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{908DFB9A-8532-41CD-8153-D6BA5A209386}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{908DFB9A-8532-41CD-8153-D6BA5A209386}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2715DFC3-147E-4FF1-84FF-3413F945A3D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2715DFC3-147E-4FF1-84FF-3413F945A3D2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2715DFC3-147E-4FF1-84FF-3413F945A3D2}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2715DFC3-147E-4FF1-84FF-3413F945A3D2}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4974EA0B-2303-4BA4-B57E-EE69FA3F0089}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4974EA0B-2303-4BA4-B57E-EE69FA3F0089}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4974EA0B-2303-4BA4-B57E-EE69FA3F0089}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4974EA0B-2303-4BA4-B57E-EE69FA3F0089}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{13865038-0CDD-4EDA-8573-45A14F71E50C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{13865038-0CDD-4EDA-8573-45A14F71E50C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{13865038-0CDD-4EDA-8573-45A14F71E50C}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{13865038-0CDD-4EDA-8573-45A14F71E50C}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BD2E35A4-6337-415E-A42F-C60BA90E3A04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BD2E35A4-6337-415E-A42F-C60BA90E3A04}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BD2E35A4-6337-415E-A42F-C60BA90E3A04}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BD2E35A4-6337-415E-A42F-C60BA90E3A04}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{39C9141D-152F-4F73-AA4B-B7EBA876CA3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{39C9141D-152F-4F73-AA4B-B7EBA876CA3B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{39C9141D-152F-4F73-AA4B-B7EBA876CA3B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{39C9141D-152F-4F73-AA4B-B7EBA876CA3B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{39C9141D-152F-4F73-AA4B-B7EBA876CA3B}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{39C9141D-152F-4F73-AA4B-B7EBA876CA3B}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{13862C0A-B482-4DAB-8B63-B97E29A13566}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{13862C0A-B482-4DAB-8B63-B97E29A13566}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{13862C0A-B482-4DAB-8B63-B97E29A13566}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{13862C0A-B482-4DAB-8B63-B97E29A13566}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{13862C0A-B482-4DAB-8B63-B97E29A13566}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{13862C0A-B482-4DAB-8B63-B97E29A13566}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{171AE0B3-0488-4500-97A2-8F4508CABE52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{171AE0B3-0488-4500-97A2-8F4508CABE52}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{171AE0B3-0488-4500-97A2-8F4508CABE52}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{171AE0B3-0488-4500-97A2-8F4508CABE52}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{171AE0B3-0488-4500-97A2-8F4508CABE52}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{171AE0B3-0488-4500-97A2-8F4508CABE52}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{13515640-4870-4679-A7D1-185884ED26AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{13515640-4870-4679-A7D1-185884ED26AF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{13515640-4870-4679-A7D1-185884ED26AF}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{13515640-4870-4679-A7D1-185884ED26AF}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F036E03A-2A87-FC19-74E3-CCB015E2D619}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F036E03A-2A87-FC19-74E3-CCB015E2D619}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F036E03A-2A87-FC19-74E3-CCB015E2D619}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F036E03A-2A87-FC19-74E3-CCB015E2D619}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F036E03A-2A87-FC19-74E3-CCB015E2D619}.Testing|Any CPU.ActiveCfg = Testing|Any CPU\n\t\t{F036E03A-2A87-FC19-74E3-CCB015E2D619}.Testing|Any CPU.Build.0 = Testing|Any CPU\n\t\t{3ADABC34-DDE6-A2CB-77E8-49E888529E11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3ADABC34-DDE6-A2CB-77E8-49E888529E11}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3ADABC34-DDE6-A2CB-77E8-49E888529E11}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3ADABC34-DDE6-A2CB-77E8-49E888529E11}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3ADABC34-DDE6-A2CB-77E8-49E888529E11}.Testing|Any CPU.ActiveCfg = Testing|Any CPU\n\t\t{3ADABC34-DDE6-A2CB-77E8-49E888529E11}.Testing|Any CPU.Build.0 = Testing|Any CPU\n\t\t{6DA3B0B5-4EFD-4D9F-2352-757B776C17CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6DA3B0B5-4EFD-4D9F-2352-757B776C17CF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6DA3B0B5-4EFD-4D9F-2352-757B776C17CF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6DA3B0B5-4EFD-4D9F-2352-757B776C17CF}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6DA3B0B5-4EFD-4D9F-2352-757B776C17CF}.Testing|Any CPU.ActiveCfg = Testing|Any CPU\n\t\t{6DA3B0B5-4EFD-4D9F-2352-757B776C17CF}.Testing|Any CPU.Build.0 = Testing|Any CPU\n\t\t{342A893E-B25F-628F-09C4-605EEFB3D879}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{342A893E-B25F-628F-09C4-605EEFB3D879}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{342A893E-B25F-628F-09C4-605EEFB3D879}.Testing|Any CPU.ActiveCfg = Testing|Any CPU\n\t\t{342A893E-B25F-628F-09C4-605EEFB3D879}.Testing|Any CPU.Build.0 = Testing|Any CPU\n\t\t{286F6C95-62FF-CCAB-EF67-DB6AADFB49E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{286F6C95-62FF-CCAB-EF67-DB6AADFB49E7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{286F6C95-62FF-CCAB-EF67-DB6AADFB49E7}.Testing|Any CPU.ActiveCfg = Testing|Any CPU\n\t\t{286F6C95-62FF-CCAB-EF67-DB6AADFB49E7}.Testing|Any CPU.Build.0 = Testing|Any CPU\n\t\t{DF78EFBE-9330-4DFE-9996-835147C6D609}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DF78EFBE-9330-4DFE-9996-835147C6D609}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DF78EFBE-9330-4DFE-9996-835147C6D609}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DF78EFBE-9330-4DFE-9996-835147C6D609}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6784F6B4-98EF-4476-B2A5-4CE6413BF086}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6784F6B4-98EF-4476-B2A5-4CE6413BF086}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6784F6B4-98EF-4476-B2A5-4CE6413BF086}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6784F6B4-98EF-4476-B2A5-4CE6413BF086}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{03B8F8AA-EA03-4A6E-8B58-C8A011A3900C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{03B8F8AA-EA03-4A6E-8B58-C8A011A3900C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{03B8F8AA-EA03-4A6E-8B58-C8A011A3900C}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{03B8F8AA-EA03-4A6E-8B58-C8A011A3900C}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{94D57C1A-C4E5-40AC-89E1-DE67D74E6750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{94D57C1A-C4E5-40AC-89E1-DE67D74E6750}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{94D57C1A-C4E5-40AC-89E1-DE67D74E6750}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{94D57C1A-C4E5-40AC-89E1-DE67D74E6750}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CDF835A4-766D-46CE-AD69-5A1D89A00A9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CDF835A4-766D-46CE-AD69-5A1D89A00A9C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CDF835A4-766D-46CE-AD69-5A1D89A00A9C}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CDF835A4-766D-46CE-AD69-5A1D89A00A9C}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7B3BB702-5BEF-48EB-91A9-8E34D99F321E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7B3BB702-5BEF-48EB-91A9-8E34D99F321E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7B3BB702-5BEF-48EB-91A9-8E34D99F321E}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7B3BB702-5BEF-48EB-91A9-8E34D99F321E}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{846B7A05-F8F0-48C1-8A17-28E9F2AD629B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{846B7A05-F8F0-48C1-8A17-28E9F2AD629B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{846B7A05-F8F0-48C1-8A17-28E9F2AD629B}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{846B7A05-F8F0-48C1-8A17-28E9F2AD629B}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{679DA9D4-D38E-4F50-AA27-3A5F50A3ED58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{679DA9D4-D38E-4F50-AA27-3A5F50A3ED58}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{679DA9D4-D38E-4F50-AA27-3A5F50A3ED58}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{679DA9D4-D38E-4F50-AA27-3A5F50A3ED58}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AA708E63-59DE-4677-B8ED-4E8549482B90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA708E63-59DE-4677-B8ED-4E8549482B90}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AA708E63-59DE-4677-B8ED-4E8549482B90}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA708E63-59DE-4677-B8ED-4E8549482B90}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C386DA5C-248C-4B91-BB00-C083EC7914AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C386DA5C-248C-4B91-BB00-C083EC7914AA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C386DA5C-248C-4B91-BB00-C083EC7914AA}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C386DA5C-248C-4B91-BB00-C083EC7914AA}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{82DC9B95-9015-4EF3-87A6-07848CB1D89E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{82DC9B95-9015-4EF3-87A6-07848CB1D89E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{82DC9B95-9015-4EF3-87A6-07848CB1D89E}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{82DC9B95-9015-4EF3-87A6-07848CB1D89E}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2} = {CC8DE3B4-BE02-45B9-BB26-30B4654DC5E2}\n\t\t{8398FE44-7164-48CB-96CF-74BA9C270BD2} = {82831295-FA89-4F5A-9420-DB6E15A8AD99}\n\t\t{78A558AF-F274-4E3C-95FE-8DE9226E0EBC} = {82831295-FA89-4F5A-9420-DB6E15A8AD99}\n\t\t{D4250011-B9BE-4326-9736-4F0122C79802} = {82831295-FA89-4F5A-9420-DB6E15A8AD99}\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F} = {25F1BD72-BA38-41C3-A24F-57110B544285}\n\t\t{A94DE6D7-D1E6-4BE2-B5B5-DC4A6A61CD80} = {82831295-FA89-4F5A-9420-DB6E15A8AD99}\n\t\t{000D1ACB-7247-42CF-A86F-987A0AF68BA1} = {2F9BC915-92B9-4973-A63E-59A05ADD4E88}\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451} = {7A84A35D-E2AC-4A05-8751-B51B99EA0967}\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B} = {7A84A35D-E2AC-4A05-8751-B51B99EA0967}\n\t\t{1253087A-070D-4BF7-B3C2-841537489910} = {7A84A35D-E2AC-4A05-8751-B51B99EA0967}\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52} = {55799BAC-652D-4A04-96AC-FCD790A38260}\n\t\t{82831295-FA89-4F5A-9420-DB6E15A8AD99} = {336BFF22-E482-46F3-97EF-D8EEB07751AB}\n\t\t{5CD8015A-76D8-4633-8469-53B62A6C1894} = {1C7429F8-2815-4612-B5D0-3825E9A381E7}\n\t\t{2DBCC960-1C0B-494F-9E21-8707A1D344C3} = {46C0FCB4-4589-42CA-8553-9647B1E58BED}\n\t\t{6D320108-78ED-40E6-83F7-9CD423471DB3} = {46C0FCB4-4589-42CA-8553-9647B1E58BED}\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354} = {2F9BC915-92B9-4973-A63E-59A05ADD4E88}\n\t\t{F1366AA6-6508-47E4-AE39-CB39537CA220} = {336BFF22-E482-46F3-97EF-D8EEB07751AB}\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E} = {F1366AA6-6508-47E4-AE39-CB39537CA220}\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27} = {F1366AA6-6508-47E4-AE39-CB39537CA220}\n\t\t{C2BEB114-B1DB-404D-8442-A75809059619} = {336BFF22-E482-46F3-97EF-D8EEB07751AB}\n\t\t{8DDD9ECE-28B0-4714-AD1A-B24FEF0C6785} = {C2BEB114-B1DB-404D-8442-A75809059619}\n\t\t{5D7BC881-21DD-4123-985E-BBFFD8D683F3} = {C2BEB114-B1DB-404D-8442-A75809059619}\n\t\t{4E24511B-CF81-4F93-AF8F-D41D306133E9} = {C2BEB114-B1DB-404D-8442-A75809059619}\n\t\t{8885C3AD-A7D0-4725-BF28-23C55522083E} = {C2BEB114-B1DB-404D-8442-A75809059619}\n\t\t{1F1C0F04-736D-4A4D-A324-8FCA8C373738} = {C4B25918-A3FA-49E6-8CE1-BF2A41FC4F45}\n\t\t{748C1FF5-D9A0-4F8D-A113-0D1C54791CE8} = {C4B25918-A3FA-49E6-8CE1-BF2A41FC4F45}\n\t\t{62B0A822-C3ED-436E-A67B-8E99A7E89B24} = {C4B25918-A3FA-49E6-8CE1-BF2A41FC4F45}\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632} = {DD59EAFD-02D1-4285-B8BE-D2DD40536304}\n\t\t{783FE270-1D23-4B43-8B17-C87C0697DBD5} = {336BFF22-E482-46F3-97EF-D8EEB07751AB}\n\t\t{7F370FB9-704B-400C-B907-F4D7B884006A} = {783FE270-1D23-4B43-8B17-C87C0697DBD5}\n\t\t{67672FFA-702D-423F-906E-5E6A6D6B9EFD} = {783FE270-1D23-4B43-8B17-C87C0697DBD5}\n\t\t{4BCB31EB-A3F8-41A0-B8E9-FFF06CFDBBF0} = {C2BEB114-B1DB-404D-8442-A75809059619}\n\t\t{32E45183-6A02-41A2-A4D5-6CB58A6D39A9} = {5F9A8C26-582F-445D-9D30-5ADAB64B92CB}\n\t\t{BC93EFB1-D740-4617-9C90-D9167F9E4545} = {32E45183-6A02-41A2-A4D5-6CB58A6D39A9}\n\t\t{896200CD-54AF-462D-881C-0C7A43F0D6AF} = {46C0FCB4-4589-42CA-8553-9647B1E58BED}\n\t\t{2B1FE78B-9BB5-4B7D-9409-B2B5A3BF85A8} = {32E45183-6A02-41A2-A4D5-6CB58A6D39A9}\n\t\t{C4B25918-A3FA-49E6-8CE1-BF2A41FC4F45} = {C2BEB114-B1DB-404D-8442-A75809059619}\n\t\t{B8DC61F4-CA64-441E-8508-206F2432AADB} = {B39F27D8-8D23-4FE4-8007-0A744BBD0645}\n\t\t{FB557EF7-8120-4B05-B250-7FA49916BBB4} = {EF5E7304-EC1C-456D-A2FD-B90E0299A6D1}\n\t\t{FA7585D8-CF3A-4027-BAA8-88CB08F273BB} = {94A758E0-FE77-4E90-8ACF-75DDDC6224B5}\n\t\t{1BAF0475-B349-44EC-907F-5F87E949D560} = {32E45183-6A02-41A2-A4D5-6CB58A6D39A9}\n\t\t{AA955C7C-5D29-4125-85E3-557D254257C5} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{8F0F0A98-19C0-443A-9666-56F92A7B6BCE} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{15640566-0ECA-4006-A55B-FDF53EAF7549} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{E221C1FB-CA6B-4B80-81BE-130F73D878AB} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{233738E3-515C-4EAD-BA80-D649BEF43255} = {7A84A35D-E2AC-4A05-8751-B51B99EA0967}\n\t\t{8FA5D0CF-619F-4B2A-9BA7-0124B2C5F325} = {25F1BD72-BA38-41C3-A24F-57110B544285}\n\t\t{DA2CF8DA-BD16-825E-CA43-EF69F2CBE95F} = {7A84A35D-E2AC-4A05-8751-B51B99EA0967}\n\t\t{DBF7E808-4DB5-67DB-2D6B-A044BE3D81F1} = {7A84A35D-E2AC-4A05-8751-B51B99EA0967}\n\t\t{3D8DDAE5-E025-4917-8570-6B428A520B7D} = {CC8DE3B4-BE02-45B9-BB26-30B4654DC5E2}\n\t\t{F2582791-2A07-0F5F-836F-AA977F7A4169} = {CC8DE3B4-BE02-45B9-BB26-30B4654DC5E2}\n\t\t{DBD36AC0-D874-25CC-4618-2A848D5E6584} = {7A84A35D-E2AC-4A05-8751-B51B99EA0967}\n\t\t{5CC076B6-F193-4954-8287-0B3DD547BB8C} = {82831295-FA89-4F5A-9420-DB6E15A8AD99}\n\t\t{BE3193C4-61CC-479B-8B0E-604F22B7AFBC} = {C2BEB114-B1DB-404D-8442-A75809059619}\n\t\t{00E352CC-021D-4D44-8B64-D2574CABD949} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{918D4D29-AF04-47E6-8354-FA26B7CD50D1} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{21B6CF7B-9960-4565-A12C-410F87299621} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{B6FCFFF3-2832-4BEB-BB00-134F8F28B7F8} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{F0B3DAEE-647E-4394-8493-B4436C988DA4} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {5F9A8C26-582F-445D-9D30-5ADAB64B92CB}\n\t\t{7F4F52EB-C9D8-4D80-BA3C-5C69C3531B73} = {896200CD-54AF-462D-881C-0C7A43F0D6AF}\n\t\t{D61F1F78-5B21-4123-9F95-6EF74BFD349B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{1A6E3BED-07A4-4FE7-868E-FDD322584559} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{67B8056E-542E-4236-B3C6-E5E2E97A7256} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{E36C050F-0B20-D6DB-E59D-04E16BF967A2} = {EF5E7304-EC1C-456D-A2FD-B90E0299A6D1}\n\t\t{7723AE83-8207-4689-94BC-FA3E6473C851} = {EF5E7304-EC1C-456D-A2FD-B90E0299A6D1}\n\t\t{ED7E1D31-1124-4A9E-9FB2-FBCDA7928BA8} = {EF5E7304-EC1C-456D-A2FD-B90E0299A6D1}\n\t\t{079C92D4-F250-4343-ACF0-4EBE567B0CBE} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{DA6E8814-3D50-485C-8687-ECD1C8D143A9} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{238BADBB-E464-4865-A16B-89273C63193B} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{ACA628BE-DD0B-41BE-B964-47DA6B1C8C36} = {8032CCCC-682E-45C3-8E4B-E2D91B63FEE5}\n\t\t{0938A266-FF63-459A-AFE7-FAFC3D0E4818} = {8032CCCC-682E-45C3-8E4B-E2D91B63FEE5}\n\t\t{5A485FF9-6DD9-4C3D-AB3F-41F0BA864853} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{C8EFA3F1-A420-053C-3DF2-0E19B4781ECD} = {2F9BC915-92B9-4973-A63E-59A05ADD4E88}\n\t\t{1755959F-9267-7500-91F3-72E0477F0532} = {2F9BC915-92B9-4973-A63E-59A05ADD4E88}\n\t\t{94A758E0-FE77-4E90-8ACF-75DDDC6224B5} = {1C7429F8-2815-4612-B5D0-3825E9A381E7}\n\t\t{06706A1F-6B97-5773-2786-48045DD25A9A} = {8032CCCC-682E-45C3-8E4B-E2D91B63FEE5}\n\t\t{173D3C32-4964-3514-6733-7185517086AE} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{B7445FDD-EFFC-A31A-3437-E3F1A36B70E3} = {94A758E0-FE77-4E90-8ACF-75DDDC6224B5}\n\t\t{3C58BD36-EC9F-E653-B04E-50B6647E74D4} = {94A758E0-FE77-4E90-8ACF-75DDDC6224B5}\n\t\t{52D56D1E-6F2F-0408-9BFD-0A910E39BEE9} = {8032CCCC-682E-45C3-8E4B-E2D91B63FEE5}\n\t\t{8032CCCC-682E-45C3-8E4B-E2D91B63FEE5} = {1C7429F8-2815-4612-B5D0-3825E9A381E7}\n\t\t{EF5E7304-EC1C-456D-A2FD-B90E0299A6D1} = {1C7429F8-2815-4612-B5D0-3825E9A381E7}\n\t\t{2F9BC915-92B9-4973-A63E-59A05ADD4E88} = {1C7429F8-2815-4612-B5D0-3825E9A381E7}\n\t\t{25F1BD72-BA38-41C3-A24F-57110B544285} = {46C0FCB4-4589-42CA-8553-9647B1E58BED}\n\t\t{7A84A35D-E2AC-4A05-8751-B51B99EA0967} = {46C0FCB4-4589-42CA-8553-9647B1E58BED}\n\t\t{4A88BE0D-10C5-4CC0-9A43-C816F2AD752C} = {1C7429F8-2815-4612-B5D0-3825E9A381E7}\n\t\t{C7306F87-56EE-44C8-9D06-F4CBA43F08B2} = {94A758E0-FE77-4E90-8ACF-75DDDC6224B5}\n\t\t{DB0FC72C-CAE7-5A8A-7F3B-85110F241BAE} = {4A88BE0D-10C5-4CC0-9A43-C816F2AD752C}\n\t\t{6448A662-EC17-8345-589E-0234EFF04CD8} = {4A88BE0D-10C5-4CC0-9A43-C816F2AD752C}\n\t\t{E4F112C9-2682-66B2-4B1E-39C3461377C6} = {94A758E0-FE77-4E90-8ACF-75DDDC6224B5}\n\t\t{DBAD0308-A4CB-4257-BC48-09C5C9CD389E} = {32E45183-6A02-41A2-A4D5-6CB58A6D39A9}\n\t\t{55799BAC-652D-4A04-96AC-FCD790A38260} = {46C0FCB4-4589-42CA-8553-9647B1E58BED}\n\t\t{857450DA-7712-16A6-71DD-79817FFD356D} = {55799BAC-652D-4A04-96AC-FCD790A38260}\n\t\t{C87ACAFD-732A-FBC3-36FA-7038145AE3CD} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{CC8DE3B4-BE02-45B9-BB26-30B4654DC5E2} = {46C0FCB4-4589-42CA-8553-9647B1E58BED}\n\t\t{167D5DF9-9712-4496-B00F-8E74AB5F8FA2} = {CC8DE3B4-BE02-45B9-BB26-30B4654DC5E2}\n\t\t{908DFB9A-8532-41CD-8153-D6BA5A209386} = {CC8DE3B4-BE02-45B9-BB26-30B4654DC5E2}\n\t\t{2715DFC3-147E-4FF1-84FF-3413F945A3D2} = {896200CD-54AF-462D-881C-0C7A43F0D6AF}\n\t\t{4974EA0B-2303-4BA4-B57E-EE69FA3F0089} = {CC8DE3B4-BE02-45B9-BB26-30B4654DC5E2}\n\t\t{13865038-0CDD-4EDA-8573-45A14F71E50C} = {55799BAC-652D-4A04-96AC-FCD790A38260}\n\t\t{BD2E35A4-6337-415E-A42F-C60BA90E3A04} = {8032CCCC-682E-45C3-8E4B-E2D91B63FEE5}\n\t\t{39C9141D-152F-4F73-AA4B-B7EBA876CA3B} = {55799BAC-652D-4A04-96AC-FCD790A38260}\n\t\t{13862C0A-B482-4DAB-8B63-B97E29A13566} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{171AE0B3-0488-4500-97A2-8F4508CABE52} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{13515640-4870-4679-A7D1-185884ED26AF} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{F036E03A-2A87-FC19-74E3-CCB015E2D619} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{3ADABC34-DDE6-A2CB-77E8-49E888529E11} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{6DA3B0B5-4EFD-4D9F-2352-757B776C17CF} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{342A893E-B25F-628F-09C4-605EEFB3D879} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{286F6C95-62FF-CCAB-EF67-DB6AADFB49E7} = {55799BAC-652D-4A04-96AC-FCD790A38260}\n\t\t{DF78EFBE-9330-4DFE-9996-835147C6D609} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{6784F6B4-98EF-4476-B2A5-4CE6413BF086} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{03B8F8AA-EA03-4A6E-8B58-C8A011A3900C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{94D57C1A-C4E5-40AC-89E1-DE67D74E6750} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{CDF835A4-766D-46CE-AD69-5A1D89A00A9C} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{7B3BB702-5BEF-48EB-91A9-8E34D99F321E} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{846B7A05-F8F0-48C1-8A17-28E9F2AD629B} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{679DA9D4-D38E-4F50-AA27-3A5F50A3ED58} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{AA708E63-59DE-4677-B8ED-4E8549482B90} = {32E45183-6A02-41A2-A4D5-6CB58A6D39A9}\n\t\t{C386DA5C-248C-4B91-BB00-C083EC7914AA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}\n\t\t{82DC9B95-9015-4EF3-87A6-07848CB1D89E} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tEnterpriseLibraryConfigurationToolBinariesPath = packages\\Unity.2.1.505.2\\lib\\NET35;packages\\Unity.2.1.505.0\\lib\\NET35\n\t\tSolutionGuid = {705647E1-B5B1-4D94-888C-1D918095554C}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Src/2sxc Multi-Target.sln.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:String x:Key=\"/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DS/@EntryIndexedValue\">DS</s:String>\n\t<s:Boolean x:Key=\"/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=auto_002Dfilled/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=Id/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=in_0020future_002C/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=piggy_002Dback/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=should_0020always_0020fallback/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=attrib/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=attribs/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Backends/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Clickable/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=cmsid/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=crossorigin/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=decryptor/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Deduplicated/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Deduplicating/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Defs/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Deps/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=desktopmodules/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=dont/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Emoji/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=enableoptimizations/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Enumerables/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Evoq/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=fallbacks/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Guids/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Imageflow/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Inetpub/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Inheritdoc/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=initializers/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Inpage/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Jungleboy/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Langs/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Lightspeed/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Mettler/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=middlewares/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Mobius/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Oqtane/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=orderby/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Patreon/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Patreons/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=polymorph/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Prefetched/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Prerender/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=rels/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=resizer/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Runtimes/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=sexycontent/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=srcset/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=startswith/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Storages/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=syscap/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=toolbars/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=tosic/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=truthy/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=unboxed/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=unsortable/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Usings/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=versioning/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=webp/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=wirings/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/2sxc for MVC PoC.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.28803.202\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Core\", \"..\\..\\eav-server\\ToSic.Eav.Core\\ToSic.Eav.Core.csproj\", \"{82F94588-269B-4CDD-98D1-D5CB14C39090}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.DataSources.Tests\", \"..\\..\\eav-server\\ToSic.Eav.DataSources.Tests\\ToSic.Eav.DataSources.Tests.csproj\", \"{C212A78C-25BB-4A77-AFBB-B5939352CE36}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Apps\", \"..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\", \"{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Persistence.Efc.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Persistence.Efc.Tests\\ToSic.Eav.Persistence.Efc.Tests.csproj\", \"{EB8491A7-4147-4A18-AC74-CD1BE957FF48}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Repository.Efc.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Repository.Efc.Tests\\ToSic.Eav.Repository.Efc.Tests.csproj\", \"{F989FE10-C84A-4B18-AAA7-4665EC85B059}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.ImportExport.Tests\", \"..\\..\\eav-server\\ToSic.Eav.ImportExport.Tests\\ToSic.Eav.ImportExport.Tests.csproj\", \"{00C8672B-E79E-42D4-A512-6C0ABCCAF046}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Testing.Shared\", \"..\\..\\eav-server\\ToSic.Testing.Shared\\ToSic.Testing.Shared.csproj\", \"{41243C6D-2D10-4285-8AF2-719497AE00DB}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Testing.Performance\", \"..\\..\\eav-server\\ToSic.Testing.Performance\\ToSic.Testing.Performance.csproj\", \"{6735DC37-2849-45DB-BA76-C5663B6FFB1F}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Core.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Core.Tests\\ToSic.Eav.Core.Tests.csproj\", \"{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.TokenEngine.Tests\", \"..\\..\\eav-server\\ToSic.Eav.TokenEngine.Tests\\ToSic.Eav.TokenEngine.Tests.csproj\", \"{EF7808DF-F67F-4E0A-A851-21358773DD25}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Eav.Apps.Tests\", \"..\\..\\eav-server\\ToSic.Eav.Apps.Tests\\ToSic.Eav.Apps.Tests.csproj\", \"{5BAEFA99-42C6-4C06-96DE-881303AAE178}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ToSic.Sxc.Tests\", \"Dnn.Tests\\ToSic.Sxc.Tests\\ToSic.Sxc.Tests.csproj\", \"{0EA1085A-D15F-4254-8A79-DE811C47EBF4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.DataSources\", \"..\\..\\eav-server\\ToSic.Eav.DataSources\\ToSic.Eav.DataSources.csproj\", \"{93149D23-E6CC-43AF-97D0-32D89D29D714}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Repository.Efc\", \"..\\..\\eav-server\\ToSic.Eav.Repository.Efc\\ToSic.Eav.Repository.Efc.csproj\", \"{CB322A0B-0C28-4165-87A8-7BBE78911451}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.Persistence.Efc\", \"..\\..\\eav-server\\ToSic.Eav.Persistence.Efc\\ToSic.Eav.Persistence.Efc.csproj\", \"{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.ImportExport\", \"..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\", \"{1253087A-070D-4BF7-B3C2-841537489910}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav\", \"..\\..\\eav-server\\ToSic.Eav\\ToSic.Eav.csproj\", \"{892F9D3B-0578-46A1-A46A-B694A7E15669}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Eav.WebApi\", \"..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\", \"{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc\", \"Sxc\\ToSic.Sxc\\ToSic.Sxc.csproj\", \"{5D87EB0C-BF67-4814-A0FF-D96256C9B852}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"2sxc Core\", \"2sxc Core\", \"{5CD8015A-76D8-4633-8469-53B62A6C1894}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Eav\", \"Eav\", \"{2DBCC960-1C0B-494F-9E21-8707A1D344C3}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Eav Tests\", \"Eav Tests\", \"{6D320108-78ED-40E6-83F7-9CD423471DB3}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.WebApi\", \"Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\", \"{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Mvc\", \"Mvc\", \"{F1366AA6-6508-47E4-AE39-CB39537CA220}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Mvc\", \"Mvc\\ToSic.Sxc.Mvc\\ToSic.Sxc.Mvc.csproj\", \"{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Website\", \"Mvc\\Website\\Website.csproj\", \"{28A58816-468A-44E0-85CA-0428F0D87E27}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Razor.Engine\", \"Razor\\ToSic.Sxc.Razor.Engine\\ToSic.Sxc.Razor.Engine.csproj\", \"{9269847A-20A1-4F72-9E14-36BFE0323632}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ToSic.Sxc.Hybrid\", \"Razor\\ToSic.Sxc.Hybrid\\ToSic.Sxc.Hybrid.csproj\", \"{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Razor\", \"Razor\", \"{DD59EAFD-02D1-4285-B8BE-D2DD40536304}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|DNN = Debug|DNN\n\t\tDebug|Windows-x64 = Debug|Windows-x64\n\t\tDebug|Windows-x86 = Debug|Windows-x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|DNN = Release|DNN\n\t\tRelease|Windows-x64 = Release|Windows-x64\n\t\tRelease|Windows-x86 = Release|Windows-x86\n\t\tTesting|Any CPU = Testing|Any CPU\n\t\tTesting|DNN = Testing|DNN\n\t\tTesting|Windows-x64 = Testing|Windows-x64\n\t\tTesting|Windows-x86 = Testing|Windows-x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Testing|DNN.ActiveCfg = Dbg Testing|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Testing|DNN.Build.0 = Dbg Testing|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Testing|Windows-x64.ActiveCfg = Dbg Testing|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Testing|Windows-x64.Build.0 = Dbg Testing|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Testing|Windows-x86.ActiveCfg = Dbg Testing|Any CPU\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178}.Testing|Windows-x86.Build.0 = Dbg Testing|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{1253087A-070D-4BF7-B3C2-841537489910}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Any CPU.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|DNN.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|DNN.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27}.Testing|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Any CPU.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|DNN.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|DNN.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Windows-x64.Build.0 = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632}.Testing|Windows-x86.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|DNN.ActiveCfg = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|DNN.Build.0 = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Windows-x64.ActiveCfg = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Windows-x64.Build.0 = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Windows-x86.ActiveCfg = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Debug|Windows-x86.Build.0 = Debug|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|DNN.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|DNN.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Windows-x64.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Release|Windows-x86.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Any CPU.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|DNN.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|DNN.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Windows-x64.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Windows-x64.Build.0 = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Windows-x86.ActiveCfg = Release|Any CPU\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A}.Testing|Windows-x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{82F94588-269B-4CDD-98D1-D5CB14C39090} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{C212A78C-25BB-4A77-AFBB-B5939352CE36} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{FA1B4495-6B85-400F-A5E3-0E292CCBFAE2} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{EB8491A7-4147-4A18-AC74-CD1BE957FF48} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{F989FE10-C84A-4B18-AAA7-4665EC85B059} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{00C8672B-E79E-42D4-A512-6C0ABCCAF046} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{41243C6D-2D10-4285-8AF2-719497AE00DB} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{6735DC37-2849-45DB-BA76-C5663B6FFB1F} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{AFED35B5-8E43-4F46-8E4D-FC3F07244D8B} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{EF7808DF-F67F-4E0A-A851-21358773DD25} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{5BAEFA99-42C6-4C06-96DE-881303AAE178} = {6D320108-78ED-40E6-83F7-9CD423471DB3}\n\t\t{0EA1085A-D15F-4254-8A79-DE811C47EBF4} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{93149D23-E6CC-43AF-97D0-32D89D29D714} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{CB322A0B-0C28-4165-87A8-7BBE78911451} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{B45F98A5-BBA9-4418-A5A1-7CA747E1698B} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{1253087A-070D-4BF7-B3C2-841537489910} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{892F9D3B-0578-46A1-A46A-B694A7E15669} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{04F3A07C-2C6C-4D87-9E8D-E2DB611B0D52} = {2DBCC960-1C0B-494F-9E21-8707A1D344C3}\n\t\t{5D87EB0C-BF67-4814-A0FF-D96256C9B852} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{80D15F35-334B-4C7C-AF94-B0FF1E6CC354} = {5CD8015A-76D8-4633-8469-53B62A6C1894}\n\t\t{AA274DBE-9E67-4B87-9D97-4E34F1D4D75E} = {F1366AA6-6508-47E4-AE39-CB39537CA220}\n\t\t{28A58816-468A-44E0-85CA-0428F0D87E27} = {F1366AA6-6508-47E4-AE39-CB39537CA220}\n\t\t{9269847A-20A1-4F72-9E14-36BFE0323632} = {DD59EAFD-02D1-4285-B8BE-D2DD40536304}\n\t\t{ACD30ED0-0B6E-48E7-A898-CF42C93E857A} = {DD59EAFD-02D1-4285-B8BE-D2DD40536304}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {705647E1-B5B1-4D94-888C-1D918095554C}\n\t\tEnterpriseLibraryConfigurationToolBinariesPath = packages\\Unity.2.1.505.2\\lib\\NET35;packages\\Unity.2.1.505.0\\lib\\NET35\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Src/Build/ToSic.Sxc.BuildTasks/BuildConfig.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace ToSic.Sxc.BuildTasks\n{\n    public class BuildConfig\n    {\n        public List<string> JsTargets { get; set; }\n        public List<string> DnnTargets { get; set; }\n        public List<string> OqtaneTargets { get; set; }\n        public List<string> Sources { get; set; }\n        public string DnnInstallPackage { get; set; }\n        public string OqtaneInstallPackage { get; set; }\n    }\n}"
  },
  {
    "path": "Src/Build/ToSic.Sxc.BuildTasks/ColorMessage.cs",
    "content": "﻿using Microsoft.Build.Utilities;\nusing System;\n\nnamespace ToSic.Sxc.BuildTasks\n{\n    public class ColorMessage : Task\n    {\n        public string Text { get; set; } = string.Empty;\n\n        public string ForegroundColor { get; set; }\n        public string BackgroundColor { get; set; }\n\n        public override bool Execute()\n        {\n            var originalForegroundColor = Console.ForegroundColor;\n            var originalBgColor = Console.BackgroundColor;\n\n            if (!string.IsNullOrEmpty(ForegroundColor))\n                if (Enum.TryParse(ForegroundColor, true, out ConsoleColor foregroundColor))\n                    Console.ForegroundColor = foregroundColor;\n\n            if (!string.IsNullOrEmpty(BackgroundColor))\n                if (Enum.TryParse(BackgroundColor, true, out ConsoleColor backgroundColor))\n                    Console.BackgroundColor = backgroundColor;\n\n            Console.Write(Text);\n            // Log.LogMessage(MessageImportance.High, Text);\n\n            Console.ForegroundColor = originalForegroundColor;\n            Console.BackgroundColor = originalBgColor;\n\n            Console.Write(\"\\n\");\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "Src/Build/ToSic.Sxc.BuildTasks/CopyNewerFileVersion.cs",
    "content": "﻿using Microsoft.Build.Framework;\nusing Microsoft.Build.Utilities;\nusing System;\nusing System.Diagnostics;\nusing System.IO;\n\nnamespace ToSic.Sxc.BuildTasks\n{\n    /// <summary>\n    /// Represents a custom MSBuild task that copies files from source to destination\n    /// with additional logic for handling assembly files (DLLs), \n    /// where overwrite will happen only if source FileVersion is newer than on destination\n    /// </summary>\n    public class CopyNewerFileVersion : Task\n    {\n        private const string LogPrefix = $\"{nameof(CopyNewerFileVersion)}:\";\n\n        /// <summary>\n        /// Gets or sets the source files to be copied.\n        /// </summary>\n        [Required]\n        public ITaskItem[] SourceFiles { get; set; }\n\n        /// <summary>\n        /// Gets or sets the destination folder where the files will be copied.\n        /// </summary>\n        [Required]\n        public string DestinationFolder { get; set; }\n\n        /// <summary>\n        /// Executes the file copy operation.\n        /// </summary>\n        /// <returns>\n        /// <c>true</c> if the operation succeeds; otherwise, <c>false</c>.\n        /// </returns>\n        /// <remarks>\n        /// This method iterates through the source files, checks if they need to be copied\n        /// (based on version comparison for DLLs), and performs the copy operation.\n        /// </remarks>\n        public override bool Execute()\n        {\n            foreach (var sourceFile in SourceFiles)\n            {\n                var sourcePath = sourceFile.ItemSpec;\n                var relativePath = sourceFile.GetMetadata(\"RecursiveDir\");\n                var destPath = Path.Combine(DestinationFolder, relativePath ?? \"\", Path.GetFileName(sourcePath));\n\n                try\n                {\n                    if (!File.Exists(sourcePath))\n                    {\n                        Log.LogMessage(MessageImportance.High, $\"{LogPrefix} Source file '{sourcePath}' not found. Skipping.\");\n                        continue;\n                    }\n\n                    var copy = true;\n\n                    if (File.Exists(destPath) && Path.GetExtension(sourcePath).Equals(\".dll\", StringComparison.OrdinalIgnoreCase))\n                    {\n                        try\n                        {\n                            var srcVer = GetFileVersion(sourcePath);\n                            var dstVer = GetFileVersion(destPath);\n\n                            if (srcVer <= dstVer)\n                            {\n                                Log.LogMessage(MessageImportance.High, $\"{LogPrefix} Skipping '{sourcePath}' — version {srcVer} <= {dstVer}\");\n                                copy = false;\n                            }\n                        }\n                        catch (Exception ex)\n                        {\n                            Log.LogMessage(MessageImportance.High, $\"{LogPrefix} Error comparing versions: {ex.Message}. Proceeding to copy.\");\n                        }\n                    }\n\n                    if (copy)\n                    {\n                        var directoryName = Path.GetDirectoryName(destPath);\n                        if (!string.IsNullOrEmpty(directoryName)) Directory.CreateDirectory(directoryName);\n\n                        File.Copy(sourcePath, destPath, true);\n                        Log.LogMessage(MessageImportance.High, $\"{LogPrefix} Copied '{sourcePath}' to '{destPath}'\");\n                    }\n                }\n                catch (Exception ex)\n                {\n                    Log.LogError($\"{LogPrefix} Error failed to copy '{sourcePath}' to '{destPath}': {ex.Message}\");\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Retrieves the version information of a file.\n        /// </summary>\n        /// <param name=\"filePath\">The path to the file.</param>\n        /// <returns>The <see cref=\"Version\"/> of the file.</returns>\n        /// <exception cref=\"FileNotFoundException\">Thrown if the file does not exist.</exception>\n        private static Version GetFileVersion(string filePath)\n        {\n            var versionInfo = FileVersionInfo.GetVersionInfo(filePath);\n            return new Version(versionInfo.FileMajorPart, versionInfo.FileMinorPart, versionInfo.FileBuildPart, versionInfo.FilePrivatePart);\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Build/ToSic.Sxc.BuildTasks/GetBuildConfig.cs",
    "content": "﻿using Microsoft.Build.Framework;\nusing Microsoft.Build.Utilities;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text.Json;\n\nnamespace ToSic.Sxc.BuildTasks\n{\n    public class GetBuildConfig : Task\n    {\n        private const string BuildConfigJsonFileName = \"2sxc-build.config.json\";\n        private const string FallbackBuildConfigJsonFileName = \"2sxc-build-fallback.config.json\";\n\n        #region json properties\n        [Output]\n        public string[] JsTargets { get; private set; } = Array.Empty<string>();\n\n        [Output]\n        public string[] DnnTargets { get; private set; } = Array.Empty<string>();\n\n        [Output]\n        public string[] OqtaneTargets { get; private set; } = Array.Empty<string>();\n        [Output]\n        public string[] Sources { get; private set; }\n\n        [Output]\n        public string DnnInstallPackage { get; private set; } = string.Empty;\n\n        [Output]\n        public string OqtaneInstallPackage { get; private set; } = string.Empty;\n        #endregion\n\n        #region calculated properties\n        [Output]\n        public string BuildConfigPath { get; private set; }\n\n        [Output]\n        public string JsTarget { get; private set; }\n\n        [Output]\n        public string DnnTarget { get; private set; }\n\n        [Output]\n        public string OqtaneTarget { get; private set; }\n\n        [Output]\n        public string Source { get; private set; }\n        #endregion\n\n        public override bool Execute()\n        {\n            try\n            {\n                BuildConfigPath = FindJsonFile(BuildConfigJsonFileName) ?? FindJsonFile(FallbackBuildConfigJsonFileName);\n                if (string.IsNullOrEmpty(BuildConfigPath))\n                {\n                    Log.LogError($\"Could not find {FallbackBuildConfigJsonFileName} or {FallbackBuildConfigJsonFileName} file.\");\n                    return false;\n                }\n\n                var jsonContent = File.ReadAllText(BuildConfigPath);\n                var buildConfig = JsonSerializer.Deserialize<BuildConfig>(jsonContent,\n                    new JsonSerializerOptions {\n                        ReadCommentHandling = JsonCommentHandling.Skip,\n                        AllowTrailingCommas = true\n                    });\n\n                Sources = FixAllTargets(buildConfig.Sources)?.ToArray();\n                Source = Sources?.FirstOrDefault();\n\n                JsTargets = FixAllTargets(buildConfig.JsTargets)?.ToArray();\n                JsTarget = JsTargets?.FirstOrDefault();\n\n                DnnTargets = FixAllTargets(buildConfig.DnnTargets)?.ToArray();\n                DnnTarget = DnnTargets?.FirstOrDefault();\n\n                OqtaneTargets = FixAllTargets(buildConfig.OqtaneTargets)?.ToArray();\n                OqtaneTarget = OqtaneTargets?.FirstOrDefault();\n\n                DnnInstallPackage = FixSingleTarget(buildConfig.DnnInstallPackage);\n\n                OqtaneInstallPackage = FixSingleTarget(buildConfig.OqtaneInstallPackage);\n\n                return true;\n            }\n            catch (Exception e)\n            {\n                Log.LogErrorFromException(e);\n                return false;\n            }\n        }\n\n\n        private static string FindJsonFile(string buildConfigJsonFileName)\n        {\n            // Start with the current directory\n            var currentDirectory = Directory.GetCurrentDirectory();\n\n            // Continue to look in the parent directories until there's no parent\n            while (currentDirectory != null)\n            {\n                // Combine the current directory with the file name to get the full path\n                var jsonFilePath = Path.Combine(currentDirectory, buildConfigJsonFileName);\n\n                // Check if the file exists in the current directory\n                if (File.Exists(jsonFilePath))\n                    return jsonFilePath;\n\n                // Move to the parent directory for the next iteration\n                currentDirectory = Directory.GetParent(currentDirectory)?.FullName;\n            }\n\n            // Return null if the file was not found in any directory\n            return null;\n        }\n\n        /// <summary>\n        /// Fix all targets, by adding the path to the target\n        /// </summary>\n        /// <param name=\"paths\">The list of target paths</param>\n        /// <param name=\"addOnPath\">The path to add to the target</param>\n        /// <returns>The list of fixed target paths</returns>\n        public static List<string> FixAllTargets(List<string> paths, string addOnPath = null) \n            => paths?.Select(t => FixSingleTarget(t, addOnPath)).ToList();\n\n        /// <summary>\n        /// Fix the target path by adding the path to the target\n        /// </summary>\n        /// <param name=\"value\">The target path</param>\n        /// <param name=\"addToPath\">The path to add to the target</param>\n        /// <returns>The fixed target path</returns>\n        public static string FixSingleTarget(string value, string addToPath = null)\n        {\n            if (string.IsNullOrEmpty(value)) return value;\n            return string.IsNullOrEmpty(addToPath) \n                ? FixPath(value, false, true) + Path.DirectorySeparatorChar\n                : Path.Combine(FixPath(value, false, true) + Path.DirectorySeparatorChar, FixPath(addToPath, false, true) + Path.DirectorySeparatorChar);\n        }\n\n        /// <summary>\n        /// Fix the path by replacing backslashes with forward slashes and removing double slashes\n        /// </summary>\n        /// <param name=\"path\">The path to fix</param>\n        /// <param name=\"removeStartingSlash\">Remove the starting slash</param>\n        /// <param name=\"removeEndingSlash\">Remove the ending slash</param>\n        /// <returns>The fixed path</returns>\n        public static string FixPath(string path, bool removeStartingSlash = false, bool removeEndingSlash = false)\n        {\n            if (string.IsNullOrEmpty(path)) return path;\n\n            var clean = path.Trim().Replace(\"\\\\\", \"/\").Replace(\"//\", \"/\");\n\n            if (removeStartingSlash && clean.StartsWith(\"/\")) clean = clean.Substring(1);\n            if (removeEndingSlash && clean.EndsWith(\"/\")) clean = clean.Remove(clean.Length - 1);\n\n            return clean.Replace('/', Path.DirectorySeparatorChar);\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Build/ToSic.Sxc.BuildTasks/ModifyXmlDocumentation.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Text.RegularExpressions;\nusing System.Xml.Linq;\nusing Microsoft.Build.Framework;\nusing Microsoft.Build.Utilities;\n\nnamespace ToSic.Sxc.BuildTasks\n{\n    public class ModifyXmlDocumentation : Task\n    {\n        [Required]\n        public string XmlDocumentationPath { get; set; }\n\n        public override bool Execute()\n        {\n            // Launches a dialog asking if you want to attach a debugger\n            //System.Diagnostics.Debugger.Launch();\n\n            try\n            {\n                var content = File.ReadAllText(XmlDocumentationPath);\n\n                var modifiedContent = ReplaceXrefsWithLinks(content);\n\n                modifiedContent = AddDocsLinkToTypesAndProperties(modifiedContent);\n\n                File.WriteAllText(XmlDocumentationPath, modifiedContent);\n                Log.LogMessage(MessageImportance.High, $\"XML documentation modified successfully at: {XmlDocumentationPath}\");\n            }\n            catch (Exception ex)\n            {\n                Log.LogErrorFromException(ex);\n                return false;\n            }\n\n            return true;\n        }\n\n        private static string ReplaceXrefsWithLinks(string content)\n        {\n            // regex pattern to handle method signatures with parentheses\n            var pattern = @\"\\[(.*?)\\]\\(xref:((?:[^()]+|\\((?:[^()]+|\\([^()]*\\))*\\))*)\\)\";\n\n            // Replacement method defined as a local function\n            string Replacement(Match m)\n            {\n                var label = m.Groups[1].Value;\n                var reference = m.Groups[2].Value;\n                // Use label if provided, otherwise use reference as label\n                var linkText = !string.IsNullOrEmpty(label) ? label : reference;\n                return $@\"<a href=\"\"https://go.2sxc.org/find?xref={reference}\"\">{linkText}</a>\";\n            }\n\n            var modifiedContent = Regex.Replace(content, pattern, new MatchEvaluator(Replacement));\n            return modifiedContent;\n        }\n\n        private string AddDocsLinkToTypesAndProperties(string content)\n        {\n            var xdoc = XDocument.Parse(content);\n            foreach (var member in xdoc.Descendants(\"member\"))\n            {\n                try\n                {\n                    var memberName = member.Attribute(\"name\")?.Value;\n\n                    if (memberName == null\n                        || !(memberName.StartsWith(\"T:\") || memberName.StartsWith(\"P:\"))\n                        || memberName.Contains(\".Internal.\")\n                        || memberName.Contains(\".Integration.\")) continue;\n\n                    var summary = member.Element(\"summary\");\n                    if (summary == null) continue;\n\n                    var summaryContent = summary.Value;\n                    if (summaryContent.Contains(\"📖\")) continue;\n\n                    var reference = memberName.Substring(2);\n                    // if it's a generic type, we need to remove the generic part and append *\n                    //if (reference.Contains(\"`\")) reference = reference.Substring(0,reference.LastIndexOf('`')) + \"*\";\n\n                    var label = reference.Substring(reference.LastIndexOf('.') + 1);\n\n                    summary.Add(new XElement(\"para\", new XElement(\"a\", new XAttribute(\"href\", $\"https://go.2sxc.org/find?xref={reference}\"), \"📖 \" + label)));\n                }\n                catch (Exception ex)\n                {\n                    Log.LogErrorFromException(ex);\n                }\n            }\n            return xdoc.ToString();\n        }\n    }\n}"
  },
  {
    "path": "Src/Build/ToSic.Sxc.BuildTasks/ToSic.Sxc.BuildTasks.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net472;net9.0</TargetFrameworks>\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <LangVersion>preview</LangVersion>\n    <WarningLevel>9999</WarningLevel>\n  </PropertyGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net472'\">\n    <Reference Include=\"Microsoft.Build.Framework\" />\n    <Reference Include=\"Microsoft.Build.Tasks.v4.0\" />\n    <Reference Include=\"Microsoft.Build.Utilities.v4.0\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <PackageReference Include=\"Microsoft.Build.Tasks.Core\" Version=\"17.14.8\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"System.Text.Json\" Version=\"9.0.5\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Data/App_Data/new-app/app.json",
    "content": "{\n  \"$schema\": \"https://schemas.2sxc.org/app/v17/app.json\",\n  /*\n    This is a JSON file but it is treated like a JSONC (with comments).\n\n    Different editors may complain about the comments. \n    To reconfigure VS Code so it knows comments are ok, do this: https://azing.org/2sxc/r/h9m1l6JO\n  */\n\n  // Export-App configuration\n  \"export\": {\n\n    // Exclude certain folders/file beginning with the values specified below\n    // Note that it may look like glob, but ATM it's a simpler starts-with mechanism\n    \"exclude\": [\n      // Skip git versioning folders, github config folders\n      \".git/\",\n      \".github/\",\n      // \".gitignore\",\n\n      // Webpack 5 temporary folder and NPM folders\n      \".temp_cache/\",\n      \"node_modules/\"\n\n      // Other examples\n      // \".vs\",\n      // \".vscode\",\n      // \"package.json\",\n      // \"package-lock.json\",\n      // \"nuget.config\",\n    ]\n  },\n  \"editions\": {\n    \"\": {\n      \"description\": \"The default edition of the app\",\n    }\n  }\n}\n"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-cms.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"2SexyContent-ContentGroup\",\n            \"Name\": \"2SexyContent-ContentGroup\",\n            \"Scope\": \"System.Cms\",\n            \"Metadata\": [\n              {\n                \"Id\": 45362,\n                \"Version\": 3,\n                \"Guid\": \"f5b4e0e9-6e36-4ef6-b5e7-bcf40dd306e6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Contains a content group in 2sxc\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Content-Groups are a fundamental part of 2sxc - they contain the definition of a set of selected items and how they should be displayed. You should almost never edit this - for more information read about it in the <a href=\\\"https://github.com/2sic/2sxc/wiki/Concept-Dnn-Module\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">wiki</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Content Group\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"2SexyContent-ContentGroup\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Template\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45265,\n                    \"Version\": 4,\n                    \"Guid\": \"ae4b5b42-924f-48c9-92a6-af60cfe1fba4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"View\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is a refernce to the view - internally it's called Template.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45357,\n                    \"Version\": 2,\n                    \"Guid\": \"b4e505f8-6603-42fc-84d1-102bb529bc03\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"2SexyContent-Template\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": false\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Content\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45266,\n                    \"Version\": 2,\n                    \"Guid\": \"99c18cf3-ba36-4efc-a8f1-784dc5ca4af3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45358,\n                    \"Version\": 2,\n                    \"Guid\": \"0a6a2fe4-59ab-47a5-81ab-8b1fb623e0e6\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": false\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Presentation\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45267,\n                    \"Version\": 2,\n                    \"Guid\": \"8a073b58-b7ed-4a56-8300-2a8a526a0766\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Presentation\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45359,\n                    \"Version\": 2,\n                    \"Guid\": \"36fbbef5-d06b-4fc3-a9f9-4635e783ac5b\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": false\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ListContent\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45268,\n                    \"Version\": 9,\n                    \"Guid\": \"1b1f604b-aa38-4239-b9ac-b6e544f92238\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Header\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This was previously called ListContent - but that was confusing.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45360,\n                    \"Version\": 7,\n                    \"Guid\": \"85216f8e-d5b1-4845-b0da-5a5d87dc0580\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": false\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ListPresentation\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45269,\n                    \"Version\": 3,\n                    \"Guid\": \"9b1e1bdb-4f8f-4422-a498-7a88432b0ecf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Header Presentation\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This was previously called ListPresentation, but this was confusing.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45361,\n                    \"Version\": 2,\n                    \"Guid\": \"c4a5f6ef-2645-487a-b850-20b13860ddcb\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": false\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"ContentGroupReference\",\n            \"Name\": \"ContentGroupReference\",\n            \"Scope\": \"System.Cms\",\n            \"Metadata\": [\n              {\n                \"Id\": 45372,\n                \"Version\": 3,\n                \"Guid\": \"c0363c70-20a4-4db6-8775-497a9842459a\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"A pointer / reference to a content group\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>A reference to a content-group. As the target group/block could be inside another app, all fields are simple string fields, because they can't enforce that the target exists. See also what the <a href=\\\"https://github.com/2sic/2sxc/wiki/Concept-Dnn-Module\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">wiki</a> says about this.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Content Group Reference\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"ContentGroupReference\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45352,\n                    \"Version\": 1,\n                    \"Guid\": \"fc7537ff-fd90-4ba5-bfa9-86c812f176fc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"App\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45353,\n                    \"Version\": 1,\n                    \"Guid\": \"b43adb4a-bea7-444d-a6f9-b51f572be2b6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"App\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentGroup\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45354,\n                    \"Version\": 2,\n                    \"Guid\": \"28101b11-6d4e-4a2e-beb0-4c3607a579a7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Group\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 84727,\n                    \"Version\": 1,\n                    \"Guid\": \"edda694f-39a2-41cf-ac3f-85d93ee782ff\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 84728,\n                    \"Version\": 1,\n                    \"Guid\": \"e3447c51-02d7-4135-9aa0-d6dad2adcb5f\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ShowTemplateChooser\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45355,\n                    \"Version\": 1,\n                    \"Guid\": \"a7b40d1a-2c2e-422d-9495-e4b8ab942ad6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"ShowTemplateChooser\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Template\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45356,\n                    \"Version\": 2,\n                    \"Guid\": \"4cf0e083-ac2e-4d16-952e-75f67984c298\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"View\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 84729,\n                    \"Version\": 1,\n                    \"Guid\": \"5d3146bc-a07b-41a0-9e93-2a8b2f62466c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 84730,\n                    \"Version\": 1,\n                    \"Guid\": \"75a75673-3336-46e2-9c93-36b733438f8d\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"2SexyContent-Template\",\n            \"Name\": \"2SexyContent-Template\",\n            \"Scope\": \"System.Cms\",\n            \"Metadata\": [\n              {\n                \"Id\": 45363,\n                \"Version\": 3,\n                \"Guid\": \"a66b920b-05d8-4d41-b8d0-33648062776a\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Contains all registered 2sxc templates\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Templates / Views determine how output is shown. This dialog helps you configure what file is used, what data it expects and more. See <a href=\\\"https://r.2sxc.org/views\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">View docs for more</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"View Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"2SexyContent-Template\"\n                }\n              },\n              {\n                \"Id\": 136793,\n                \"Version\": 7,\n                \"Guid\": \"1b9c635f-7aed-4b09-bad2-0ebf7f1d0808\",\n                \"Type\": {\n                  \"Id\": \"c490b369-9cd2-4298-af74-19c1e438cdfc\",\n                  \"Name\": \"MetadataExpectedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"<p>If you remove this, this view will not be the default any more.</p>\"\n                    },\n                    \"MetadataTypes\": {\n                      \"en-us\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Is Default Decorator on Views\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 4\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"2SexyContent-Template\"\n                }\n              },\n              {\n                \"Id\": 183807,\n                \"Version\": 2,\n                \"Guid\": \"1406d8fe-e333-42c0-8284-59ca2e2cd652\",\n                \"Type\": {\n                  \"Id\": \"c490b369-9cd2-4298-af74-19c1e438cdfc\",\n                  \"Name\": \"MetadataExpectedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"MetadataTypes\": {\n                      \"en-us\": \"be34f64b-7d1f-4ad0-b488-dabbbb01a186\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Expects LightSpeedOutputDecorator\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 4\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"2SexyContent-Template\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Name\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45270,\n                    \"Version\": 1,\n                    \"Guid\": \"06c96a88-1fe5-4bcf-a88c-26e26f005ca0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just a nice name which will be shown in dropdowns and similar</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45271,\n                    \"Version\": 1,\n                    \"Guid\": \"4f5ac6bf-0185-4827-aeb3-2c2a19a028d8\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45272,\n                    \"Version\": 1,\n                    \"Guid\": \"d8232645-15b9-4670-9035-435a24f99905\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupTemplate\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45278,\n                    \"Version\": 9,\n                    \"Guid\": \"010e97d2-bc29-4457-ab0f-bba93542eb63\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Template\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The template is a html or code file, which is&nbsp;will generate the output.&nbsp;It could be simple HTML showing a decorative line, a token-based HTML with placeholders like <em>[Content:Title]</em>, or an advanced c# Razor template with placeholders like <em>@Content.Title</em> as well as conditions, loops etc.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"204e815f-a0e6-4820-abf5-43851e0b9831\",\n                            \"1d80d0b3-9ffe-4496-90f1-9ae1027e6d16\",\n                            \"a40d7865-f0d4-41c4-a30f-c4ba8bbe2953\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45279,\n                    \"Version\": 9,\n                    \"Guid\": \"bbef64eb-5ea3-4f32-8395-7d5679bbf984\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Type\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45280,\n                    \"Version\": 3,\n                    \"Guid\": \"3973286f-32aa-4713-bc98-7bca03cbbdd8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"C# Razor\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Type\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>this type determines which view-engine will be used to render the result</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"37302ae7-4aa9-4c45-a99d-efe5ff9be05d\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45281,\n                    \"Version\": 3,\n                    \"Guid\": \"afcc31a1-b2e1-48d8-8158-0440b8977dd9\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45282,\n                    \"Version\": 3,\n                    \"Guid\": \"1ef3b54e-0806-467c-ac96-c9bb73bda214\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"Token\\nC# Razor\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Location\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45283,\n                    \"Version\": 10,\n                    \"Guid\": \"e319559d-eaeb-4f51-aeae-5b8babcdbab3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Site\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Location\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>templates are usually stored&nbsp;in the portal - or in rare cases&nbsp;or in the shared, default-zone - note that sharing templates has various caveats, so you should read about <a href=\\\"http://2sxc.org/help?tag=app\\\" target=\\\"_blank\\\">shared templates here</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"bbe01933-12da-4052-975e-795733012b74\",\n                            \"137d7d82-69dc-4216-8b16-7b28ce01f324\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45284,\n                    \"Version\": 10,\n                    \"Guid\": \"536be02b-b517-4efc-939f-ca5030a1bae5\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45285,\n                    \"Version\": 10,\n                    \"Guid\": \"a9c9393e-b5b5-494e-99ac-78f6722d50f9\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"Site:App Files in the Current Site\\nGlobal:App Files in Shared (Global) section \\uD83E\\uDD1D\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Path\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-template-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45286,\n                    \"Version\": 1,\n                    \"Guid\": \"69c72b8f-1246-46b4-95cf-baf5499c6393\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-template-picker\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Template file\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>choose or create the template file - <a href=\\\"http://2sxc.org/help?tag=templates\\\" target=\\\"_blank\\\">more help</a></p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45287,\n                    \"Version\": 1,\n                    \"Guid\": \"b723401a-b3e0-446b-b43a-b8d65777e705\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarCustomIcon\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130445,\n                    \"Version\": 6,\n                    \"Guid\": \"61696aa2-e970-40a1-96bb-370e6e0a35b7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"VarCustomIcon\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Determine how the icon (if any) is provided. See <a href=\\\"https://r.2sxc.org/app-icons\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"09cfe676-91a0-4f5f-8a20-a8b0d0fd420f\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130449,\n                    \"Version\": 5,\n                    \"Guid\": \"086a2c16-6684-47bd-9c90-5b1940b449e3\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Icon uses the same-named file in the template folder or a default symbol\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Use Custom Icon\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Icon\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130446,\n                    \"Version\": 8,\n                    \"Guid\": \"12314234-571e-4399-8915-815a026ba6b9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Icon\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>We recommend using the [App:Path] placeholder - see <a href=\\\"https://r.2sxc.org/app-icons\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"Drop file or use [App:Path]/filename.png for files in your app-folder\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"4c014396-a4b7-4b2c-897e-b383d6f23021\",\n                            \"d14a0d46-518d-4dc9-b8a4-05444b70f97b\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130452,\n                    \"Version\": 6,\n                    \"Guid\": \"eb8f4150-4d29-4469-b31a-ab18e69de3fa\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupShowHide\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130153,\n                    \"Version\": 6,\n                    \"Guid\": \"a0673981-299e-49a2-b79b-59458c3db589\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Show / Hide View Rules\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Views are visible and selectable by default. Here you can change how this behaves. Some reasons you may want to do this:</p>\\n<ol>\\n<li>If your view is only needed on one page and then shouldn't be available any more (because it's an admin view or something) then you want to add it to that page and then configure to <strong>Hide from Editor</strong>.</li>\\n<li>If your view is a details-view (so another list has a link which will show this, then...\\n<ol>\\n<li>You want to specify that it only shows if a term is in the URL</li>\\n<li>And you probably want to also hide it, so editors don't choose this view to add to a page directly.</li>\\n</ol>\\n</li>\\n</ol>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"295c8af6-cb9e-4394-9fcc-1f957907e94c\",\n                            \"50d9926b-bdc0-4e6e-a837-046fa1e59eee\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130154,\n                    \"Version\": 5,\n                    \"Guid\": \"31aeacdd-225c-41e3-aaf0-c106e1cbcb95\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IsHidden\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45276,\n                    \"Version\": 2,\n                    \"Guid\": \"8df13ac0-3763-470e-90e9-6ca08ed7be57\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Hide from editor\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>hide this template from the normal selection -&nbsp;this is for templates you only want to insert once or twice, and then&nbsp;prevent additional uses</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45277,\n                    \"Version\": 2,\n                    \"Guid\": \"bc7a124e-87e7-45be-9348-b6241279c6ae\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Show in View Selection (default)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Hidden in View Selection ⛔\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ViewNameInUrl\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45273,\n                    \"Version\": 2,\n                    \"Guid\": \"b7a0ac98-3599-4c91-8a9c-af90235b720b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"/* compatibility: 1.0 */\\n\\n// must must do some special stuff here\\n// but for code maintenance reasons, we put it in the normal 2sxc-code\\n\\n// pick up the code-block already prepared, and give it back\\nvar cs = window[\\\"2sxc-template-picker-custom-script-for-name-field\\\"];\\nreturn cs;\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Name in URL Path\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>specify this if you&nbsp;want this template to be activated&nbsp;automatically, when some keywords appear in the url - like showing&nbsp;details when <strong>/post/395</strong> is&nbsp;in the path (note: this only works in Apps) - <a href=\\\"http://2sxc.org/help?tag=view-name\\\" target=\\\"_blank\\\">read more</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45274,\n                    \"Version\": 2,\n                    \"Guid\": \"ffb32750-dfe6-414e-8e07-95906ad50d64\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45275,\n                    \"Version\": 2,\n                    \"Guid\": \"5d5fe141-b048-4cf7-b7aa-ca0d2240939e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130236,\n                    \"Version\": 1,\n                    \"Guid\": \"94b2bc0a-9cf9-4410-91c9-28a051bab69d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupEnd\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarViewDataModel\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130164,\n                    \"Version\": 16,\n                    \"Guid\": \"e492bb92-066b-4617-bbd0-0a7ac8d1ebc7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Data Model used in View\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This shows/hides various settings based on what you need.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"07958470-13f6-4e7d-b2a2-901517058e2a\",\n                            \"d259040a-daca-473b-8fbe-7d8aacf8fa5e\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130165,\n                    \"Version\": 15,\n                    \"Guid\": \"21c7077f-1441-4c96-b5c3-ca21f6f9f1c3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130166,\n                    \"Version\": 15,\n                    \"Guid\": \"4af51efc-6099-46ae-8749-e17117830025\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"Please choose...:\\nView doesn't need Data:-\\nSingle Content Item:c\\nList of Content Items:cl\\nData from Query:q\\nData from Query with Module-Content:cq\\nShow all Settings:clq\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarPresentation\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130195,\n                    \"Version\": 12,\n                    \"Guid\": \"acb08960-2653-4d4b-be18-35e755d773c3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Show Presentation Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Content-items can have a <a href=\\\"https://r.2sxc.org/presentation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Presentation item</a> to describe how it should be styled when shown on a specific Module instance.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"7ef8345b-d7dd-45d6-b786-025a839f9e50\",\n                            \"fb171277-ef31-4a9b-957d-97f19ab3d7eb\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130196,\n                    \"Version\": 11,\n                    \"Guid\": \"c22acd85-0b45-4919-87e0-28d36c0af349\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Don't use Presentation on Content-Items\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Activate Presentation on Content-Items\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupContent\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45288,\n                    \"Version\": 8,\n                    \"Guid\": \"bc2fdef6-59e4-49d3-b700-eebd6a7877fb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content-Item\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Templates show either Content, Data, both, or neither. If you're just getting started, Content is the way to go. Read more about this&nbsp;in the <a href=\\\"http://2sxc.org/help?tag=templates\\\" target=\\\"_blank\\\">online help</a>. &nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"58a965e4-844e-42e7-86eb-272a5518c4f1\",\n                            \"c0459a50-fec5-44af-a9ec-178c11cc0066\",\n                            \"aa42949c-b740-4132-91f7-b32bb4b13cac\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45289,\n                    \"Version\": 8,\n                    \"Guid\": \"b93717a1-66ac-4158-b450-fdca3d1963c4\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypeStaticName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45290,\n                    \"Version\": 2,\n                    \"Guid\": \"e1e88b2e-13eb-496b-9079-108a1c93538e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Type\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>the type of content this template will show - like a person, simple content, etc.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45291,\n                    \"Version\": 6,\n                    \"Guid\": \"f478424f-edaf-4638-80d7-2d04e52d5287\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53724,\n                    \"Version\": 5,\n                    \"Guid\": \"49d68cc0-1d3f-48ac-9520-7256e15d79c9\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"appid=[App:AppId]\"\n                        },\n                        \"Value\": {\n                          \"*\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentDemoEntity\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45292,\n                    \"Version\": 5,\n                    \"Guid\": \"267ef446-7e3e-4dc0-b028-a07419df6308\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Demo Item\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>this item will be used for previews, so the user can see what the template does without entering any data</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"76f2bae3-c5db-4eb7-ab3f-492c0b423f96\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45293,\n                    \"Version\": 3,\n                    \"Guid\": \"2bdb92d8-3161-4715-983a-6c98cc1c902e\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"[ContentTypeStaticName]\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupEnd2\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130239,\n                    \"Version\": 1,\n                    \"Guid\": \"224870b4-4652-4e98-aee2-fd4961cf4879\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupEndi2\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupContentPresentation\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45294,\n                    \"Version\": 8,\n                    \"Guid\": \"bce3f386-7820-4d9d-8d80-1500c7ff4e50\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content-Item Presentation\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Presentation settings are used to configure <em>how</em> your content will be shown. You can do very sophisticated things with this. <a href=\\\"https://r.2sxc.org/presentation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Read more about it in&nbsp;help</a>.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"a233ee52-fe97-4725-98ba-8db297d2bfdd\",\n                            \"c3b896f8-40ce-4c5a-8c93-71d29da61e2a\",\n                            \"bb822c03-2199-4358-a206-a7fd0e80bc8f\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45295,\n                    \"Version\": 8,\n                    \"Guid\": \"2900df3a-3d19-45e7-aa5f-b03dc9549eea\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PresentationTypeStaticName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45296,\n                    \"Version\": 6,\n                    \"Guid\": \"7307c1f1-54c0-46ce-97bd-b3e33df57804\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Presentation Type\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"Content-Type which is used for presentation-settings\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45297,\n                    \"Version\": 5,\n                    \"Guid\": \"1a9554d0-2161-4232-9ec4-0f5a418933f4\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53725,\n                    \"Version\": 4,\n                    \"Guid\": \"7fb11e1f-4719-46c2-8b74-a02239589b6d\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"appid=[App:AppId]\"\n                        },\n                        \"Value\": {\n                          \"*\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PresentationDemoEntity\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45298,\n                    \"Version\": 4,\n                    \"Guid\": \"9304ce52-2cfc-4e5e-a4b7-7e41ac1aec27\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Demo item\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>this will contain a demo entity which is&nbsp;used as a default (when the editor&nbsp;doesn't provide custom presentation settings) as well as for preview&nbsp;- when the template is just showing the demo-item to the editor - <a href=\\\"https://r.2sxc.org/presentation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">more</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"Content Presentation Demo Item\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"3d21c563-c7f4-4b62-9326-d9362124f2eb\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45299,\n                    \"Version\": 4,\n                    \"Guid\": \"4a6305ee-96f4-4571-98a9-9caa40adcc30\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"[PresentationTypeStaticName]\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupList\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45300,\n                    \"Version\": 4,\n                    \"Guid\": \"0c46e686-71ee-49e4-bae4-7e45f5970d1f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"List Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>You can create templates which show multiple items - like a list of links or images. enable this here to&nbsp;tell the edit-UI, that this template can show more than just 1 item - so this will provide more buttons like&nbsp;<em>add</em>,&nbsp;<em>move-up/down,</em> etc. - <a href=\\\"http://2sxc.org/help?tag=lists\\\" target=\\\"_blank\\\">more</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"4773a195-22b5-4bd6-b26e-e2d4ca3e4d37\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45301,\n                    \"Version\": 4,\n                    \"Guid\": \"76a380d9-a5d9-4445-9c5a-7ef930342046\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UseForList\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45302,\n                    \"Version\": 1,\n                    \"Guid\": \"8c834ae1-1ff8-4ac0-8209-ea67bb3d5acb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Enable list\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>turn this on, to tell the UI that this template handles lists</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45303,\n                    \"Version\": 1,\n                    \"Guid\": \"b6456f82-b538-4c11-8ce7-467f8d4d1ac3\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ListContentTypeStaticName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45304,\n                    \"Version\": 6,\n                    \"Guid\": \"dd197dbf-cb4a-4b64-bea8-442e85525fd2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Header Item ContentType\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>this is the content-type for the Header item in a list-template - <a href=\\\"http://2sxc.org/help?tag=lists\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">more</a>&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45305,\n                    \"Version\": 5,\n                    \"Guid\": \"aff8c996-a71a-4151-ae67-2fb432d32f38\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53726,\n                    \"Version\": 4,\n                    \"Guid\": \"577b2f0d-0639-40f8-99bf-dae5cda79742\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"appid=[App:AppId]\"\n                        },\n                        \"Value\": {\n                          \"*\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ListContentDemoEntity\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45306,\n                    \"Version\": 4,\n                    \"Guid\": \"e09c78d0-3956-41af-b4df-a51fc4513d36\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Demo Item for the Header\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>the default / demo-item for the list Header item - <a href=\\\"http://2sxc.org/help?tag=lists\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">more</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"3ecf8c26-2961-4e78-ad7a-008baa1fdd7e\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45307,\n                    \"Version\": 4,\n                    \"Guid\": \"a8e6c8fa-a615-425a-96f2-b7e9dcca80b9\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"[ListContentTypeStaticName]\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ListPresentationTypeStaticName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45308,\n                    \"Version\": 12,\n                    \"Guid\": \"220523e5-b075-4ce8-924a-0b98078ca8a1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Type of the Header Presentation\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Configure presentation settings of the list Header - read more <a href=\\\"http://2sxc.org/help?tag=lists\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">about lists</a> or <a href=\\\"https://r.2sxc.org/presentation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">presentation settings</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"da75905d-4dd7-4153-9956-a449af20b0c1\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45309,\n                    \"Version\": 11,\n                    \"Guid\": \"6d543491-8ad6-4dee-bc9c-b79ef027c630\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53727,\n                    \"Version\": 10,\n                    \"Guid\": \"4b30969b-6522-4063-87c4-7341b65aa974\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"appid=[App:AppId]\"\n                        },\n                        \"Value\": {\n                          \"*\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ListPresentationDemoEntity\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45310,\n                    \"Version\": 4,\n                    \"Guid\": \"e75e76a4-feaa-427d-923c-d8d4980e2eb0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Demo Item for the Header Presentation\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>the default/demo item for list presentations - <a href=\\\"https://r.2sxc.org/presentation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">more about presentation settings</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"9d39e5f7-e53e-4c1d-84be-f7347688a77d\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45311,\n                    \"Version\": 4,\n                    \"Guid\": \"422e0309-5658-45cf-b9d9-b60359252a31\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"[ListPresentationTypeStaticName]\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupQuery\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45312,\n                    \"Version\": 7,\n                    \"Guid\": \"582d633e-631a-4a31-b2c2-ebc377783a79\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Query Data for this Template\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>A template instance can work with Content, Data, both or neither. Here you can configure the system to&nbsp;provide pre-processed data to the template. <a href=\\\"http://2sxc.org/help?tag=data\\\" target=\\\"_blank\\\">more</a></p>\\n<p>Important:&nbsp;queries can only be used in views of an App. They are not available for normal Content. <a href=\\\"http://2sxc.org/help?tag=app\\\" target=\\\"_blank\\\">more</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8adcdefa-88e1-46d4-9874-c6a541774b6b\",\n                            \"b8e974f6-1a2a-4f56-8481-0ac781714f29\",\n                            \"1c1ac0c8-4d72-4314-a2ae-9fa54807e8e1\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45313,\n                    \"Version\": 7,\n                    \"Guid\": \"7f8ca82e-da0c-4ce9-bc21-39e32c024deb\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Pipeline\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45314,\n                    \"Version\": 1,\n                    \"Guid\": \"0ad46a09-0682-4be7-be01-e6613ccf8953\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Data Query\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>a prepared query which will provide data to this template - <a href=\\\"http://2sxc.org/help?tag=data\\\" target=\\\"_blank\\\">more</a></p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45315,\n                    \"Version\": 1,\n                    \"Guid\": \"3457bc4e-b88d-4ea0-bf65-61c79ded6629\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"DataPipeline\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": false\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupSearch\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130461,\n                    \"Version\": 7,\n                    \"Guid\": \"8070e0e6-f374-49a5-aaa5-2e9d7f74bd5a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Search Indexing Configuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If the platform like DNN has built-in search, it will find the data shown on this view point to the page this view is on. There are cases where you may want to customize this. See <a href=\\\"https://r.2sxc.org/customize-search\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"fe973517-5145-4292-b275-226d6d3cff04\",\n                            \"06582961-f1e3-4a1c-b470-c72e883ba829\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130466,\n                    \"Version\": 6,\n                    \"Guid\": \"5127665e-4048-4430-bd42-d28aa365e726\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarSearchIsDefault\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130486,\n                    \"Version\": 4,\n                    \"Guid\": \"e4655b81-2b3c-4161-b38f-075658f811be\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"VarSearchIsDefault\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"a71cb2c5-6724-44aa-95c1-f5d56e3b0dc6\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130487,\n                    \"Version\": 3,\n                    \"Guid\": \"24133bc9-4f4f-41f0-a085-a9c1d5e76440\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Custom Search Indexing (configure yourself)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Default Search Indexing (all Module-Data is given to the Search Index)\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SearchIndexingDisabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130469,\n                    \"Version\": 4,\n                    \"Guid\": \"3167240f-9739-41d9-84c5-884d0fcdb072\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"SearchIndexingDisabled\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"fc7fdefa-49b0-43d0-b0ea-e7065f8c7a3c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130470,\n                    \"Version\": 3,\n                    \"Guid\": \"9e06473b-c10a-4470-a4b9-c642970d2679\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Enable Search Indexing (default)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Disable Search Index (will not give data to the search indexer)\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarCustomSearchStreams\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130473,\n                    \"Version\": 7,\n                    \"Guid\": \"86036beb-68a5-4222-8621-740ea47507c5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"VarCustomSearchStreams\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8f0eb938-3077-40d4-a09d-d2bb240f216c\",\n                            \"e9388505-2517-4d00-8cbe-1574371b53a5\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130474,\n                    \"Version\": 6,\n                    \"Guid\": \"bcdc7191-29d0-45ea-959b-026b7ab1751d\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Pass all Query-Streams to the Search Index (default)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Restrict which Streams in the Query are passed to the Search Index\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SearchIndexingStreams\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130472,\n                    \"Version\": 5,\n                    \"Guid\": \"02969b50-b35e-44bd-9897-754214a18c05\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Query Streams to Use in the Search Index\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"60332050-45b6-434a-b982-eeb2dee9db0a\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130475,\n                    \"Version\": 3,\n                    \"Guid\": \"56b069d8-c4dc-4760-9a7b-bdbb93c023bb\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130476,\n                    \"Version\": 3,\n                    \"Guid\": \"e9b79aee-b5f4-4d78-b45b-2b43d57736fe\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.QueryInfo\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"QueryName=[Pipeline]&StreamName=Default\"\n                        },\n                        \"Value\": {\n                          \"*\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": true\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarCustomViewController\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130490,\n                    \"Version\": 4,\n                    \"Guid\": \"6415e564-b7d3-4c73-a5af-e74a300e4d69\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"VarCustomViewController\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"79b8d7f1-9f3b-441b-be61-633dee1526dd\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130491,\n                    \"Version\": 3,\n                    \"Guid\": \"3be8ba4e-5be1-4cf5-931a-dcc2c15e970f\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Index Data As-Is / Unmodified (default)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Use Code to Customize how Data is Modified\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ViewController\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-template-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130462,\n                    \"Version\": 7,\n                    \"Guid\": \"3ed13e96-d26a-4829-b97b-b5ef2999bc3c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-template-picker\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Controller for Search Results\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"9fe6801b-3bc1-4aea-86b9-a6ef180f5324\",\n                            \"567a2811-c819-4ce5-bc50-3f757628dace\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130463,\n                    \"Version\": 6,\n                    \"Guid\": \"de1a75b7-3abc-4f1c-95a2-43bb08cfb5f6\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130464,\n                    \"Version\": 1,\n                    \"Guid\": \"3ab7e362-9b8f-471f-a9cf-21ee6c6e2171\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183990,\n                    \"Version\": 1,\n                    \"Guid\": \"ee0d0e18-2dac-4efc-96b4-4eda019dd270\",\n                    \"Type\": {\n                      \"Id\": \"7775df1b-9c6d-4344-8f64-f6683b324615\",\n                      \"Name\": \"FieldSettingsGeneric\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"SettingsGeneric\": {\n                          \"en-us\": \"{\\r\\n  \\\"FileType\\\": \\\"C# Search\\\"\\r\\n}\"\n                        },\n                        \"Title\": {\n                          \"en-us\": \"View Configuration - ViewController (Search) - Provide Settings for Type/Location Masks\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupEnd3\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130245,\n                    \"Version\": 1,\n                    \"Guid\": \"bfd42a5d-aab0-4073-aad8-1d064dbfa6be\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupEnd3\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarShowAdvanced\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130198,\n                    \"Version\": 8,\n                    \"Guid\": \"b180997f-ecf6-49ea-b1fc-f135ad2cf252\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"VarShowAdvancedNew\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"b4f42c20-54fc-431b-8794-3fd3439615a7\",\n                            \"761e8fb2-c185-4707-a318-0ecee18944d4\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130199,\n                    \"Version\": 6,\n                    \"Guid\": \"e3627a2d-a26e-4bd0-8b18-8c0bb26dd9d1\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Hide Advanced Settings\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Show Advanced Settings\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupPublishData\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45316,\n                    \"Version\": 6,\n                    \"Guid\": \"c1b72ab2-f2fa-4eb4-99b2-1b4b2276234b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced Data Publishing Settings (Old, Deprecated, Avoid using)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is a deprecated feature. If you need something similar or are migrating away, check out the guide on <a href=\\\"https://r.2sxc.org/brc-13-id\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">https://r.2sxc.org/brc-13-id</a>&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"d4c5db00-2209-44fe-8a29-d1ad03c6b5df\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45317,\n                    \"Version\": 6,\n                    \"Guid\": \"6daab442-85d8-45dd-bab0-fa7becc228a7\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PublishData\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45318,\n                    \"Version\": 3,\n                    \"Guid\": \"9a20e57f-04b8-4795-b3b8-b9de9341fa06\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Enable Data-Publishing\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>enables instances of this&nbsp;view to provide the data it would render on the server&nbsp;as JSON - <a href=\\\"http://2sxc.org/help?tag=templates\\\" target=\\\"_blank\\\">more&nbsp;about templates</a>&nbsp;and more <a href=\\\"http://2sxc.org/help?tag=data\\\" target=\\\"_blank\\\">about publishing JSON data</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45319,\n                    \"Version\": 2,\n                    \"Guid\": \"275066db-6f5c-43a4-b26b-4299fca22128\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"StreamsToPublish\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45320,\n                    \"Version\": 2,\n                    \"Guid\": \"b8aa0d08-e2f4-4ebb-ab19-bddd3b4605d4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Published Streams\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>if you choose to publish data, you must specify which streams you will publish for security reasons - <a href=\\\"http://2sxc.org/help?tag=data\\\" target=\\\"_blank\\\">more</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45321,\n                    \"Version\": 2,\n                    \"Guid\": \"554d4efe-fb8b-41cb-9afe-527cf79563b3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45322,\n                    \"Version\": 2,\n                    \"Guid\": \"450cd512-c24d-4d23-ae8c-3e87729ee228\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupResources\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130400,\n                    \"Version\": 9,\n                    \"Guid\": \"a0af2b48-e3e0-43ca-b754-b7e5e46211a6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"View Settings and Resources\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Settings allow your Razor templates to be configured at View-level, or you can also use the Identifier for this. Resources are for multi-language labels and logos. <a href=\\\"https://r.2sxc.org/views\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">See View docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"0c93c5e3-43d7-46e8-a8fc-6e5b04814277\",\n                            \"04e7161e-5867-4108-8a6b-aab2bd1778f2\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130404,\n                    \"Version\": 8,\n                    \"Guid\": \"20938536-6f9e-4a9d-a5b1-e93b2c030efe\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarCustomIdentifier\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130448,\n                    \"Version\": 5,\n                    \"Guid\": \"8a1939a7-903c-4a09-b5b0-4a78d1e6f0a3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Use a Custom Identifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"a58024ab-bcca-4e5a-a288-82d3ab36e668\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130450,\n                    \"Version\": 4,\n                    \"Guid\": \"b0d4853a-ce5f-4b87-814a-10d65484c0c3\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Don't use a Custom Identifier (default)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Use a Custom Identifier for this View\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Identifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130447,\n                    \"Version\": 4,\n                    \"Guid\": \"ac8c6055-851f-44c5-bd2f-e259842eb49b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Custom Identifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is a unique ID for the view, which your code may access on <a href=\\\"https://docs.2sxc.org/api/dot-net/ToSic.Sxc.Context.ICmsView.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">CmsContext.View.Identifier</a> to change it's behaviour based on this identifier. Usually you will either use this OR use the settings.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"Templates can change their behavior based on this Identifier\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"7ed0691d-067d-41f3-8398-cfe75d21e77c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130454,\n                    \"Version\": 3,\n                    \"Guid\": \"42ebbe7f-626c-4081-995a-4de81870d868\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130455,\n                    \"Version\": 3,\n                    \"Guid\": \"b060d9e9-957a-4dcb-a8dd-e8f4b34745b6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarSettingsType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130417,\n                    \"Version\": 6,\n                    \"Guid\": \"83697f0b-73f0-4db2-84c0-d324c3b041f6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Settings Content-Type\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"Types in the Configuration Scope\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8f95c620-6b88-4212-b1cf-4f5a7b66ef46\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130428,\n                    \"Version\": 5,\n                    \"Guid\": \"2d334fbb-2221-4bd5-a32e-88f15ea8fe43\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130429,\n                    \"Version\": 5,\n                    \"Guid\": \"70dc81b7-0f04-45dd-960e-d82221ddf9af\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"appid=[App:AppId]&scope=System.Configuration\"\n                        },\n                        \"Value\": {\n                          \"*\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Settings\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130402,\n                    \"Version\": 5,\n                    \"Guid\": \"9b25bb9d-17c5-43b9-821a-9dc1edd2f833\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Settings Item\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"87dd3509-3510-49d8-8534-4a6f7136f34c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130431,\n                    \"Version\": 4,\n                    \"Guid\": \"9729b0fa-a0b2-4daf-86e6-70c0ffe109e4\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"[VarSettingsType]\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarResourcesType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130416,\n                    \"Version\": 11,\n                    \"Guid\": \"22b3093b-4af0-469f-83ba-2ba8e22b8834\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Resources Content-Type\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"Types in the Configuration Scope\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"6cac1021-b78b-4164-9736-dd66397e7432\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130418,\n                    \"Version\": 10,\n                    \"Guid\": \"42f4603e-aad1-4a49-ac2a-f2c61e5d7610\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130419,\n                    \"Version\": 10,\n                    \"Guid\": \"906010c9-8e14-4c9b-9d1e-f6f2252ff04b\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"appid=[App:AppId]&scope=System.Configuration\"\n                        },\n                        \"Value\": {\n                          \"*\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Resources\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130401,\n                    \"Version\": 7,\n                    \"Guid\": \"d7090d73-c986-4cc0-9063-fabcd899ad08\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Resources Item\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"7ec071ef-228d-4c9b-a86d-49d5724bc7ba\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130430,\n                    \"Version\": 6,\n                    \"Guid\": \"ffbcad72-19e7-4bfa-ba23-8c010bc0f8e0\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"[VarResourcesType]\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130201,\n              \"Version\": 3,\n              \"Guid\": \"204e815f-a0e6-4820-abf5-43851e0b9831\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Name; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide till name is added\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130249,\n              \"Version\": 17,\n              \"Guid\": \"1d80d0b3-9ffe-4496-90f1-9ae1027e6d16\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) {\\n  var path = data.Path ? data.Path : '';\\n  var icon = data.Icon ? '\\uD83D\\uDDBC️' : '';\\n  var preIcon = data.Location.toLowerCase() == 'global' ? '\\uD83E\\uDD1D ' : '';\\n  var add = path + (path || icon ? ' ' : '') + icon;\\n  if(add) add = ' (' + add + ')';\\n  return data.default + preIcon + add;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name: with path\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130250,\n              \"Version\": 23,\n              \"Guid\": \"a40d7865-f0d4-41c4-a30f-c4ba8bbe2953\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n if(context.cache.secondRun) return data.value;\\n context.cache.secondRun = true;\\n return !!data.Path;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Collapsed\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Collapsed: on initial load\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130178,\n              \"Version\": 8,\n              \"Guid\": \"37302ae7-4aa9-4c45-a99d-efe5ff9be05d\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.VarShowAdvanced; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show only if show-advanced\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130179,\n              \"Version\": 5,\n              \"Guid\": \"bbe01933-12da-4052-975e-795733012b74\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.VarShowAdvanced; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show only if ShowAdvanced\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130456,\n              \"Version\": 1,\n              \"Guid\": \"137d7d82-69dc-4216-8b16-7b28ce01f324\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n\\n  if(data.value == 'Portal File System') return 'Site';\\n  if(data.value == 'Host File System') return 'Global';\\n  return data.value;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value: Convert from old names to new automatically\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130194,\n              \"Version\": 5,\n              \"Guid\": \"58a965e4-844e-42e7-86eb-272a5518c4f1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Name && data.VarViewDataModel.indexOf('c') > -1; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show if Type \\\"C\\\" and Name ready\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130501,\n              \"Version\": 1,\n              \"Guid\": \"c0459a50-fec5-44af-a9ec-178c11cc0066\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n  return !!data.ContentTypeStaticName;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Collapsed\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Collapsed:  on load if already set\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130504,\n              \"Version\": 3,\n              \"Guid\": \"aa42949c-b740-4132-91f7-b32bb4b13cac\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  var typeOk = (data.ContentTypeStaticName ? ' ✅' : '');\\n  var demoOk = (data.ContentDemoEntity.length ? '✅' : '➖');\\n  var indicator = typeOk + (typeOk ? '/' + demoOk : '');\\n  return data.default + indicator;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name: Show if configured\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130397,\n              \"Version\": 2,\n              \"Guid\": \"76f2bae3-c5db-4eb7-ab3f-492c0b423f96\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!data.ContentTypeStaticName || !!data.ContentDemoEntity.length; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130171,\n              \"Version\": 5,\n              \"Guid\": \"a233ee52-fe97-4725-98ba-8db297d2bfdd\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.VarPresentation; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide if not VarPresentation\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 134246,\n              \"Version\": 2,\n              \"Guid\": \"c3b896f8-40ce-4c5a-8c93-71d29da61e2a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n  return data.PresentationDemoEntity.length > 0;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Collapsed\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Collapsed\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 134247,\n              \"Version\": 3,\n              \"Guid\": \"bb822c03-2199-4358-a206-a7fd0e80bc8f\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  var typeOk = (data.PresentationTypeStaticName ? ' ✅' : '');\\n  var demoOk = (data.PresentationDemoEntity.length ? '✅' : '➖');\\n  var indicator = typeOk + (typeOk ? '/' + demoOk : '');\\n  return data.default + indicator;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130398,\n              \"Version\": 1,\n              \"Guid\": \"3d21c563-c7f4-4b62-9326-d9362124f2eb\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!data.PresentationTypeStaticName || !!data.PresentationDemoEntity.length; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130193,\n              \"Version\": 5,\n              \"Guid\": \"4773a195-22b5-4bd6-b26e-e2d4ca3e4d37\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Name && data.VarViewDataModel.indexOf('l') > -1; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show if ViewDataModel has L and name ready\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130399,\n              \"Version\": 1,\n              \"Guid\": \"3ecf8c26-2961-4e78-ad7a-008baa1fdd7e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!data.ListContentTypeStaticName || !!data.ListContentDemoEntity.length; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130172,\n              \"Version\": 5,\n              \"Guid\": \"da75905d-4dd7-4153-9956-a449af20b0c1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.VarPresentation; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show based on VarPresentation\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130173,\n              \"Version\": 8,\n              \"Guid\": \"9d39e5f7-e53e-4c1d-84be-f7347688a77d\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { \\n  return data.VarPresentation\\n  && (!!data.ListPresentationTypeStaticName || !!data.ListPresentationDemoEntity.length);\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show based on VarPresentation\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130192,\n              \"Version\": 9,\n              \"Guid\": \"8adcdefa-88e1-46d4-9874-c6a541774b6b\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Name && data.VarViewDataModel.indexOf('q') > -1; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show if Q is set and name ready\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130502,\n              \"Version\": 1,\n              \"Guid\": \"b8e974f6-1a2a-4f56-8481-0ac781714f29\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n  return !!data.Pipeline;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Collapsed\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Collapsed: onload if already has value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130503,\n              \"Version\": 3,\n              \"Guid\": \"1c1ac0c8-4d72-4314-a2ae-9fa54807e8e1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  return data.default + (data.Pipeline.length ? ' (✅)' : '');\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name: Show value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130177,\n              \"Version\": 6,\n              \"Guid\": \"d4c5db00-2209-44fe-8a29-d1ad03c6b5df\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.PublishData || context.debug; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show only if show-advanced\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130188,\n              \"Version\": 13,\n              \"Guid\": \"07958470-13f6-4e7d-b2a2-901517058e2a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  // skip if already set\\n  if(context.cache.notFirstRun) {\\n    // set useList if it contains an 'l', but is not 'clq' which is show all\\n    const value = data.value[0];\\n    const useList = value != 'clq' && value.indexOf('l') != -1;\\n    // console.log('VarViewModel - debug value', data.value, useList);\\n    return {\\n      value: data.value,\\n      fields: [\\n        { name: 'UseForList', value: useList },\\n      ]\\n    };\\n  }\\n\\n  // First-Run Scenario\\n  context.cache.notFirstRun = true;\\n\\n  // new without name - set empty so it's still required\\n  if(!data.Name)\\n    return '';\\n\\n  const hasQuery = data.Pipeline.length == 1;\\n  const hasList = data.UseForList;\\n  const hasContent = data.ContentTypeStaticName != '';\\n  const key = (hasContent || hasList ? 'c' : '') + (hasList ? 'l' : '') + (hasQuery ? 'q':'');\\n  if(key == '')\\n    return '-'; // default to No-Content if not set\\n  return key;\\n});\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Value: Initialize based on state\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130238,\n              \"Version\": 4,\n              \"Guid\": \"d259040a-daca-473b-8fbe-7d8aacf8fa5e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Name && !!data.Path; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide till name && template\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130197,\n              \"Version\": 6,\n              \"Guid\": \"7ef8345b-d7dd-45d6-b786-025a839f9e50\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  if(context.cache.notFirstRun) return data.value || false;\\n  context.cache.notFirstRun = true;\\n\\n  // skip once it's been set; so only run this set-value on initial set\\n  // if(data.value != null) return data.value;\\n\\n  if(data.PresentationTypeStaticName || data.ListPresentationTypeStaticName) return true;\\n\\n  return false;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value: Set inital state\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130240,\n              \"Version\": 4,\n              \"Guid\": \"fb171277-ef31-4a9b-957d-97f19ab3d7eb\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Name && data.VarViewDataModel.indexOf('c') > -1; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Req. Name & content\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130200,\n              \"Version\": 9,\n              \"Guid\": \"b4f42c20-54fc-431b-8794-3fd3439615a7\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n// console.log('var show advanced', data, context);\\n  if(context.cache.notFirstRun) return data.value || false;\\n  context.cache.notFirstRun = true;\\n\\n  // Init with true if advanced stuff is set\\n  if(data.Type != 'C# Razor') return true;\\n  // check for both old/new value, as the value-init may not have run already\\n  if(data.Location != 'Site' && data.Location != 'Portal File System') return true;\\n  if(data.PublishData == true) return true;\\n\\n  // don't init otherwise\\n  return false;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value: Initialize if already using advanced stuff\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130237,\n              \"Version\": 3,\n              \"Guid\": \"761e8fb2-c185-4707-a318-0ecee18944d4\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Name; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide till name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130403,\n              \"Version\": 3,\n              \"Guid\": \"0c93c5e3-43d7-46e8-a8fc-6e5b04814277\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!data.Path; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: Hide till window.beta = true\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130499,\n              \"Version\": 4,\n              \"Guid\": \"04e7161e-5867-4108-8a6b-aab2bd1778f2\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  var resSuffix = data.Resources.length ? 'Resources: ✅' : '';\\n  var setSuffix = data.Settings.length ? 'Settings: ✅' : '';\\n  var setIdent = data.Identifier ? 'Ident: ' + data.Identifier : '';\\n  var suffix = resSuffix + (resSuffix && setSuffix ? ', ' : '') + setSuffix;\\n  suffix = suffix + (suffix && setIdent ? ', ' : '') + setIdent;\\n  if(suffix) suffix = ' (' + suffix + ')';\\n  return data.default + suffix;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name: Show if we have values\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130554,\n              \"Version\": 2,\n              \"Guid\": \"7ec071ef-228d-4c9b-a86d-49d5724bc7ba\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!(data.Resources.length || data.VarResourcesType); }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: Hide if empty and no type selected\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130555,\n              \"Version\": 1,\n              \"Guid\": \"87dd3509-3510-49d8-8534-4a6f7136f34c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!(data.Settings.length || data.VarSettingsType); }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: hide if empty and no settings-type\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130434,\n              \"Version\": 2,\n              \"Guid\": \"6cac1021-b78b-4164-9736-dd66397e7432\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  // After second run, once visible, keep visible. \\n  if(context.cache.secondRun && data.value) return true;\\n\\n  context.cache.secondRun = true;\\n  return data.Resources.length == 0;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: Show if needed\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130435,\n              \"Version\": 1,\n              \"Guid\": \"8f95c620-6b88-4212-b1cf-4f5a7b66ef46\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  // After second run, once visible, keep visible. \\n  if(context.cache.secondRun && data.value) return true;\\n\\n  context.cache.secondRun = true;\\n  return data.Settings.length == 0;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: Show if needed\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130488,\n              \"Version\": 4,\n              \"Guid\": \"a71cb2c5-6724-44aa-95c1-f5d56e3b0dc6\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n  var result =\\n    !data.SearchIndexingDisabled\\n    && data.SearchIndexingStreams.length == 0\\n    && data.ViewController == ''; \\n  return result;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130492,\n              \"Version\": 3,\n              \"Guid\": \"79b8d7f1-9f3b-441b-be61-633dee1526dd\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { \\n  var result =  !data.ViewController \\n    && !data.VarSearchIsDefault \\n    && !data.SearchIndexingDisabled;  \\n  return result;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130216,\n              \"Version\": 4,\n              \"Guid\": \"295c8af6-cb9e-4394-9fcc-1f957907e94c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Path; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show when template is set\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130252,\n              \"Version\": 3,\n              \"Guid\": \"50d9926b-bdc0-4e6e-a837-046fa1e59eee\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.default + (data.IsHidden ? ' ⛔': '') + (data.ViewNameInUrl ? ' \\uD83D\\uDD17': ''); }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130458,\n              \"Version\": 3,\n              \"Guid\": \"09cfe676-91a0-4f5f-8a20-a8b0d0fd420f\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!data.Path && !data.Icon; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: once path is known and no icon added yet\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 163996,\n              \"Version\": 2,\n              \"Guid\": \"4c014396-a4b7-4b2c-897e-b383d6f23021\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  const icon = data.Icon.toLowerCase();\\n  if (icon.indexOf('[app:path]/') == 0)\\n    return data.default + ' \\uD83D\\uDC4D\\uD83C\\uDFFD [App:Path]/... is the best option';\\n  if (icon.indexOf('file:') == 0)\\n    return data.default + \\\" ⚠️ using 'file:...' is not ideal, see docs link in description below\\\";\\n  return data.default;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130451,\n              \"Version\": 1,\n              \"Guid\": \"d14a0d46-518d-4dc9-b8a4-05444b70f97b\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.VarCustomIcon || !!data.Icon; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130453,\n              \"Version\": 1,\n              \"Guid\": \"7ed0691d-067d-41f3-8398-cfe75d21e77c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.VarCustomIdentifier || !!data.Identifier; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130500,\n              \"Version\": 2,\n              \"Guid\": \"a58024ab-bcca-4e5a-a288-82d3ab36e668\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !data.Identifier; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: Hide if set\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130467,\n              \"Version\": 5,\n              \"Guid\": \"fe973517-5145-4292-b275-226d6d3cff04\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) {\\n  // always show if there is search-configuration active\\n  if(!data.VarSearchIsDefault) return true;\\n  var result = !!data.Name \\n    && !!data.VarViewDataModel \\n    && data.VarViewDataModel.indexOf('-') == -1;\\n  return result;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130468,\n              \"Version\": 7,\n              \"Guid\": \"06582961-f1e3-4a1c-b470-c72e883ba829\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  var hint = data.SearchIndexingDisabled \\n    ? 'disabled'\\n    : (data.ViewController ? '⚙️ ' + data.ViewController : 'use default behavior');\\n\\n  if(data.SearchIndexingStreams.length > 0)\\n    hint += '; filter Query-Streams';\\n  return data.default + ' (' + hint + ')'; \\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Name:  show checkbox if used\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130465,\n              \"Version\": 2,\n              \"Guid\": \"9fe6801b-3bc1-4aea-86b9-a6ef180f5324\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return 'C# Search'; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.FileType\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting FileType: set to 'C# Search'\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130471,\n              \"Version\": 4,\n              \"Guid\": \"567a2811-c819-4ce5-bc50-3f757628dace\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { \\n  return !data.VarSearchIsDefault // hide if default\\n    && !data.SearchIndexingDisabled // hide if disabled\\n    // show if has content or toggle is on\\n    && (!!data.ViewController || data.VarCustomViewController);\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130489,\n              \"Version\": 1,\n              \"Guid\": \"fc7fdefa-49b0-43d0-b0ea-e7065f8c7a3c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !data.VarSearchIsDefault; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130478,\n              \"Version\": 2,\n              \"Guid\": \"60332050-45b6-434a-b982-eeb2dee9db0a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!data.SearchIndexingStreams || data.VarCustomSearchStreams; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130477,\n              \"Version\": 3,\n              \"Guid\": \"8f0eb938-3077-40d4-a09d-d2bb240f216c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.Pipeline.length == 1 && !data.VarSearchIsDefault && !data.SearchIndexingDisabled; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: Show if query and not disabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130479,\n              \"Version\": 2,\n              \"Guid\": \"e9388505-2517-4d00-8cbe-1574371b53a5\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n\\n  return !!data.SearchIndexingStreams;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value: Initial true if already set\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"3937fa17-ef2d-40a7-b089-64164eb10bab\",\n            \"Name\": \"2sxcPolymorphismConfiguration\",\n            \"Scope\": \"System.Cms\",\n            \"Metadata\": [\n              {\n                \"Id\": 72639,\n                \"Version\": 1,\n                \"Guid\": \"b45790f7-5a84-47a5-b1fa-72925948f4da\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Based on this configuration, 2sxc will use other template files if it can find them. To understand this and discover more, read about <a href=\\\"https://r.2sxc.org/polymorphism\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">polymorphism</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"View Polymorphism Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"3937fa17-ef2d-40a7-b089-64164eb10bab\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Mode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 72636,\n                    \"Version\": 4,\n                    \"Guid\": \"376830b7-1f8e-4865-9feb-df6805c01485\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Mode\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The mode determines how Polymorphism should auto-detect other editions.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 72637,\n                    \"Version\": 3,\n                    \"Guid\": \"3f7eb00b-4c08-4357-9242-2fd89f2aec39\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 72638,\n                    \"Version\": 3,\n                    \"Guid\": \"0c9042ac-395d-43d0-ad97-0cbe6bb6499a\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"None:\\nKoi CSS Framework:Koi?cssFramework\\nHost user staging/live:Permissions?IsSuperUser\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UsersWhoMaySwitchEditions\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183779,\n                    \"Version\": 5,\n                    \"Guid\": \"61b2da59-8201-49ba-b33f-e5f14f580a5f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Users Who May Switch Editions\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>...in addition to the SuperUser</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"afa379c8-d1a2-4a7b-bfef-8217a3bde6bb\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183780,\n                    \"Version\": 3,\n                    \"Guid\": \"e8e7c3d9-b590-4888-b101-161f26fa7592\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"4bd91a3d-ea09-4ae5-b984-42d934f072ae\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183783,\n              \"Version\": 1,\n              \"Guid\": \"afa379c8-d1a2-4a7b-bfef-8217a3bde6bb\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  // if selection is Permissions, also show the who-may-switch\\n  return data.Mode.includes('Permissions?');\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183781,\n              \"Version\": 1,\n              \"Guid\": \"4bd91a3d-ea09-4ae5-b984-42d934f072ae\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"[Item:Name] ([Item:UserName])\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.Users\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Get all Users\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Id\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"1f1c8118-8ea5-4db5-8e3d-f5ef2131050b\",\n            \"Name\": \"OpenGraph\",\n            \"Scope\": \"System.Cms\",\n            \"Metadata\": [\n              {\n                \"Id\": 150900,\n                \"Version\": 2,\n                \"Guid\": \"9f68aa8a-4d9d-463b-a9f8-77eba12050f9\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>BETA / EXPERIMENTAL - Configure Open-Graph Data for this Page/Object</p>\\n<p>As of right now it can only specify the type and title. In future, we'll add a lot of fields and also add merging OpenGraph values with other OpenGraph values added by content.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Open Graph Metadata\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"1f1c8118-8ea5-4db5-8e3d-f5ef2131050b\"\n                }\n              },\n              {\n                \"Id\": 150901,\n                \"Version\": 4,\n                \"Guid\": \"ddf58645-a30a-4486-b5f7-e63529709fb5\",\n                \"Type\": {\n                  \"Id\": \"acc185a7-f300-4468-bce8-d6a64038989d\",\n                  \"Name\": \"ToolbarButtonDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Command\": {\n                      \"en-us\": \"metadata\"\n                    },\n                    \"Ui\": {\n                      \"en-us\": \"\"\n                    },\n                    \"UiColor\": {\n                      \"en-us\": \"759BC5\"\n                    },\n                    \"UiIcon\": {\n                      \"en-us\": \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" height=\\\"48\\\" width=\\\"48\\\"><path d=\\\"M36.35 44q-2.35 0-4.025-1.675Q30.65 40.65 30.65 38.3q0-.35.075-.825t.225-.875L15.8 27.8q-.75.85-1.85 1.375t-2.25.525q-2.35 0-4.025-1.675Q6 26.35 6 24q0-2.4 1.675-4.05T11.7 18.3q1.15 0 2.2.45 1.05.45 1.9 1.3l15.15-8.7q-.15-.35-.225-.8-.075-.45-.075-.85 0-2.4 1.675-4.05T36.35 4q2.4 0 4.05 1.65t1.65 4.05q0 2.35-1.65 4.025-1.65 1.675-4.05 1.675-1.15 0-2.225-.375Q33.05 14.65 32.3 13.8l-15.15 8.4q.1.4.175.925.075.525.075.875t-.075.75q-.075.4-.175.8l15.15 8.6q.75-.7 1.75-1.125 1-.425 2.3-.425 2.4 0 4.05 1.65t1.65 4.05q0 2.35-1.65 4.025Q38.75 44 36.35 44Zm0-31.6q1.15 0 1.925-.775.775-.775.775-1.925t-.775-1.925Q37.5 7 36.35 7t-1.925.775q-.775.775-.775 1.925t.775 1.925q.775.775 1.925.775ZM11.7 26.7q1.15 0 1.925-.775.775-.775.775-1.925t-.775-1.925Q12.85 21.3 11.7 21.3t-1.925.775Q9 22.85 9 24t.775 1.925q.775.775 1.925.775ZM36.35 41q1.15 0 1.925-.775.775-.775.775-1.925t-.775-1.925Q37.5 35.6 36.35 35.6t-1.925.775q-.775.775-.775 1.925t.775 1.925Q35.2 41 36.35 41Zm0-31.3ZM11.7 24Zm24.65 14.3Z\\\"/></svg>\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"1f1c8118-8ea5-4db5-8e3d-f5ef2131050b\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"OgTitle\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 150896,\n                    \"Version\": 1,\n                    \"Guid\": \"40652b36-3a53-4f4b-930a-fdcf3ed12897\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"OgType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 150895,\n                    \"Version\": 5,\n                    \"Guid\": \"f3d9bd90-0361-492f-9311-1b5a3a7a2744\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"website\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Open Graph Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150898,\n                    \"Version\": 3,\n                    \"Guid\": \"916d769b-3023-4e50-9b1d-d75176982315\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150899,\n                    \"Version\": 3,\n                    \"Guid\": \"9e8a4598-cc0a-4313-822e-acc79292af09\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"article\\nbook\\nmusic.song\\nmusic.album\\nmusic.playlist\\nmusic.radio_station\\nprofile\\nvideo.movie\\nvideo.episode\\nvideo.tv_show\\nvideo.other\\nwebsite\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"b535b6aa-d0a1-40c1-b996-b7e8461efc0c\",\n            \"Name\": \"\\uD83E\\uDD77PolymorphismPreviewSettings\",\n            \"Scope\": \"System.Cms\",\n            \"Metadata\": [\n              {\n                \"Id\": 184171,\n                \"Version\": 3,\n                \"Guid\": \"3019e511-9198-47df-9d7e-28e3e93f9703\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Polymorphism Preview Settings\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"b535b6aa-d0a1-40c1-b996-b7e8461efc0c\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Background\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184180,\n                    \"Version\": 3,\n                    \"Guid\": \"3ee5e316-5935-431c-b736-9682d93c8b9b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Background Info Regarding Polymorphism\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<h3>What is this Polymorphism thing?</h3>\\n<p>Apps can have multiple editions of the code which generates the output. This is called&nbsp;<a href=\\\"http://go.2sxc.org/polymorphism\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Polymorphism</a>.</p>\\n<p>Some apps use polymorphism to detect the bootstrap version and show the appropriate output. Others use it so developers can create a&nbsp;<em>staging</em> edition of the code, while the editors and the general public see the<em> live</em> edition.&nbsp;</p>\\n<p>But in some situations - such as a \\\"preview before release\\\" or if a developer needs to see what the general public sees, it's important to quickly switch editions - which is what this is for.&nbsp;</p>\\n<h3>How does it work?</h3>\\n<p>If you select a specific edition, it will set a cookie&nbsp;<em>specific to this App</em> which will tell the backend to prefer the edition you have selected here.&nbsp;</p>\\n<p>Note that if that edition does not exist, it will still default to the standard edition, as is configured in each view.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184182,\n                    \"Version\": 2,\n                    \"Guid\": \"dfd04c70-ab0c-4222-9372-ddab8788e7f0\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"BackgroundInfoEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184181,\n                    \"Version\": 1,\n                    \"Guid\": \"b41c241a-7ea1-4a87-b88f-9c9a2f61880d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"BackgroundInfoEnd\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CurrentValues\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184173,\n                    \"Version\": 7,\n                    \"Guid\": \"46ed2ab3-27a3-4f55-b6aa-e88f25bc0cde\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Current Values\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>You are currently making preview settings for:</p>\\n<ul>\\n<li>App: <strong>[AppId]</strong></li>\\n<li>Cookie Name: <strong>[CookieId]</strong></li>\\n<li>Edition in the cookie:&nbsp;<strong>[Edition]</strong></li>\\n</ul>\\n<p><em>If a view does not exist in this edition, it will load the view from the default location.</em></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"450a2dbf-1dbf-45ad-afa3-19b7bb552fbe\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Edition\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184174,\n                    \"Version\": 5,\n                    \"Guid\": \"d19efb20-028e-4893-b766-70496aa775e6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Edition\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Pick any value - or use free text entry to specify another edition</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"55572d4e-a204-4a49-b460-193400a3e2e9\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184175,\n                    \"Version\": 3,\n                    \"Guid\": \"ee3bd6e3-e14b-45bf-87db-3e5dbf159a08\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184176,\n                    \"Version\": 3,\n                    \"Guid\": \"5370bad1-c4d7-4bc0-be64-bfb022aeb631\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Not configured (empty - usually recomended)\\nlive:live edition\\nstaging:staging edition\\nbs5:bs5 edition (Bootstrap5)\\nbs4:b4 edition (Bootstrap4)\\nbs3:bs3 edition (Bootstrap3)\\n\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 184177,\n              \"Version\": 5,\n              \"Guid\": \"450a2dbf-1dbf-45ad-afa3-19b7bb552fbe\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  // Helper from https://stackoverflow.com/a/25490531/5044294\\n  const getCookieValue = (name) => (\\n    document.cookie.match('(^|;)\\\\\\\\s*' + name + '\\\\\\\\s*=\\\\\\\\s*([^;]+)')?.pop() || ''\\n  )\\n  const appId = context.app.appId;\\n  const cookieId = `app-${appId}-edition`;\\n  const editionFromCookie = getCookieValue(cookieId);\\n  const result = data.default\\n    .replace('[AppId]', appId)\\n    .replace('[ZoneId]', context.app.zoneId)\\n    .replace('[CookieId]', cookieId)\\n    .replace('[Edition]', editionFromCookie || '(empty - use default)');\\n  return result;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Notes\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Notes\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184178,\n              \"Version\": 5,\n              \"Guid\": \"55572d4e-a204-4a49-b460-193400a3e2e9\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  // Helper from https://stackoverflow.com/a/25490531/5044294\\n  const getCookieValue = (name) => (\\n    document.cookie.match('(^|;)\\\\\\\\s*' + name + '\\\\\\\\s*=\\\\\\\\s*([^;]+)')?.pop() || ''\\n  )\\n  const cookieName = `app-${context.app.appId}-edition`;\\n\\n  if (!context.cache.alreadyRun) {\\n    context.cache.alreadyRun = true;\\n    return {\\n      value: getCookieValue(cookieName) ?? \\\"\\\"\\n    };\\n  }\\n\\n  const edition = data.value;\\n\\n  // Empty: flush cookie\\n  if (data.value == '') {\\n    console.log(`Will unset cookie ${cookieName}`);\\n    document.cookie = `${cookieName}=flush; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;\\n  }\\n  else {\\n    console.log(`Will set cookie ${cookieName}=${edition}`)\\n    document.cookie = `${cookieName}=${edition}; path=/;`;\\n  }\\n  // don't return anything, as we won't change the value\\n  // return data.value;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-copyright.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"077835ec-889e-433f-8acf-a4715acb3503\",\n            \"Name\": \"CopyrightDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 182602,\n                \"Version\": 2,\n                \"Guid\": \"3103d5f8-04da-480b-8747-5603cbd311a7\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Copyright Metadata \\uD83C\\uDFF7️\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"<p>Add Copyright Information to anything (decorator)</p>\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgLTk2MCA5NjAgOTYwIiB3aWR0aD0iMjQiPjxwYXRoIGQ9Ik00MDAtMzIwaDE2MHExNyAwIDI4LjUtMTEuNVQ2MDAtMzYwdi04MGgtODB2NDBoLTgwdi0xNjBoODB2NDBoODB2LTgwcTAtMTctMTEuNS0yOC41VDU2MC02NDBINDAwcS0xNyAwLTI4LjUgMTEuNVQzNjAtNjAwdjI0MHEwIDE3IDExLjUgMjguNVQ0MDAtMzIwWm04MCAyNDBxLTgzIDAtMTU2LTMxLjVUMTk3LTE5N3EtNTQtNTQtODUuNS0xMjdUODAtNDgwcTAtODMgMzEuNS0xNTZUMTk3LTc2M3E1NC01NCAxMjctODUuNVQ0ODAtODgwcTgzIDAgMTU2IDMxLjVUNzYzLTc2M3E1NCA1NCA4NS41IDEyN1Q4ODAtNDgwcTAgODMtMzEuNSAxNTZUNzYzLTE5N3EtNTQgNTQtMTI3IDg1LjVUNDgwLTgwWm0wLTgwcTEzNCAwIDIyNy05M3Q5My0yMjdxMC0xMzQtOTMtMjI3dC0yMjctOTNxLTEzNCAwLTIyNyA5M3QtOTMgMjI3cTAgMTM0IDkzIDIyN3QyMjcgOTNabTAtMzIwWiIvPjwvc3ZnPg==\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"077835ec-889e-433f-8acf-a4715acb3503\"\n                }\n              },\n              {\n                \"Id\": 182603,\n                \"Version\": 1,\n                \"Guid\": \"53450d95-11ec-42c4-b65a-55d245e6dc5e\",\n                \"Type\": {\n                  \"Id\": \"acc185a7-f300-4468-bce8-d6a64038989d\",\n                  \"Name\": \"ToolbarButtonDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Command\": {\n                      \"en-us\": \"metadata\"\n                    },\n                    \"Ui\": {\n                      \"en-us\": \"classes=single-field\"\n                    },\n                    \"UiColor\": {\n                      \"en-us\": \"\"\n                    },\n                    \"UiIcon\": {\n                      \"en-us\": \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" height=\\\"24\\\" viewBox=\\\"0 -960 960 960\\\" width=\\\"24\\\"><path d=\\\"M400-320h160q17 0 28.5-11.5T600-360v-80h-80v40h-80v-160h80v40h80v-80q0-17-11.5-28.5T560-640H400q-17 0-28.5 11.5T360-600v240q0 17 11.5 28.5T400-320Zm80 240q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z\\\"/></svg>\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"077835ec-889e-433f-8acf-a4715acb3503\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"CopyrightInfoType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182592,\n                    \"Version\": 6,\n                    \"Guid\": \"0feaad4c-aa5a-42f7-a60f-b11ff8ac26ec\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Copyright Information Type\",\n                          \"de-de\": \"Copyright Typ\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182595,\n                    \"Version\": 5,\n                    \"Guid\": \"7455795f-cd85-48e1-81bb-c72610683deb\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182596,\n                    \"Version\": 5,\n                    \"Guid\": \"2d8f2653-f6bd-49a3-9411-69f251e022de\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Not specified / unknown\\nsimple:Simple Copyright Information\\nadvanced:Advanced Copyright (reusable definitions)\",\n                          \"de-de\": \":Unbekannt / nicht angegeben\\nsimple:Einfache Angaben\\nadvanced:Erweiterte Angaben (mehrfach verwendbar)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CopyrightMessage\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182593,\n                    \"Version\": 3,\n                    \"Guid\": \"eff0239b-2d2c-458d-8f37-366d731935fd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Copyright Message\",\n                          \"de-de\": \"Copyright Mitteilung\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Simple message/text to describe the copyright. eg. \\\"by John Doe 2023, use only with permission\\\"</p>\",\n                          \"de-de\": \"<p>Einfacher Text um das Copyright zu beschreiben, bsp. \\\"von Erich Muster 2023\\\"</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"ba8bd5b8-4585-4761-b329-2f97ed812602\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182597,\n                    \"Version\": 1,\n                    \"Guid\": \"11cbf1f0-2644-4d7e-8e7e-1d504eed8669\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182598,\n                    \"Version\": 1,\n                    \"Guid\": \"906783ed-0d81-4a36-a21b-77702824f1a5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Copyrights\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182626,\n                    \"Version\": 3,\n                    \"Guid\": \"f0c30664-514b-48d8-89cb-8b35026be2d9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Copyrights\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"2994546c-d5b8-4d7e-9240-ee852cb9ad24\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182627,\n                    \"Version\": 1,\n                    \"Guid\": \"67623a6f-fc13-414a-a357-2cc7791337e1\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"\\uD83D\\uDDBACopyright\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 182631,\n              \"Version\": 2,\n              \"Guid\": \"2994546c-d5b8-4d7e-9240-ee852cb9ad24\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return data.CopyrightInfoType == 'advanced'; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182601,\n              \"Version\": 3,\n              \"Guid\": \"ba8bd5b8-4585-4761-b329-2f97ed812602\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return data.CopyrightInfoType == 'simple'; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"ac3df5f0-c637-45e7-a52b-b323d50e52ac\",\n            \"Name\": \"\\uD83D\\uDDBACopyright\",\n            \"Scope\": \"System.Cms\",\n            \"Metadata\": [\n              {\n                \"Id\": 182610,\n                \"Version\": 1,\n                \"Guid\": \"3ae81de2-7065-4beb-b00b-97a0c0e0ff82\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Copyright Information\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"ac3df5f0-c637-45e7-a52b-b323d50e52ac\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"CopyrightMessage\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182606,\n                    \"Version\": 3,\n                    \"Guid\": \"302389b4-d3fa-44a1-b9a1-b37468518700\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Copyright Title / Message\",\n                          \"de-de\": \"Urheberrechts-Titel / Beschreibung\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"example: John Doe 2023\",\n                          \"de-de\": \"Beispiel: Erich Muster 2023\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182615,\n                    \"Version\": 2,\n                    \"Guid\": \"fdda7148-bcef-4ef1-8d3b-f725c308620e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182616,\n                    \"Version\": 2,\n                    \"Guid\": \"4c96f7ad-ef82-43ba-9177-83d70445a204\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CopyrightType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182605,\n                    \"Version\": 7,\n                    \"Guid\": \"2d8f0d8f-5de4-4a7b-a136-c7dc95597139\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"copyright\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Copyright Type\",\n                          \"de-de\": \"Urheberrechts-Typ\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182611,\n                    \"Version\": 6,\n                    \"Guid\": \"217706a2-dd13-4298-9db1-920718254926\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182612,\n                    \"Version\": 6,\n                    \"Guid\": \"74028df4-2e51-4be2-a98a-db5ca19ec7a9\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":unknown / not defined\\nnone:none / no copyright\\ncopyright:Copyright (without specific details)\\nCC0:CC0 - Creative Commons - CC0 (no restrictions, like public domain)\\nCC BY:CC BY - Creative Commons Attribution\\nCC BY-SA:CC BY-SA Creative Commons Attribution-ShareAlike\\nCC BY-NC:CC BY-SA-NC Creat. Com. Attribution-NonCommercial\\nCC BY-NC-SA:CC BY-NC-SA Creat. Com. Attribution-NonCommercial-ShareAlike\\nCC BY-ND:CC BY-ND Creat. Com. Attribution-NonDerivative\\nCC BY-NC-ND:CC BY-NC-ND Creat. Com. Attribution-NonCommercial-NonDerivative\\nPD:Public Domain (free to use without any restrictions)\\nAGPLv3:Software AGPL (open-source, copy-left)\\nBSD:Software BSD\\nApache:Software Apache (open-source)\\nGPLv3:Software GPLv3 (open-source, copy-left)\\nLGPLv3:Software LGPLv3\\nMIT:Software MIT (open source)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CopyrightYear\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182607,\n                    \"Version\": 4,\n                    \"Guid\": \"12a39577-5ba7-48e4-8e07-209b43cea942\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Year\",\n                          \"de-de\": \"Jahr\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"acd75358-5ea3-4578-bd65-a2138c5a3e37\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182617,\n                    \"Version\": 2,\n                    \"Guid\": \"879d7307-0589-488f-bc2b-c661a763333e\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CopyrightOwner\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182608,\n                    \"Version\": 4,\n                    \"Guid\": \"6cbb8323-2854-47ff-90ad-07efe1bba113\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Owner\",\n                          \"de-de\": \"Eigentümer\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"7fa739ca-b340-4157-94a8-52ece8599442\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182618,\n                    \"Version\": 2,\n                    \"Guid\": \"a8e7759f-ae9a-44da-a747-85e4253d0f7a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182619,\n                    \"Version\": 2,\n                    \"Guid\": \"a06dc7a0-9950-4978-942d-1e3478f2ed57\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CopyrightLink\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182609,\n                    \"Version\": 4,\n                    \"Guid\": \"8c71d6f6-d04d-4dfd-a48c-ad1fd9736070\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Link\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"90ddd50e-1b48-43da-9207-1bf808476035\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182620,\n                    \"Version\": 2,\n                    \"Guid\": \"ffa020f3-661f-48c3-88c2-ffb01771a14e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182621,\n                    \"Version\": 2,\n                    \"Guid\": \"8f15982a-dbed-42c5-bb0b-77f009657b68\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 182622,\n              \"Version\": 3,\n              \"Guid\": \"acd75358-5ea3-4578-bd65-a2138c5a3e37\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"// v2((data) => { var ct = data.CopyrightType; return ct != '' && ct != 'none'; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182623,\n              \"Version\": 2,\n              \"Guid\": \"7fa739ca-b340-4157-94a8-52ece8599442\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"// v2((data) => { var ct = data.CopyrightType; return ct != '' && ct != 'none'; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182624,\n              \"Version\": 3,\n              \"Guid\": \"90ddd50e-1b48-43da-9207-1bf808476035\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"// v2((data) => { var ct = data.CopyrightType; return ct != '' && ct != 'none'; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-datasources.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"5c84cd3f-f853-40b3-81cf-dee6a07dc411\",\n            \"Name\": \"DsSerializationConfiguration\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 129147,\n                \"Version\": 3,\n                \"Guid\": \"e6cda735-769c-46a3-9c9a-abe756e64bc6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>You can configure what system properties (ID/Guid etc.) will be included in serialized data. This allows you to harden the APIs and not include any data you don't want to. Read about it in the <a href=\\\"https://r.2sxc.org/DsSerializationConfiguration\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\\n<p>This doesn't prevent code or data-sources from accessing the properties, but ensures that it won't be included in the JSON when serialized for WebApi.</p>\\n<p><em>This should usually be your last step in a Query, as other processing after this may prevent the configuration from reaching the serializer.&nbsp;</em></p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Serialization Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"<p>Configures how to serialize data coming through this DataSource.</p>\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5c84cd3f-f853-40b3-81cf-dee6a07dc411\"\n                }\n              },\n              {\n                \"Id\": 137442,\n                \"Version\": 1,\n                \"Guid\": \"6f1e6f06-a273-4141-a6a8-e6b02e3a60c8\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5c84cd3f-f853-40b3-81cf-dee6a07dc411\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129144,\n                    \"Version\": 2,\n                    \"Guid\": \"a94de776-35ed-47f1-af0f-25cffa11ac83\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Serialization Configuration\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Just a title for you to identify this data.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129161,\n                    \"Version\": 1,\n                    \"Guid\": \"19780bed-87b8-4510-9b79-24ac7ca8ba73\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129162,\n                    \"Version\": 1,\n                    \"Guid\": \"514a1037-9e7f-40f8-b07d-fb6f06aa366b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129145,\n                    \"Version\": 3,\n                    \"Guid\": \"cc20498e-239c-497b-b416-7b144cfbc6c8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Notes for your own use, to document why you did this.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129159,\n                    \"Version\": 2,\n                    \"Guid\": \"90172cab-8948-4ae1-b1a5-06682d736069\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129160,\n                    \"Version\": 2,\n                    \"Guid\": \"09bf74c7-6425-4baf-ab69-cd0ab8ae4b79\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupSystemProperties\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129114,\n                    \"Version\": 4,\n                    \"Guid\": \"c17ebb79-d707-4ce4-8ce0-10556d811f38\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"System Properties\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is about general system properties like ID, Guid and internal dates etc.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129115,\n                    \"Version\": 4,\n                    \"Guid\": \"35c9aa01-f3bc-45ab-8a95-cd03d656d54a\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129116,\n                    \"Version\": 2,\n                    \"Guid\": \"9251a6fb-c953-445a-80a0-d842efc6bf31\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Id\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129117,\n                    \"Version\": 2,\n                    \"Guid\": \"9afd84d4-c1ad-4a7e-9996-a91567d9a337\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129118,\n                    \"Version\": 2,\n                    \"Guid\": \"81d352a9-528b-42b4-93da-046d7c799fdf\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeGuid\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129119,\n                    \"Version\": 4,\n                    \"Guid\": \"5ee0ac4c-be6f-4cf5-8220-32a967f3b705\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Guid\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129120,\n                    \"Version\": 3,\n                    \"Guid\": \"56357812-54f1-433a-9389-bed89c5aa1b1\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129121,\n                    \"Version\": 3,\n                    \"Guid\": \"05151ecd-87ec-4a10-8451-c4de15beaa7c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"System Default (include for editors, don't for viewers):\\nDon't include:false\\nInclude:true\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeTitle\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129122,\n                    \"Version\": 3,\n                    \"Guid\": \"4cc2648e-74e8-48c6-befd-12ccfc83c4f6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129123,\n                    \"Version\": 2,\n                    \"Guid\": \"7debff63-f3c6-41e5-8d12-1cb9b3c0d19a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129124,\n                    \"Version\": 2,\n                    \"Guid\": \"344a28b5-3321-4b8b-a418-699e7b0f205e\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"System Default (include):\\nDon't include:false\\nInclude:true\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeCreated\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129125,\n                    \"Version\": 3,\n                    \"Guid\": \"a1c36ca1-35f3-44ff-9b18-fb0696582c3b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Created Date\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129126,\n                    \"Version\": 2,\n                    \"Guid\": \"3d4f16b4-7b7e-43b6-b4b8-a99762e2a63e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129127,\n                    \"Version\": 2,\n                    \"Guid\": \"f82133a7-7c60-41fb-ab15-b09790d218f6\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"System Default (include):\\nDon't include:false\\nInclude:true\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeModified\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129128,\n                    \"Version\": 3,\n                    \"Guid\": \"5e6076d4-38c9-4777-af80-74941d411aa0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Modified Date\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129129,\n                    \"Version\": 2,\n                    \"Guid\": \"f27ca86d-c33c-4561-b755-0b2cb3acb819\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129130,\n                    \"Version\": 2,\n                    \"Guid\": \"43bc2390-67d7-45a0-b82c-61012ae70e75\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"System Default (include):\\nDon't include:false\\nInclude:true\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeAppId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166530,\n                    \"Version\": 3,\n                    \"Guid\": \"ffb5d0e0-e734-45bd-99b1-c796ae9196cf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include AppId\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Normally not needed, but in rare cases where we load from multiple Apps it helps the UI to not offer edit-buttons.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166531,\n                    \"Version\": 2,\n                    \"Guid\": \"b388a2df-53c6-45b4-839b-44591a1d43eb\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166532,\n                    \"Version\": 2,\n                    \"Guid\": \"f1aa2183-af92-4cea-8bac-7b378a09c076\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupTypeProperties\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184106,\n                    \"Version\": 3,\n                    \"Guid\": \"932b2a02-089f-44d3-af98-f74c931072ca\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Type Properties\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Include information about the Content Type</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184112,\n                    \"Version\": 2,\n                    \"Guid\": \"a9ece415-15da-4b3c-9232-585b83f7d42d\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeTypeAs\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184107,\n                    \"Version\": 3,\n                    \"Guid\": \"0d013f78-1bfc-4711-806e-42ed15a077bf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Type Information\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184113,\n                    \"Version\": 1,\n                    \"Guid\": \"4fe64341-20e4-47ad-a86d-b7fa81f5178b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184114,\n                    \"Version\": 1,\n                    \"Guid\": \"3ae13b22-4cf8-422e-8599-a3ae81a9eed4\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Explicitly Don't include\\nobject:Include as an object structure\\nflat:Include as flat properties\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeTypeId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184110,\n                    \"Version\": 3,\n                    \"Guid\": \"3fb4baa9-380d-4bd1-b312-ed98d4496ebd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Type Id\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184115,\n                    \"Version\": 1,\n                    \"Guid\": \"3a0f8c69-bd35-4e74-8f91-769e7c979edf\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184116,\n                    \"Version\": 1,\n                    \"Guid\": \"674c6242-a59c-4b33-8409-06de312d0540\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeTypeName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184111,\n                    \"Version\": 3,\n                    \"Guid\": \"ee1d684b-b592-4cab-a121-d3dd4ef1c840\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Type Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184117,\n                    \"Version\": 1,\n                    \"Guid\": \"bba116c0-4304-46e5-9d83-239ce111d329\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184118,\n                    \"Version\": 1,\n                    \"Guid\": \"276f3efa-7bc4-40ee-9e35-8dc3d601a81c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TypePropertyNames\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184108,\n                    \"Version\": 3,\n                    \"Guid\": \"cdde0c93-93f1-4ade-9b95-2dcf02aebf49\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Type\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Type Property Name(s)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184119,\n                    \"Version\": 1,\n                    \"Guid\": \"e389c19c-3780-4d98-85e2-eb0e47d0d17b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184120,\n                    \"Version\": 1,\n                    \"Guid\": \"b8a2be59-a245-4d6c-8ac8-9e43160a4004\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default (Type)\\nType\\nContentType\\n\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupRelationshipProperties\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129134,\n                    \"Version\": 4,\n                    \"Guid\": \"04139ddc-10a5-4ace-9bd7-ce055dadd534\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Relationships\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This determines how information about related items / entities are included in the JSON.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129146,\n                    \"Version\": 3,\n                    \"Guid\": \"77b79718-f61b-4923-9017-fdff5846f091\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeRelationships\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129178,\n                    \"Version\": 3,\n                    \"Guid\": \"b94ea98a-30d1-4345-97d8-05a153364604\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Relationships\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129179,\n                    \"Version\": 2,\n                    \"Guid\": \"1bec5f1c-3d34-4adb-a84d-b4b856d214fd\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129180,\n                    \"Version\": 2,\n                    \"Guid\": \"fabc9c19-4d57-4c6f-8f16-4008f1b3c604\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeRelationshipsAsCsv\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167693,\n                    \"Version\": 4,\n                    \"Guid\": \"ef4f7188-f0d3-4062-ba18-1024b558da9e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Relationships As CSV\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"34febfa2-fb09-43d7-880d-9103e4d6f52a\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167694,\n                    \"Version\": 2,\n                    \"Guid\": \"9838782c-a2fc-45a6-8cac-d0842491675b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167695,\n                    \"Version\": 2,\n                    \"Guid\": \"1b8107ad-fa98-4df7-b5f6-5aff653579b9\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (return an object)\\nfalse:Return object\\ntrue:Return comma separated list of IDs as a string\\narray:Return a real array [..., ...] - especially for JSON\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeRelationshipId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129135,\n                    \"Version\": 3,\n                    \"Guid\": \"c18e9209-7a9f-49e5-86ae-3ca839b00252\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Relationship Id\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129136,\n                    \"Version\": 3,\n                    \"Guid\": \"239e1ccf-1b95-4628-bac4-585f5d22c655\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129137,\n                    \"Version\": 3,\n                    \"Guid\": \"0c65b2b0-606e-45e1-b56c-7b12588e2d05\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeRelationshipGuid\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129138,\n                    \"Version\": 3,\n                    \"Guid\": \"19ab21c4-a01a-4d0e-9de5-e9199e8472d8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Relationship Guid\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129139,\n                    \"Version\": 3,\n                    \"Guid\": \"9029512e-080c-4144-8ca6-ceb6369f569e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129140,\n                    \"Version\": 3,\n                    \"Guid\": \"7f4dbc5f-8f95-40f3-b6cf-e08453793d1b\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeRelationshipTitle\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129141,\n                    \"Version\": 5,\n                    \"Guid\": \"bf72b2eb-b165-48e1-9fc0-3ec583f51814\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Relationship Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"7813fc65-c96c-4a2e-a101-2018d3041d6f\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129142,\n                    \"Version\": 5,\n                    \"Guid\": \"8feb67b0-2a4c-4c4d-b044-8107fdff60e9\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129143,\n                    \"Version\": 5,\n                    \"Guid\": \"b8c22f77-9f56-43bf-a095-bae2c4f2a7dd\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupMetadata\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129165,\n                    \"Version\": 3,\n                    \"Guid\": \"d9332400-888a-4972-95f3-c282b33c36fb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Metadata\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>In case you're new to Metadata, read the <a href=\\\"https://r.2sxc.org/metadata\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129181,\n                    \"Version\": 2,\n                    \"Guid\": \"07ab6152-b6c4-4d9c-bc17-e5d788989dec\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeMetadata\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129169,\n                    \"Version\": 5,\n                    \"Guid\": \"8d176fb0-f52a-489e-b1c3-d7b8b5971cbd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Metadata\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129170,\n                    \"Version\": 3,\n                    \"Guid\": \"fa838c83-210e-4d06-a88c-79b003d190ae\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129171,\n                    \"Version\": 1,\n                    \"Guid\": \"ad69c663-5ca5-40dc-859a-fc6f39fe47b9\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129182,\n                    \"Version\": 2,\n                    \"Guid\": \"ba7eea6f-e077-4791-89c6-a27af84f8d11\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeMetadataId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129166,\n                    \"Version\": 5,\n                    \"Guid\": \"3ea1478a-e04a-481d-b838-680c26c260a8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Metadata Id\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"48274f4d-b0ce-434c-9c73-83bb91b9f2c6\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129172,\n                    \"Version\": 4,\n                    \"Guid\": \"c007f56e-76c6-4b93-b751-ccc4d9a553c8\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129173,\n                    \"Version\": 4,\n                    \"Guid\": \"6eb95953-f224-4542-8a4f-b0ce2f145317\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeMetadataGuid\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129167,\n                    \"Version\": 5,\n                    \"Guid\": \"453ec67b-d12a-4622-b9f8-2405d01e4574\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Metadata Guid\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"d8270ac1-8933-4883-a1a4-28911a31106c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129174,\n                    \"Version\": 4,\n                    \"Guid\": \"4afe2533-f277-44b2-9a06-5b66d256e34f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129175,\n                    \"Version\": 4,\n                    \"Guid\": \"fe629d77-e876-4d40-876b-4ec9f5ea6ff0\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeMetadataTitle\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129168,\n                    \"Version\": 6,\n                    \"Guid\": \"19d60555-7c29-4711-8015-05a62c3271b3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Metadata Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"6ee62e9e-2671-4e97-83a7-89731c1705e8\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129176,\n                    \"Version\": 5,\n                    \"Guid\": \"87a255b6-fb39-4574-9467-acd03aabaa6a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129177,\n                    \"Version\": 5,\n                    \"Guid\": \"d84062b3-c483-4e56-a966-6dc3c7110130\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupMetadataFor\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134192,\n                    \"Version\": 3,\n                    \"Guid\": \"9553bbcd-b348-4b32-abeb-a4236e423be9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Metadata For\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If an entity is metadata&nbsp;<strong>for</strong> something else, this would include the target information.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134194,\n                    \"Version\": 2,\n                    \"Guid\": \"b76c3631-617e-4ce5-95bd-587b22953e96\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeMetadataFor\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129131,\n                    \"Version\": 3,\n                    \"Guid\": \"5a8d5bdf-a9e3-46fb-91ac-181fe62555b3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Metadata-For information\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If you need to know more, read about <a href=\\\"https://r.2sxc.org/metadata\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">metadata</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129132,\n                    \"Version\": 3,\n                    \"Guid\": \"37f994eb-bb4a-45f8-bef3-85021d4a0e8b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129133,\n                    \"Version\": 3,\n                    \"Guid\": \"68e745a0-3194-4faf-93d5-5180e2c308f6\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (include for editors, don't for viewers)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeMetadataForId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134193,\n                    \"Version\": 6,\n                    \"Guid\": \"ef390c31-6230-4cf1-942c-65934d9a4c2e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Metadata-For Id / Key\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"9f210b50-38c1-4dae-8a57-b792c8246899\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134200,\n                    \"Version\": 5,\n                    \"Guid\": \"b6f0bb60-6f6d-48b7-a80b-10495b4876ed\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134201,\n                    \"Version\": 5,\n                    \"Guid\": \"32acde7a-5edb-4397-b84d-ab307694ee7d\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeMetadataForType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134202,\n                    \"Version\": 5,\n                    \"Guid\": \"3a9b4430-b202-47f1-a0ee-a74ef6acbeda\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Metadata-For Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"13578018-6550-406b-a9c8-4e1410891a33\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134204,\n                    \"Version\": 4,\n                    \"Guid\": \"57f0a2bd-3e47-480b-abf7-898095c81b11\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134205,\n                    \"Version\": 4,\n                    \"Guid\": \"e755f4a1-99e8-4398-84c4-c580c1732621\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't include)\\nfalse:Don't include\\ntrue:Include\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupOptimizations\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134206,\n                    \"Version\": 3,\n                    \"Guid\": \"87a15405-bb2f-4316-837f-07d6fb592809\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Optimizations\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These settings should make the JSON smaller, for example by not transporting null values. This is still experimental.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134208,\n                    \"Version\": 2,\n                    \"Guid\": \"d05935d1-ff55-430f-a693-d93e86cb021a\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RemoveNullValues\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134207,\n                    \"Version\": 8,\n                    \"Guid\": \"0074e7af-5dbf-4c2f-8b30-6f55e3a8a0fe\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Remove Null Values\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Will make the JSON smaller by omiting null values (usually null-strings).</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134209,\n                    \"Version\": 7,\n                    \"Guid\": \"96ab992f-6693-40c7-83b7-1d787bcf8966\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134210,\n                    \"Version\": 7,\n                    \"Guid\": \"ad354109-5995-47cb-baa3-8626c05df80c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't remove)\\nfalse:Don't remove null values\\ntrue:Remove null values\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RemoveZeroValues\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134211,\n                    \"Version\": 5,\n                    \"Guid\": \"ab98e5ec-38ca-4d48-83ce-9494980f46e2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Remove Zero Values\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Will make the JSON smaller by omitting zero values (usually numbers).</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134213,\n                    \"Version\": 4,\n                    \"Guid\": \"ffd42bbb-e9f1-45bb-8878-f497442940dd\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134214,\n                    \"Version\": 4,\n                    \"Guid\": \"3150b52a-a864-4ec6-b13f-46b3cf856a56\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't remove)\\nfalse:Don't remove zero values\\ntrue:Remove zero values\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RemoveEmptyStringValues\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134212,\n                    \"Version\": 3,\n                    \"Guid\": \"30129d49-6c0c-4b02-88fa-fec4f8318f29\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Remove Empty Strings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Will make the JSON smaller by omitting empty strings.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134215,\n                    \"Version\": 2,\n                    \"Guid\": \"b2daee8c-8d76-46b5-b881-742de2ec8440\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134216,\n                    \"Version\": 2,\n                    \"Guid\": \"eb3113a7-33a6-41ed-9410-0af638e0f5dd\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't remove)\\nfalse:Don't remove empty strings\\ntrue:Remove empty strings\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RemoveFalseValues\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134240,\n                    \"Version\": 5,\n                    \"Guid\": \"0bfafa12-3374-41de-b24d-e34067d4a85f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Remove Boolean False Values\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Will make the JSON smaller by omitting false booleans.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134241,\n                    \"Version\": 4,\n                    \"Guid\": \"ea66f1a9-ee00-4617-918e-407c8c558f2e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134242,\n                    \"Version\": 4,\n                    \"Guid\": \"cd8312fa-907b-42b3-b3ca-9eef6319392d\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":System Default (don't drop/remove)\\nfalse:Don't drop/remove false booleans\\ntrue:Drop / Remove false booleans\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 167696,\n              \"Version\": 2,\n              \"Guid\": \"7813fc65-c96c-4a2e-a101-2018d3041d6f\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.IncludeRelationshipsAsCsv == 'true'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Disabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 134195,\n              \"Version\": 2,\n              \"Guid\": \"48274f4d-b0ce-434c-9c73-83bb91b9f2c6\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.IncludeMetadata == 'true'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 134197,\n              \"Version\": 2,\n              \"Guid\": \"d8270ac1-8933-4883-a1a4-28911a31106c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.IncludeMetadata == 'true'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 134198,\n              \"Version\": 2,\n              \"Guid\": \"6ee62e9e-2671-4e97-83a7-89731c1705e8\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.IncludeMetadata == 'true'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 134199,\n              \"Version\": 2,\n              \"Guid\": \"9f210b50-38c1-4dae-8a57-b792c8246899\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.IncludeMetadataFor == 'true'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 134203,\n              \"Version\": 2,\n              \"Guid\": \"13578018-6550-406b-a9c8-4e1410891a33\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.IncludeMetadataFor == 'true'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 167697,\n              \"Version\": 2,\n              \"Guid\": \"34febfa2-fb09-43d7-880d-9103e4d6f52a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return data.IncludeRelationshipsAsCsv == 'true'\\n    ? 'CSV like \\\"27,42,999\\\"'\\n    : 'object like { id: 27, guid: \\\"guid-guid-guidguid\\\" }';\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Notes\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Notes\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.App\",\n            \"Name\": \"ToSic.Eav.DataSources.App\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 43017,\n                \"Version\": 2,\n                \"Guid\": \"588a0fe7-d1ea-430c-873e-761660a358d9\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"used to configure an App DataSource\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Learn more about the <a href=\\\"https://r.2sxc.org/DsApp\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">App data source in the wiki</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"App Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.App\"\n                }\n              },\n              {\n                \"Id\": 137425,\n                \"Version\": 1,\n                \"Guid\": \"870138c6-0506-4b70-b632-f30969a4ea45\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.App\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"ZoneSwitch\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40469,\n                    \"Version\": 6,\n                    \"Guid\": \"0d595197-1a7b-4ad8-b37a-c5963e1c8c5f\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46340,\n                    \"Version\": 3,\n                    \"Guid\": \"e1993559-5fc5-467e-ba1b-cac641fbff64\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43015,\n                    \"Version\": 3,\n                    \"Guid\": \"01efbdf4-d530-4ee6-a7b5-aead2bd98f19\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"TenantName\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Zones\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 137119,\n                    \"Version\": 4,\n                    \"Guid\": \"a4535811-8482-4ce8-9504-d8b408dcb025\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"ZoneSwitch\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AppSwitch\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40464,\n                    \"Version\": 6,\n                    \"Guid\": \"4a0853f9-35e7-475d-be14-48de7d4c4e20\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"App Switch\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Leave blank by default (to get data from current app). If you give this an&nbsp;App number then the data provided by this source will come from that app. <a href=\\\"http://2sxc.org/help?tag=ToSic.Eav.DataSources.App\\\" target=\\\"_blank\\\">Learn more in help</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40466,\n                    \"Version\": 1,\n                    \"Guid\": \"75bd688c-08e5-405e-8dc6-d62d3ef8bd92\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43016,\n                    \"Version\": 4,\n                    \"Guid\": \"f92bfa04-f390-45fc-a1e2-210c168490ea\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Apps\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"ZoneId=[ZoneSwitch]\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 137120,\n                    \"Version\": 2,\n                    \"Guid\": \"18d0050b-ece2-4a2b-b8f4-c2bfbe293f31\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupExperimental\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169164,\n                    \"Version\": 3,\n                    \"Guid\": \"5e9091d7-356c-451c-9a14-6797f4a150ab\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Experimental (v15)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These are very experimental settings, you should not use them yet.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"622e3024-b35e-4b9e-aaa5-ea6265148b0b\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169169,\n                    \"Version\": 1,\n                    \"Guid\": \"e00d498b-10d2-48c3-86b2-6fddc2decc47\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"WithAncestors\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169165,\n                    \"Version\": 2,\n                    \"Guid\": \"44312377-408c-4a54-84ca-0a44d989add3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"With Ancestors\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is a super advanced setting, you should normally not use this.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169166,\n                    \"Version\": 1,\n                    \"Guid\": \"9c020580-4fd7-4368-8346-2898270dca75\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169167,\n                    \"Version\": 1,\n                    \"Guid\": \"765665ca-eda1-43ba-9a37-6f532fae8ec7\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Not set (default) - without ancestors\\ntrue:With ancestors\\nfalse:Without ancestors\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 169168,\n              \"Version\": 2,\n              \"Guid\": \"622e3024-b35e-4b9e-aaa5-ea6265148b0b\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return context.debug; });\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"c5918cb8-d35a-48c7-9380-a437edde66d2\",\n            \"Name\": \"AttributeRename\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 70893,\n                \"Version\": 1,\n                \"Guid\": \"22bb9fea-e354-4fbe-8271-c74c917840b8\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Modify how attributes are renamed. For more information, check out the <a href=\\\"https://r.2sxc.org/DsAttributeRename\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">AttributeRename</a> docs.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Attribute Rename Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"c5918cb8-d35a-48c7-9380-a437edde66d2\"\n                }\n              },\n              {\n                \"Id\": 137426,\n                \"Version\": 1,\n                \"Guid\": \"dfdf5d12-296c-495d-be58-ba04a2925c47\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"c5918cb8-d35a-48c7-9380-a437edde66d2\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 70894,\n                    \"Version\": 3,\n                    \"Guid\": \"52bc209f-9df6-46ee-a9c8-c5f897e99d3a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Attribute Rename Configuration\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Just a title so you know what this configuration is for.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 70898,\n                    \"Version\": 2,\n                    \"Guid\": \"bf55f28a-6fba-4aa9-9b45-b207b0bd9c26\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 70899,\n                    \"Version\": 2,\n                    \"Guid\": \"1f1bfb85-2d7c-4ae6-ab12-34d924f3c1e5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AttributeMap\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 70895,\n                    \"Version\": 5,\n                    \"Guid\": \"c7aa1cc5-d686-48a6-8ba9-9f87a378e98a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"NewField1=OldField1\\nNewField2=OldField2\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Attribute Map\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The renaming map for the attributes. This is multi-line, one rename per line. The syntax:</p>\\n<p>NewFieldName=OldFieldName<br />NewField2=OldFieldName2</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 70900,\n                    \"Version\": 4,\n                    \"Guid\": \"42591d43-2d82-4752-aa28-9a10896472ab\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 70901,\n                    \"Version\": 4,\n                    \"Guid\": \"51271a1a-8379-4ba8-88f4-eaf26bbc8c0f\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 10.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 70904,\n                    \"Version\": 2,\n                    \"Guid\": \"ac272821-e90e-4975-9e1b-af467f4c5990\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Advanced\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Advanced settings - we recommend to leave the default settings.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 70905,\n                    \"Version\": 1,\n                    \"Guid\": \"f2ad7355-6248-453b-9cc0-154d8f6339be\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"KeepOtherAttributes\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 70896,\n                    \"Version\": 4,\n                    \"Guid\": \"3cfeeb1c-05df-4869-949b-e14f5ad0a707\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Keep Other Attributes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If true, the attributes / fields / properties which have not been renamed are preserved. If false, your new Entity only contains the renamed fields.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 137121,\n                    \"Version\": 2,\n                    \"Guid\": \"013606cb-d80b-43e0-8c46-5f46ffd375b9\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TypeName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 70897,\n                    \"Version\": 4,\n                    \"Guid\": \"5c1cb2e2-b63b-471b-92e2-c40eaf6b039d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Type Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Leave empty to keep the previous type name. If you add something here, the modified entities will have this new type name.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 70902,\n                    \"Version\": 3,\n                    \"Guid\": \"6d8b647c-ded6-4009-934e-c7bedc017b00\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 70903,\n                    \"Version\": 3,\n                    \"Guid\": \"23e8f194-185e-45e4-85dd-5f3b01bef27d\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.AttributeFilter\",\n            \"Name\": \"ToSic.Eav.DataSources.AttributeFilter\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 45082,\n                \"Version\": 7,\n                \"Guid\": \"066dcac5-c6fc-4c9e-85ad-f584b49a22cf\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Used to configure an AttributeFilter DataSource\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Filter out attributes/properties you don't want to pass on. This is usually to keep the output smaller, or to hide fields which you don't want to be published on the wire. Read about it in the <a href=\\\"https://r.2sxc.org/DsAttributeFilter\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Attribute/Property Filter\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.AttributeFilter\"\n                }\n              },\n              {\n                \"Id\": 137427,\n                \"Version\": 1,\n                \"Guid\": \"de16f715-85e5-43b8-9f7a-92a5eaa13614\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.AttributeFilter\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129151,\n                    \"Version\": 2,\n                    \"Guid\": \"f6a58a4d-947f-4e05-b8ae-c6b2760c056e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Attribute Filter\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Just a title to help you identify this data.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129155,\n                    \"Version\": 1,\n                    \"Guid\": \"474e8123-1cb1-4930-bd4a-7132ec13334e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129156,\n                    \"Version\": 1,\n                    \"Guid\": \"57d6d96b-b3ea-432b-b104-edaeabb96fe0\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129152,\n                    \"Version\": 3,\n                    \"Guid\": \"314458e9-e426-43a2-a354-defe78fe55b2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Notes for your own use, to document why you did this.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129157,\n                    \"Version\": 2,\n                    \"Guid\": \"d481e590-2a91-424a-bacf-afe6a44dcaed\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129158,\n                    \"Version\": 2,\n                    \"Guid\": \"4430ce6a-a601-4e70-8053-0adb8557e39f\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupConfiguration\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129153,\n                    \"Version\": 3,\n                    \"Guid\": \"adc0f72a-f5b4-413c-b2bb-de7b44aaa0e4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Configuration\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Put one property name on each line.</p>\\n<p>You can also leave the list empty if to keep all or remove all.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129154,\n                    \"Version\": 2,\n                    \"Guid\": \"3e770bc9-9a0b-4079-acce-9ddb7ae3a474\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Mode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129148,\n                    \"Version\": 5,\n                    \"Guid\": \"5ba338a4-3744-456a-beac-bd62fb07bd5a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"+\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Filter Mode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129149,\n                    \"Version\": 4,\n                    \"Guid\": \"1e833b16-cdc5-4682-8122-45d9b6ff5deb\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129150,\n                    \"Version\": 4,\n                    \"Guid\": \"c3e73a09-15c2-48d2-9a74-e4aa54fe9edf\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"Keep only attributes/properties listed below (default):+\\nRemove only attributes/properties listed below:-\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AttributeNames\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40470,\n                    \"Version\": 6,\n                    \"Guid\": \"27decc65-4c58-455f-8963-7db3c102aa08\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Attribute Names\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Write the attributes you want to keep in here. All others won't be passed on and won't be available upstream.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 129074,\n                    \"Version\": 3,\n                    \"Guid\": \"33759d00-3a14-4757-b688-949cd370b852\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129075,\n                    \"Version\": 3,\n                    \"Guid\": \"550b762d-03ff-4896-bade-b00a05096eab\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 10.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.Caches.CacheAllStreams\",\n            \"Name\": \"ToSic.Eav.DataSources.Caches.CacheAllStreams\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 74252,\n                \"Version\": 2,\n                \"Guid\": \"df93578a-f967-469c-844b-6ce5849fb338\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configuration for CacheAllStreams data source\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Cache All Streams\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.Caches.CacheAllStreams\"\n                }\n              },\n              {\n                \"Id\": 137428,\n                \"Version\": 1,\n                \"Guid\": \"67aeb808-3fc7-445f-9252-cae78cf5e202\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.Caches.CacheAllStreams\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40472,\n                    \"Version\": 2,\n                    \"Guid\": \"5552490c-89b9-466f-8960-85fda043ace6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"Cache All Streams Data Source\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Just a nice title so you know what this cache-component should do for you. Learn more about the <a href=\\\"http://2sxc.org/en/help?tag=ds-cacheallstreams\\\" target=\\\"_blank\\\">CacheAllStreams</a>&nbsp;data source.</p>\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RefreshOnSourceRefresh\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40473,\n                    \"Version\": 5,\n                    \"Guid\": \"8da8b556-7441-4292-81f3-f36d444f5df9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"True\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Refresh On Source Refresh\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is to cache things where the up-stream is already cached - for example when caching a filtered list of 2sxc-content-items. When this is set, the cache will check if the up-stream has been reloaded and if it has, then it will rebuild this cache as well. Learn more and check out best practices in&nbsp;<a href=\\\"http://2sxc.org/en/help?tag=ds-cacheallstreams\\\" target=\\\"_blank\\\" style=\\\"font-size: 13px; line-height: 18px;\\\">help</a><span style=\\\"font-family: Arial, Helvetica, sans-serif; font-size: 13px; line-height: 18px;\\\">.</span></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43025,\n                    \"Version\": 3,\n                    \"Guid\": \"58533ee6-81da-42df-ac36-a8dc10d8846b\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"true\\nfalse\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 137122,\n                    \"Version\": 2,\n                    \"Guid\": \"7ae46ea2-dd27-4874-af24-b4c6a3bf87ea\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CacheDurationInSeconds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40474,\n                    \"Version\": 5,\n                    \"Guid\": \"2ffc0160-7ac0-4534-b7ad-492a581c9cf3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"86400\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Cache Duration In Seconds\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>How long the cache will be kept / when it will be refreshed automatically. Common numbers are 86400 (1 day) or 3600 (1 hour). Learn more in <a href=\\\"http://2sxc.org/en/help?tag=ds-cacheallstreams\\\" target=\\\"_blank\\\">help</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43026,\n                    \"Version\": 3,\n                    \"Guid\": \"8a187244-d25a-4019-82a2-0d0a507b859e\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"10 seconds:10\\n1 minute:60\\n1 hour:3600\\n1 day:86400\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 137123,\n                    \"Version\": 2,\n                    \"Guid\": \"b7419403-16a9-4c04-9aa9-1aa8de0fa2dc\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CacheErrorDurationInSeconds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184154,\n                    \"Version\": 2,\n                    \"Guid\": \"afcb4644-b6c3-4897-9f09-9fe5fad1456d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"CacheErrorDurationInSeconds\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Determine how long streams should be cached which contain errors.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184155,\n                    \"Version\": 1,\n                    \"Guid\": \"93169d80-1521-4c87-8df1-6ea4d980db5f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184156,\n                    \"Version\": 1,\n                    \"Guid\": \"24f8267e-81bf-4b01-8707-e8c5be0424e8\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"0:0 = Cache for 3 times as-long-as-it-takes to generate source data (delay retry on slow source)\\n-1:-1 = don't cache at all and retry immediately\\n15:15 seconds\\n60:60 seconds\\n300:5 minutes\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"832cd470-49f2-4909-a08a-77644457713e\",\n            \"Name\": \"ChildrenDataSourceConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 135454,\n                \"Version\": 5,\n                \"Guid\": \"b52b5cfd-0424-4e68-9ec0-d8479e588cfb\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>The <a href=\\\"https://r.2sxc.org/DsChildren\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Children Data Source</a> will get you the children relationships of all the items in the Default In-Stream. Note that if you need parent relationships, use the <a href=\\\"https://r.2sxc.org/DsParents\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Parents DataSource</a>.</p>\\n<p>You only need the Default In-Stream, because the items themselves already know about their relationships. The resulting stream will contain all the children matching the criteria provided.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Children DataSource Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"832cd470-49f2-4909-a08a-77644457713e\"\n                }\n              },\n              {\n                \"Id\": 137429,\n                \"Version\": 1,\n                \"Guid\": \"aa4e478f-26ed-4113-8016-d5f7ee4b1181\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"832cd470-49f2-4909-a08a-77644457713e\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135455,\n                    \"Version\": 3,\n                    \"Guid\": \"933ca063-522c-47e0-baa4-c50e016367f5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Get Children Items\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135479,\n                    \"Version\": 2,\n                    \"Guid\": \"3fef31d4-20f7-4812-889f-f8e5e99e47ce\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135480,\n                    \"Version\": 2,\n                    \"Guid\": \"36a7a438-862b-4abc-9056-6a2d8209e17e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FilterDuplicates\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135507,\n                    \"Version\": 5,\n                    \"Guid\": \"b2a736a3-9242-4e5d-b2b5-0a918280ead8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Filter Duplicates (Distinct)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135508,\n                    \"Version\": 4,\n                    \"Guid\": \"6759fc38-a910-42c9-a231-7b263b42f0fb\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135509,\n                    \"Version\": 4,\n                    \"Guid\": \"d56499dd-36a1-4552-85cd-c6d93a6a6046\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"true:True - filter duplicates, return each entity once even if referenced many times\\nfalse:False - don't filter, return each related entity even if it's referenced many times\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FieldName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135456,\n                    \"Version\": 6,\n                    \"Guid\": \"03a15bbf-e250-4aef-bc3b-ad02eb2faea8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Field Name of Relationships\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field which contains the related items/entities. If you leave this empty, it will get you all the childen of the incoming items, on every relationship field.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"Type field name if you only want the relationships of a specific field\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135477,\n                    \"Version\": 5,\n                    \"Guid\": \"4314289a-8972-4d0f-81e2-c76aef2273c1\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135478,\n                    \"Version\": 5,\n                    \"Guid\": \"71e001c6-e667-4974-bca5-b68b0168a263\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarSetContentTypeName\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135458,\n                    \"Version\": 5,\n                    \"Guid\": \"dcbef482-f33e-49a1-b35c-ea89aae1499e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"VarSetContentTypeName\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"df9b7729-3e28-46be-af3a-940475bcb702\",\n                            \"4b8ae79c-6414-45c3-be57-78e0983e7d03\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135462,\n                    \"Version\": 4,\n                    \"Guid\": \"f5c16c6a-339a-48aa-bf32-8a71db8802c3\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Only filter by Relationship Field (recommended)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Also filter by Type of the Related Item\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MessageContentTypeName\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135459,\n                    \"Version\": 4,\n                    \"Guid\": \"8c22ec13-95bf-406e-a472-f690915d73e4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"ContentType - Important\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Setting the ContentType is rarely needed, which is why the settings is hidden by default.&nbsp;</p>\\n<p>Make sure you really need to set this - otherwise best leave as is.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"76a493c7-6e78-4cb2-bc5f-ba1b4a39a752\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypeName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135457,\n                    \"Version\": 5,\n                    \"Guid\": \"e9d4ecde-9d6b-4285-8a30-c1f57361bf09\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"ContentType Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"92754f97-369d-4d09-959f-411fd5aaebdb\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135465,\n                    \"Version\": 4,\n                    \"Guid\": \"6021e650-bbd8-43bd-993e-33cf0ad936ca\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135466,\n                    \"Version\": 5,\n                    \"Guid\": \"b935d46d-69b4-4f8e-986b-ecf95d96b67c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 135464,\n              \"Version\": 3,\n              \"Guid\": \"92754f97-369d-4d09-959f-411fd5aaebdb\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.VarSetContentTypeName; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 135460,\n              \"Version\": 2,\n              \"Guid\": \"df9b7729-3e28-46be-af3a-940475bcb702\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n  return data.ContentTypeName.length > 0;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 135461,\n              \"Version\": 1,\n              \"Guid\": \"4b8ae79c-6414-45c3-be57-78e0983e7d03\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.value; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 135463,\n              \"Version\": 2,\n              \"Guid\": \"76a493c7-6e78-4cb2-bc5f-ba1b4a39a752\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.VarSetContentTypeName; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"7c2b2bc2-68c6-4bc3-ba18-6e6b5176ba02\",\n            \"Name\": \"ToSic.SexyContent.DataSources.ModuleDataSource\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 41472,\n                \"Version\": 6,\n                \"Guid\": \"731fdd95-4e2a-4317-bf90-dd48d7e7d1f6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Module DataSource with Data of a specific module\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This will return the items of a Module Instance, in two streams <em>Content</em> and <em>Header</em>.&nbsp;By default, it takes the module-id from the current context, but you can specify a specific module if you need it.&nbsp;Read more in the <a href=\\\"https://docs.2sxc.org\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a> about the <a href=\\\"https://docs.2sxc.org/api/dot-net/ToSic.Sxc.DataSources.CmsBlock.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">CmsBlock DataSource</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"CMS Block (Module)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"7c2b2bc2-68c6-4bc3-ba18-6e6b5176ba02\"\n                }\n              },\n              {\n                \"Id\": 137430,\n                \"Version\": 1,\n                \"Guid\": \"579af211-1044-44aa-98d8-8884ab45edf2\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"7c2b2bc2-68c6-4bc3-ba18-6e6b5176ba02\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41473,\n                    \"Version\": 2,\n                    \"Guid\": \"97948f14-12db-4d93-8c97-91746eeea501\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just a title for your own use - not important</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41476,\n                    \"Version\": 1,\n                    \"Guid\": \"a8c092fb-45f3-4df5-aecd-b7cc73805b75\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41474,\n                    \"Version\": 3,\n                    \"Guid\": \"da05a42f-079e-4bfc-ad99-311156702318\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>general notes so you know what this is for - like \\\"this is the module where the editor configures xyz-settings\\\"</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41477,\n                    \"Version\": 2,\n                    \"Guid\": \"90a282e3-be70-4f91-be7c-b15f555d15d8\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 3.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 144346,\n                    \"Version\": 1,\n                    \"Guid\": \"71fcc862-d82e-4326-8248-63d9a174df69\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"InstanceId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41475,\n                    \"Version\": 6,\n                    \"Guid\": \"f02ca527-c77b-42c2-8c41-01a812d7394d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"[Module:Id]\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"InstanceId / ModuleId\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The moduleID or a token giving you the module. By default it's [Module:Id]</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41478,\n                    \"Version\": 5,\n                    \"Guid\": \"211222c2-2d30-45a8-910e-e11915f0083d\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 133317,\n                    \"Version\": 4,\n                    \"Guid\": \"e871b431-6a8d-4d72-8f8a-93b6a9772d47\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.CsvDataSource\",\n            \"Name\": \"ToSic.Eav.DataSources.CsvDataSource\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 74253,\n                \"Version\": 4,\n                \"Guid\": \"f331b3c3-145f-4b71-96a6-5eb9265b8170\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configure the CSV data source.\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>This DataSource will read CSV files and provide them as Data Entities. Best read the <a href=\\\"https://r.2sxc.org/DsCsv\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"CSV DataSource\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.CsvDataSource\"\n                }\n              },\n              {\n                \"Id\": 137431,\n                \"Version\": 1,\n                \"Guid\": \"eabdcf88-67f7-4bea-9e7b-e4d3fc47db8f\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.CsvDataSource\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40475,\n                    \"Version\": 4,\n                    \"Guid\": \"ffee6fe6-bd48-4da4-87fb-8645af408cbb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Csv Data Source\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Just a title to help you know what this is for.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 129236,\n                    \"Version\": 2,\n                    \"Guid\": \"c2dd27b2-3d4c-44c2-8d89-f3c60f69dea9\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129246,\n                    \"Version\": 1,\n                    \"Guid\": \"1df3550d-3920-40c9-8046-679521bf71c4\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129247,\n                    \"Version\": 3,\n                    \"Guid\": \"8cdd9119-6282-44b4-81eb-ae759585b6f3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Notes to help you remember why you configured stuff :)</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129249,\n                    \"Version\": 2,\n                    \"Guid\": \"acde2607-5af1-41ed-9f84-89f0a552d96c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129250,\n                    \"Version\": 2,\n                    \"Guid\": \"e0edabca-6de6-437a-a452-86cdc567f0db\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupSettings\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129248,\n                    \"Version\": 2,\n                    \"Guid\": \"72027819-2f78-4716-a98f-91a02f0eb42b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129251,\n                    \"Version\": 1,\n                    \"Guid\": \"c4d8f725-d722-48e6-8151-95275aae85bc\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FilePath\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40476,\n                    \"Version\": 5,\n                    \"Guid\": \"d67d3b2e-e929-4aec-bbb2-133a42b535a7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"File Path\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>File path relative to the web root, for example '/Portals/0/Data/MyMeasurements.csv' or '[App:Path]/demo.csv'. Read the <a href=\\\"https://r.2sxc.org/DsCsv\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">online help</a> for more.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 129238,\n                    \"Version\": 3,\n                    \"Guid\": \"c4d309c3-4f7d-4167-9b1c-834141c81b43\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137124,\n                    \"Version\": 2,\n                    \"Guid\": \"bc957612-77ef-4c56-bdb6-cb9ac60c932e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Delimiter\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40477,\n                    \"Version\": 8,\n                    \"Guid\": \"070d8dd9-9f77-4477-86ae-c5fba15fcafa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \";\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Value Delimiter\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Delimiter of values in the&nbsp;rows, for example the&nbsp;';', ','&nbsp;or tab. Leave blank for default (i.e.&nbsp;the tab). Read the <a href=\\\"https://r.2sxc.org/DsCsv\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">online help&nbsp;</a>for more incl. how to add special characters like tab.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43024,\n                    \"Version\": 5,\n                    \"Guid\": \"abc35e60-4770-4c1c-924c-c6a01a9c6446\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \",\\n;\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 137125,\n                    \"Version\": 2,\n                    \"Guid\": \"8d294ff1-694d-442e-a87d-7a7738b4c2a0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40478,\n                    \"Version\": 5,\n                    \"Guid\": \"9df5c027-d058-4fa5-bbcc-0130d60afd57\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Csv Data\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Type Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The content type of the entities passed to the output stream. This can be an arbitrary name.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 129241,\n                    \"Version\": 3,\n                    \"Guid\": \"c4824c6b-6c3e-4259-a4a3-291a5d4a5b70\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137126,\n                    \"Version\": 2,\n                    \"Guid\": \"9b3c5cf2-09b7-4898-b562-ed62b84532ec\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IdColumnName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40479,\n                    \"Version\": 5,\n                    \"Guid\": \"d65dbbdc-a54a-4969-bd25-9cdc52ee520b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Id Column Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The <em>case sensitive</em> name of the column that should be used for the entity IDs. If no name is specified, the row numbers will be used for the IDs.&nbsp;See the <a href=\\\"https://r.2sxc.org/DsCsv\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">online help&nbsp;</a>for more.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 129243,\n                    \"Version\": 3,\n                    \"Guid\": \"653c862e-2d58-4ba7-bf84-115d6737f27a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137127,\n                    \"Version\": 2,\n                    \"Guid\": \"2a05d383-b81b-41c3-8316-50ca9dcf1b4a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TitleColumnName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40480,\n                    \"Version\": 5,\n                    \"Guid\": \"73f64afd-362a-4735-8983-2d4617d2a7df\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title Column Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The <em>case sensitive</em> name of the column used for the entity titles. Leave blank to automatically take the first column.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 129245,\n                    \"Version\": 3,\n                    \"Guid\": \"8d875e74-5a53-467a-83f5-bb9aa586e2d0\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137128,\n                    \"Version\": 2,\n                    \"Guid\": \"7b376c55-2ec1-4fa1-a850-85f6c4a7913c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.EntityIdFilter\",\n            \"Name\": \"ToSic.Eav.DataSources.EntityIdFilter\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 45083,\n                \"Version\": 2,\n                \"Guid\": \"12886273-383d-448f-a55a-804cd01aafa7\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"used to configure an EntityIdFilter DataSource\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Use the Item-Id Filter to keep only one or a few items - of which you know the ID. The ID can also come from a URL or something, when used in details-pages. Read about it in the <a href=\\\"https://r.2sxc.org/DsIdFilter\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Entity ID Filter\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.EntityIdFilter\"\n                }\n              },\n              {\n                \"Id\": 137432,\n                \"Version\": 1,\n                \"Guid\": \"145ae44d-ac93-4b6e-8ec1-1ee65e9aaff8\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.EntityIdFilter\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"EntityIds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40481,\n                    \"Version\": 1,\n                    \"Guid\": \"f5417b6e-d4e9-4438-9d41-7b2a05e9e9f7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"Name\": {\n                          \"*\": \"EntityIds\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Comma separated list of Entity IDs, like 503,522,5066,32\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.EntityTypeFilter\",\n            \"Name\": \"ToSic.Eav.DataSources.EntityTypeFilter\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 43019,\n                \"Version\": 2,\n                \"Guid\": \"a7d07d42-32ad-4ad6-ae9f-3e5c7aa006c2\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"used to configure an EntityTypeFilter DataSource\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Learn more about the <a href=\\\"https://r.2sxc.org/DsTypeFilter\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">content-type / Entity-type filter in the wiki</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Entity Type Filter\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.EntityTypeFilter\"\n                }\n              },\n              {\n                \"Id\": 137433,\n                \"Version\": 1,\n                \"Guid\": \"c1553b86-a79c-4d3a-8549-1a66cb9d938c\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.EntityTypeFilter\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"TypeName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40483,\n                    \"Version\": 3,\n                    \"Guid\": \"21ab2b50-e283-4fe1-bea1-524e4466e4fb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Type\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The name of the content type</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43018,\n                    \"Version\": 2,\n                    \"Guid\": \"11cd2452-30c6-4aff-871b-a9e7bd542ec5\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"7b4fce73-9c29-4517-af14-0a704da5b958\",\n            \"Name\": \"LanguageModelerDSConfiguration\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 129464,\n                \"Version\": 2,\n                \"Guid\": \"1b87d76b-d158-4eca-95ba-4b5f0abe5fc6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Change tabular language data into Entities.\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>This helps you turn tabular language data into multi-language properties the way 2sxc uses it.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Language Modeler\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"7b4fce73-9c29-4517-af14-0a704da5b958\"\n                }\n              },\n              {\n                \"Id\": 137434,\n                \"Version\": 1,\n                \"Guid\": \"9a560261-cdfa-40b8-9f44-bcecd6f3d144\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"7b4fce73-9c29-4517-af14-0a704da5b958\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129454,\n                    \"Version\": 2,\n                    \"Guid\": \"fa7c5378-05d7-4851-b817-21b04f1e92f5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Language Modeler Configuration\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Just a title for you to give this configuration a name.\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129455,\n                    \"Version\": 2,\n                    \"Guid\": \"00a0c1af-7782-4aa0-8c9c-100f0bdecf91\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129456,\n                    \"Version\": 2,\n                    \"Guid\": \"3b106041-ff3b-4b5e-af38-62089b073e10\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129457,\n                    \"Version\": 3,\n                    \"Guid\": \"6716e4c2-3d27-474e-91ad-0605c95109bf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"just notes for yourself to better understand what this is for\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129458,\n                    \"Version\": 2,\n                    \"Guid\": \"98133cff-2e55-431d-bd49-120fe078ef58\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129459,\n                    \"Version\": 1,\n                    \"Guid\": \"5eb259f1-5061-4ffc-bfca-a641c06ba30b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144347,\n                    \"Version\": 1,\n                    \"Guid\": \"fd6e5b68-5d64-4461-8f6e-2a69d13a8026\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FieldMap\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129460,\n                    \"Version\": 4,\n                    \"Guid\": \"0e52c404-8088-4119-add1-f8c147493163\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"ChangeTo:ValueFrom\\nName:en-us=NameEn,de-de=NameDe\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"FieldMap\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Enter one mapping each line. Example: <strong>Target:Source</strong> will change the attribute name of 'Source' field to 'Target'. For multi-language mappings, use commas to separate languages and = to separate language and source field. Example: <strong>Value:en-us=ValueEn,de-de=ValueDe</strong> will map ValueEn and ValueDe to a new field Value which contains both values as multi-language entity.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129461,\n                    \"Version\": 4,\n                    \"Guid\": \"283857a2-291e-4be1-9734-639f118d6fd3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129462,\n                    \"Version\": 4,\n                    \"Guid\": \"aa1664ef-6341-45ab-8b12-7bdf2b657b78\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 10.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"d7858b36-1ef1-4c3d-b15c-c567b0d7bdd4\",\n            \"Name\": \"MetadataDataSourceConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 135531,\n                \"Version\": 5,\n                \"Guid\": \"b914fbaf-fcbb-412e-8ba2-d2d945274fd2\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This will retrieve Metadata of the items in the default stream. In most cases you don't really want to configure much here. See <a href=\\\"https://r.2sxc.org/DsMetadata\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Metadata docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Metadata DataSource Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"https://r.2sxc.org/DsMetadata\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"d7858b36-1ef1-4c3d-b15c-c567b0d7bdd4\"\n                }\n              },\n              {\n                \"Id\": 137435,\n                \"Version\": 1,\n                \"Guid\": \"a22bb631-4c0d-4232-b8ca-0f32990aea54\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"d7858b36-1ef1-4c3d-b15c-c567b0d7bdd4\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135532,\n                    \"Version\": 2,\n                    \"Guid\": \"e44177d1-7756-4a74-aab3-d1a389985e95\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Get Metadata\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135534,\n                    \"Version\": 1,\n                    \"Guid\": \"51fd248f-cc49-4659-bcd3-b4ca75662e73\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135535,\n                    \"Version\": 1,\n                    \"Guid\": \"6f5e3858-2cae-4dfe-a14d-e18d8e012900\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupContentType\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135538,\n                    \"Version\": 4,\n                    \"Guid\": \"dfa17e38-9ad9-4587-a6f8-36247aaa96de\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced (Content-Type)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>In most cases you will just want to get all the metadata of an item, no matter what type the metadata has. But in very complex situation an item could have a lot of metadata, so you may only want to retrieve specific types you care about.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135539,\n                    \"Version\": 2,\n                    \"Guid\": \"6b39e6b4-ab79-4fa1-87fe-43143d73757e\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypeName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135533,\n                    \"Version\": 4,\n                    \"Guid\": \"389f5c99-c5cd-4659-8775-2f853b1a4cfb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Type Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135536,\n                    \"Version\": 2,\n                    \"Guid\": \"53efabfe-b718-422f-8e92-4d9ef480289d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135537,\n                    \"Version\": 4,\n                    \"Guid\": \"3561aa76-6924-4aa1-b892-9dacafbc8628\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"7dcd26eb-a70c-4a4f-bb3b-5bd5da304232\",\n            \"Name\": \"MetadataTargetDataSourceConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 135540,\n                \"Version\": 2,\n                \"Guid\": \"187244ec-9262-40d5-a006-6efcec465733\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This will get you the&nbsp;<strong>targets</strong> of metadata - so if an item is metadata, it will get you the items which this metadata describes. See <a href=\\\"https://r.2sxc.org/DsMetadataTargets\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Metadata Targets</a> docs.</p>\\n<p>Important: it can only get you <strong>Entity targets</strong>. So if your metadata describes something else, it will not be included here.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Metadata Target Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"https://r.2sxc.org/DsMetadataTargets\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"7dcd26eb-a70c-4a4f-bb3b-5bd5da304232\"\n                }\n              },\n              {\n                \"Id\": 137436,\n                \"Version\": 1,\n                \"Guid\": \"19bf5535-ca31-4908-ab28-d6bea91a314b\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"7dcd26eb-a70c-4a4f-bb3b-5bd5da304232\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135541,\n                    \"Version\": 3,\n                    \"Guid\": \"0d133a5b-b17a-4730-8fcd-981131452a73\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Get Metadata Targets\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135544,\n                    \"Version\": 2,\n                    \"Guid\": \"e61001fa-023f-4d07-aa6a-c6139660e539\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135545,\n                    \"Version\": 2,\n                    \"Guid\": \"87e3393f-c0d1-41ed-932a-14f691a867e2\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypeName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135542,\n                    \"Version\": 3,\n                    \"Guid\": \"09ae423c-b0f1-4702-8d38-a29a891991a7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Type Name (optional)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Limit the returned items to such that have the specified content type.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135546,\n                    \"Version\": 2,\n                    \"Guid\": \"7651ece2-bf3a-4c9a-9fba-b618d4399bcf\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135547,\n                    \"Version\": 3,\n                    \"Guid\": \"0195ce7d-feed-40b7-8c8f-ef8ec7abacbd\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FilterDuplicates\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135543,\n                    \"Version\": 2,\n                    \"Guid\": \"7f99273e-e09c-4719-a6f0-db4b7ba6ed03\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Filter Duplicates\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135548,\n                    \"Version\": 1,\n                    \"Guid\": \"0622cff0-6984-4e97-bf20-5ff67b139ae4\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Don't filter duplicates (return them as often as they are used)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Filter duplicates (return them only once - default)\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.OwnerFilter\",\n            \"Name\": \"ToSic.Eav.DataSources.OwnerFilter\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 45081,\n                \"Version\": 2,\n                \"Guid\": \"4c5f7f1a-237c-430f-ae36-8b35b9a518ef\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"to configure the owner-filter\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Used to show only items which were created / owned by a specific owner. Read the <a href=\\\"https://r.2sxc.org/DsOwnerFilter\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a> for more.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Owner Filter\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.OwnerFilter\"\n                }\n              },\n              {\n                \"Id\": 137437,\n                \"Version\": 1,\n                \"Guid\": \"dccd09e0-2fc7-40ca-957e-de9a9a02f064\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.OwnerFilter\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"IdentityCode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40485,\n                    \"Version\": 1,\n                    \"Guid\": \"a87a030b-a735-4462-ae6c-1b9050ea392e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"dnn:userid=[User:UserId]\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Identity Code\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The&nbsp;identifier of the user - in DNN it could be the sequence 'dnn:userid=[User:UserId]'. Learn more on <a href=\\\"//2sxc.org/help?tag=datasource-filter-owner\\\" target=\\\"_blank\\\">2sxc.org/help?tag=datasource-filter-owner</a></p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40486,\n                    \"Version\": 1,\n                    \"Guid\": \"39f7ea07-edc5-4e0f-8a8b-71d89be993b4\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.Paging\",\n            \"Name\": \"ToSic.Eav.DataSources.Paging\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 74254,\n                \"Version\": 1,\n                \"Guid\": \"e1e6a24e-58bb-4f8a-84ed-022b2df2025f\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configuration of Paging DataSources\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Read the <a href=\\\"https://r.2sxc.org/DsPaging\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Paging\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.Paging\"\n                }\n              },\n              {\n                \"Id\": 137438,\n                \"Version\": 1,\n                \"Guid\": \"e906daf8-7c61-44ff-9bdb-8772acf14ca3\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.Paging\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40487,\n                    \"Version\": 1,\n                    \"Guid\": \"41bbb177-0bff-4421-8034-556c082199cd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"Paging data source\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Any title you want - for your convenience to name this. If you need any help, check out <a href=\\\"2sxc.org/help?tag=ds-paging\\\" target=\\\"_blank\\\">2sxc.org/help?tag=ds-paging</a></p>\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PageSize\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40488,\n                    \"Version\": 5,\n                    \"Guid\": \"7ef12a73-934b-4ce4-a83e-eaf3eb1ffa66\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"10\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"PageSize\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Amount of items per page. By default this is 10. Also set this to the amount you want if you're using this to just get a short-list of 5 items or something - then set to 5. You could also use parameters like [QueryString:ItemsPerPage] but in general you'll probably want a number or something.&nbsp;</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43020,\n                    \"Version\": 3,\n                    \"Guid\": \"a73b5bf7-e580-4e0e-a55b-7c5ad42ac7c2\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"10\\n25\\n50\\n100\\nget count from url:[QueryString:Count]\\nget pagesize from url:[QueryString:PageSize]\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PageNumber\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40489,\n                    \"Version\": 4,\n                    \"Guid\": \"ea6ec57d-28f7-4584-a9c6-b7dd70a034fd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"1\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"PageNumber\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The page we're on, by default it's 1. If you only want to use the first page (like get the top 5 of something) then set 1. Otherwise use a url parameter or something - so you would use [QueryString:Page] or similar. Check out&nbsp;<span><a href=\\\"2sxc.org/help?tag=ds-paging\\\" target=\\\"_blank\\\">2sxc.org/help?tag=ds-paging</a> for more help.&nbsp;</span></p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43021,\n                    \"Version\": 2,\n                    \"Guid\": \"e843f374-dfce-4385-a214-35b1f1314f67\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"1\\nget page from url:[QueryString:Page]\\nget p from url:[QueryString:P]\\nget PageNum from url:[QueryString:PageNum]\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"a72cb2f4-52bb-41e6-9281-10e69aeb0310\",\n            \"Name\": \"ParentsDataSourceConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 135467,\n                \"Version\": 4,\n                \"Guid\": \"59b4538c-2ff7-4d3f-bc17-ad91ebc3d32e\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Use the <a href=\\\"https://r.2sxc.org/DsParents\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Parents DataSource</a> to retrieve items/entities which point to the items/entities in the Default In-Stream. Note that if you need children relationships use the <a href=\\\"https://r.2sxc.org/DsChildren\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Children DataSource</a>.</p>\\n<p>You only need the Default In-Stream, because the items themselves already know about their relationships. The resulting stream will contain all the parents matching the criteria provided.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Parents DataSource Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"a72cb2f4-52bb-41e6-9281-10e69aeb0310\"\n                }\n              },\n              {\n                \"Id\": 137439,\n                \"Version\": 1,\n                \"Guid\": \"9269ff50-4cf9-45e9-b90a-76d0b1fe9891\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"a72cb2f4-52bb-41e6-9281-10e69aeb0310\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135468,\n                    \"Version\": 4,\n                    \"Guid\": \"d62ab183-9d7a-43b4-9ca5-dd33b13f6b37\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Get Parent Items\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135471,\n                    \"Version\": 3,\n                    \"Guid\": \"f633aa4e-9c32-4ac5-8d04-d4ec476314e0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135472,\n                    \"Version\": 3,\n                    \"Guid\": \"9749a228-dcd8-481b-8ad7-1ce1cdbf5eb9\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FilterDuplicates\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135510,\n                    \"Version\": 2,\n                    \"Guid\": \"dda895e8-64ed-4501-a2b0-733f397ac586\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Filter Duplicates (Distinct)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135511,\n                    \"Version\": 1,\n                    \"Guid\": \"c654bc67-3f5d-47b0-89c2-7e68e4d059ff\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135512,\n                    \"Version\": 1,\n                    \"Guid\": \"3aff6978-264e-49fc-878c-eaf1018ab3a5\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"true:True - filter duplicates, return each entity once even if referenced many times\\nfalse:False - don't filter, return each related entity even if it's referenced many times\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypeName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135469,\n                    \"Version\": 4,\n                    \"Guid\": \"ed3b80a1-0ff4-4068-b20e-08fc6724a493\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"ContentType Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Type of the parents to retrieve. If left empty, will retrieve all parents, no matter what type they are.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135473,\n                    \"Version\": 3,\n                    \"Guid\": \"2fab0989-9c18-4dae-adbd-dcf27170cc23\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135474,\n                    \"Version\": 4,\n                    \"Guid\": \"131e7817-bdc1-4b52-9444-05df5614852c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FieldName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135470,\n                    \"Version\": 3,\n                    \"Guid\": \"eba82386-9f91-418d-b78a-10bbc1800411\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Field Name containing the Relationship\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Field on the parent which points to this item. Use this if parents can have multiple fields (like&nbsp;<em>Author</em> and&nbsp;<em>Illustrator</em>) referencing this item, and you only need one of them.&nbsp;</p>\\n<p>If you leave this empty, it will get all the relationships, no matter what fields refer to them.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135475,\n                    \"Version\": 2,\n                    \"Guid\": \"f0768fdb-0864-4662-9036-43595308640c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135476,\n                    \"Version\": 3,\n                    \"Guid\": \"bb9ffe47-e7cb-4984-b6db-0382e3181dd4\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Attributes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"ContentTypeName=[ContentTypeName]\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"78d25ea6-66cc-44a2-b45d-77749cd9420a\",\n            \"Name\": \"QueryRunConfiguration\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 63446,\n                \"Version\": 2,\n                \"Guid\": \"99b8323b-3634-4545-a4d9-df083a48d718\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Run another query\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Request data from another query. See <a href=\\\"https://docs.2sxc.org/api/dot-net/ToSic.Eav.DataSources.QueryRun.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Query Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"78d25ea6-66cc-44a2-b45d-77749cd9420a\"\n                }\n              },\n              {\n                \"Id\": 137440,\n                \"Version\": 1,\n                \"Guid\": \"02a3551f-bad9-4a1e-ae05-d5ca5aab3938\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"78d25ea6-66cc-44a2-b45d-77749cd9420a\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63431,\n                    \"Version\": 2,\n                    \"Guid\": \"a72e9ca2-5747-48b2-923c-09f90fb253c7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just a title so you know what it's about</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63437,\n                    \"Version\": 1,\n                    \"Guid\": \"136f2a7d-101b-4005-b99e-7abeed161b36\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63438,\n                    \"Version\": 1,\n                    \"Guid\": \"d3c8425f-9f16-484a-b26c-5d3f7498d1c4\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63432,\n                    \"Version\": 2,\n                    \"Guid\": \"5f6e3673-fcce-48e0-a7a1-e3c17740e4bf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 144348,\n                    \"Version\": 1,\n                    \"Guid\": \"73e91497-c39a-4b86-aef4-aa05ea287a48\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144349,\n                    \"Version\": 1,\n                    \"Guid\": \"9c7e59b0-1bdd-4348-84fa-c82268c25c62\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"QueryGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63440,\n                    \"Version\": 2,\n                    \"Guid\": \"b239c96f-e27b-4a43-aca1-599e4dfc7e52\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Query Configuration\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63442,\n                    \"Version\": 1,\n                    \"Guid\": \"5d1edc11-7802-4e34-87cb-d573922185d3\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Query\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63433,\n                    \"Version\": 2,\n                    \"Guid\": \"6ee1a0ff-6b07-48c3-a8ec-9b27e4068df9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Query\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Pick the query you want to run.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63443,\n                    \"Version\": 1,\n                    \"Guid\": \"e5bdaf0f-2b20-484c-b8c5-02d721a5d7ce\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63444,\n                    \"Version\": 2,\n                    \"Guid\": \"c42b372a-dc99-4d36-bb46-84d5597c495c\",\n                    \"Type\": {\n                      \"Id\": \"@entity-query\",\n                      \"Name\": \"@entity-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Query\": {\n                          \"en-us\": \"System.Queries\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Params\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63434,\n                    \"Version\": 3,\n                    \"Guid\": \"22c2e0cb-5f54-4e7e-8c6f-131db4a3f330\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Params\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>List of params - one per line. Format <strong>key=value</strong><em>.</em> Can be tokenised like <strong>key=[QueryString:Id]</strong>.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63435,\n                    \"Version\": 2,\n                    \"Guid\": \"4b4b655c-28de-44a8-acd0-727f56ddd929\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63436,\n                    \"Version\": 2,\n                    \"Guid\": \"82f76193-b431-4283-b75c-ec8a4d3a25d0\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 10.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.RelationshipFilter\",\n            \"Name\": \"ToSic.Eav.DataSources.RelationshipFilter\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 40510,\n                \"Version\": 4,\n                \"Guid\": \"db398e88-fc4e-4062-918e-b731ab2bae6f\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"used to configure a RelationshipFilter DataSource\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This will filter the items and only return those with the relationship-requirements as configured. See also <a href=\\\"https://r.2sxc.org/DsRelationshipFilter\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Relationship Filter</a> docs.</p>\\n<p>Important: If you only want to get all the children or parents of an entity, use the <a href=\\\"https://r.2sxc.org/DsChildren\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Children</a> or <a href=\\\"https://r.2sxc.org/DsParents\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Parents</a> DataSource instead.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Relationship Filter\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.RelationshipFilter\"\n                }\n              },\n              {\n                \"Id\": 137441,\n                \"Version\": 1,\n                \"Guid\": \"e15d5806-0434-46e4-8d07-210c833d048c\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.RelationshipFilter\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40511,\n                    \"Version\": 3,\n                    \"Guid\": \"0d03c0c9-f8ef-457d-9399-4bbb00b6e376\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Relationship Filter\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just a title so you know what it's about</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40514,\n                    \"Version\": 2,\n                    \"Guid\": \"f3ffdd61-6a10-4721-9d68-aea5e4fe2987\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40512,\n                    \"Version\": 4,\n                    \"Guid\": \"803afd9b-f945-4ede-9cba-93dbe6a9c9e1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>your notes about this filter, to help you remember what you were thinking...</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40515,\n                    \"Version\": 1,\n                    \"Guid\": \"57bbf159-cda6-499c-8884-be64b470e050\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 144350,\n                    \"Version\": 1,\n                    \"Guid\": \"c72fea0d-b9cf-44a7-8c9b-1622170ba811\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144351,\n                    \"Version\": 1,\n                    \"Guid\": \"988500ee-9148-4ee5-aa5c-e1ff89b475ac\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"BasicsGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40522,\n                    \"Version\": 2,\n                    \"Guid\": \"b9c9ad66-f587-4969-91cb-aa69ead3d21b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Basics\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Here you can specify what relationship you are comparing for, and what value you expect in the related items. If the list contains&nbsp;<em>Book</em> items and you want to keep only those with the&nbsp;<em>Author</em> being <em>Daniel Mettler</em>, then you would type&nbsp;<strong>Author</strong> in the relationship-field and&nbsp;<strong>Daniel Mettler</strong> in the filter-value field.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40524,\n                    \"Version\": 1,\n                    \"Guid\": \"fc2ddbe7-b52d-447d-b0d7-f195c746bd28\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Relationship\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40490,\n                    \"Version\": 3,\n                    \"Guid\": \"5dd119a2-79e1-4d6f-b29c-31cf6b89beef\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Relationship Field\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The property we're comparing. So if this is a list of books, and we want to check which ones have an Author called \\\"Daniel\\\", then the relationship-field is <em>Author</em></p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Filter\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40492,\n                    \"Version\": 8,\n                    \"Guid\": \"b2cf2638-4914-4987-8526-d94e5c0563d6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Filter (on the related items)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>the value we want in the related data - if you're on a book-list and only want those with the Author \\\"Daniel\\\", then this is where you would write <em>Daniel.&nbsp;</em>Remember that you can also use tokens, like [QueryString:Author]</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40516,\n                    \"Version\": 3,\n                    \"Guid\": \"60832427-0db9-45c3-8566-60ba0ed82b6d\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AdvancedGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40523,\n                    \"Version\": 2,\n                    \"Guid\": \"8335b7a4-609e-4d57-a0b5-ddd7c86f826d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Advanced Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Sometimes you want to use much more advanced comparisons or compare on another field than just the title.&nbsp;</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40525,\n                    \"Version\": 1,\n                    \"Guid\": \"35612763-eb87-4eab-92db-039f8675c85d\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AttributeOnRelationship\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40513,\n                    \"Version\": 2,\n                    \"Guid\": \"e4254d87-c48d-400f-8637-81f3aeee0678\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"EntityTitle\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Relationship Attribute\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The field of the related items we're checking for. By default it's the title (EntityTitle), but you could also check for the ID (EntityId) or for other properties. For example, if you have a list of books and you only want to keep those of Authors who are from Switzerland, then here you would <em>not</em> write EntityTitle, but instead <em>Country</em>.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40517,\n                    \"Version\": 1,\n                    \"Guid\": \"af83298d-2955-4471-be4e-caf1b6be042a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Comparison\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40518,\n                    \"Version\": 9,\n                    \"Guid\": \"882c82bc-25d8-4fad-9af0-5cfd19b5524f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Operation / Comparison\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This determines how we will compare. The following operations exist in 2sxc 9.9+:</p>\\n<ol>\\n<li>the (blank) default is the same as&nbsp;<strong>contains</strong>&nbsp;- we will check if the related items contains such an item, so if in a list of tags, one has <em>all</em> the mentioned tag(s)</li>\\n<li>with a <strong>not-contains</strong> the related items may not contain <em>all</em> of the tags&nbsp;</li>\\n<li>if you use <strong>containsany</strong>, it will return all items where the related-items has <em>any one</em> of the filter criterias</li>\\n<li>with a <strong>not-containsany</strong>, it will return those which don't have any of the items you listed in filter</li>\\n<li>in case of a&nbsp;<strong>first</strong> the first item in the relationships must be what we want - this is typical for lists where the first item is like the primary category. If you specify multiple items in filter, the first will be valid if it matches any of those.</li>\\n<li>in case of a <strong>not-first</strong> the first item may not match this</li>\\n<li>use <strong>any&nbsp;</strong>it will ignore the filter-value and simply keep all items having any relationships&nbsp;</li>\\n<li>with <strong>not-any</strong> it will return all items not having any relationships</li>\\n<li>with&nbsp;<strong>count</strong> it will keep all items having exactly the desired amount of related-items, the amount is specified in the <em>filter</em>-field</li>\\n<li>if <strong>not-count</strong> it will keep all items having a different amount than the desired amount</li>\\n</ol>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42341,\n                    \"Version\": 4,\n                    \"Guid\": \"03f819e8-8e60-439a-81cb-fa19e2ec79e8\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"(default = contains):\\ncontains - keep these that have all of these:contains\\nnot-contains - keep these that don't have all:not-contains\\ncontainsany - keep these that have any of these:containsany\\nnot-containsany - keep these that have none of these:not-containsany\\nfirst - keep these where the first item is one of these:first\\nnot-first - keep these where the first item is none of these:not-first\\nany - keep these that have relationships:any\\nnot-any - keep these that have no relationships:not-any\\ncount - keep these with the exact child-amount in filter:count\\nnot-count - keep these with a different child amount than in filter:not-count\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Separator\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40520,\n                    \"Version\": 8,\n                    \"Guid\": \"0ae70c4f-40fd-45b2-89db-5eef37b5076b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Separator Character\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>if you want to check for multiple relationships (like having multiple tags), then the filter-value will contain a string with multiple values. By default the separator is blank - so the filter-value will not be separated. Usually you would use a comma, so that you can write \\\"online,2017,seo\\\", but there are cases where your strings may themselves contain commas - so this is why you can specify your own separation character.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42342,\n                    \"Version\": 3,\n                    \"Guid\": \"901e562b-fdd6-4f68-afdc-5e7fbbdaa6e1\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"(none):\\ncomma ,:,\\nbar / pipe |:|\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"1b9fd9d1-dde0-40ad-bb66-5cd7f30de18d\",\n            \"Name\": \"RolesDataSourceConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 160758,\n                \"Version\": 3,\n                \"Guid\": \"c557999e-cd4b-4f9c-b60d-661a69083293\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure which roles will be returned by this data source. See <a href=\\\"https://r.2sxc.org/ds-roles\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Roles DataSource Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"1b9fd9d1-dde0-40ad-bb66-5cd7f30de18d\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"RoleIds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 160744,\n                    \"Version\": 7,\n                    \"Guid\": \"02e9725f-7c53-40bd-a2b8-6141b1520be3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Roles (only show these Roles)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160752,\n                    \"Version\": 6,\n                    \"Guid\": \"ae599e62-0c3c-48f6-bf68-70200a0c7c29\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160753,\n                    \"Version\": 7,\n                    \"Guid\": \"f7563905-dd8c-4d21-8ae4-26979fb5c78d\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Roles\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ExcludeRoleIds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 160745,\n                    \"Version\": 6,\n                    \"Guid\": \"fb39ec12-5f5d-4f26-a734-44398f640658\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Exclude (remove from result)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160754,\n                    \"Version\": 5,\n                    \"Guid\": \"e56e4c26-b81f-4d12-a93e-0849d8bf8f64\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160755,\n                    \"Version\": 6,\n                    \"Guid\": \"fc9cd5bc-accb-45c2-8324-0089a1766dc0\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Roles\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"38e7822b-1049-4539-bb3f-f99949b1b1d1\",\n            \"Name\": \"ToSic.Eav.DataSources.Shuffle\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 38968,\n                \"Version\": 2,\n                \"Guid\": \"46b356e4-6a13-4f25-8620-f8652221d2af\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configure a shuffling data-source\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Use this to configure how shuffling should work. Basically just specify how many items should be returned in the end. Learn more about this in the <a href=\\\"https://docs.2sxc.org\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc docs</a> on the <a href=\\\"https://r.2sxc.org/DsShuffle\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Shuffle DataSource</a> page.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Shuffle DataSource\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"38e7822b-1049-4539-bb3f-f99949b1b1d1\"\n                }\n              },\n              {\n                \"Id\": 137443,\n                \"Version\": 1,\n                \"Guid\": \"94681d1d-b258-4e3c-ac4f-6b6dbeb1b76b\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"38e7822b-1049-4539-bb3f-f99949b1b1d1\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Take\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38967,\n                    \"Version\": 1,\n                    \"Guid\": \"f93f5287-9a90-49fb-b13a-cbd3acad2fea\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Take\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"c76901b5-0345-4866-9fa3-6208de7f8543\",\n            \"Name\": \"ToSic.Eav.DataSources.SqlDataSource\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 38700,\n                \"Version\": 2,\n                \"Guid\": \"4ac0f5b5-4b65-4563-a85f-3ad3a0466e2b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Config type for the Sql DataSource\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Use the SQL DataSource to get SQL data. Just write a <em>SELECT ... FROM ...</em> and you're good to go.&nbsp;</p>\\n<p>If this is the first time you're using this, you may want some help to get started. You can find more help in the <a href=\\\"https://docs.2sxc.org\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc docs</a>&nbsp;(see <a href=\\\"https://r.2sxc.org/DsSql\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">SqlDataSource</a>) or in the general <a href=\\\"https://2sxc.org/en/Help?tag=visualquerydesigner\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc help about data sources</a>.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"SQL DataSource\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"c76901b5-0345-4866-9fa3-6208de7f8543\"\n                }\n              },\n              {\n                \"Id\": 137444,\n                \"Version\": 1,\n                \"Guid\": \"b4ebc4eb-d9cc-403e-b57b-3f28a634d198\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"c76901b5-0345-4866-9fa3-6208de7f8543\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38682,\n                    \"Version\": 2,\n                    \"Guid\": \"956328b0-7686-4f9d-b84e-4cfce2a21558\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Sql Query\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just a nice name so you remember what it's for</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38692,\n                    \"Version\": 1,\n                    \"Guid\": \"dc220921-410e-44ff-98d8-5fddf4e252f8\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38710,\n                    \"Version\": 4,\n                    \"Guid\": \"f75fb66b-914b-4805-9f7f-8ad6c988ad2c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>just add some notes for yourself, so you know what the query is for and what special things you did to make it work</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38711,\n                    \"Version\": 3,\n                    \"Guid\": \"f0b52662-e210-4ca8-9237-44edd53fdb03\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 3.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 144352,\n                    \"Version\": 1,\n                    \"Guid\": \"3839279a-3614-430d-ab62-aa9a8b882a89\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ConnectionGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38683,\n                    \"Version\": 3,\n                    \"Guid\": \"bda43aac-7f3e-4c4d-b244-c78a17ad8ee1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Connection Information\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>How to connect to the DB</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38691,\n                    \"Version\": 2,\n                    \"Guid\": \"fbf51a2d-0744-439d-9a0d-997febfc5c26\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ConnectionStringName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38684,\n                    \"Version\": 11,\n                    \"Guid\": \"a8d5dcc6-5a4e-41d7-84f4-491a71ab3914\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"(default)\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Connection Name (preferred)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Use connection names from web.config / appsettings.json. To enter another Manual <strong>Connection Name</strong> use the TT button to the right.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"e4d42e3d-4de7-453a-a68f-e9e015ac46c3\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38693,\n                    \"Version\": 1,\n                    \"Guid\": \"c5e4826f-c5d2-4ac9-86df-cb165ebd7478\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 163991,\n                    \"Version\": 7,\n                    \"Guid\": \"15a37632-244f-4c6d-89fa-4b4e3c9b7a04\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 163992,\n                    \"Version\": 7,\n                    \"Guid\": \"a6e8e9cb-b14e-4c62-a24d-fdce6c1d4e0c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"(default):Default Database (Dnn/Oqtane)\\nSiteSqlServer:SiteSqlServer (DNN)\\nDefaultConnection:DefaultConnection (Oqtane)\\n:Manual Connection String\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ConnectionString\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38685,\n                    \"Version\": 3,\n                    \"Guid\": \"a0434f14-b0b9-4a41-9ac1-3ec63dd8b708\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Connection String (alternative)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>alternative: write the connection string instead of the connection name</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"ab0b768e-4af4-4cfb-b93c-efd349b5ec68\",\n                            null\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38694,\n                    \"Version\": 1,\n                    \"Guid\": \"45c99f5d-6bdb-40d8-9d8b-f69338a2477a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"QueryGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38686,\n                    \"Version\": 2,\n                    \"Guid\": \"b102202f-097a-47e1-ba11-947ca40ffadd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Query\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>What do you want to query, and how to treat the result</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38695,\n                    \"Version\": 1,\n                    \"Guid\": \"3ce28b0b-7d4b-4958-bc68-537302609968\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SelectCommand\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38687,\n                    \"Version\": 3,\n                    \"Guid\": \"4c39ad49-3845-4c5c-b335-399c414b9357\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"-- Demo SQL - select top 10 table names\\n\\nSELECT Top(10) *\\nFROM SYSOBJECTS\\nWHERE xtype = 'U'\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"SQL\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>SQL select statement</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38696,\n                    \"Version\": 2,\n                    \"Guid\": \"04180b43-3f81-4cb8-971d-39a8cf37c019\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 163995,\n                    \"Version\": 1,\n                    \"Guid\": \"e25a5e21-8a9c-48ed-bb53-5dc0d0a28c2c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38688,\n                    \"Version\": 2,\n                    \"Guid\": \"11897030-b94a-4322-bd62-c089391d0bde\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"SqlData\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Type Name\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Name of the content-type in result</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38697,\n                    \"Version\": 1,\n                    \"Guid\": \"c665c68e-bf51-4c0d-8748-5d0e01bf733b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EntityIdField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38689,\n                    \"Version\": 3,\n                    \"Guid\": \"260d9cf5-58e1-4d3b-8379-258f1af0cfa6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Id Field\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>name of the ID field, if blank, defaults to <em>EntityId</em></p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38698,\n                    \"Version\": 2,\n                    \"Guid\": \"e6e8742f-6a19-411f-b3cd-08845ce77ea6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EntityTitleField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 38690,\n                    \"Version\": 2,\n                    \"Guid\": \"5820ec5c-cc1d-4043-b701-95513355e949\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title Field\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>name of the title field, if blank, defaults to <em>EntityTitle</em></p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 38699,\n                    \"Version\": 1,\n                    \"Guid\": \"58e806ad-3bff-4350-ae14-704c19685b42\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 163989,\n              \"Version\": 2,\n              \"Guid\": \"e4d42e3d-4de7-453a-a68f-e9e015ac46c3\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.ConnectionString === ''; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 163990,\n              \"Version\": 2,\n              \"Guid\": \"ab0b768e-4af4-4cfb-b93c-efd349b5ec68\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.ConnectionStringName === ''; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"67b19864-df6d-400b-9f37-f41f1dd69c4a\",\n            \"Name\": \"StreamPick\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 66897,\n                \"Version\": 1,\n                \"Guid\": \"994aa260-2b0e-4a32-9452-7bef1ff43634\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configure a Stream-Pick Data Source\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Pick a stream to be passed on. Usually you will use some kind of parameter, like [Params:Stream]</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Stream Pick\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"67b19864-df6d-400b-9f37-f41f1dd69c4a\"\n                }\n              },\n              {\n                \"Id\": 137445,\n                \"Version\": 1,\n                \"Guid\": \"0a83fd37-4a49-4b6f-9772-2509fe3ee225\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"67b19864-df6d-400b-9f37-f41f1dd69c4a\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"StreamName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 66898,\n                    \"Version\": 2,\n                    \"Guid\": \"12e1ef4e-9ef9-47ba-8504-6c444a27fc42\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Stream Name\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Name of the stream to be provided.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 66899,\n                    \"Version\": 1,\n                    \"Guid\": \"52c9a309-42f5-4597-a4be-8114a476bcc3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 66900,\n                    \"Version\": 1,\n                    \"Guid\": \"49aee364-192f-4c0a-8068-fa284b24eb49\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"fabc849e-b426-42ea-8e1c-c04e69facd9b\",\n            \"Name\": \"ToSic.Eav.DataSources.Apps\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 43007,\n                \"Version\": 4,\n                \"Guid\": \"91efe9e2-82e9-4c62-9a29-a6c206c88cb9\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"config of Apps\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Get a list of apps - either of the current zone (default / empty) or of a selected zone. For more help, <a href=\\\"https://docs.2sxc.org/api/dot-net/ToSic.Eav.DataSources.System.Apps.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">read the docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"System - Get Apps\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"fabc849e-b426-42ea-8e1c-c04e69facd9b\"\n                }\n              },\n              {\n                \"Id\": 137446,\n                \"Version\": 1,\n                \"Guid\": \"d873acc8-18e7-411a-b6de-96638a0d932d\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"fabc849e-b426-42ea-8e1c-c04e69facd9b\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42588,\n                    \"Version\": 4,\n                    \"Guid\": \"bec36365-c1bc-4d7c-bf70-f62cdec771fe\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title / Notes\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just notes for yourself to better understand what this is for</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42591,\n                    \"Version\": 3,\n                    \"Guid\": \"aa39a58b-11e0-469f-a1c1-1f9eb7c7f679\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ZoneId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42590,\n                    \"Version\": 10,\n                    \"Guid\": \"4a35b2dc-d8ad-4452-bb6c-fd500be23d69\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Zone Number\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The number of the zone of which you want to get the apps. If blank, it won't return any apps.&nbsp;</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42593,\n                    \"Version\": 1,\n                    \"Guid\": \"f399a17b-2189-4d1c-9b76-42736e13b501\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46341,\n                    \"Version\": 1,\n                    \"Guid\": \"bea6c649-3b8d-4405-af3e-c074e26caeca\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42914,\n                    \"Version\": 8,\n                    \"Guid\": \"c78c45c6-6f45-4b05-9ddf-ce0a80931389\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"TenantName\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Zones\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"5461d34d-7dc6-4d38-9250-a0729cc8ead3\",\n            \"Name\": \"ToSic.Eav.DataSources.Attributes\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 43008,\n                \"Version\": 4,\n                \"Guid\": \"8b39334c-c025-418c-9262-5039401ed8c2\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Get the attributes of a content-type. For more help, <a href=\\\"https://docs.2sxc.org/api/dot-net/ToSic.Eav.DataSources.System.Attributes.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">read the docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"System - Get Attributes\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5461d34d-7dc6-4d38-9250-a0729cc8ead3\"\n                }\n              },\n              {\n                \"Id\": 137447,\n                \"Version\": 1,\n                \"Guid\": \"3519d75f-2ed9-44e5-8f06-076d8d6db3bb\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5461d34d-7dc6-4d38-9250-a0729cc8ead3\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42594,\n                    \"Version\": 2,\n                    \"Guid\": \"69bae27c-019d-4375-bd9a-8ab02615a17f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title / Notes\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just notes for yourself to better understand what this is for</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42975,\n                    \"Version\": 1,\n                    \"Guid\": \"24458b38-9a60-40a7-86d7-b03d55970db9\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypeName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42596,\n                    \"Version\": 4,\n                    \"Guid\": \"4d2cb677-caa4-4cc2-92a9-d8a9106497fa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Type\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Choose the content-type of which you want to see the attributes</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43005,\n                    \"Version\": 3,\n                    \"Guid\": \"3b31ea46-619e-4cd9-9f9f-b02e84406d3c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"37b25044-29bb-4c78-85e4-7b89f0abaa2c\",\n            \"Name\": \"ToSic.Eav.DataSources.ContentTypes\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 43010,\n                \"Version\": 2,\n                \"Guid\": \"6906e6b4-35df-4c2d-8884-9cc0c520ffc4\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"config of content-types\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Query what content-types you want. If left blank, will use current app. Read more about this in the <a href=\\\"https://docs.2sxc.org/api/dot-net/ToSic.Eav.DataSources.System.ContentTypes.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">wiki</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"System - Get ContentTypes\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"37b25044-29bb-4c78-85e4-7b89f0abaa2c\"\n                }\n              },\n              {\n                \"Id\": 137448,\n                \"Version\": 1,\n                \"Guid\": \"e80b737b-25f7-44f0-bc3a-47d2360b3c8d\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"37b25044-29bb-4c78-85e4-7b89f0abaa2c\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42958,\n                    \"Version\": 3,\n                    \"Guid\": \"0e30efed-8008-417a-b547-3cf9113f08db\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title / Notes\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just notes for yourself to better understand what this is for</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42962,\n                    \"Version\": 2,\n                    \"Guid\": \"86e02488-8844-410c-9046-36633463c29e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AppId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42960,\n                    \"Version\": 5,\n                    \"Guid\": \"3c2a0596-9eb5-4c44-8f81-9aa64d90d899\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"App Id\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The ID of an app or a token which delivers it. Will use current app if left empty.&nbsp;</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42964,\n                    \"Version\": 1,\n                    \"Guid\": \"be8920b5-02fc-49dd-95b3-a0cb604308f5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43009,\n                    \"Version\": 3,\n                    \"Guid\": \"219fe6a9-fde9-45ee-b971-5df7acb2916e\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Apps\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Scope\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42961,\n                    \"Version\": 3,\n                    \"Guid\": \"4aba770d-073d-4dd0-aa6a-de19ac88f701\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Scope\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The scope for which to get the content-types - by default it's always Default</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42965,\n                    \"Version\": 1,\n                    \"Guid\": \"4d4ea6d4-c7e4-4ab1-aae4-ecaabf25bd8c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"Default\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"4638668f-d506-4f5c-ae37-aa7fdbbb5540\",\n            \"Name\": \"ToSic.Eav.DataSources.QueryInfo\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 43013,\n                \"Version\": 2,\n                \"Guid\": \"eba9974c-1736-4d53-b0ed-333dd0277c99\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Query-Info configuration\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Use this to configure a query-info datasource. This is a very advanced topic, read more about it in the <a href=\\\"https://docs.2sxc.org/api/dot-net/ToSic.Eav.DataSources.System.QueryInfo.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"System - Get QueryInfo\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"4638668f-d506-4f5c-ae37-aa7fdbbb5540\"\n                }\n              },\n              {\n                \"Id\": 137449,\n                \"Version\": 1,\n                \"Guid\": \"b8f3e036-7898-4ad0-b4cf-b8f4ff547fe1\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"4638668f-d506-4f5c-ae37-aa7fdbbb5540\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42939,\n                    \"Version\": 2,\n                    \"Guid\": \"32170df5-e83b-47e6-8bbc-585bd1dd9f7d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title / Notes\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>just notes for yourself to better understand what this is for</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42974,\n                    \"Version\": 1,\n                    \"Guid\": \"f83febe0-9b72-48e1-8563-65312d09c495\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"QueryName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42941,\n                    \"Version\": 5,\n                    \"Guid\": \"0703a10a-2111-45a2-ac7d-76503c792c23\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Query\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Select a query...</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42955,\n                    \"Version\": 1,\n                    \"Guid\": \"32f83a2e-0b0a-47d0-b263-6ba7eca4916d\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43011,\n                    \"Version\": 3,\n                    \"Guid\": \"20d1d9d7-1bdf-4466-acb1-9081cc0023c3\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Queries\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"StreamName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42953,\n                    \"Version\": 5,\n                    \"Guid\": \"c56f8ca3-404c-42da-9316-0a3faa31d196\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Stream\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Select a stream of the query you choose.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42956,\n                    \"Version\": 2,\n                    \"Guid\": \"e04180b5-d9a4-49e6-b683-9a3f62d52e32\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43012,\n                    \"Version\": 2,\n                    \"Guid\": \"0e3c3805-59b7-4d48-918d-7f7ba7111264\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.QueryInfo\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"d167054a-fe0f-4e98-b1f1-0a9990873e86\",\n            \"Name\": \"RelationshipModelerDsConfiguration\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 129463,\n                \"Version\": 2,\n                \"Guid\": \"c16d7030-d953-425a-b33a-181d2afc46c4\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Convert flat data into 2sxc relationships\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Use this to connect records which are tabular but would represent a hierarchy / tree-structure. Data passing through this data source will then have Children / and or Parent-relationships.&nbsp;</p>\\n<p>Note that the purpose of this is really to build a tree structure, so it assumes that each child can only have one parent / folder.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Tree Relationship Modeler\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"d167054a-fe0f-4e98-b1f1-0a9990873e86\"\n                }\n              },\n              {\n                \"Id\": 137450,\n                \"Version\": 1,\n                \"Guid\": \"14b5c6ad-aca9-4bc4-939f-8c42bd7ac1ae\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"d167054a-fe0f-4e98-b1f1-0a9990873e86\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129431,\n                    \"Version\": 3,\n                    \"Guid\": \"4e9058b6-6e7c-4fb7-9f61-a79de33f2e0e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Tree Relationship Modeler Configuration\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Just a title for you to give this configuration a name.\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129432,\n                    \"Version\": 3,\n                    \"Guid\": \"e1ddc413-37b7-45e9-8c45-958200124ed5\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129433,\n                    \"Version\": 3,\n                    \"Guid\": \"301c07d5-c52e-4882-a24b-01bee8487780\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129434,\n                    \"Version\": 3,\n                    \"Guid\": \"b96f16be-0543-4197-9f42-f8cd79ba5ff6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"just notes for yourself to better understand what this is for\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129435,\n                    \"Version\": 2,\n                    \"Guid\": \"92e98745-acca-4f18-8323-cd73c869605a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129436,\n                    \"Version\": 1,\n                    \"Guid\": \"1cf4f282-469c-48da-bfad-e729e1da9501\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144353,\n                    \"Version\": 1,\n                    \"Guid\": \"e6b5d4ea-07dc-421c-a8b0-d3d0862b6381\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"OriginalIDsToMatch\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129437,\n                    \"Version\": 2,\n                    \"Guid\": \"52a141a7-ad3e-4076-b3f9-c7895dac67bc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Original IDs to match\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>We need two things</p>\\n<ol>\\n<li>References on the Children to Parents</li>\\n<li>Ways to find the Parent / Folder etc.</li>\\n</ol>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129438,\n                    \"Version\": 2,\n                    \"Guid\": \"39eb3544-08d0-41cd-8cfa-5b3c74fe6af4\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ChildParentAttribute\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129439,\n                    \"Version\": 3,\n                    \"Guid\": \"0783bfbf-c4a1-47e5-a2c1-5382623a3bd9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"ParentGuid\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Field pointing to the Parent or Folder ID\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The property on the Child with points to the parent. It should contain a GUID or a number.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129440,\n                    \"Version\": 3,\n                    \"Guid\": \"7c305bce-306d-4c99-920d-7e264a1fa377\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129441,\n                    \"Version\": 3,\n                    \"Guid\": \"20a55f82-7bea-4035-90b9-aa0b3123b76f\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ParentIdentifierAttribute\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129442,\n                    \"Version\": 1,\n                    \"Guid\": \"cfdc65cc-6c86-486e-8cb9-7bad574c2f8b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129443,\n                    \"Version\": 3,\n                    \"Guid\": \"430778f5-a6bf-403b-a858-8be36629a1e2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"EntityGuid\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Identifier of the Parent / Folder (Parent ID)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Enter the attribute which should be used to identify entities. The datasource will look for entities in the 'Children' stream with a 'Child Parent Attribute' that matches the 'Parent Identifier Attribute' in the 'Default' stream.<br />Currently this datasource only supports EntityGuid and EntityId.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129444,\n                    \"Version\": 3,\n                    \"Guid\": \"7c6d4a24-806c-4c5b-8577-b30b97828e5c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129445,\n                    \"Version\": 3,\n                    \"Guid\": \"22ee83e0-af7a-4f9c-9580-de92642292d6\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"EntityGuid\\nEntityId\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"NewFieldsContainingRelationships\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129446,\n                    \"Version\": 2,\n                    \"Guid\": \"80eac42f-ad79-4272-9bcb-9032673b01a9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"New fields containing relationships\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Configure the fields which will contain the relationships.\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129447,\n                    \"Version\": 1,\n                    \"Guid\": \"c228385e-7e6b-4caa-9bbe-f81b545a39bc\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TargetChildrenAttribute\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129448,\n                    \"Version\": 4,\n                    \"Guid\": \"bbc491d2-d5b0-4e7d-bd13-d8473a8e83cb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Children\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Property of Parent to Access Children\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Property where the child relationships are mapped. If you enter <em>Children</em> you can access the child entities with <em>item.Children</em>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129449,\n                    \"Version\": 4,\n                    \"Guid\": \"1123add6-1f2a-4906-b417-7a84c833521a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129450,\n                    \"Version\": 4,\n                    \"Guid\": \"5932119c-9658-4ba4-adf5-e2b5b5431454\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TargetParentAttribute\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129451,\n                    \"Version\": 3,\n                    \"Guid\": \"dedac772-47a9-4a78-a590-c3eafa419b59\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Parent\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Property of Child to Access Parent\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Property where the parent relationship is added. If you enter <em>Folder</em>&nbsp; you can access the parent Entity with <em>item.Folder</em>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129452,\n                    \"Version\": 3,\n                    \"Guid\": \"a4a292b5-97de-40ff-8df5-bc4a079966d2\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129453,\n                    \"Version\": 3,\n                    \"Guid\": \"f7db7485-7d96-43c5-b707-3987745d3a39\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"ac11fae7-1916-4d2d-8583-09872e1e6966\",\n            \"Name\": \"UsersDataSourceConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 160779,\n                \"Version\": 2,\n                \"Guid\": \"910bb098-0184-4134-8ea4-f121a30acafe\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure which users to show.</p>\\n<p>It will return <a href=\\\"http://go.2sxc.org/find?xref=ToSic.Sxc.Cms.Users\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">users and roles</a>&nbsp;entities.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Users DataSource Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"ac11fae7-1916-4d2d-8583-09872e1e6966\"\n                }\n              },\n              {\n                \"Id\": 166589,\n                \"Version\": 1,\n                \"Guid\": \"8da53d14-f2e4-446c-aae6-1692eb0b959d\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"ac11fae7-1916-4d2d-8583-09872e1e6966\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"GroupFilters\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167704,\n                    \"Version\": 2,\n                    \"Guid\": \"06a447e9-6fa5-4185-9f9c-a51859f1b55d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Optional Filters\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167705,\n                    \"Version\": 1,\n                    \"Guid\": \"9f138f55-7f73-40b0-91f9-ad9399c87eaa\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UserIds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 160763,\n                    \"Version\": 3,\n                    \"Guid\": \"c8bcc1a1-d859-4760-8d6c-f566e9ae37e5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Users (only show specific users)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160774,\n                    \"Version\": 2,\n                    \"Guid\": \"eeb07d0d-4527-4658-b5fe-1376abda0d96\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160775,\n                    \"Version\": 3,\n                    \"Guid\": \"d0ff2328-ecbc-4176-bd1a-ac2075429325\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Users\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ExcludeUserIds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 160764,\n                    \"Version\": 2,\n                    \"Guid\": \"2778d533-89aa-4fcd-b8a5-d2762e9d6ddb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Exclude Users\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160776,\n                    \"Version\": 1,\n                    \"Guid\": \"4c4384ec-0f86-4722-b022-775c9cfdd140\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160777,\n                    \"Version\": 2,\n                    \"Guid\": \"9d7780de-f4b6-43a3-ab78-22b98fcd51e8\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Users\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RoleIds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 160765,\n                    \"Version\": 3,\n                    \"Guid\": \"aa5f7b67-f918-4191-b49e-37f8be7e6700\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Roles (only users in these Roles)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160768,\n                    \"Version\": 2,\n                    \"Guid\": \"315f386a-c8e8-46e1-9c78-e0ea2b9d4941\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160769,\n                    \"Version\": 3,\n                    \"Guid\": \"98b88c37-9ca3-4343-8109-dffb00b27777\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Roles\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ExcludeRoleIds\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 160766,\n                    \"Version\": 2,\n                    \"Guid\": \"f274894e-62ae-4f12-9ac7-71a70b9b9118\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Exclude Roles\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160770,\n                    \"Version\": 1,\n                    \"Guid\": \"a176d70f-cf42-4c6e-b9bc-36cfebb66988\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160771,\n                    \"Version\": 2,\n                    \"Guid\": \"131caffa-31b2-4799-8b8c-723dc4f5fbce\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Roles\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Id\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeSystemAdmins\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 160767,\n                    \"Version\": 3,\n                    \"Guid\": \"2f465b34-6a19-4ce0-9641-60ba2f494e1d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include System Admins\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160772,\n                    \"Version\": 2,\n                    \"Guid\": \"3ff21448-631a-4e4d-9a8b-57495bf13f57\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160773,\n                    \"Version\": 2,\n                    \"Guid\": \"cef3abfb-d416-44be-aeae-1773cbbbfecc\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"false:Don't include System Admins\\ntrue:Include System Admins\\nrequired:Include ONLY System Admins\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAddMoreFields\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167685,\n                    \"Version\": 3,\n                    \"Guid\": \"46bf25aa-c72d-46d2-9d5e-1485662e8791\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Add Special Fields\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167688,\n                    \"Version\": 2,\n                    \"Guid\": \"0f6e0ddc-ce96-4e3b-813d-f793d0b0692f\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AddRoles\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167686,\n                    \"Version\": 4,\n                    \"Guid\": \"8c12c87d-3e52-499d-b7b4-86af98c91d7b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Add \\\"Roles\\\"\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Include the Field Roles referencing the roles each user is in.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167689,\n                    \"Version\": 3,\n                    \"Guid\": \"f02973a1-24e6-4a4a-9b90-4cc130d2cb86\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167690,\n                    \"Version\": 3,\n                    \"Guid\": \"0adfbeef-3580-4758-a61c-0694dfbc66e9\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default (add)\\nfalse:Do not add Roles\\ntrue:Add Roles\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.ValueFilter\",\n            \"Name\": \"ToSic.Eav.DataSources.ValueFilter\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 74255,\n                \"Version\": 1,\n                \"Guid\": \"19f4cd25-effb-40b4-aafa-f2a0c0bf44e2\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"used to configure a ValueFilter DataSource\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Check out the <a href=\\\"https://r.2sxc.org/DsValueFilter\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Value Filter\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.ValueFilter\"\n                }\n              },\n              {\n                \"Id\": 137451,\n                \"Version\": 1,\n                \"Guid\": \"fc784f3f-3958-4e80-941f-492115ee5d4a\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.ValueFilter\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Attribute\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40494,\n                    \"Version\": 1,\n                    \"Guid\": \"7436af3b-2aef-40aa-9534-58c1cf9bfbeb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"UrlId\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Attribute\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The object attribute (property) we will filter on, like \\\"FirstName\\\" or similar. Find more <a href=\\\"http://2sxc.org/help?tag=ToSic.Eav.DataSources.ValueFilter\\\" target=\\\"_blank\\\">help about this filter here</a>.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40496,\n                    \"Version\": 1,\n                    \"Guid\": \"db64e023-a504-449d-b519-4fd74f5a7bcc\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Operator\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40500,\n                    \"Version\": 12,\n                    \"Guid\": \"b6f685cc-4903-4c89-8377-3be3748623dd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"==\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Operator\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This determines how things will be compared, so if it's a \\\"field = value\\\" or \\\"field contains value\\\" etc. There are&nbsp;many operators and which one you use depends a bit on what data-type you are comparing. For example, a number can be \\\"<em>between</em> 17 and 25\\\" or a text can \\\"<em>!contain</em> daniel\\\". Read more about the possible operators in <a href=\\\"http://2sxc.org/help?tag=ToSic.Eav.DataSources.ValueFilter\\\" target=\\\"_blank\\\">help</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40502,\n                    \"Version\": 1,\n                    \"Guid\": \"417cdfe0-8f36-4a5f-96fe-89a6546e7673\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 137474,\n                    \"Version\": 2,\n                    \"Guid\": \"0182a293-b3c9-4ef2-a9e7-17e9a2c745b8\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137475,\n                    \"Version\": 2,\n                    \"Guid\": \"897ac000-27e3-4eef-8c85-ca8fa8f6aca9\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"== equals (case insensitive, numbers, etc.):==\\n=== case-sensitive, exact equals:===\\n!= not equal, case insensitive:!=\\nbegins means it begins with this:begins\\ncontains means it contains this:contains\\n!contains doesn't contain:!contains\\n> for numbers:>\\n< for numbers:<\\n>= for numbers:>=\\n<= for numbers:<=\\nbetween for numbers - in filter use '7 and 10':between\\n!between for numbers - use '7 and 10:!between\\nbetween for dates - use '2016-01-01 and 2017-01-01':between\\n!between for dates - use '2016-01-01 and 2017-01-01':!between\\nget Operator from url:[QueryString:Operator]\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Value\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40497,\n                    \"Version\": 1,\n                    \"Guid\": \"7c3adf68-41ae-4bc0-8aa7-5c94e4991b04\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"[QueryString:Id]\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Value\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The information we want to use to filter - like \\\"John\\\" or \\\"[QueryString:Name]\\\". There are many&nbsp;things you can do with this, so always <a href=\\\"http://2sxc.org/help?tag=ToSic.Eav.DataSources.ValueFilter\\\" target=\\\"_blank\\\">check more information in help</a>.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40499,\n                    \"Version\": 1,\n                    \"Guid\": \"f7b3632a-af0d-427f-a786-94dcbcd59d36\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Take\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 40503,\n                    \"Version\": 4,\n                    \"Guid\": \"906caad5-c07d-4f7a-bcb1-da6b3b946350\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Take / Stop after so many\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Get only 1 or whatever amount you need. This improves performance if you have many thousand items, and only need a few. Leave blank to take all.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 40505,\n                    \"Version\": 1,\n                    \"Guid\": \"f92ce3b1-daf5-43d7-aa4d-419cd758c73f\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43023,\n                    \"Version\": 2,\n                    \"Guid\": \"6db381e4-68ed-45ef-9e22-ec7777f43865\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"all (leave blank):\\n10\\n25\\n50\\n100\\n[QueryString:max]\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Languages\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 125116,\n                    \"Version\": 6,\n                    \"Guid\": \"b154dde1-7239-4d67-a7c3-cf0c28907aa0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Language to filter on\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Choose which language this filter is applied to.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 125117,\n                    \"Version\": 5,\n                    \"Guid\": \"d7c77256-da4a-4576-867b-cde8e8b7316c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 125118,\n                    \"Version\": 5,\n                    \"Guid\": \"0730cfe9-5f71-4a47-9402-b825c9d40716\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"System Default (only primary language):\\nOnly primary language:default\\nFirst try current language (otherwise fall back to primary):current\\nEnglish US (for other language, switch to type-mode and enter it there):en-US\\nUse language from url-param language:[QueryString:language]\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"|Config ToSic.Eav.DataSources.ValueSort\",\n            \"Name\": \"ToSic.Eav.DataSources.ValueSort\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 46948,\n                \"Version\": 2,\n                \"Guid\": \"c763f5fc-eca2-481d-b0d2-2f4d68767e5d\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"used to configure a ValueSort DataSource\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Read more about this in the <a href=\\\"https://r.2sxc.org/DsValueSort\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a></p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Value Sort\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.ValueSort\"\n                }\n              },\n              {\n                \"Id\": 137452,\n                \"Version\": 1,\n                \"Guid\": \"cff1d7aa-c10b-476f-bce4-48f4af7fdbbc\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"|Config ToSic.Eav.DataSources.ValueSort\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Attributes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46926,\n                    \"Version\": 3,\n                    \"Guid\": \"18af5723-92ab-409b-95f7-4cfe2095d271\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Attributes\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Names of attributes (fields), sepparated by a comma\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46927,\n                    \"Version\": 2,\n                    \"Guid\": \"d66107ee-31a0-47c5-9fe7-a8c302e47fe4\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46931,\n                    \"Version\": 1,\n                    \"Guid\": \"21e4dfb1-18ff-4dc4-84e0-4fb0e243b84a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Directions\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46928,\n                    \"Version\": 4,\n                    \"Guid\": \"a17987aa-53da-4dd8-aa0b-69be7cf14f7f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Directions (see notes for multiple sorts)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"if you have multiple fields to sort by, switch to manual entry in the field\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46929,\n                    \"Version\": 3,\n                    \"Guid\": \"a701f39c-b0e9-4d70-ba28-240d833fcb8c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46930,\n                    \"Version\": 2,\n                    \"Guid\": \"a5434cfe-95f5-4957-b66a-ede966b22976\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"asc\\ndesc\\n1\\n0\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Languages\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 125120,\n                    \"Version\": 3,\n                    \"Guid\": \"0d36d037-0149-4886-9c12-4257272822fd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Language to Sort By\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Choose which language this sort is applied to.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 125121,\n                    \"Version\": 2,\n                    \"Guid\": \"aad4c300-4466-4a98-b962-8047a418ef29\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 125122,\n                    \"Version\": 2,\n                    \"Guid\": \"0475169e-8f28-4595-b63d-48e7e2501c86\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"System Default (only primary language):\\nOnly primary language:default\\nFirst try current language (otherwise fall back to primary):current\\nEnglish US (for other language, switch to type-mode and enter it there):en-US\\nUse language from url-param language:[QueryString:language]\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"3d970d2b-32cb-4ecb-aeaf-c49fbcc678a5\",\n            \"Name\": \"PagesDataSourceConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 167673,\n                \"Version\": 2,\n                \"Guid\": \"4dc0c5ab-5cdf-4832-b13b-71753584bdb1\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure settings for the Pages DataSource.</p>\\n<p>It will return <a href=\\\"http://go.2sxc.org/find?xref=ToSic.Sxc.Cms.Pages\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">pages</a>&nbsp;entities.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"PagesDataSourceConfig\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"3d970d2b-32cb-4ecb-aeaf-c49fbcc678a5\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167656,\n                    \"Version\": 2,\n                    \"Guid\": \"c3222f5d-aee9-40e1-9779-ef57e2447aa2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Pages Configuration\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167657,\n                    \"Version\": 1,\n                    \"Guid\": \"7db3f426-8a4d-41a8-88c0-5658b2db6488\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167658,\n                    \"Version\": 1,\n                    \"Guid\": \"97bcdcd0-9c82-4e4d-a5f1-16130280577e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupTypes\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167675,\n                    \"Version\": 2,\n                    \"Guid\": \"f9763ce6-d095-42ce-a313-0e456975e7b0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Special Page Types to Get\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>By default, most special page types are not returned.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167676,\n                    \"Version\": 1,\n                    \"Guid\": \"de420b09-3400-45db-9ece-89c4e13d8c9e\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeLinks\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167653,\n                    \"Version\": 5,\n                    \"Guid\": \"13fa408e-ebc4-4dee-b3ac-477164b47113\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Links-Only Items from the Navigation\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These are virtual pages which actually just point to some URL.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167667,\n                    \"Version\": 4,\n                    \"Guid\": \"da6bd79c-3a2e-47e7-b402-1691cbe3ae25\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167668,\n                    \"Version\": 4,\n                    \"Guid\": \"11975ebd-cd70-4179-81be-83724c5b7b78\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"false:\\uD83D\\uDEAB False\\ntrue:✅ True\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeHidden\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167649,\n                    \"Version\": 5,\n                    \"Guid\": \"7063e10b-beae-4115-b211-3deafdce55e2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Hidden Pages\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These are pages which are configured to not show in the menu.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167659,\n                    \"Version\": 4,\n                    \"Guid\": \"27555baa-9572-4162-beef-82dba7e76631\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167660,\n                    \"Version\": 4,\n                    \"Guid\": \"5ff3189c-6135-4a6f-8235-bcb4eff08e20\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"false:\\uD83D\\uDEAB False\\ntrue:✅ True\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeDeleted\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167650,\n                    \"Version\": 5,\n                    \"Guid\": \"b73641a3-08f8-49e1-9efd-38f49270489c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Deleted Pages\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These are pages which are deleted and still in the recycle bin.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167661,\n                    \"Version\": 4,\n                    \"Guid\": \"6565b7a2-caed-4ce4-909c-cd84d7efcb36\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167662,\n                    \"Version\": 4,\n                    \"Guid\": \"2a3e60cf-ff1b-425f-984e-36ef195a5724\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"false:\\uD83D\\uDEAB False\\ntrue:✅ True\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeAdmin\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167651,\n                    \"Version\": 5,\n                    \"Guid\": \"a729819e-931e-4df9-b784-dcffe19127bf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include Admin Pages\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These are pages to admin the current site, such as file manager.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167663,\n                    \"Version\": 4,\n                    \"Guid\": \"aaee7dbc-e6fd-4119-9f7f-30e8223479f5\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167664,\n                    \"Version\": 4,\n                    \"Guid\": \"f3254a72-971a-49fa-99fc-97ae0ec06bb5\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"false:\\uD83D\\uDEAB False\\ntrue:✅ True\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IncludeSystem\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167652,\n                    \"Version\": 4,\n                    \"Guid\": \"864527a4-8d63-475e-b2b7-61c4dce3dc9e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Include System Pages\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These are pages to admin the current system, such as modules management.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167665,\n                    \"Version\": 3,\n                    \"Guid\": \"55c805f6-b579-47a8-8214-d28958e6dee1\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167666,\n                    \"Version\": 3,\n                    \"Guid\": \"8ca618b4-1ae5-4cd7-8c8d-6f51834a4c5f\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"false:\\uD83D\\uDEAB False\\ntrue:✅ True\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupPermissions\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167674,\n                    \"Version\": 2,\n                    \"Guid\": \"a33aa4a3-dcf4-4028-b3ff-0901cdb968f1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Permissions the Current User Must Have\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167677,\n                    \"Version\": 1,\n                    \"Guid\": \"b6f52a1e-f495-4551-8610-acc850d1b24c\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RequireViewPermissions\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167654,\n                    \"Version\": 3,\n                    \"Guid\": \"23c6a97f-b7a3-4c8a-b892-3b8a875aca4d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Only Include Pages to Which the User has View Permissions\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167669,\n                    \"Version\": 2,\n                    \"Guid\": \"af8f905f-b4ca-460f-8ff5-9d28c34907e2\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167670,\n                    \"Version\": 2,\n                    \"Guid\": \"00532880-110e-4c31-b888-fd7702dda9f8\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"false:\\uD83D\\uDEAB False\\ntrue:✅ True\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RequireEditPermissions\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167655,\n                    \"Version\": 4,\n                    \"Guid\": \"c1f088e0-d0fb-4a17-bb4b-e72f3f4c70a2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Only Include Pages to Which the User has Edit Permissions\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167671,\n                    \"Version\": 3,\n                    \"Guid\": \"69539405-654b-4711-a989-fcbe54924b62\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167672,\n                    \"Version\": 3,\n                    \"Guid\": \"013c2eaa-ec44-4a33-b825-059fa7dff145\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"false:\\uD83D\\uDEAB False\\ntrue:✅ True\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"f9aca0f0-1b1b-4414-b42e-b337de124124\",\n            \"Name\": \"SystemStackConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 169107,\n                \"Version\": 1,\n                \"Guid\": \"75371e3d-fe95-4cb3-bd1f-f8ad05f2f548\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure what the SystemStack DataSource should return.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"System Stack Configuration (Settings/Resources)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"f9aca0f0-1b1b-4414-b42e-b337de124124\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"StackNames\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169104,\n                    \"Version\": 5,\n                    \"Guid\": \"64b78479-890b-41ac-a56c-5f813a3f4076\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Stack Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Which stack you want.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169109,\n                    \"Version\": 4,\n                    \"Guid\": \"e0270815-3d9f-4e62-be67-4a7d895385a3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169110,\n                    \"Version\": 4,\n                    \"Guid\": \"bc0836f6-b6c0-4434-85f8-de9c99be90d8\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"Settings:Settings\\nResources:Resources\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Keys\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169105,\n                    \"Version\": 2,\n                    \"Guid\": \"6da2bd43-f156-445a-ad35-b9f3f8f0e179\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Key\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169113,\n                    \"Version\": 1,\n                    \"Guid\": \"221c51f7-b774-4fab-af92-d0cd723d48fa\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169114,\n                    \"Version\": 2,\n                    \"Guid\": \"932c04ce-73c7-4027-912b-036138ae833e\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Settings\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Title\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AddValues\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169106,\n                    \"Version\": 2,\n                    \"Guid\": \"438a8bae-f345-4691-a28e-f6fd71d78c03\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Add Values in Result\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Determine if you also want the values of settings. If no you'll just get the keys.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169111,\n                    \"Version\": 1,\n                    \"Guid\": \"d521e078-d931-4706-bf4d-2fff26503b14\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169112,\n                    \"Version\": 1,\n                    \"Guid\": \"e78000a1-3d59-46cc-9c6d-3317926d52da\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default - add values\\ntrue:Add Values\\nfalse:Do not add values\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"477d5de4-5ffa-43ef-8553-37354cb27660\",\n            \"Name\": \"AppFilesDataSourceConfig\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 184019,\n                \"Version\": 2,\n                \"Guid\": \"0136ff45-c55a-4e3e-9b59-2c59ddf2b914\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Specify how to get lists of files and/or folders from the App.</p>\\n<p>It will return <a href=\\\"http://go.2sxc.org/find?xref=ToSic.Sxc.Cms.Assets\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">file and folder asset</a> entities.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"App Files DataSource Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"477d5de4-5ffa-43ef-8553-37354cb27660\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184007,\n                    \"Version\": 2,\n                    \"Guid\": \"cd91967a-8d75-4fa0-8e30-ced96d27475b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"App Files\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Just a title so you can remember what this does.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184010,\n                    \"Version\": 1,\n                    \"Guid\": \"3c1a7e07-edd8-495e-9c1a-26ad68d6fc9e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184011,\n                    \"Version\": 1,\n                    \"Guid\": \"652430c0-e23c-4a61-b7eb-620b10d7023f\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RootFolder\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184008,\n                    \"Version\": 2,\n                    \"Guid\": \"942a2cab-1149-4cb3-ac42-f195c9b18c84\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"/\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Root Folder\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The starting folder in the app, where retrieving files should start. Must begin with a \\\"/\\\"</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184012,\n                    \"Version\": 1,\n                    \"Guid\": \"670c495b-e2de-4821-af63-c16fa45d3f21\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184013,\n                    \"Version\": 1,\n                    \"Guid\": \"fa3ff680-eab4-4a25-b529-1af7dda424a6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FileFilter\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184009,\n                    \"Version\": 2,\n                    \"Guid\": \"036fb1e9-9303-454e-aa1a-9ec7c26ad7ad\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"*.*\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"File Filter\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Which files to retrieve.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184014,\n                    \"Version\": 1,\n                    \"Guid\": \"5fad3202-a5ee-4b44-8333-ad8c05f93811\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184015,\n                    \"Version\": 1,\n                    \"Guid\": \"64870e4f-4377-47e1-b96d-11f661443016\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SearchSubfolders\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184016,\n                    \"Version\": 3,\n                    \"Guid\": \"36de8534-4269-4036-bd54-59498f4bacf0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Search Subfolders\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184018,\n                    \"Version\": 2,\n                    \"Guid\": \"9184dc3d-96d4-4c00-aad5-8dc39fddb460\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"radio\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"7d4c2dd7-b23a-4c70-a3c3-8f5a53a88ae0\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 184017,\n              \"Version\": 1,\n              \"Guid\": \"7d4c2dd7-b23a-4c70-a3c3-8f5a53a88ae0\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title\\nfalse,\\\"Do not search subfolders (default)\\\"\\ntrue,\\\"Search Subfolders\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PreviewValue\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"AppFilesDataSourceConfig - SearchSubfolders\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-decorators.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"4f6d1484-4672-43d5-9c48-94ff3ec11069\",\n            \"Name\": \"EditUiConfigurationDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 144360,\n                \"Version\": 4,\n                \"Guid\": \"ede19b00-8396-47b1-b6db-e0f572b7014e\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Configure modified behavior in the Edit-UI\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This adjusts some features of the edit UI. It is still beta, so anything you do here may change in future.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Edit Configuration (Decorator for Content-Types)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE5LjQzIDEyLjk4Yy4wNC0uMzIuMDctLjY0LjA3LS45OCAwLS4zNC0uMDMtLjY2LS4wNy0uOThsMi4xMS0xLjY1Yy4xOS0uMTUuMjQtLjQyLjEyLS42NGwtMi0zLjQ2Yy0uMDktLjE2LS4yNi0uMjUtLjQ0LS4yNS0uMDYgMC0uMTIuMDEtLjE3LjAzbC0yLjQ5IDFjLS41Mi0uNC0xLjA4LS43My0xLjY5LS45OGwtLjM4LTIuNjVDMTQuNDYgMi4xOCAxNC4yNSAyIDE0IDJoLTRjLS4yNSAwLS40Ni4xOC0uNDkuNDJsLS4zOCAyLjY1Yy0uNjEuMjUtMS4xNy41OS0xLjY5Ljk4bC0yLjQ5LTFjLS4wNi0uMDItLjEyLS4wMy0uMTgtLjAzLS4xNyAwLS4zNC4wOS0uNDMuMjVsLTIgMy40NmMtLjEzLjIyLS4wNy40OS4xMi42NGwyLjExIDEuNjVjLS4wNC4zMi0uMDcuNjUtLjA3Ljk4IDAgLjMzLjAzLjY2LjA3Ljk4bC0yLjExIDEuNjVjLS4xOS4xNS0uMjQuNDItLjEyLjY0bDIgMy40NmMuMDkuMTYuMjYuMjUuNDQuMjUuMDYgMCAuMTItLjAxLjE3LS4wM2wyLjQ5LTFjLjUyLjQgMS4wOC43MyAxLjY5Ljk4bC4zOCAyLjY1Yy4wMy4yNC4yNC40Mi40OS40Mmg0Yy4yNSAwIC40Ni0uMTguNDktLjQybC4zOC0yLjY1Yy42MS0uMjUgMS4xNy0uNTkgMS42OS0uOThsMi40OSAxYy4wNi4wMi4xMi4wMy4xOC4wMy4xNyAwIC4zNC0uMDkuNDMtLjI1bDItMy40NmMuMTItLjIyLjA3LS40OS0uMTItLjY0bC0yLjExLTEuNjV6bS0xLjk4LTEuNzFjLjA0LjMxLjA1LjUyLjA1LjczIDAgLjIxLS4wMi40My0uMDUuNzNsLS4xNCAxLjEzLjg5LjcgMS4wOC44NC0uNyAxLjIxLTEuMjctLjUxLTEuMDQtLjQyLS45LjY4Yy0uNDMuMzItLjg0LjU2LTEuMjUuNzNsLTEuMDYuNDMtLjE2IDEuMTMtLjIgMS4zNWgtMS40bC0uMTktMS4zNS0uMTYtMS4xMy0xLjA2LS40M2MtLjQzLS4xOC0uODMtLjQxLTEuMjMtLjcxbC0uOTEtLjctMS4wNi40My0xLjI3LjUxLS43LTEuMjEgMS4wOC0uODQuODktLjctLjE0LTEuMTNjLS4wMy0uMzEtLjA1LS41NC0uMDUtLjc0cy4wMi0uNDMuMDUtLjczbC4xNC0xLjEzLS44OS0uNy0xLjA4LS44NC43LTEuMjEgMS4yNy41MSAxLjA0LjQyLjktLjY4Yy40My0uMzIuODQtLjU2IDEuMjUtLjczbDEuMDYtLjQzLjE2LTEuMTMuMi0xLjM1aDEuMzlsLjE5IDEuMzUuMTYgMS4xMyAxLjA2LjQzYy40My4xOC44My40MSAxLjIzLjcxbC45MS43IDEuMDYtLjQzIDEuMjctLjUxLjcgMS4yMS0xLjA3Ljg1LS44OS43LjE0IDEuMTN6TTEyIDhjLTIuMjEgMC00IDEuNzktNCA0czEuNzkgNCA0IDQgNC0xLjc5IDQtNC0xLjc5LTQtNC00em0wIDZjLTEuMSAwLTItLjktMi0ycy45LTIgMi0yIDIgLjkgMiAyLS45IDItMiAyeiIvPjwvc3ZnPg==\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"4f6d1484-4672-43d5-9c48-94ff3ec11069\"\n                }\n              },\n              {\n                \"Id\": 144361,\n                \"Version\": 1,\n                \"Guid\": \"60fb7885-7356-4183-9794-b933b7d5d39c\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for Content-Type\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"4f6d1484-4672-43d5-9c48-94ff3ec11069\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144363,\n                    \"Version\": 1,\n                    \"Guid\": \"9fc5956a-762d-4709-9acc-ae6fc7649219\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Features\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144362,\n                    \"Version\": 2,\n                    \"Guid\": \"b974d450-1e1c-4fe9-adbf-02b350e50881\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Features\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144364,\n                    \"Version\": 1,\n                    \"Guid\": \"f519e76b-8313-4109-9b30-ed813562b73b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144365,\n                    \"Version\": 1,\n                    \"Guid\": \"cd0fe453-e2af-4905-97ca-02291c50e99a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n            \"Name\": \"SystemExportDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 165963,\n                \"Version\": 3,\n                \"Guid\": \"f7a6d76d-ce9d-479d-9cb8-6b7d325ecace\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for Content Types\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 100\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"32698880-1c2e-41ab-bcfc-420091d3263f\"\n                }\n              },\n              {\n                \"Id\": 165964,\n                \"Version\": 4,\n                \"Guid\": \"8eb1bb44-b148-43aa-a758-537a5f0fc2d1\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"*\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for all Entities\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 100\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 4\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"32698880-1c2e-41ab-bcfc-420091d3263f\"\n                }\n              },\n              {\n                \"Id\": 165965,\n                \"Version\": 3,\n                \"Guid\": \"0408571a-dbc0-4081-9b66-d1fc7251974f\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Export Decorator\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"<p>Mark something in the system to be part of an export set.&nbsp;</p>\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0iTTEwLjk3NSAyMS45NXEtMS45LS4yLTMuNTM3LTEuMDYzUTUuOCAyMC4wMjUgNC42IDE4LjY4OHEtMS4yLTEuMzM4LTEuODg3LTMuMDYzLS42ODgtMS43MjUtLjY4OC0zLjY1IDAtMy44NzUgMi41NjMtNi43MTNRNy4xNSAyLjQyNSAxMSAydjJxLTMuMDI1LjQyNS01IDIuNjg3LTEuOTc1IDIuMjYzLTEuOTc1IDUuMjg4UTQuMDI1IDE1IDYgMTcuMjYycTEuOTc1IDIuMjYzIDQuOTc1IDIuNjg4Wm0xLTQuOTVMNi45NSAxMS45NWwxLjQyNS0xLjQyNSAyLjYgMi42VjdoMnY2LjEyNWwyLjU3NS0yLjU3NUwxNi45NzUgMTJabTEgNC45NXYtMnExLjA3NS0uMTUgMi4wNjMtLjU3NS45ODctLjQyNSAxLjgzNy0xLjA3NWwxLjQ1IDEuNDVxLTEuMTc1LjkyNS0yLjUyNSAxLjQ4OC0xLjM1LjU2Mi0yLjgyNS43MTJabTMuOTUtMTYuM1ExNi4wNSA1IDE1LjA2MiA0LjU3NSAxNC4wNzUgNC4xNSAxMyA0VjJxMS40NzUuMTUgMi44MjUuNzEyIDEuMzUuNTYzIDIuNSAxLjQ4OFptMi44IDEyLjY1LTEuNC0xLjQyNXEuNjUtLjg1IDEuMDUtMS44MzguNC0uOTg3LjU1LTIuMDYyaDIuMDVxLS4yIDEuNDc1LS43NSAyLjgzNy0uNTUgMS4zNjMtMS41IDIuNDg4Wm0uMi03LjMyNXEtLjE1LTEuMDc1LS41NS0yLjA2My0uNC0uOTg3LTEuMDUtMS44MzdsMS40LTEuNDI1cS45NSAxLjEyNSAxLjUyNSAyLjQ4Ny41NzUgMS4zNjMuNzI1IDIuODM4WiIvPjwvc3ZnPg==\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"32698880-1c2e-41ab-bcfc-420091d3263f\"\n                }\n              },\n              {\n                \"Id\": 166418,\n                \"Version\": 1,\n                \"Guid\": \"0ec49108-e863-412f-9f8a-05f492be4d54\",\n                \"Type\": {\n                  \"Id\": \"19655377-6626-4986-aea0-ec3c187186ad\",\n                  \"Name\": \"RequirementDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Feature\": {\n                      \"en-us\": \"DataExportImportBundles\"\n                    },\n                    \"License\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Platform\": {\n                      \"en-us\": \"\"\n                    },\n                    \"RequirementType\": {\n                      \"en-us\": \"feature\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Requires feature DataExportImportBundles\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"32698880-1c2e-41ab-bcfc-420091d3263f\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Configuration\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 165962,\n                    \"Version\": 4,\n                    \"Guid\": \"364f9a97-c3f8-4edc-8303-80dcb246a7f9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Configuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 165966,\n                    \"Version\": 3,\n                    \"Guid\": \"ab13ffb3-bd08-441a-946b-3f0b113522fd\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"d7f2e4fa-5306-41bb-a3cd-d9529c838879\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"cb27a0f2-f921-48d0-a3bc-37c0e77b1d0c\",\n            \"Name\": \"ImageDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 144405,\n                \"Version\": 5,\n                \"Guid\": \"0808ea36-2012-4c8e-9c81-9388ad6aaf91\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\",\n                      \"de-de\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Image Details and Configuration\",\n                      \"de-de\": \"Bild-Beschreibung und -Konfiguration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"cb27a0f2-f921-48d0-a3bc-37c0e77b1d0c\"\n                }\n              },\n              {\n                \"Id\": 158792,\n                \"Version\": 1,\n                \"Guid\": \"9c99a32e-dbfa-47d5-aea2-2e0c0e21115a\",\n                \"Type\": {\n                  \"Id\": \"acc185a7-f300-4468-bce8-d6a64038989d\",\n                  \"Name\": \"ToolbarButtonDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Command\": {\n                      \"en-us\": \"metadata\"\n                    },\n                    \"Ui\": {\n                      \"en-us\": \"classes=single-field\"\n                    },\n                    \"UiColor\": {\n                      \"en-us\": \"\"\n                    },\n                    \"UiIcon\": {\n                      \"en-us\": \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" height=\\\"24px\\\" viewBox=\\\"0 0 24 24\\\" width=\\\"24px\\\" fill=\\\"#000000\\\"><path d=\\\"M0 0h24v24H0V0z\\\" fill=\\\"none\\\"/><path d=\\\"M5 15H3v6h6v-2H5v-4zM5 5h4V3H3v6h2V5zm16-2h-6v2h4v4h2V3zm-2 16h-4v2h6v-6h-2v4zM12 9c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z\\\"/></svg>\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"cb27a0f2-f921-48d0-a3bc-37c0e77b1d0c\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"WarningGlobalFile\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 176327,\n                    \"Version\": 6,\n                    \"Guid\": \"c1f8cd4a-c057-4e98-8bd6-75aaea8dd8eb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"WarningGlobalFile\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<h3>&nbsp;⚠️ Warning: This is a Shared File</h3>\\n<p><em>Normally you would add settings to images which belong to a specific thing, like images which belong to a blog-post. This file is shared, so it could be used in many places. The settings you edit here will apply everywhere this file used. See <a href=\\\"https://go.2sxc.org/image-share-warning\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</em></p>\",\n                          \"de-de\": \"<h3>&nbsp;⚠️Warnung: Gemeinsam genutzte Datei</h3>\\n<p><em>Normalerweise setzt man Einstellungen bei Bildern, die zu einem bestimmten Ding geh&ouml;ren, beispielsweise Bilder eines Blog-Beitrags.&nbsp;Diese Datei ist global und kann an vielen Orten verwendet werden. Diese Einstellungen gelten auch, wenn diese Datei anderswo eingesetzt wird.</em></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"1aef80c1-fb18-493a-90b9-e5f8c702965e\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"InfoPresets\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183849,\n                    \"Version\": 3,\n                    \"Guid\": \"4d01de7e-b3bc-4b38-a894-03029196f693\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"InfoPresets\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Configure Presets on a Field, like the default Resize and Lightbox behavior on</p>\\n<ul>\\n<li>WYSIWYG fields</li>\\n<li>Image fields</li>\\n<li>Image Library fields</li>\\n</ul>\\n<p>These presets will be picked up automatically by the API such as ImageService.Img(...) and ImageService.Picture(...) as well as the .Html(...) method.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"f350e7cb-829a-407a-b442-bd481ddc02bb\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescription\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 177517,\n                    \"Version\": 4,\n                    \"Guid\": \"b309674f-e06c-4657-9b07-30a32df2e762\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title & Description\",\n                          \"de-de\": \"Titel & Beschreibung\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Describe your image for screen readers and SEO.</p>\",\n                          \"de-de\": \"<p>Beschreibe dein Bild f&uuml;r Menschen mit Behinderungen und Google / SEO.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"b0948915-0f4a-4843-9b4f-eb1604321457\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 177518,\n                    \"Version\": 2,\n                    \"Guid\": \"7eaa2ece-4ce6-4307-8253-cc521404bbee\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144396,\n                    \"Version\": 3,\n                    \"Guid\": \"91e1a644-6a08-4eea-8b5f-69befa7e38f7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Image Description\",\n                          \"de-de\": \"Bildbeschreibung\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"f8e9b585-f00f-4f25-9679-500024209d98\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144403,\n                    \"Version\": 1,\n                    \"Guid\": \"50d521e5-5071-415d-917b-8b02b3cbd4e4\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144404,\n                    \"Version\": 1,\n                    \"Guid\": \"e74260b4-d2d3-45f9-b0a6-8776cfe01dd1\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SkipFallbackTitle\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 176316,\n                    \"Version\": 3,\n                    \"Guid\": \"cec3a006-939e-4189-9068-4b44e527ac05\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"SkipFallbackTitle\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"2ab4855c-9699-4f33-8a8c-b17ef8f86bed\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 176317,\n                    \"Version\": 1,\n                    \"Guid\": \"66eca87d-f9c3-4536-8a3f-9271db0b9916\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Use a default title (as none is specified here)\",\n                          \"de-de\": \"Verwende Standardbeschriftung (da hier keine angegeben wurde)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Leave title empty\",\n                          \"de-de\": \"Keine Beschriftung verwenden\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DescriptionExtended\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 176320,\n                    \"Version\": 7,\n                    \"Guid\": \"e2bd110b-f7d5-4644-b264-ed904ed7ce94\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Extended Description\",\n                          \"de-de\": \"Erweiterte Beschreibung\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is only shown in special scenarios like when used in galleries.</p>\",\n                          \"de-de\": \"<p>Dies wird nur in speziellen F&auml;llen angezeigt, beispielsweise in Galerien.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"6bcded21-014b-430a-b968-b095bc627776\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 176324,\n                    \"Version\": 5,\n                    \"Guid\": \"2d814147-6cc9-46eb-b567-ac1af1ee338f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 176325,\n                    \"Version\": 5,\n                    \"Guid\": \"b4b62531-015b-445e-91dd-7b1e3c18b136\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        },\n                        \"WysiwygConfiguration\": {\n                          \"en-us\": \"3e9dd123-ccef-4d81-80e7-4c6ae6f5ddc6\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AddDescriptionDetailed\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 176319,\n                    \"Version\": 6,\n                    \"Guid\": \"bd63a2ef-22fa-4566-892f-5e07683a99ca\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Add Detailed / Extended Description\",\n                          \"de-de\": \"Erweiterte Beschreibung hinzufügen\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"7d4c5b6f-9831-4a72-bbaa-5b82c4564851\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 176321,\n                    \"Version\": 4,\n                    \"Guid\": \"969bca03-8a22-48f5-8acc-2eb02123eeaf\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"without detailed description\",\n                          \"de-de\": \"ohne erweiterte Beschreibung\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"with detailed description\",\n                          \"de-de\": \"mit erweiterter Beschreibung\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupCrop\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 177515,\n                    \"Version\": 3,\n                    \"Guid\": \"32bf5ace-2134-46f3-bb9c-4cf841127bf4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Image Cropping\",\n                          \"de-de\": \"Bild zuschneiden\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Specify how the image should be cropped if it is automatically resized.</p>\",\n                          \"de-de\": \"<p>Gib an wie das Bild zugeschnitten werden soll, wenn es automatisch angepasst wird.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 177516,\n                    \"Version\": 2,\n                    \"Guid\": \"7536e75b-9ffd-4ae6-b84c-f9f4603a4ae3\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CropBehavior\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144395,\n                    \"Version\": 5,\n                    \"Guid\": \"c505bdcc-24de-48a8-9492-4945caf59570\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Crop Behavior\",\n                          \"de-de\": \"Zuschnitt-Verhalten\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144397,\n                    \"Version\": 4,\n                    \"Guid\": \"ff64899a-b9f2-4eab-bc54-4c9e38c8de05\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144398,\n                    \"Version\": 4,\n                    \"Guid\": \"fb106616-3e50-46bf-b204-567e06e26675\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default Crop - Use image as the template expects it, usually crop to center\\nnone:Don't Crop - the entire image should be visible\\nto:Corner or Side Crop - the most important part is in a corner or on a side\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CropTo\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144399,\n                    \"Version\": 6,\n                    \"Guid\": \"d6923ea6-f842-456f-ba8e-75200f411231\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Crop Focus / Crop To\",\n                          \"de-de\": \"Zuschnitt - Fokus\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"e448061e-6587-4833-9071-143ded271a76\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144401,\n                    \"Version\": 5,\n                    \"Guid\": \"c88bde06-956b-48cc-98bb-2ff68edc7a34\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144402,\n                    \"Version\": 5,\n                    \"Guid\": \"fe5255fe-e806-426e-b433-61119f6507df\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":\\uD83C\\uDFAF Default - Center\\ntl:↖️ Top Left\\ntc:⬆️ Top Center\\ntr:↗️ Top Right\\nml:⬅️ Middle Left\\nmc:\\uD83C\\uDFAF Middle Center\\nmr:➡️ Middle Right\\nbl:↙️ Bottom Left\\nbc:⬇️ Bottom Center\\nbr:↘️ Bottom Right\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ResizeSettings\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183831,\n                    \"Version\": 8,\n                    \"Guid\": \"67110684-0e52-4c18-9599-8c254dd684f3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Resize Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Override the resize settings on this image.</p>\",\n                          \"de-de\": \"<p>Verwende eigene Einstellungen f&uuml;r die Anzeigegr&ouml;sse dieses Bildes.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"c4185f6f-ef3e-4718-bdc9-2ca262fa4437\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183832,\n                    \"Version\": 1,\n                    \"Guid\": \"d44c8aa9-2ba7-4f8a-aa26-78308821ea5f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183833,\n                    \"Version\": 1,\n                    \"Guid\": \"5f0a75f7-90be-41c5-a543-0531becaaa79\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183838,\n                    \"Version\": 4,\n                    \"Guid\": \"4e6de09a-9ed0-4bff-8c49-0fc18065ab7e\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"29e24872-6359-4c9e-9c0c-c5a9e68a4a7d\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MessageCropRequirements\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 163986,\n                    \"Version\": 5,\n                    \"Guid\": \"11587585-b4e1-48e4-8f4b-51d4f3bba01f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MessageCropRequirements\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><em>Tip: Crop settings will only take effect if the template creating the HTML interprets the settings. If it seems like the settings don't work, please contact your web developer.&nbsp;</em></p>\",\n                          \"de-de\": \"<p><em>Tipp: Die Einstellungen wirken nur, wenn das Template (der Teil, welches HTML generiert) diese ber&uuml;cksichtigt. Sollten die Einstellungen nicht wirken, dann frag deinen Webdesigner.</em></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"6e1d7fe2-f790-4a16-9ca9-4d93210c5c34\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupLightbox\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183822,\n                    \"Version\": 3,\n                    \"Guid\": \"dcc4368d-49f3-4907-ab25-b1e245547365\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Lightbox / PopUp Settings\",\n                          \"de-de\": \"Lightbox / PopUp Einstellungen\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>For help, see&nbsp;<a href=\\\"https://go.2sxc.org/image-lightbox\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183825,\n                    \"Version\": 2,\n                    \"Guid\": \"4e3ec7ee-5211-41de-b921-6f520f1f8d2c\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"LightboxIsEnabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183823,\n                    \"Version\": 3,\n                    \"Guid\": \"7c5e13b3-758d-4fa2-9285-b919a3d3497f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"LightboxIsEnabled\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183826,\n                    \"Version\": 2,\n                    \"Guid\": \"6387d26a-87d5-4c6e-93a7-ac1b894c68b8\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No Lightbox / PopUp\",\n                          \"de-de\": \"Keine Lightbox / kein PopUp\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"Lightbox / PopUp not configured (use defaults)\",\n                          \"de-de\": \"LightBox / PopUp nicht konfiguriert (nutze Standardeinstellungen)\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Use Lightbox / PopUp\",\n                          \"de-de\": \"Lightbox / PopUp aktiviert\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"LightboxGroup\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183824,\n                    \"Version\": 3,\n                    \"Guid\": \"18d661da-a45c-4876-a898-9adb14f32050\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Lightbox Group\",\n                          \"de-de\": \"Lightbox Gruppe\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Images in the same lightbox group will work together like an album.</p>\",\n                          \"de-de\": \"<p>Bilder in der selben Lightbox-Gruppe funktionieren gemeinsam wie ein Album.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8737cc85-67ee-457f-9221-7337ae006d4b\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183827,\n                    \"Version\": 1,\n                    \"Guid\": \"2137373f-3bed-4f39-ac84-d96396990a8d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183828,\n                    \"Version\": 1,\n                    \"Guid\": \"c1e30ff2-5cbd-40a0-bdce-04bcaac1dd4c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":No Group - this image will open stand alone\\ndefault:Default Group - all images in this group will be in an album together\",\n                          \"de-de\": \":Keine Gruppe - dieses Bild öffnet alleine\\ndefault:Standard Gruppe - alle Bilder in dieser Gruppe sind wie ein Album\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 176328,\n              \"Version\": 3,\n              \"Guid\": \"1aef80c1-fb18-493a-90b9-e5f8c702965e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return !!data.parameters?.showWarningGlobalFile; });\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183852,\n              \"Version\": 1,\n              \"Guid\": \"f350e7cb-829a-407a-b442-bd481ddc02bb\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const forAttribute = context.target.entity.for.targetType == 2;\\n  return { value: forAttribute, stop: true };\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183850,\n              \"Version\": 1,\n              \"Guid\": \"b0948915-0f4a-4843-9b4f-eb1604321457\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const forAttribute = context.target.entity.for.targetType == 2;\\n  return { value: !forAttribute, stop: true };\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183851,\n              \"Version\": 1,\n              \"Guid\": \"f8e9b585-f00f-4f25-9679-500024209d98\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const forAttribute = context.target.entity.for.targetType == 2;\\n  return forAttribute\\n    ? { value: 'Image Render Presets', stop: true }\\n    : { value: data.value, stop: true };\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 176318,\n              \"Version\": 3,\n              \"Guid\": \"2ab4855c-9699-4f33-8a8c-b17ef8f86bed\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"// Only show if the description is not null/whitespace etc.\\n// https://stackoverflow.com/questions/10232366\\nv2((data) => {\\n  const str = data.Description;\\n  return str === null || (/^\\\\s*$/).test(str);\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 176323,\n              \"Version\": 4,\n              \"Guid\": \"6bcded21-014b-430a-b968-b095bc627776\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const detailsBlank = data.DescriptionExtended == '';\\n  return !detailsBlank || data.AddDescriptionDetailed;\\n});\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 176322,\n              \"Version\": 4,\n              \"Guid\": \"7d4c5b6f-9831-4a72-bbaa-5b82c4564851\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"// Only show if the description is not null/whitespace AND data.DescriptionExtended is empty\\nv2((data) => {\\n  const detailsBlank = data.DescriptionExtended == '';\\n  const title = data.Description;\\n  const titleBlank = title == null || (/^\\\\s*$/).test(title);\\n  return detailsBlank && !titleBlank;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144400,\n              \"Version\": 3,\n              \"Guid\": \"e448061e-6587-4833-9071-143ded271a76\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.CropBehavior == 'to'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183834,\n              \"Version\": 2,\n              \"Guid\": \"c4185f6f-ef3e-4718-bdc9-2ca262fa4437\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  // show when crop-to is available, or if it's not empty\\n  return data.CropBehavior == 'to' || !!data.ResizeSettings;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183837,\n              \"Version\": 6,\n              \"Guid\": \"29e24872-6359-4c9e-9c0c-c5a9e68a4a7d\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Description]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Title\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.SettingsEntities\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"ContentType=⚙️Image\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Settings - Image Resizes\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Title\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 163987,\n              \"Version\": 2,\n              \"Guid\": \"6e1d7fe2-f790-4a16-9ca9-4d93210c5c34\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.CropBehavior !== ''; }\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183829,\n              \"Version\": 1,\n              \"Guid\": \"8737cc85-67ee-457f-9221-7337ae006d4b\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return !!data.LightboxIsEnabled;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n            \"Name\": \"IsDefaultDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 136476,\n                \"Version\": 6,\n                \"Guid\": \"ecfce611-9af3-4075-8422-924cec7a3eb0\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Mark something as the Default (like a preferred View)\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This marks something as being the default. There are no properties to edit.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Is-Default (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0cHgiIGZpbGw9IiMwMDAwMDAiPjxnPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYweiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYweiIgZmlsbD0ibm9uZSIvPjwvZz48Zz48cGF0aCBkPSJNMTIgMTcuMjcgMTguMTggMjFsLTEuNjQtNy4wM0wyMiA5LjI0bC03LjE5LS42MUwxMiAyIDkuMTkgOC42MyAyIDkuMjRsNS40NiA0LjczTDUuODIgMjEgMTIgMTcuMjd6Ii8+PC9nPjwvc3ZnPg==\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\"\n                }\n              },\n              {\n                \"Id\": 136483,\n                \"Version\": 1,\n                \"Guid\": \"00d5d915-0783-4511-9af5-0d6f0d0740a7\",\n                \"Type\": {\n                  \"Id\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\",\n                  \"Name\": \"SaveEmptyDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\"\n                }\n              },\n              {\n                \"Id\": 137093,\n                \"Version\": 3,\n                \"Guid\": \"53a8c895-cb55-46fc-bbde-fa9ca0e99b21\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"2SexyContent-Template\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for Views\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 4\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\"\n                }\n              },\n              {\n                \"Id\": 137094,\n                \"Version\": 2,\n                \"Guid\": \"3ef76165-8963-443a-9889-c411e0eebd6a\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for Content-Type\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"852fe15e-bf23-44e6-a856-0a130203496c\",\n            \"Name\": \"IsObsoleteDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 135940,\n                \"Version\": 7,\n                \"Guid\": \"13d2799b-85ac-4620-8a32-6e577c40f900\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Mark something as obsolete/deprecated\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This marks things which should be seen as obsolete in the UI. For example obsolete input-types.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Is-Obsolete (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEyIDJDNi40OCAyIDIgNi40OCAyIDEyczQuNDggMTAgMTAgMTAgMTAtNC40OCAxMC0xMFMxNy41MiAyIDEyIDJ6bTAgMThjLTQuNDIgMC04LTMuNTgtOC04IDAtMS44NS42My0zLjU1IDEuNjktNC45TDE2LjkgMTguMzFDMTUuNTUgMTkuMzcgMTMuODUgMjAgMTIgMjB6bTYuMzEtMy4xTDcuMSA1LjY5QzguNDUgNC42MyAxMC4xNSA0IDEyIDRjNC40MiAwIDggMy41OCA4IDggMCAxLjg1LS42MyAzLjU1LTEuNjkgNC45eiIvPjwvc3ZnPg==\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"852fe15e-bf23-44e6-a856-0a130203496c\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Message\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135941,\n                    \"Version\": 2,\n                    \"Guid\": \"c3abca6c-00c4-4d78-90d8-7f29df0a99cc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Message\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136474,\n                    \"Version\": 1,\n                    \"Guid\": \"4f4bed7d-c41f-4861-8cec-1aa18067008b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136475,\n                    \"Version\": 1,\n                    \"Guid\": \"a3550cc5-8581-41e3-8163-e5760ec01a60\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"c740085a-d548-41f3-8d06-0a48b8692345\",\n            \"Name\": \"IsRecommendedDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 136477,\n                \"Version\": 5,\n                \"Guid\": \"894d67fc-b92a-460f-b56b-8647859e86a9\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Mark things as recommended (for example input-types)\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Mark an item as recommended.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Is-Recommended (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6bTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTkgMjFoOWMuODMgMCAxLjU0LS41IDEuODQtMS4yMmwzLjAyLTcuMDVjLjA5LS4yMy4xNC0uNDcuMTQtLjczdi0yYzAtMS4xLS45LTItMi0yaC02LjMxbC45NS00LjU3LjAzLS4zMmMwLS40MS0uMTctLjc5LS40NC0xLjA2TDE0LjE3IDEgNy41OCA3LjU5QzcuMjIgNy45NSA3IDguNDUgNyA5djEwYzAgMS4xLjkgMiAyIDJ6TTkgOWw0LjM0LTQuMzRMMTIgMTBoOXYybC0zIDdIOVY5ek0xIDloNHYxMkgxeiIvPjwvc3ZnPg==\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"c740085a-d548-41f3-8d06-0a48b8692345\"\n                }\n              },\n              {\n                \"Id\": 137096,\n                \"Version\": 2,\n                \"Guid\": \"0d0cc58d-09b2-4217-86b1-1420f4fadfbe\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for Content-Types (to use on Input-Types)\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"c740085a-d548-41f3-8d06-0a48b8692345\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Message\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 136468,\n                    \"Version\": 1,\n                    \"Guid\": \"e6056049-836b-4ff8-81b2-4b12af337d95\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Message\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"18d2b1db-e1ed-45bc-8746-cd8885651063\",\n            \"Name\": \"IsSharedDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 139093,\n                \"Version\": 4,\n                \"Guid\": \"517f4730-5564-4061-9c1e-4994da7bd839\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Mark Apps as being shared / global\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Is-Shared (Decorator) - for Apps\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0cHgiIGZpbGw9IiMwMDAwMDAiPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iMjQiIHdpZHRoPSIyNCIvPjxwYXRoIGQ9Ik0xOSwxMmgzTDEyLDNMMiwxMmgzdjNIM3YyaDJ2M2gydi0zaDR2M2gydi0zaDR2M2gydi0zaDJ2LTJoLTJWMTJ6IE03LDE1di00LjgxbDQtMy42VjE1SDd6IE0xMywxNVY2LjU5bDQsMy42VjE1SDEzeiIvPjwvc3ZnPg==\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"18d2b1db-e1ed-45bc-8746-cd8885651063\"\n                }\n              },\n              {\n                \"Id\": 139094,\n                \"Version\": 3,\n                \"Guid\": \"dc2fdeed-e789-4b8c-b817-6c711d2927e7\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"<p>If you remove this, the App will not be shared any more. This would break any app which inherits this.</p>\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for App\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 3\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"18d2b1db-e1ed-45bc-8746-cd8885651063\"\n                }\n              },\n              {\n                \"Id\": 139095,\n                \"Version\": 3,\n                \"Guid\": \"ff32388b-9431-43c0-aeda-91b478ffb1ee\",\n                \"Type\": {\n                  \"Id\": \"19655377-6626-4986-aea0-ec3c187186ad\",\n                  \"Name\": \"RequirementDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Feature\": {\n                      \"en-us\": \"bb6656ef-fb81-4943-bf88-297e516d2616\"\n                    },\n                    \"License\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Platform\": {\n                      \"en-us\": \"\"\n                    },\n                    \"RequirementType\": {\n                      \"en-us\": \"feature\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Requires Feature Shared-App\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"18d2b1db-e1ed-45bc-8746-cd8885651063\"\n                }\n              },\n              {\n                \"Id\": 139097,\n                \"Version\": 1,\n                \"Guid\": \"22c65c23-ec7d-4f38-88a6-18ce22b42b69\",\n                \"Type\": {\n                  \"Id\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\",\n                  \"Name\": \"SaveEmptyDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"18d2b1db-e1ed-45bc-8746-cd8885651063\"\n                }\n              },\n              {\n                \"Id\": 142970,\n                \"Version\": 2,\n                \"Guid\": \"1f83e841-4d74-453d-93a7-05fee8bcc2b2\",\n                \"Type\": {\n                  \"Id\": \"19655377-6626-4986-aea0-ec3c187186ad\",\n                  \"Name\": \"RequirementDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Feature\": {\n                      \"en-us\": \"\"\n                    },\n                    \"License\": {\n                      \"en-us\": \"da7274c1-b893-4edb-8acb-ae2995a07321\"\n                    },\n                    \"Platform\": {\n                      \"en-us\": \"\"\n                    },\n                    \"RequirementType\": {\n                      \"en-us\": \"license\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Requires License EnterpriseCms\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"18d2b1db-e1ed-45bc-8746-cd8885651063\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n            \"Name\": \"LanguagesDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 137417,\n                \"Version\": 3,\n                \"Guid\": \"ad99d7b5-7557-43a7-83f1-29b9edf4527e\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This configures a Content-Type to have custom languages / translation settings</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Language and Translation Settings (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEyLjg3IDE1LjA3bC0yLjU0LTIuNTEuMDMtLjAzYzEuNzQtMS45NCAyLjk4LTQuMTcgMy43MS02LjUzSDE3VjRoLTdWMkg4djJIMXYxLjk5aDExLjE3QzExLjUgNy45MiAxMC40NCA5Ljc1IDkgMTEuMzUgOC4wNyAxMC4zMiA3LjMgOS4xOSA2LjY5IDhoLTJjLjczIDEuNjMgMS43MyAzLjE3IDIuOTggNC41NmwtNS4wOSA1LjAyTDQgMTlsNS01IDMuMTEgMy4xMS43Ni0yLjA0ek0xOC41IDEwaC0yTDEyIDIyaDJsMS4xMi0zaDQuNzVMMjEgMjJoMmwtNC41LTEyem0tMi42MiA3bDEuNjItNC4zM0wxOS4xMiAxN2gtMy4yNHoiLz48L3N2Zz4=\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\"\n                }\n              },\n              {\n                \"Id\": 137423,\n                \"Version\": 1,\n                \"Guid\": \"a212e85e-190d-417b-ac4b-cc54c04ccd06\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for ContentTypes\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\"\n                }\n              },\n              {\n                \"Id\": 137424,\n                \"Version\": 1,\n                \"Guid\": \"0d565ac3-c3fb-4b55-a114-574fb997f247\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Languages / Translation Settings\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 137418,\n                    \"Version\": 2,\n                    \"Guid\": \"e1a556da-bcf9-41f5-8c39-d4e8dda53d5e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Languages / Translation Settings\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137420,\n                    \"Version\": 1,\n                    \"Guid\": \"8df5f0b8-4acf-4a5a-8c48-259150163ddf\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137421,\n                    \"Version\": 1,\n                    \"Guid\": \"0eaec010-4f8b-43d6-86a3-ee6354615689\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Enabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 137419,\n                    \"Version\": 2,\n                    \"Guid\": \"5145fbe8-e744-464b-a3cd-4f90553d0046\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Enabled\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137422,\n                    \"Version\": 1,\n                    \"Guid\": \"53583b42-c59c-4d6e-9a11-df5349ae5a6f\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Translation Disabled (items of this type can only be edited in the primary language)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"Default = Enabled (items of this type can be translated)\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Translation Enabled (items of this type can be translated)\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"be34f64b-7d1f-4ad0-b488-dabbbb01a186\",\n            \"Name\": \"LightSpeedOutputDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 144418,\n                \"Version\": 6,\n                \"Guid\": \"f95dcbca-0080-460c-9190-eb72be7a7225\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Configure LightSpeed Output Caching\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p><img srcset=\\\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyNi4yLjEsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iRWJlbmVfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAxMTExLjkgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxMTExLjkgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojMDAwMDNFO30NCjwvc3R5bGU+DQo8Zz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMzY3LjMsMTY4LjdoLTE0LjJjLTIuMywwLTMtMC43LTMtM1Y3Mi4zYzAtMi4zLDAuNy0zLDMtM2gxMS4yYzIuMywwLDMsMC43LDMsM1YxNjguN3ogTTM3NC42LDE1NGgzNi44DQoJCWMyLjMsMCwzLDAuNiwzLDN2OC43YzAsMi4zLTAuNywzLTMsM2gtMzYuOFYxNTR6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTQ0MSw2My43YzUuNCwwLDkuOSw0LjUsOS45LDEwLjFjMCw1LjUtNC41LDkuOC05LjksOS44Yy01LjUsMC05LjktNC4zLTkuOS05LjhTNDM1LjUsNjMuNyw0NDEsNjMuN3oNCgkJIE00MzMuMSw5OS40YzAtMi4zLDAuNy0zLDMtM2gxMC4yYzIuMywwLDMsMC43LDMsM3Y2Ni4zYzAsMi4zLTAuNywzLTMsM0g0MzZjLTIuMywwLTMtMC43LTMtM1Y5OS40SDQzMy4xeiIvPg0KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01MTkuMSwxMTQuNmMtMy4zLTMuMy03LjUtNS41LTEzLjEtNS41Yy0xMS44LDAtMjAuMywxMC4yLTIwLjMsMjMuNGMwLDEyLjgsOC41LDIzLjMsMjAuMywyMy4zDQoJCWM0LjgsMCw5LjEtMS43LDEzLjEtNS41djE0LjZjLTQuMSwzLTkuMiw1LjQtMTYuNiw1LjRjLTE5LjUsMC0zMi44LTE3LTMyLjgtMzcuOGMwLTIwLjIsMTMuMy0zNy42LDMyLjgtMzcuNg0KCQljNy43LDAsMTIuMSwyLDE2LjYsNC41VjExNC42eiBNNTI2LjIsMTAwLjFjMS0yLjEsMy0zLjcsNS4zLTMuN2g4YzIuMywwLDMsMC43LDMsM3Y2My4zYzAsMjguNS0xMi41LDQxLTM0LjYsNDENCgkJYy0xNS44LDAtMjYuNC00LjQtMjguNy01LjNjLTItMC45LTIuMy0xLjMtMS43LTMuNWwyLjEtOC41YzAuNi0yLjQsMS0yLjcsMy4xLTEuOGM0LjUsMS44LDEyLjUsNSwyMi42LDVjMTMuNiwwLDIxLTcuOCwyMS0yNC44DQoJCUw1MjYuMiwxMDAuMUw1MjYuMiwxMDAuMXoiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNTgyLjMsMTY1LjdjMCwyLjMtMC42LDMtMywzaC0xMC4yYy0yLjEsMC0zLTAuNy0zLTNWNjYuOWMwLTIuMywwLjktMywzLTNoMTAuMmMyLjMsMCwzLDAuNywzLDNWMTY1Ljd6DQoJCSBNNTg5LjQsOTguN2MzLjMtMi4zLDcuNS0zLjgsMTIuOS0zLjhjMTUuNiwwLDI3LjUsOC40LDI3LjUsMzIuOHYzOC4xYzAsMi4zLTAuNiwzLTMsM2gtMTAuMmMtMi4xLDAtMy0wLjctMy0zdi0zNC41DQoJCWMwLTE1LjEtNS40LTIxLjktMTUuNS0yMS45Yy00LDAtNi41LDEuNi04LjgsMy4zTDU4OS40LDk4LjdMNTg5LjQsOTguN3oiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNjQ4LjMsMTA5LjNjLTIuMywwLTMtMC43LTMtM3YtN2MwLTIuMywwLjctMywzLTNoNS4zVjgyLjVjMC0yLjMsMC42LTMsMy0zaDEwLjFjMi4zLDAsMywwLjcsMywzdjEzLjloMjEuOQ0KCQljMi4zLDAsMywwLjcsMywzLjF2Ni44YzAsMi4zLTAuNywzLTMsM0g2NDguM3ogTTY2OS42LDExNi42djIxLjNjMCwxMi44LDQuNCwxNy45LDEzLjEsMTcuOWMzLjEsMCw1LjUtMC4zLDguNS0xLjcNCgkJYzIuNy0xLjQsMy4zLTEuMywzLjgsMS43bDEuMyw3LjFjMC40LDIuMSwwLjMsMi44LTEuNiwzLjhjLTUuNywzLjUtMTEuOSwzLjUtMTMuOCwzLjVjLTE4LjcsMC0yNy40LTExLjgtMjcuNC0zMS40di0yMi4zDQoJCUw2NjkuNiwxMTYuNkw2NjkuNiwxMTYuNnoiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNzMzLjcsMTcwYy03LjQtMS4xLTE1LjItMi44LTI0LjEtOC44Yy0yLTEuNC0xLjctMi4zLTAuNy00LjNsMy4xLTUuNGMxLTIsMS43LTMsNC0xLjMNCgkJYzQuOCwzLjMsMTAuMiw2LDE3LjgsNy4xTDczMy43LDE3MEw3MzMuNywxNzB6IE03NDAuOCwxNTcuNmM4LjctMC43LDEyLjgtNC41LDEyLjgtOS43YzAtNC43LTYuMi03LTE3LTguNA0KCQljLTE0LjgtMi0yNy43LTYuNS0yNy43LTIxLjdjMC0xMy4zLDEwLjUtMjIuNiwyOC4xLTIzdjEyLjdjLTkuMiwwLjYtMTIuOCw0LjEtMTIuOCw5LjVjMCw1LjUsNi4xLDcsMTcsOC41DQoJCWMxNC44LDEuOCwyNy43LDYuNSwyNy43LDIxLjZjMCwxMy4zLTEwLjksMjIuNC0yOC4xLDIzLjFWMTU3LjZ6IE03NDQsOTUuM2M2LjIsMS4xLDEyLjIsMi42LDIwLjksNy41YzIuMywxLjQsMS43LDIuNCwwLjksNC40DQoJCWwtMy4xLDUuM2MtMSwyLTEuOCwyLjgtNCwxLjRjLTUuMy0zLjMtOS4xLTUuMS0xNC42LTZWOTUuM0g3NDR6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTgwMi40LDE5NC43YzAsMi4zLTAuNywzLTMsM2gtMTAuMmMtMi4zLDAtMy0wLjctMy0zVjk5LjRjMC0yLjMsMC43LTMsMy0zaDVjMS43LDAsMy43LDAuOSw1LjQsMi40bDIuOCwzLjgNCgkJVjE5NC43eiBNODA5LjUsOTkuNGM0LjgtMi44LDkuMi00LjUsMTYuNi00LjVjMTkuMywwLDMyLjgsMTcuNSwzMi44LDM3LjZjMCwyMC43LTEzLjUsMzcuOC0zMi44LDM3LjhjLTYuNywwLTEyLjItMi4xLTE2LjYtNS40DQoJCXYtMTQuNmMzLjMsMy4xLDcuMSw1LjUsMTMuMSw1LjVjMTEuOCwwLDIwLjItMTAuNSwyMC4yLTIzLjNjMC0xMy4yLTguNC0yMy40LTIwLjItMjMuNGMtNS4xLDAtOS41LDItMTMuMSw1LjVWOTkuNHoiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNODg3LjksMTMzLjJjMCwxMy4yLDkuNCwyMy4xLDIxLjksMjMuMWM1LDAsMTIuMS0xLjEsMTkuNS01LjRjMi4xLTEsMi44LTEuNiw0LjMsMC4zbDQuMSw1LjENCgkJYzEuNCwxLjcsMS43LDIuNiwwLjQsNGMtNi41LDYuNC0xOC4zLDkuOS0yOC43LDkuOWMtMjEuNCwwLTM4LjItMTYuOS0zOC4yLTM3LjZjMC0xOS41LDE0LjYtMzUuNSwzMy40LTM3LjV2MTMuNA0KCQljLTEwLjIsMi4xLTE2LjYsMTEuMi0xNi42LDIzLjd2MUg4ODcuOXogTTg5NS4zLDEyNy4yaDMyLjFjLTEtOC40LTYtMTYuOS0xNS44LTE4LjlWOTVjMjEuMiwxLjcsMzIuMiwxOS4yLDMyLjIsMzkuOA0KCQljMCwyLjMtMC40LDMuMS0yLjgsMy4xaC00NS43Qzg5NC40LDEzNC42LDg5NC40LDEzMC41LDg5NS4zLDEyNy4yeiIvPg0KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik05NzEuOSwxMzMuMmMwLDEzLjIsOS40LDIzLjEsMjEuOSwyMy4xYzUsMCwxMi4xLTEuMSwxOS41LTUuNGMyLjEtMSwyLjgtMS42LDQuMywwLjNsNC4xLDUuMQ0KCQljMS40LDEuNywxLjcsMi42LDAuNCw0Yy02LjUsNi40LTE4LjMsOS45LTI4LjcsOS45Yy0yMS40LDAtMzguMi0xNi45LTM4LjItMzcuNmMwLTE5LjUsMTQuNi0zNS41LDMzLjQtMzcuNXYxMy40DQoJCWMtMTAuMiwyLjEtMTYuNiwxMS4yLTE2LjYsMjMuN3YxSDk3MS45eiBNOTc5LjMsMTI3LjJoMzIuMWMtMS04LjQtNi0xNi45LTE1LjgtMTguOVY5NWMyMS4yLDEuNywzMi4yLDE5LjIsMzIuMiwzOS44DQoJCWMwLDIuMy0wLjQsMy4xLTIuOCwzLjFoLTQ1LjdDOTc4LjUsMTM0LjYsOTc4LjUsMTMwLjUsOTc5LjMsMTI3LjJ6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTEwODguNywxNjUuN2MtNSwyLjgtOS40LDQuNS0xNi42LDQuNWMtMTkuNSwwLTMyLjgtMTcuMy0zMi44LTM3LjZjMC0yMC43LDEzLjMtMzcuOCwzMi44LTM3LjgNCgkJYzYuNSwwLDEyLjIsMi4xLDE2LjYsNS40djE0LjZjLTMuMy0zLjEtNy4yLTUuNS0xMy4xLTUuNWMtMTEuOCwwLTIwLjMsMTAuNS0yMC4zLDIzLjNjMCwxMy4yLDguNSwyMy40LDIwLjMsMjMuNA0KCQljNS4xLDAsOS41LTIsMTMuMS01LjVWMTY1Ljd6IE0xMDk1LjgsNjYuOWMwLTIuMywwLjYtMywzLTNoMTAuMmMyLjMsMCwzLDAuNywzLDN2OTguOGMwLDIuMy0wLjcsMy0zLDNoLTVjLTEuOCwwLTMuOC0wLjctNS41LTIuNA0KCQlsLTIuNy0zLjhWNjYuOXoiLz4NCjwvZz4NCjxnIGlkPSJFYmVuZV8yXzAwMDAwMDIxMDkwNjY3ODg0NzcxMjE5ODMwMDAwMDAyNjYyMTU1MjkzOTQzODcyMTg1XyI+DQo8L2c+DQo8ZyBpZD0iRWJlbmVfMyI+DQo8L2c+DQo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTc4LjMsMTgxLjRjLTAuNC0wLjctMC4zLTEuNiwwLjQtMmMwLjctMC41LDEuNi0wLjMsMi4xLDAuM2wzOC40LDUwLjRjMTEuMS05LjIsMTkuOC0yMS4yLDI1LjEtMzQuOQ0KCWwtMTMuNi05LjdjLTAuNy0wLjUtMC44LTEuNC0wLjQtMmMwLjQtMC43LDEuMy0wLjksMi0wLjVsMTMuNCw4YzEuNS00LjcsMi43LTkuNSwzLjQtMTQuNmMtMTAuNS01LjItMjEuMy0xMC42LTMwLjEtMTUNCgljLTAuNy0wLjQtMS0xLjItMC43LTJjMC4zLTAuNywxLjItMS4xLDEuOS0wLjhsMjkuNSwxMS42YzAuMS0yLDAuMi00LDAuMi02di0yMS43bC00Ni42LTEwLjdjLTAuOC0wLjItMS4zLTAuOS0xLjEtMS43DQoJYzAuMS0wLjgsMC45LTEuMywxLjctMS4ybDQ2LjEsNS41VjQ5LjhsLTYyLjQsMzcuM2MtMC4yLDAuMS0wLjUsMC4yLTAuOCwwLjJjLTAuNSwwLTEtMC4yLTEuMy0wLjdjLTAuNC0wLjctMC4zLTEuNiwwLjQtMkwyNTAsMzcuNA0KCVYwSDEyMC44bC0wLjMsNDQuOWMwLDAuOC0wLjYsMS41LTEuNCwxLjVjMCwwLDAsMC0wLjEsMGMtMC44LDAtMS40LTAuNi0xLjUtMS40bC00LjItNDVIODUuNkM3Ny4xLDAsNjksMS4yLDYxLjMsMy41YzAsMCwwLDAsMCwwDQoJbDQ2LjYsNzAuNmMwLjQsMC43LDAuMywxLjYtMC40LDJjLTAuMywwLjItMC42LDAuMy0wLjksMC4zYy0wLjUsMC0wLjktMC4yLTEuMi0wLjZsLTUxLjctNjhjLTAuMy0wLjQtMC40LTAuOC0wLjMtMS4yDQoJYzAtMC4yLDAuMS0wLjMsMC4yLTAuNEMzOS40LDExLjksMjcuMiwyMS4zLDE4LDMzLjJsNDkuMSwzNWMwLjcsMC41LDAuOCwxLjQsMC40LDJjLTAuMywwLjQtMC44LDAuNy0xLjMsMC43DQoJYy0wLjMsMC0wLjUtMC4xLTAuOC0wLjJMMTMuNSwzOS41QzUsNTIuOCwwLDY4LjYsMCw4NS42Vjg3YzEzLjUsMy4xLDQzLjYsMTAuMiw2OS43LDE2LjRjMC44LDAuMiwxLjMsMSwxLjEsMS43DQoJYy0wLjEsMC43LTAuOCwxLjItMS41LDEuMmMtMC4xLDAtMC4xLDAtMC4yLDBMMCw5Ni41djE1LjlsNTIuMywxYzAuOCwwLDEuNSwwLjcsMS41LDEuNWMwLDAuOC0wLjYsMS41LTEuNCwxLjVsLTUyLjMsMnY4NC4yDQoJbDYyLjEtMzcuMWMwLjctMC40LDEuNi0wLjIsMiwwLjVjMC40LDAuNywwLjMsMS42LTAuNCwyTDAsMjE1djM1aDUuM2MtMC4xLTAuNSwwLTEsMC40LTEuNGw1MS00Ny40YzAuNi0wLjUsMS41LTAuNSwyLjEsMA0KCWMwLjYsMC42LDAuNiwxLjUsMC4xLDIuMUwxNi4xLDI1MGgzMi41Yy0wLjEtMC4xLTAuMi0wLjItMC4yLTAuM2MtMC4zLTAuNS0wLjMtMS4xLDAtMS42bDMwLjgtNDguOWMwLjQtMC43LDEuMy0wLjksMi0wLjUNCgljMC43LDAuNCwxLDEuMywwLjYsMkw1NywyNDkuM2MtMC4yLDAuNC0wLjUsMC42LTAuOSwwLjdoNzEuNmw1LjQtNzYuNmMwLjEtMC44LDAuNy0xLjQsMS41LTEuNGMwLjgsMCwxLjQsMC43LDEuNSwxLjVsMS45LDc2LjUNCgloMjYuNWMxOC4yLDAsMzUtNS43LDQ4LjktMTUuNEwxNzguMywxODEuNHogTTE5NC43LDQyLjlsMzAuNC00MS41YzAuMy0wLjUsMC45LTAuNywxLjUtMC42bDUuOSwxLjFjMC41LDAuMSwxLDAuNSwxLjEsMQ0KCWMwLjIsMC41LDAuMSwxLjEtMC4zLDEuNWwtMzYuMyw0MC4zYy0wLjMsMC4zLTAuNywwLjUtMS4xLDAuNWMtMC4zLDAtMC43LTAuMS0wLjktMC4zQzE5NC40LDQ0LjQsMTk0LjMsNDMuNSwxOTQuNyw0Mi45eg0KCSBNMTIwLjIsMTIxLjVjMC43LTAuMSwxLjQsMC4yLDEuNywwLjljMC4zLDAuNywwLjEsMS40LTAuNSwxLjhsLTYsNC4xYy0wLjEsMC4xLTAuMiwwLjEtMC40LDAuMmwtNy4zLDIuNWMtMC4yLDAuMS0wLjMsMC4xLTAuNSwwLjENCgljLTAuNSwwLTEuMS0wLjMtMS4zLTAuOGMtMC4zLTAuNy0wLjItMS41LDAuNC0xLjlsNy41LTUuNWMwLjItMC4xLDAuNC0wLjIsMC42LTAuM0wxMjAuMiwxMjEuNXogTTExOC4xLDgzLjQNCgljMC4xLDAuMSwwLjEsMC4yLDAuMiwwLjNsMS42LDQuOWMwLjIsMC43LTAuMSwxLjUtMC44LDEuOGMtMC4yLDAuMS0wLjQsMC4xLTAuNiwwLjFjLTAuNSwwLTEtMC4zLTEuMy0wLjdsLTIuOC00LjYNCgljMC0wLjEtMC4xLTAuMS0wLjEtMC4ybC0yLjUtNmMtMC4zLTAuNywwLTEuNSwwLjctMS45YzAuNy0wLjQsMS41LTAuMSwyLDAuNUwxMTguMSw4My40eiBNMTAyLjIsNDguOGMwLDAsMC0wLjEtMC4xLTAuMUw5MS4yLDIyLjUNCgljLTAuMy0wLjcsMC0xLjYsMC43LTEuOWMwLjctMC4zLDEuNi0wLjEsMiwwLjdsMTIuNywyMy45YzAsMC4xLDAuMSwwLjEsMC4xLDAuMmw4LjMsMjEuM2MwLjMsMC43LTAuMSwxLjYtMC44LDEuOQ0KCWMtMC4yLDAuMS0wLjQsMC4xLTAuNiwwLjFjLTAuNSwwLTEuMS0wLjMtMS4zLTAuOEwxMDIuMiw0OC44eiBNMTA3LjQsMTA4LjZjMC4xLDAsMC4xLDAsMC4yLDAuMWw0LDJjMC43LDAuMywxLDEuMSwwLjcsMS44DQoJYy0wLjIsMC42LTAuOCwxLTEuNCwxYy0wLjEsMC0wLjIsMC0wLjMsMGwtNC4zLTFjLTAuMSwwLTAuMy0wLjEtMC40LTAuMWwtNi42LTMuNWMtMC43LTAuNC0xLTEuMi0wLjctMS45YzAuMy0wLjcsMS4xLTEuMSwxLjktMC44DQoJTDEwNy40LDEwOC42eiBNOTguNywxMzAuNWwtMTMuNSw2Yy0wLjEsMC0wLjEsMC4xLTAuMiwwLjFMNjcuOSwxNDFjLTAuMSwwLTAuMywwLTAuNCwwYy0wLjYsMC0xLjItMC40LTEuNC0xDQoJYy0wLjMtMC43LDAuMS0xLjUsMC44LTEuOWwxNi44LTcuOGMwLjEtMC4xLDAuMi0wLjEsMC40LTAuMWwxMy43LTIuNmMwLjctMC4xLDEuNSwwLjMsMS43LDFDOTkuNywxMjkuNCw5OS40LDEzMC4yLDk4LjcsMTMwLjV6DQoJIE02Mi4yLDU3bDE2LjYsMTEuNmwxOC44LDE4LjFMNzYuNyw3Mi4yTDYyLjIsNTd6IE02OS40LDkyLjNjLTAuNy0wLjQtMS0xLjItMC43LTEuOWMwLjMtMC43LDEuMS0xLjEsMS45LTAuOGwxOS4xLDYuNw0KCWMwLjEsMCwwLjEsMCwwLjIsMC4xbDEwLjksNS42YzAuNywwLjMsMSwxLjEsMC43LDEuOGMtMC4yLDAuNi0wLjgsMS0xLjQsMWMtMC4xLDAtMC4yLDAtMC4zLDBsLTExLjktMi42Yy0wLjEsMC0wLjMtMC4xLTAuNC0wLjENCglMNjkuNCw5Mi4zeiBNNDkuOCwxMzUuOGMtMC4xLDAtMC4xLDAtMC4yLDBsLTI4LjUsMy40Yy0wLjEsMC0wLjEsMC0wLjIsMGMtMC43LDAtMS4zLTAuNS0xLjUtMS4yYy0wLjEtMC44LDAuNC0xLjUsMS4xLTEuNw0KCWwyNy45LTYuN2MwLjEsMCwwLjEsMCwwLjIsMGwyNi45LTMuNGMwLjgtMC4xLDEuNSwwLjQsMS43LDEuMmMwLjEsMC44LTAuMywxLjUtMS4xLDEuN0w0OS44LDEzNS44eiBNODUuOCwxNzJMNjUuNCwxOTENCgljLTAuMywwLjMtMC43LDAuNC0xLDAuNGMtMC40LDAtMC43LTAuMS0xLTAuNGMtMC42LTAuNS0wLjYtMS40LTAuMi0ybDE3LjktMjIuNmMwLDAsMC4xLTAuMSwwLjEtMC4xbDI0LjktMjQuOQ0KCWMwLjYtMC42LDEuNS0wLjYsMi4xLTAuMWMwLjYsMC41LDAuNywxLjQsMC4yLDIuMWwtMjIuNSwyOC40Qzg1LjksMTcxLjksODUuOCwxNzEuOSw4NS44LDE3MnogTTEyMi43LDE2NC4zbC04LjEsMjcuOA0KCWMwLDAuMSwwLDAuMS0wLjEsMC4ybC04LjcsMjAuOWMtMC4yLDAuNi0wLjgsMC45LTEuNCwwLjljLTAuMiwwLTAuMywwLTAuNS0wLjFjLTAuOC0wLjMtMS4yLTEuMS0wLjktMS44bDYuNC0yMi4xYzAsMCwwLTAuMSwwLTAuMQ0KCWwxMC4zLTI2LjZjMC4zLTAuNywxLjEtMS4xLDEuOS0wLjlDMTIyLjUsMTYyLjgsMTIzLDE2My42LDEyMi43LDE2NC4zeiBNMTI1LjUsMTMybC03LjEsMTQuNGMwLDAuMS0wLjEsMC4xLTAuMSwwLjJsLTYuOSwxMC40DQoJYy0wLjMsMC40LTAuOCwwLjctMS4zLDAuN2MtMC4zLDAtMC41LTAuMS0wLjctMC4yYy0wLjctMC40LTAuOS0xLjMtMC42LTJsNS43LTExLjRjMCwwLDAtMC4xLDAuMS0wLjFsOC4zLTEzLjMNCgljMC40LTAuNywxLjMtMC45LDItMC41QzEyNS42LDEzMC41LDEyNS45LDEzMS4zLDEyNS41LDEzMnogTTIyMCwxNDcuMmwxOS42LDExLjNjMC43LDAuNCwwLjksMS4yLDAuNiwyYy0wLjMsMC41LTAuOCwwLjktMS40LDAuOQ0KCWMtMC4yLDAtMC40LDAtMC41LTAuMWwtMjAuMS03LjljLTAuMSwwLTAuMi0wLjEtMC4yLTAuMWwtMTUuNS05LjdjLTAuNy0wLjQtMC45LTEuMy0wLjUtMS45YzAuMy0wLjcsMS4yLTEsMS45LTAuN2wxNiw2LjMNCglDMjE5LjksMTQ3LjEsMjIwLDE0Ny4xLDIyMCwxNDcuMnogTTIwNC4zLDEzNC43YzAuNywwLjMsMS4yLDEuMSwwLjksMS44Yy0wLjIsMC43LTAuOCwxLjEtMS40LDEuMWMtMC4xLDAtMC4yLDAtMC4zLDBsLTIzLjYtNC43DQoJYy0wLjEsMC0wLjIsMC0wLjMtMC4xbC0xOS03LjZjLTAuNy0wLjMtMS4xLTEuMS0wLjktMS44YzAuMi0wLjcsMS0xLjIsMS43LTFsMTguOCwzLjdjMC4xLDAsMC4xLDAsMC4yLDAuMUwyMDQuMywxMzQuN3oNCgkgTTE5Ni41LDk4LjFjMC4xLDAsMC4xLDAsMC4yLDBsMjguNS0zLjRjMC44LTAuMSwxLjUsMC40LDEuNywxLjJjMC4xLDAuOC0wLjQsMS41LTEuMSwxLjdsLTI3LjksNi43Yy0wLjEsMC0wLjEsMC0wLjIsMGwtMjYuOSwzLjQNCgljLTAuMSwwLTAuMSwwLTAuMiwwYy0wLjcsMC0xLjMtMC41LTEuNS0xLjJjLTAuMS0wLjgsMC4zLTEuNSwxLjEtMS43TDE5Ni41LDk4LjF6IE0xNjMuNSw5MC4xbDktOS4xYzAuNi0wLjYsMS41LTAuNiwyLjEtMC4xDQoJYzAuNiwwLjUsMC43LDEuNCwwLjIsMi4xbC04LjIsMTAuM2MwLDAuMS0wLjEsMC4xLTAuMSwwLjJsLTcuNCw2LjljLTAuMywwLjMtMC43LDAuNC0xLDAuNGMtMC40LDAtMC43LTAuMS0xLTAuNA0KCWMtMC42LTAuNS0wLjYtMS40LTAuMi0ybDYuNS04LjJDMTYzLjQsOTAuMiwxNjMuNSw5MC4yLDE2My41LDkwLjF6IE0xNDUuOSw5Mi4zbDYuMi0yMC42YzAtMC4xLDAuMS0wLjIsMC4xLTAuM2w3LjEtMTMuNQ0KCWMwLjQtMC43LDEuMi0xLDEuOS0wLjdjMC43LDAuMywxLjEsMS4xLDAuOSwxLjhMMTU3LDc1LjJjMCwwLjEsMCwwLjEtMC4xLDAuMmwtOC4yLDE3LjljLTAuMywwLjUtMC44LDAuOS0xLjQsMC45DQoJYy0wLjIsMC0wLjQsMC0wLjUtMC4xQzE0Niw5My44LDE0NS42LDkzLDE0NS45LDkyLjN6IE0xNDAuMiwxMTQuMmwyLjMtNy41YzAtMC4xLDAuMS0wLjIsMC4xLTAuM2wyLjYtNC45YzAuNC0wLjcsMS4yLTEsMS45LTAuNw0KCWMwLjcsMC4zLDEuMSwxLjEsMC45LDEuOGwtMS45LDUuOWMwLDAuMSwwLDAuMS0wLjEsMC4ybC0zLDYuNWMtMC4zLDAuNS0wLjgsMC45LTEuNCwwLjljLTAuMiwwLTAuNCwwLTAuNS0wLjENCglDMTQwLjQsMTE1LjgsMTQwLDExNSwxNDAuMiwxMTQuMnogTTE0Ni44LDE5OC44Yy0wLjEsMC0wLjEsMC0wLjIsMGMtMC43LDAtMS4zLTAuNS0xLjUtMS4ybC01LjctMjkuN2MwLTAuMSwwLTAuMSwwLTAuMmwtMS4zLTIzLjcNCglsLTAuNC0xLjhjMC0wLjEsMC0wLjEsMC0wLjJsLTAuNS05LjdjMC0wLjgsMC41LTEuNSwxLjMtMS42YzAuOC0wLjEsMS41LDAuNCwxLjcsMS4ybDEuNiw4LjZjMCwwLjEsMCwwLjEsMCwwLjJsMC43LDguNGwyLjksMTUuMw0KCWMwLDAuMSwwLDAuMSwwLDAuMmwyLjYsMzIuN0MxNDguMiwxOTgsMTQ3LjYsMTk4LjcsMTQ2LjgsMTk4Ljh6IE0xNDguNSwxMzhjLTAuMiwwLjEtMC41LDAuMi0wLjcsMC4yYy0wLjUsMC0wLjktMC4yLTEuMi0wLjYNCglsLTIuMi0zLjFjLTAuMS0wLjEtMC4xLTAuMi0wLjItMC40bC0wLjktMi43Yy0wLjItMC43LDAuMS0xLjUsMC44LTEuOGMwLjctMC4zLDEuNS0wLjEsMS45LDAuNWwxLjcsMi41YzAuMSwwLjEsMC4xLDAuMiwwLjEsMC4yDQoJbDEuNCwzLjRDMTQ5LjQsMTM2LjgsMTQ5LjEsMTM3LjYsMTQ4LjUsMTM4eiBNMTUwLjEsMTIxLjFjLTAuNywwLTEuMy0wLjUtMS41LTEuMmMtMC4xLTAuOCwwLjMtMS41LDEuMS0xLjdsOS42LTIuNA0KCWMwLjEsMCwwLjEsMCwwLjIsMGwxMC40LTEuMmMwLjgtMC4xLDEuNSwwLjQsMS43LDEuMmMwLjEsMC44LTAuNCwxLjUtMS4xLDEuN2wtMTAuMiwyLjRjLTAuMSwwLTAuMSwwLTAuMiwwbC05LjgsMS4yDQoJQzE1MC4yLDEyMS4xLDE1MC4yLDEyMS4xLDE1MC4xLDEyMS4xeiBNMTY0LjgsMTU0LjZjLTAuMiwwLjEtMC41LDAuMi0wLjcsMC4yYy0wLjUsMC0wLjktMC4yLTEuMi0wLjZsLTUuOS04LjYNCgljLTAuMS0wLjEtMC4xLTAuMi0wLjItMC40bC0yLjUtNy41Yy0wLjItMC43LDAuMS0xLjUsMC44LTEuOGMwLjctMC4zLDEuNS0wLjEsMS45LDAuNWw0LjYsNi45YzAuMSwwLjEsMC4xLDAuMiwwLjEsMC4ybDMuOSw5LjINCglDMTY1LjcsMTUzLjQsMTY1LjQsMTU0LjIsMTY0LjgsMTU0LjZ6IE0xNzQuOSwxNDcuMWMwLjUtMC42LDEuNC0wLjcsMi0wLjJsMTQuMSwxMGMwLjEsMCwwLjEsMC4xLDAuMiwwLjFsMTYuNCwxNS43DQoJYzAuNiwwLjUsMC42LDEuNCwwLjEsMmMtMC4zLDAuNC0wLjcsMC41LTEuMiwwLjVjLTAuMywwLTAuNi0wLjEtMC45LTAuM0wxODgsMTYyLjVjLTAuMS0wLjEtMC4xLTAuMS0wLjItMC4ybC0xMi44LTEzLjINCglDMTc0LjQsMTQ4LjYsMTc0LjQsMTQ3LjcsMTc0LjksMTQ3LjF6Ii8+DQo8L3N2Zz4NCg==\\\" alt=\\\"\\\" width=\\\"100%\\\" /></p>\\n<p>This is an extremely powerful system to optimize performance. Read the <a href=\\\"https://r.2sxc.org/lightspeed\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"LightSpeed Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"be34f64b-7d1f-4ad0-b488-dabbbb01a186\"\n                }\n              },\n              {\n                \"Id\": 144419,\n                \"Version\": 1,\n                \"Guid\": \"1ce0744c-eab6-4c1d-82c0-75cbe472fef5\",\n                \"Type\": {\n                  \"Id\": \"19655377-6626-4986-aea0-ec3c187186ad\",\n                  \"Name\": \"RequirementDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Feature\": {\n                      \"en-us\": \"LightSpeedOutputCache\"\n                    },\n                    \"License\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Platform\": {\n                      \"en-us\": \"\"\n                    },\n                    \"RequirementType\": {\n                      \"en-us\": \"feature\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Requirement to use this\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"be34f64b-7d1f-4ad0-b488-dabbbb01a186\"\n                }\n              },\n              {\n                \"Id\": 144420,\n                \"Version\": 1,\n                \"Guid\": \"8e4db30f-a9c8-42b5-afb0-9fca9fe36a68\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for App\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 3\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"be34f64b-7d1f-4ad0-b488-dabbbb01a186\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"MsgWarningNotEnabled\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144457,\n                    \"Version\": 3,\n                    \"Guid\": \"a4190965-e0b2-4af6-841f-89f2a954f733\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Warning: LightSpeed Cache is not Enabled\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<h3><span style=\\\"color: #e03e2d;\\\">Warning </span>⚠️</h3>\\n<p>You are editing configuration for LightSpeed Cache, but <strong><span style=\\\"color: #e03e2d;\\\">LightSpeed Cache is not enabled</span></strong>.&nbsp;</p>\\n<p>The settings you change here will therefor not have an effect.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"21f878f4-f822-45cf-a840-8d7d581e8f0d\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144444,\n                    \"Version\": 4,\n                    \"Guid\": \"dfe4df36-8c2b-4481-b3e7-c5bf335dbfe6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"48dfbe23-bdad-4fd3-a216-3e28dd072d39\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144446,\n                    \"Version\": 2,\n                    \"Guid\": \"b88d4c56-fdf6-4d5d-9642-adba4e599a85\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144447,\n                    \"Version\": 2,\n                    \"Guid\": \"6969706e-0629-4663-bb88-c6a7594d4b22\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IsEnabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144417,\n                    \"Version\": 4,\n                    \"Guid\": \"0405bb5f-3249-42cd-b93e-6908f1f120c8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"IsEnabled\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144427,\n                    \"Version\": 2,\n                    \"Guid\": \"081f7c25-5c5b-42de-83b3-61c8af08e954\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Disabled\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"System Default (disabled if not enabled elsewhere)\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Enabled\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDurations\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183798,\n                    \"Version\": 3,\n                    \"Guid\": \"45d8cb18-ff0c-4b6b-8bc7-b8bb26836cbd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Caching Durations\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"3cdbdd23-27c8-4fbd-8b56-43501a9606bb\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183800,\n                    \"Version\": 1,\n                    \"Guid\": \"3e4a521b-dd33-4bc2-a869-81d98cdd8bdd\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Duration\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144424,\n                    \"Version\": 6,\n                    \"Guid\": \"74fc20e0-384c-4409-aa8a-0cb17b5432bc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"-1\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Duration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>value is stored as as seconds</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144425,\n                    \"Version\": 5,\n                    \"Guid\": \"a57e4184-93b0-417b-9aaf-d26b20c6f75a\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144426,\n                    \"Version\": 5,\n                    \"Guid\": \"b7669760-128f-447c-a9e3-e4f74d8767e9\",\n                    \"Type\": {\n                      \"Id\": \"@number-dropdown\",\n                      \"Name\": \"@number-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Empty / no value\\n-1:Disabled\\n10:10 Seconds\\n30:30 Seconds\\n60:60 Seconds\\n300:5 Minutes\\n3600:1 hour\\n14400:4 hours\\n86400:1 day\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DurationUsers\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144428,\n                    \"Version\": 6,\n                    \"Guid\": \"4dd37997-a627-4de0-be37-5fc96fb1a113\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"-1\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Duration for Logged In Users (but not editors)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The cache will be kept separate for each user. If you have many users, this could require a lot of memory, so we recommend to disable this.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144431,\n                    \"Version\": 5,\n                    \"Guid\": \"d687f779-d3ab-4e89-9961-fedcdcff8da5\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144432,\n                    \"Version\": 5,\n                    \"Guid\": \"ac9c54ca-8ab0-4291-979c-e1a54b5ffc12\",\n                    \"Type\": {\n                      \"Id\": \"@number-dropdown\",\n                      \"Name\": \"@number-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Empty / no value\\n-1:Disabled\\n10:10 Seconds\\n30:30 Seconds\\n60:60 Seconds\\n300:5 Minutes\\n3600:1 hour\\n14400:4 hours\\n86400:1 day\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DurationEditors\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144429,\n                    \"Version\": 6,\n                    \"Guid\": \"7e79b272-211a-49de-832c-42b00e55649d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"300\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Duration for Editors\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Editors spend a lot of time on the site, so some caching will improve the experience.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144433,\n                    \"Version\": 5,\n                    \"Guid\": \"2b930e33-0c02-4bd2-882b-36006ed117e1\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144434,\n                    \"Version\": 5,\n                    \"Guid\": \"81849c1b-a597-4410-9026-a7a8e2b1b1fa\",\n                    \"Type\": {\n                      \"Id\": \"@number-dropdown\",\n                      \"Name\": \"@number-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Empty / no value\\n-1:Disabled\\n10:10 Seconds\\n30:30 Seconds\\n60:60 Seconds\\n300:5 Minutes\\n3600:1 hour\\n14400:4 hours\\n86400:1 day\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DurationSystemAdmin\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144436,\n                    \"Version\": 4,\n                    \"Guid\": \"cf8667cd-801a-4ec7-9ae9-367ce1f59527\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"60\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Duration System Admins\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is for super-users / host-users.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144437,\n                    \"Version\": 3,\n                    \"Guid\": \"335e40c0-04aa-4aab-895a-313cc27d33e5\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144438,\n                    \"Version\": 3,\n                    \"Guid\": \"8ae02ba2-e3b0-46ad-b11b-caa9bb3f07b5\",\n                    \"Type\": {\n                      \"Id\": \"@number-dropdown\",\n                      \"Name\": \"@number-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Empty / no value\\n-1:Disabled\\n10:10 Seconds\\n30:30 Seconds\\n60:60 Seconds\\n300:5 Minutes\\n3600:1 hour\\n14400:4 hours\\n86400:1 day\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDurationsEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183816,\n                    \"Version\": 1,\n                    \"Guid\": \"13feffb6-e9fe-49e1-b44a-c7c9c69cf143\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupDurationsEnd\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ViewConfigurationMessage\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183815,\n                    \"Version\": 5,\n                    \"Guid\": \"e596ea80-ac99-4da4-9967-00c7eaae0b9a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"ViewConfigurationMessage\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>The View-Configuration is only for configuring URL parameters.&nbsp;</strong></p>\\n<p>As of now, it doesn't support configuring alternate durations.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"46b375ba-3a11-4f04-8faf-33ef4ef5b29a\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183818,\n                    \"Version\": 1,\n                    \"Guid\": \"f302a03d-5982-4a84-a9b3-204ae77b83f6\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupVaryByUrl\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183799,\n                    \"Version\": 4,\n                    \"Guid\": \"f9ae6ce9-32c1-4fc2-bba6-12172fd23a7f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Vary Cache by URL Parameters\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Your code may return different results based on URL parameters. If this is the case, then you want to vary by URL parameters.&nbsp;</p>\\n<p>⚠️ Warning:&nbsp;Be careful with this configuration. If you don't specify which url parameters are allowed, you can easily build up tens of thousands of cache entries which may slow down your system.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"11e753a0-2e69-46dc-b67e-c5b0bec47ac0\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183801,\n                    \"Version\": 2,\n                    \"Guid\": \"ac85e0c8-1078-4281-b115-bb8764d6fb7e\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ByUrlParameters\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144430,\n                    \"Version\": 2,\n                    \"Guid\": \"7181ed82-78fa-4189-85a0-ee90d1901d4d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Cache By Url Parameters (for blogs etc. which have different pages)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144435,\n                    \"Version\": 1,\n                    \"Guid\": \"1cfa77c9-8073-4f33-a8be-a9d7f0153e65\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Use same cache even if URL parameters change\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Use new cache if URL parameter changes\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UrlParametersCaseSensitive\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144439,\n                    \"Version\": 2,\n                    \"Guid\": \"8817375d-2d0f-4b62-a83e-32ba102f8821\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"UrlParameterCaseSensitive\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144440,\n                    \"Version\": 1,\n                    \"Guid\": \"bf17846b-4129-4bc1-868f-7848cab5489a\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Url parameters are NOT case-sensitive: A=a, É=é (recommended)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Url parameters are case sensitive: A≠a & É≠é\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UrlParameterNames\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183808,\n                    \"Version\": 5,\n                    \"Guid\": \"9b6c8a4a-9070-490c-8f89-3f7058d6133b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"URL Parameter Names (one on each line)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Put each url parameter on an own line. Optionally with <code>// comment</code> behind it. <code>*</code> means all url parameters - not recommended ⚠️.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"example     // vary the cache by the url parameter example=abcd\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183810,\n                    \"Version\": 4,\n                    \"Guid\": \"1399c3ca-ba76-4bfc-ab4c-092dbf91895c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183811,\n                    \"Version\": 4,\n                    \"Guid\": \"f12a5eee-4758-4ee4-bc62-acadca65ff50\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UrlParametersOthersDisableCache\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183809,\n                    \"Version\": 3,\n                    \"Guid\": \"6fbc03a7-8e66-4cfa-a537-54f2db77adf3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"UrlParametersOthersDisableCache\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183812,\n                    \"Version\": 2,\n                    \"Guid\": \"2935f7d2-ab1b-4a9c-81d5-ea30193a9780\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"If other url parameters are used, cache as if they don't matter\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"If other url parameters are used, don't cache\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Advanced\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-json\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144441,\n                    \"Version\": 3,\n                    \"Guid\": \"c635552d-9e99-422e-b16e-d5b36e529e05\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-json\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"46e32523-21b2-4485-8e10-ae846009e305\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144442,\n                    \"Version\": 1,\n                    \"Guid\": \"47e29f52-7437-4d60-982f-59e300644a19\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144443,\n                    \"Version\": 1,\n                    \"Guid\": \"297753ad-bdc8-4e18-8014-9c7fe8c74ccd\",\n                    \"Type\": {\n                      \"Id\": \"@string-json\",\n                      \"Name\": \"@string-json\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"JsonSchemaMode\": {\n                          \"en-us\": \"none\"\n                        },\n                        \"JsonSchemaRaw\": {\n                          \"en-us\": \"\"\n                        },\n                        \"JsonSchemaSource\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"JsonValidation\": {\n                          \"en-us\": \"strict\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"JsonSchemaUrl\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"Rows\": {\n                          \"en-us\": 25\n                        }\n                      },\n                      \"Boolean\": {\n                        \"JsonCommentsAllowed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupVaryByUrlEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183817,\n                    \"Version\": 1,\n                    \"Guid\": \"95634d5d-f5ef-4b17-93bf-ef42cbe88f1a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupVaryByUrlEnd\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarShowDuration\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183802,\n                    \"Version\": 4,\n                    \"Guid\": \"da781d7a-95c7-45e5-b9ac-9220065d38d8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"VarShowDuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"3d006350-3b3c-4294-8b1a-ad6e4f12857d\",\n                            \"a247ff46-76f7-45d2-bbc2-a20e4a3a4a98\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183803,\n                    \"Version\": 1,\n                    \"Guid\": \"0d57e6d1-2f94-4df6-bad4-b59b502a8bc8\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 144458,\n              \"Version\": 4,\n              \"Guid\": \"21f878f4-f822-45cf-a840-8d7d581e8f0d\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  if (context.cache.alreadyRun) return data.value;\\n  context.cache.alreadyRun = true;\\n  const enabled = context.features.isEnabled('LightSpeedOutputCache');\\n  // console.log(\\\"enabled\\\", enabled);\\n  return !enabled;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144445,\n              \"Version\": 4,\n              \"Guid\": \"48dfbe23-bdad-4fd3-a216-3e28dd072d39\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  var partMsg = function(target, value) {\\n    if (value == -1) return target + ' \\uD83D\\uDEAB';\\n    return target + ' ' + value + 's';\\n  }\\n  var msg = '';\\n  if (!data.IsEnabled)\\n    return '\\uD83D\\uDEAB';\\n  msg = '✅ - ';\\n  msg += partMsg('Users', data.Duration);\\n  msg += ', ' + partMsg('Reg', data.DurationUsers);\\n  msg += ', ' + partMsg('Editors', data.DurationEditors);\\n  msg += ', ' + partMsg('SysAdmins', data.DurationSystemAdmin);\\n  return msg;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183804,\n              \"Version\": 2,\n              \"Guid\": \"3cdbdd23-27c8-4fbd-8b56-43501a9606bb\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.VarShowDuration && data.IsEnabled != false;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183819,\n              \"Version\": 4,\n              \"Guid\": \"46b375ba-3a11-4f04-8faf-33ef4ef5b29a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"// if parameters has a forView then take that, otherwise default to false\\nv2((data, context) => {\\n  return { \\n    value: data.parameters.forView == 'true', // defaults to false\\n    stop: true,\\n  }\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183805,\n              \"Version\": 1,\n              \"Guid\": \"11e753a0-2e69-46dc-b67e-c5b0bec47ac0\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.IsEnabled != false;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144523,\n              \"Version\": 2,\n              \"Guid\": \"46e32523-21b2-4485-8e10-ae846009e305\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return context.debug;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183814,\n              \"Version\": 2,\n              \"Guid\": \"3d006350-3b3c-4294-8b1a-ad6e4f12857d\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"// if parameters has a showDuration then take that, otherwise default to true\\nv2((data, context) => {\\n  return { \\n    value: data.parameters.showDuration != 'false', // defaults to true\\n    stop: true,\\n  }\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183813,\n              \"Version\": 1,\n              \"Guid\": \"a247ff46-76f7-45d2-bbc2-a20e4a3a4a98\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return context.debug;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"c490b369-9cd2-4298-af74-19c1e438cdfc\",\n            \"Name\": \"MetadataExpectedDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 136761,\n                \"Version\": 6,\n                \"Guid\": \"4449b427-9239-4cd4-9939-ac5d8cdffd86\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Configure what Metadata is expected on something\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This configures what Metadata is expected on this kind of item. It's mainly used to help create toolbars automatically.&nbsp;</p>\\n<p><em>Important: This wil not prevent other metadata, but simply make work easier.&nbsp;</em></p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Metadata-Expected (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTIxLjQxIDExLjU4bC05LTlDMTIuMDUgMi4yMiAxMS41NSAyIDExIDJINGMtMS4xIDAtMiAuOS0yIDJ2N2MwIC41NS4yMiAxLjA1LjU5IDEuNDJsOSA5Yy4zNi4zNi44Ni41OCAxLjQxLjU4czEuMDUtLjIyIDEuNDEtLjU5bDctN2MuMzctLjM2LjU5LS44Ni41OS0xLjQxcy0uMjMtMS4wNi0uNTktMS40MnpNMTMgMjAuMDFMNCAxMVY0aDd2LS4wMWw5IDktNyA3LjAyeiIvPjxjaXJjbGUgY3g9IjYuNSIgY3k9IjYuNSIgcj0iMS41Ii8+PC9zdmc+\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"c490b369-9cd2-4298-af74-19c1e438cdfc\"\n                }\n              },\n              {\n                \"Id\": 137095,\n                \"Version\": 2,\n                \"Guid\": \"0a653153-99a8-4794-bafc-acfeac3d5461\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Mark a Content-Type to expect a specific Metadata\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"c490b369-9cd2-4298-af74-19c1e438cdfc\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 136755,\n                    \"Version\": 2,\n                    \"Guid\": \"e8a15273-661b-46d7-ac5d-b9d1da220ffa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Metadata which this item expects\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136757,\n                    \"Version\": 1,\n                    \"Guid\": \"e8c3ea9d-1212-4984-97c3-bb9d5a6e7125\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136758,\n                    \"Version\": 1,\n                    \"Guid\": \"539be49a-b460-492f-9506-8a9fa09116cf\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TargetType\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 142967,\n                    \"Version\": 4,\n                    \"Guid\": \"90881082-be21-4807-b6f3-4d7ccc20c37d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TargetType\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Determines what exactly expects this target.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142968,\n                    \"Version\": 3,\n                    \"Guid\": \"d6c17084-1b87-4b84-83b3-128374e279b1\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142969,\n                    \"Version\": 3,\n                    \"Guid\": \"669a22d2-28ce-4983-bb2d-1c5f5ec0bbc9\",\n                    \"Type\": {\n                      \"Id\": \"@number-dropdown\",\n                      \"Name\": \"@number-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"0:Not set\\n4:Entity (Item)\\n5:Content Type\\n2:Content Type Attribute (Field / Property)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MetadataTypes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 136756,\n                    \"Version\": 4,\n                    \"Guid\": \"c8b86d5c-b0f7-438b-bcfc-e1eb0022562f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MetadataTypes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136759,\n                    \"Version\": 3,\n                    \"Guid\": \"9ff2bae8-dfbe-4673-9bdc-80a0d0af1e5b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136760,\n                    \"Version\": 3,\n                    \"Guid\": \"4bef723e-f1a2-48e0-b4fe-1a79d92d5848\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"StaticName\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Amount\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 137110,\n                    \"Version\": 2,\n                    \"Guid\": \"07cb5d7b-0402-4c43-8024-246d22504b4b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"1\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Amount\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>How many of these are expected, typically 1. Use a large number like 100 to indicated lots. 0 means it shouldn't be used, so the UI can show a warning.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137112,\n                    \"Version\": 1,\n                    \"Guid\": \"6c39a2a0-9d2d-48bd-b918-d3b311ed2f8c\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DeleteWarning\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 137111,\n                    \"Version\": 3,\n                    \"Guid\": \"b9a102e1-bcfe-461f-a5e5-9f1e99917298\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"DeleteWarning\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142663,\n                    \"Version\": 1,\n                    \"Guid\": \"dea8bcd3-6d41-4955-bd5c-00730391f452\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142664,\n                    \"Version\": 1,\n                    \"Guid\": \"0813f099-fe73-4b9e-b036-a56eb85751be\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"1\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n            \"Name\": \"MetadataForDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 136807,\n                \"Version\": 2,\n                \"Guid\": \"e308627d-c9cf-4a78-b030-956cf60e2cae\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for Content Types\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\"\n                }\n              },\n              {\n                \"Id\": 136808,\n                \"Version\": 5,\n                \"Guid\": \"fada7228-9712-4ce2-a0f9-4dce2098c734\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Mark a Content-Type as being Metadata for a specific target type (App, Content-Type etc.)\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Used to decorate Content-Types to tell them what they usually describe.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Metadata-For (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTIxLjQxIDExLjU4bC05LTlDMTIuMDUgMi4yMiAxMS41NSAyIDExIDJINGMtMS4xIDAtMiAuOS0yIDJ2N2MwIC41NS4yMiAxLjA1LjU5IDEuNDJsOSA5Yy4zNi4zNi44Ni41OCAxLjQxLjU4czEuMDUtLjIyIDEuNDEtLjU5bDctN2MuMzctLjM2LjU5LS44Ni41OS0xLjQxcy0uMjMtMS4wNi0uNTktMS40MnpNMTMgMjAuMDFMNCAxMVY0aDd2LS4wMWw5IDktNyA3LjAyeiIvPjxjaXJjbGUgY3g9IjYuNSIgY3k9IjYuNSIgcj0iMS41Ii8+PHBhdGggZD0iTTguOSAxMi41NWMwIC41Ny4yMyAxLjA3LjYgMS40NWwzLjUgMy41IDMuNS0zLjVjLjM3LS4zNy42LS44OS42LTEuNDUgMC0xLjEzLS45Mi0yLjA1LTIuMDUtMi4wNS0uNTcgMC0xLjA4LjIzLTEuNDUuNmwtLjYuNi0uNi0uNTljLS4zNy0uMzgtLjg5LS42MS0xLjQ1LS42MS0xLjEzIDAtMi4wNS45Mi0yLjA1IDIuMDV6Ii8+PC9zdmc+\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 136797,\n                    \"Version\": 2,\n                    \"Guid\": \"805c7157-cefd-479e-969c-508ef3298ac3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Metadata for ...\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136805,\n                    \"Version\": 1,\n                    \"Guid\": \"a89b269c-875e-42e8-a8e5-bd929c57b8bf\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136806,\n                    \"Version\": 1,\n                    \"Guid\": \"0d850d53-ed8b-4f46-b31b-3f0590da889e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TargetType\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 136798,\n                    \"Version\": 7,\n                    \"Guid\": \"5c6419d5-7b4f-4c3d-8e94-da7cee04204e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"0\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Target Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136801,\n                    \"Version\": 4,\n                    \"Guid\": \"f8cd9db8-2fe3-4449-b797-185dfc74b5b9\",\n                    \"Type\": {\n                      \"Id\": \"@number-dropdown\",\n                      \"Name\": \"@number-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"0:Not set\\n2:Field Definition (Attribute) - not supported yet\\n3:App\\n4:Entity (Item)\\n5:Content Type\\n6:Zone - not supported yet\\n10:CmsItem - not supported yet\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185418,\n                    \"Version\": 1,\n                    \"Guid\": \"4ec32f7e-7c45-4721-85b5-45760ae9d135\",\n                    \"Type\": {\n                      \"Id\": \"2421dded-3aeb-47d2-ab9d-e2b72a2d821d\",\n                      \"Name\": \"@number-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"6e3f3520-77b9-4cb9-80ea-2d507bea197d\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TargetName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 136799,\n                    \"Version\": 2,\n                    \"Guid\": \"ab51d6df-9697-426d-82e4-3e8b56e406d9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Target Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"9df378c7-c7f5-4171-99c7-521505c6126f\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136803,\n                    \"Version\": 1,\n                    \"Guid\": \"272f1363-a416-4765-8e42-60ead7af5649\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 136804,\n                    \"Version\": 1,\n                    \"Guid\": \"91f17d7e-aa91-4284-b06f-d3b0fa3776dc\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Amount\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 137105,\n                    \"Version\": 2,\n                    \"Guid\": \"1abf2c57-fc68-4747-ba3a-ac0119310dc8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"1\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Amount\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>How many of these are expected, typically 1. Use a large number like 100 to indicated lots. 0 means it shouldn't be used, so the UI can show a warning.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137107,\n                    \"Version\": 1,\n                    \"Guid\": \"186c70b3-4814-4114-a552-19f5af1809e9\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DeleteWarning\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 137106,\n                    \"Version\": 4,\n                    \"Guid\": \"fa840bb5-dec5-46b1-a148-edea4425bafa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Delete Warning\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Special warning to show when deleting. Use this for primary-metadata like content-type description.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137108,\n                    \"Version\": 2,\n                    \"Guid\": \"c8b216f7-0b35-4742-8a7e-c0c6914ad5c5\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137109,\n                    \"Version\": 1,\n                    \"Guid\": \"a5895b98-a6e2-4d7a-b931-b5c8b67f54bd\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142662,\n                    \"Version\": 1,\n                    \"Guid\": \"782934d3-b8de-433f-b62a-34bd484ad495\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"1\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 185417,\n              \"Version\": 3,\n              \"Guid\": \"6e3f3520-77b9-4cb9-80ea-2d507bea197d\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:NameId]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"NameId\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.SysData\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"SysDataSource=System.MetadataTargetTypes\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Query: SysData MetadataTargetType\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Id\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 136802,\n              \"Version\": 2,\n              \"Guid\": \"9df378c7-c7f5-4171-99c7-521505c6126f\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  const t = data.TargetType;\\n  return t == 2 || t == 4 || t == 10;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"5e958dc6-2922-4d68-835c-7b9711538b12\",\n            \"Name\": \"NoteDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 142650,\n                \"Version\": 3,\n                \"Guid\": \"293bc9e7-e6e2-4f35-866f-5ccfbde667ae\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Allows adding notes to something.\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Note\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0cHgiIGZpbGw9IiMwMDAwMDAiPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iMjQiIHdpZHRoPSIyNCIvPjxwYXRoIGQ9Ik0xOSw1djlsLTUsMGwwLDVINVY1SDE5IE0xOSwzSDVDMy45LDMsMywzLjksMyw1djE0YzAsMS4xLDAuOSwyLDIsMmgxMGw2LTZWNUMyMSwzLjksMjAuMSwzLDE5LDN6IE0xMiwxNEg3di0yaDVWMTR6IE0xNywxMEg3VjhoMTBWMTB6Ii8+PC9zdmc+\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5e958dc6-2922-4d68-835c-7b9711538b12\"\n                }\n              },\n              {\n                \"Id\": 142661,\n                \"Version\": 1,\n                \"Guid\": \"76df3695-a4fb-4c41-81df-26595db24679\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for any Entity\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 4\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5e958dc6-2922-4d68-835c-7b9711538b12\"\n                }\n              },\n              {\n                \"Id\": 144366,\n                \"Version\": 2,\n                \"Guid\": \"1b333b13-8aa5-465b-8046-c0cb238a5b78\",\n                \"Type\": {\n                  \"Id\": \"4f6d1484-4672-43d5-9c48-94ff3ec11069\",\n                  \"Name\": \"EditUiConfigurationDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Features\": {\n                      \"en-us\": \"EditUiShowNotes=false\\nEditUiShowMetadataFor=false\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Disable Notes and Metadata Display\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5e958dc6-2922-4d68-835c-7b9711538b12\"\n                }\n              },\n              {\n                \"Id\": 150892,\n                \"Version\": 2,\n                \"Guid\": \"7ad912e0-632f-4d1c-8c5f-ac131572df87\",\n                \"Type\": {\n                  \"Id\": \"acc185a7-f300-4468-bce8-d6a64038989d\",\n                  \"Name\": \"ToolbarButtonDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Command\": {\n                      \"en-us\": \"metadata\"\n                    },\n                    \"Ui\": {\n                      \"en-us\": \"\"\n                    },\n                    \"UiColor\": {\n                      \"en-us\": \"D9CA1F\"\n                    },\n                    \"UiIcon\": {\n                      \"en-us\": \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" height=\\\"48\\\" width=\\\"48\\\"><path d=\\\"M9 39h20V29h10V9H9v30Zm0 3q-1.25 0-2.125-.875T6 39V9q0-1.25.875-2.125T9 6h30q1.25 0 2.125.875T42 9v21L30 42Zm6-15v-3h8.5v3Zm0-8v-3h18v3ZM9 39V9v30Z\\\"/></svg>\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5e958dc6-2922-4d68-835c-7b9711538b12\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 143979,\n                    \"Version\": 5,\n                    \"Guid\": \"7e5d91bb-dc27-4a9d-9b59-392a7542929d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The title is auto-generated from the note. It removes HTML etc.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"7faf0496-dc03-4e45-a1ae-e43629965344\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 143980,\n                    \"Version\": 3,\n                    \"Guid\": \"46ebd741-8f64-4474-a141-8e032b61feeb\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 143981,\n                    \"Version\": 3,\n                    \"Guid\": \"8dbb1592-0b7a-41b9-9cc7-1d686bd76b21\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Note\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 142651,\n                    \"Version\": 1,\n                    \"Guid\": \"e6ced411-a0fe-40de-8e35-13b339ffd246\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Note\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ShowAdvanced\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 142657,\n                    \"Version\": 5,\n                    \"Guid\": \"a5f6e2bb-af9b-4bd1-8e30-4ab0853a3040\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced\",\n                          \"de-de\": \"Erweitert\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"ea487371-6b1f-4718-a751-62bf389739a6\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142658,\n                    \"Version\": 4,\n                    \"Guid\": \"8fb889ae-4146-45a9-8124-f9d202240e97\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"NoteType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 142652,\n                    \"Version\": 9,\n                    \"Guid\": \"b2937760-6aa4-414d-a820-79224ad9f889\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"note\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Type\",\n                          \"de-de\": \"Typ\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Optional, only set this for special notes which have another function.&nbsp;</p>\",\n                          \"de-de\": \"<p>Optional, bitte nur setzen wenn die Notiz wirklich eine andere Funktion hat.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"dc7e8c8d-6633-4a09-ad2c-afb0f4727ef0\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142653,\n                    \"Version\": 8,\n                    \"Guid\": \"2531413d-6057-42fa-8c1e-6308c3c8c1bc\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142654,\n                    \"Version\": 8,\n                    \"Guid\": \"25583753-85ba-4d65-81f5-ea4f1ed9a59b\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"note:Note\\nwarning:Warning\",\n                          \"de-de\": \"note:Notiz\\nwarning:Warnung\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 143982,\n              \"Version\": 3,\n              \"Guid\": \"7faf0496-dc03-4e45-a1ae-e43629965344\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  const empty = 'empty';\\n  const len = 30;\\n  // Remove HTML in note\\n  const noHtml = data.Note.replace(/<\\\\/?[^>]+(>|$)/g, ' ');\\n  if (!noHtml || noHtml == ' ') return empty;\\n\\n  // remove html things like &nbsp;\\n  const converterTextArea = context.cache.converter \\n    || document.createElement(\\\"textarea\\\");\\n  converterTextArea.innerHTML = noHtml;\\n  const cleanText = converterTextArea.value;\\n\\n  // Trim multiple spaces, created by multiple tags\\n  var final = cleanText.replace(/\\\\s+/g, ' ').trim();\\n\\n  if (!final) return empty;\\n\\n  if (final.length > len) final = final.substring(0, len) + \\\"...\\\"\\n  return final || empty;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 142660,\n              \"Version\": 2,\n              \"Guid\": \"ea487371-6b1f-4718-a751-62bf389739a6\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return !data.ShowAdvanced; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 142659,\n              \"Version\": 2,\n              \"Guid\": \"dc7e8c8d-6633-4a09-ad2c-afb0f4727ef0\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.ShowAdvanced; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"19655377-6626-4986-aea0-ec3c187186ad\",\n            \"Name\": \"RequirementDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 139092,\n                \"Version\": 3,\n                \"Guid\": \"b9fc0ebf-33e9-4be6-9091-27459f8399c5\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Sets restrictions to use something.\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Requirement (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0IDI0IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0cHgiIGZpbGw9IiMwMDAwMDAiPjxnPjxyZWN0IGZpbGw9Im5vbmUiIGhlaWdodD0iMjQiIHdpZHRoPSIyNCIvPjwvZz48Zz48Zy8+PGc+PHBhdGggZD0iTTEyLDFMMyw1djZjMCw1LjU1LDMuODQsMTAuNzQsOSwxMmM1LjE2LTEuMjYsOS02LjQ1LDktMTJWNUwxMiwxeiBNMTksMTFjMCwxLjg1LTAuNTEsMy42NS0xLjM4LDUuMjFsLTEuNDUtMS40NSBjMS4yOS0xLjk0LDEuMDctNC41OC0wLjY0LTYuMjljLTEuOTUtMS45NS01LjEyLTEuOTUtNy4wNywwYy0xLjk1LDEuOTUtMS45NSw1LjEyLDAsNy4wN2MxLjcxLDEuNzEsNC4zNSwxLjkyLDYuMjksMC42NCBsMS43MiwxLjcyYy0xLjE5LDEuNDItMi43MywyLjUxLTQuNDcsMy4wNEM3Ljk4LDE5LjY5LDUsMTUuNTIsNSwxMVY2LjNsNy0zLjExbDcsMy4xMVYxMXogTTEyLDE1Yy0xLjY2LDAtMy0xLjM0LTMtM3MxLjM0LTMsMy0zIHMzLDEuMzQsMywzUzEzLjY2LDE1LDEyLDE1eiIvPjwvZz48L2c+PC9zdmc+\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"19655377-6626-4986-aea0-ec3c187186ad\"\n                }\n              },\n              {\n                \"Id\": 182589,\n                \"Version\": 2,\n                \"Guid\": \"ee57b531-b480-4687-bb6d-3a482ad062aa\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Requirement Metadata for Apps\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 100\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 3\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"19655377-6626-4986-aea0-ec3c187186ad\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 139074,\n                    \"Version\": 2,\n                    \"Guid\": \"4cdf080b-a3e5-476c-bc09-03b934b60410\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Requirement to use this\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139090,\n                    \"Version\": 1,\n                    \"Guid\": \"535dfe53-b605-4751-bfee-cf1e0e88cb02\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139091,\n                    \"Version\": 1,\n                    \"Guid\": \"50d6493e-2d80-4b53-9b7c-3b285d08134a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RequirementType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 139075,\n                    \"Version\": 5,\n                    \"Guid\": \"ffdb77e4-6925-4c6e-8e05-b7e3cf351abb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139078,\n                    \"Version\": 4,\n                    \"Guid\": \"7ef09298-209d-41a8-ad79-ecc5f7bc0e82\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139079,\n                    \"Version\": 4,\n                    \"Guid\": \"ba08d423-e7c2-444d-aab5-a12086870109\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"feature:Requires a specific Feature to be active\\nlicense:Requires a specific License\\nplatform:Requires a specific Platform\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Feature\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 139076,\n                    \"Version\": 4,\n                    \"Guid\": \"21a8da00-9e2c-4515-95f6-1868f3d4cce0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Required Feature (NameId)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"Please enter feature NameId\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"c32b4384-1d19-4e09-8904-c5c2d12ec159\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139082,\n                    \"Version\": 2,\n                    \"Guid\": \"4ea73284-29c7-40b2-a0fb-28c9ab20b184\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139083,\n                    \"Version\": 1,\n                    \"Guid\": \"cbf05c87-65ea-4852-b964-263b9d727842\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182590,\n                    \"Version\": 1,\n                    \"Guid\": \"be9144ac-5539-48a1-8b12-c09227f5640f\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Features\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"NameId\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"License\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 139077,\n                    \"Version\": 3,\n                    \"Guid\": \"f82f513e-37bd-42b2-9cc6-10fa97dd87e5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Required License\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"2e0e113a-d53b-49c8-9f79-6136d2322dad\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139084,\n                    \"Version\": 2,\n                    \"Guid\": \"7251969d-76ef-4b57-b05e-0ffd78651886\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139085,\n                    \"Version\": 2,\n                    \"Guid\": \"7b360ef1-3475-4962-9a35-b324ca165970\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Platform\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 139080,\n                    \"Version\": 2,\n                    \"Guid\": \"e7d9ffc9-0449-47bc-9718-c01d92b668b6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"RequiredPlatform\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"0c4515dd-4257-479e-8b8f-923c68667e33\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139087,\n                    \"Version\": 1,\n                    \"Guid\": \"09b1ddb4-8477-46c8-b0a9-b545e62e09f3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139088,\n                    \"Version\": 1,\n                    \"Guid\": \"6ce256c8-1e39-4024-bb5f-72bc0d6230d8\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Any platform\\ndnn:Dnn (DotNetNuke)\\noqt:Oqtane\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 139081,\n              \"Version\": 2,\n              \"Guid\": \"c32b4384-1d19-4e09-8904-c5c2d12ec159\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.RequirementType == 'feature'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 139096,\n              \"Version\": 3,\n              \"Guid\": \"2e0e113a-d53b-49c8-9f79-6136d2322dad\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.RequirementType == 'license'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 139086,\n              \"Version\": 2,\n              \"Guid\": \"0c4515dd-4257-479e-8b8f-923c68667e33\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.RequirementType == 'platform'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\",\n            \"Name\": \"SaveEmptyDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 136480,\n                \"Version\": 5,\n                \"Guid\": \"900fd1ee-6cb4-48a7-a8f2-6d7a22e3a3c1\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Mark a Content-Type to allow empty-items to be saved.\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>By default, content-types without fields would result in empty items, and they would not be saved.&nbsp;</p>\\n<p>Use this decorator to mark a content-type which should save items even if they are completely empty.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Save-Empty (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTMgNXY0aDJWNWg0VjNINWMtMS4xIDAtMiAuOS0yIDJ6bTIgMTBIM3Y0YzAgMS4xLjkgMiAyIDJoNHYtMkg1di00em0xNCA0aC00djJoNGMxLjEgMCAyLS45IDItMnYtNGgtMnY0em0wLTE2aC00djJoNHY0aDJWNWMwLTEuMS0uOS0yLTItMnoiLz48L3N2Zz4=\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\"\n                }\n              },\n              {\n                \"Id\": 136482,\n                \"Version\": 1,\n                \"Guid\": \"fc928cf4-c692-4ecb-a662-b71388273a57\",\n                \"Type\": {\n                  \"Id\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\",\n                  \"Name\": \"SaveEmptyDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\"\n                }\n              },\n              {\n                \"Id\": 139098,\n                \"Version\": 1,\n                \"Guid\": \"bd5293a6-e674-471e-9888-329ca01822a5\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for SaveEmpty - Target Content-Type\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"acc185a7-f300-4468-bce8-d6a64038989d\",\n            \"Name\": \"ToolbarButtonDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 150890,\n                \"Version\": 1,\n                \"Guid\": \"f98bd75d-b516-4f43-b45e-28322eba8101\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>WARNING - EXPERIMENTAL</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Toolbar Button Configuration (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"acc185a7-f300-4468-bce8-d6a64038989d\"\n                }\n              },\n              {\n                \"Id\": 150891,\n                \"Version\": 1,\n                \"Guid\": \"f68ce262-6b8a-4498-a7c0-7bb91a72a87f\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for content types\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 10\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"acc185a7-f300-4468-bce8-d6a64038989d\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Command\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 150878,\n                    \"Version\": 5,\n                    \"Guid\": \"3bcbb4da-0920-4584-8b73-f0a8d6cf8345\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"metadata\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Command\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The command / button this config is for.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150882,\n                    \"Version\": 1,\n                    \"Guid\": \"dce4d52e-4be4-4662-ae61-0595fb89c53a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185424,\n                    \"Version\": 1,\n                    \"Guid\": \"7afa9fdf-5c7a-4815-8fcc-bacefde345cf\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.SysData\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"SysDataSource=System.ToolbarButtonActions\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Ui\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 150879,\n                    \"Version\": 2,\n                    \"Guid\": \"68542f68-48a6-4458-a1e9-db057358936b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Ui\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Any UI parameters which should be applied to the button.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150884,\n                    \"Version\": 1,\n                    \"Guid\": \"cade50c7-5332-43c2-a44d-12041b23cf24\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150885,\n                    \"Version\": 1,\n                    \"Guid\": \"56727ffd-d81d-4bfc-b3ad-8380b213cad8\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UiColor\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 150880,\n                    \"Version\": 3,\n                    \"Guid\": \"5bca2223-ee75-4cdc-a988-e7ca8d60d680\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"UI Color (Button Background)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The color parameter of the UI</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150886,\n                    \"Version\": 2,\n                    \"Guid\": \"8c3fe0be-822e-42ed-b359-f6399b41b79d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150887,\n                    \"Version\": 2,\n                    \"Guid\": \"f83c66f6-f7f5-4207-91ca-c1797d3944d6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UiIcon\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 150881,\n                    \"Version\": 3,\n                    \"Guid\": \"fe8a5ae8-9330-4dea-baaf-f86f606beb87\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"UI Icon (SVG)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>An SVG (as plain text) to use.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150888,\n                    \"Version\": 2,\n                    \"Guid\": \"2e047acf-a3c2-4ff3-b089-b9efae3b998a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150889,\n                    \"Version\": 2,\n                    \"Guid\": \"13fb5912-56fb-4fbc-9e4d-a9900345faed\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UiData\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 150893,\n                    \"Version\": 2,\n                    \"Guid\": \"e04f2af2-5eee-4daa-8028-44b07231d43e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Ui - include Data\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 150894,\n                    \"Version\": 1,\n                    \"Guid\": \"e3736f0e-f9ec-4e42-b146-549961603e95\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Don't include data\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"Default - don't include data\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Include Data for UI\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"5efb0bc2-03c3-45e0-a20b-dabf71b8cfd1\",\n            \"Name\": \"IsTemplateDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 183772,\n                \"Version\": 1,\n                \"Guid\": \"1b1c9808-6145-42d2-ab44-92389bba2db4\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"Mark Apps as being templates, so when installing, you must set the name\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Is Template (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5efb0bc2-03c3-45e0-a20b-dabf71b8cfd1\"\n                }\n              },\n              {\n                \"Id\": 183773,\n                \"Version\": 1,\n                \"Guid\": \"264cdcc6-6f95-4ba4-910b-1111bd41f5cd\",\n                \"Type\": {\n                  \"Id\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\",\n                  \"Name\": \"SaveEmptyDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5efb0bc2-03c3-45e0-a20b-dabf71b8cfd1\"\n                }\n              },\n              {\n                \"Id\": 183775,\n                \"Version\": 1,\n                \"Guid\": \"10fd7b99-8178-47b5-9307-317096877d4e\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for App\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 3\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5efb0bc2-03c3-45e0-a20b-dabf71b8cfd1\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\",\n            \"Name\": \"IsPickerSourceDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 183919,\n                \"Version\": 3,\n                \"Guid\": \"03d0bc06-f18e-49b5-a4f7-eee4b3e1abdd\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This marks content types which are picker sources.</p>\\n<p>There are no properties to edit.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Is Picker Source (Decorator)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"base64:PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSIyNHB4IiBmaWxsPSIjZThlYWVkIj48cGF0aCBkPSJNMzIwLTI4MHExNyAwIDI4LjUtMTEuNVQzNjAtMzIwcTAtMTctMTEuNS0yOC41VDMyMC0zNjBxLTE3IDAtMjguNSAxMS41VDI4MC0zMjBxMCAxNyAxMS41IDI4LjVUMzIwLTI4MFptMC0xNjBxMTcgMCAyOC41LTExLjVUMzYwLTQ4MHEwLTE3LTExLjUtMjguNVQzMjAtNTIwcS0xNyAwLTI4LjUgMTEuNVQyODAtNDgwcTAgMTcgMTEuNSAyOC41VDMyMC00NDBabTAtMTYwcTE3IDAgMjguNS0xMS41VDM2MC02NDBxMC0xNy0xMS41LTI4LjVUMzIwLTY4MHEtMTcgMC0yOC41IDExLjVUMjgwLTY0MHEwIDE3IDExLjUgMjguNVQzMjAtNjAwWm0xMjAgMzIwaDI0MHYtODBINDQwdjgwWm0wLTE2MGgyNDB2LTgwSDQ0MHY4MFptMC0xNjBoMjQwdi04MEg0NDB2ODBaTTIwMC0xMjBxLTMzIDAtNTYuNS0yMy41VDEyMC0yMDB2LTU2MHEwLTMzIDIzLjUtNTYuNVQyMDAtODQwaDU2MHEzMyAwIDU2LjUgMjMuNVQ4NDAtNzYwdjU2MHEwIDMzLTIzLjUgNTYuNVQ3NjAtMTIwSDIwMFptMC04MGg1NjB2LTU2MEgyMDB2NTYwWm0wLTU2MHY1NjAtNTYwWiIvPjwvc3ZnPg==\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\"\n                }\n              },\n              {\n                \"Id\": 183921,\n                \"Version\": 1,\n                \"Guid\": \"f4a28d83-923e-4809-8776-e3f462fbbd0b\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Content Types can be Picker Source Configurations\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\"\n                }\n              },\n              {\n                \"Id\": 183923,\n                \"Version\": 1,\n                \"Guid\": \"977cb2e5-4480-4522-83ad-c0e9c1b33d99\",\n                \"Type\": {\n                  \"Id\": \"8c78dabf-e0ad-4c26-b750-48138ecb8a39\",\n                  \"Name\": \"SaveEmptyDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"7775df1b-9c6d-4344-8f64-f6683b324615\",\n            \"Name\": \"FieldSettingsGeneric\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 183983,\n                \"Version\": 1,\n                \"Guid\": \"5c4445aa-e14e-4cd2-abca-011dfa4a2023\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This is for development / internal features only.</p>\\n<p>Goal is to be able to quickly add some generic settings to an input field, which affect the field without having to first create a content-type for these.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Field Settings - Generic (Development only)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"7775df1b-9c6d-4344-8f64-f6683b324615\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183985,\n                    \"Version\": 2,\n                    \"Guid\": \"3664805a-7ed8-407f-ab44-bbf3caa3ca54\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Title so you know why this was added.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183987,\n                    \"Version\": 1,\n                    \"Guid\": \"91194b53-491d-4cff-9f7e-9d4335f16174\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183988,\n                    \"Version\": 1,\n                    \"Guid\": \"6f22c773-321f-4e1b-bcd7-7fe37d12d25b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SettingsGeneric\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-json\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183986,\n                    \"Version\": 2,\n                    \"Guid\": \"957ec393-6088-406f-850c-d672fd030b57\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-json\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Settings - Generic\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183991,\n                    \"Version\": 1,\n                    \"Guid\": \"f2084a14-006b-4b7b-9d78-f8b2b5ece02a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183992,\n                    \"Version\": 1,\n                    \"Guid\": \"65d4e5d2-2ce4-46db-82e9-29e4936e1197\",\n                    \"Type\": {\n                      \"Id\": \"@string-json\",\n                      \"Name\": \"@string-json\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"JsonSchemaMode\": {\n                          \"en-us\": \"none\"\n                        },\n                        \"JsonSchemaRaw\": {\n                          \"en-us\": \"\"\n                        },\n                        \"JsonSchemaSource\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"JsonValidation\": {\n                          \"en-us\": \"strict\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"JsonSchemaUrl\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"Rows\": {\n                          \"en-us\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"9db5de57-7c16-4370-8d16-a8bf4cfe8e5b\",\n            \"Name\": \"DataStorageDecorator\",\n            \"Scope\": \"System.Decorators\",\n            \"Metadata\": [\n              {\n                \"Id\": 184358,\n                \"Version\": 2,\n                \"Guid\": \"da8be7d4-a851-401b-a102-538f833a2c7b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Data Storage Decorator (for Content-Type) BETA\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"9db5de57-7c16-4370-8d16-a8bf4cfe8e5b\"\n                }\n              },\n              {\n                \"Id\": 185416,\n                \"Version\": 1,\n                \"Guid\": \"505d7505-2836-40d8-a43d-6616c09bd33d\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for Content Types\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"9db5de57-7c16-4370-8d16-a8bf4cfe8e5b\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"GroupSave\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184346,\n                    \"Version\": 1,\n                    \"Guid\": \"30766961-07f7-4eb8-9606-bbc155a09a83\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Data Save / Store Settings BETA\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184351,\n                    \"Version\": 1,\n                    \"Guid\": \"3964022d-fdcd-4f94-ae5a-3c0599fca5ea\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"StoreType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184347,\n                    \"Version\": 1,\n                    \"Guid\": \"efde2481-56d4-4ae3-bc92-dcb82309ef95\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Store Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184352,\n                    \"Version\": 1,\n                    \"Guid\": \"33165ed1-ca4f-4d35-bf64-97c48d65087e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184353,\n                    \"Version\": 1,\n                    \"Guid\": \"dd4ea4b3-438c-4718-932d-50d89c96220a\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":EAV (default)\\neav:EAV\\nsql:SQL (beta)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SaveIsDisabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184348,\n                    \"Version\": 1,\n                    \"Guid\": \"d4c0ffa5-eabb-45c9-b831-82263b97e35f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Never Save\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184354,\n                    \"Version\": 1,\n                    \"Guid\": \"cdc0d72b-f7db-479f-b24d-56f87383ecda\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Enable Save\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Never Save\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemsMax\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184349,\n                    \"Version\": 1,\n                    \"Guid\": \"353bef96-cd53-4006-8d9b-2275c8d1b6f7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Max Items\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Specify maximum amount of items expected. Default is -1 (infinite)</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184355,\n                    \"Version\": 1,\n                    \"Guid\": \"337d489a-7370-4648-845c-d6f1f5e297ea\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        },\n                        \"Max\": {\n                          \"en-us\": 99999999\n                        },\n                        \"Min\": {\n                          \"en-us\": -1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DataProcessingHandler\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184350,\n                    \"Version\": 5,\n                    \"Guid\": \"252d083c-1c30-448f-84ac-22917b76c1fd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Data Processing Handler\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>.net class responsible for any special data processing before save, after save, etc.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184356,\n                    \"Version\": 1,\n                    \"Guid\": \"42268f9b-4e3f-4f1f-aeac-9eafae0108b3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184357,\n                    \"Version\": 1,\n                    \"Guid\": \"00ab0a0f-8100-4916-835e-df4aa06968b3\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185413,\n                    \"Version\": 3,\n                    \"Guid\": \"6e22bac0-63b6-49f5-9bbd-2592683361db\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"a148a07e-7bd0-41ae-9911-a00583215ae5\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 185412,\n              \"Version\": 4,\n              \"Guid\": \"a148a07e-7bd0-41ae-9911-a00583215ae5\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:AssemblyQualifiedName]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"FullName\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.SysData\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"SysDataSource=System.DataProcessors\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Query: SysData DataProcessors\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"FullName\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ],\n      \"Entities\": [\n        {\n          \"Id\": 182559,\n          \"Version\": 5,\n          \"Guid\": \"5f49cf41-62b9-4d99-8642-59eece7ecdc2\",\n          \"Type\": {\n            \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n            \"Name\": \"UiPickerSourceQuery\",\n            \"AttributeMap\": {\n              \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n              \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n              \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n              \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n            }\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"CreateTypes\": {\n                \"en-us\": \"\"\n              },\n              \"Description\": {\n                \"en-us\": \"<p>Get All System Capabilities - WIP, probably not used...</p>\"\n              },\n              \"ItemInformation\": {\n                \"en-us\": \"\"\n              },\n              \"ItemTooltip\": {\n                \"en-us\": \"\"\n              },\n              \"Label\": {\n                \"en-us\": \"Default\"\n              },\n              \"MoreFields\": {\n                \"en-us\": \"\"\n              },\n              \"Query\": {\n                \"en-us\": \"System.SystemCapabilities\"\n              },\n              \"QueryParameters\": {\n                \"en-us\": \"\"\n              },\n              \"StreamName\": {\n                \"en-us\": \"Default\"\n              },\n              \"Title\": {\n                \"en-us\": \"System Capabilities\"\n              },\n              \"Value\": {\n                \"en-us\": \"NameId\"\n              }\n            },\n            \"Hyperlink\": {\n              \"ItemLink\": {\n                \"en-us\": \"\"\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 182560,\n              \"Version\": 1,\n              \"Guid\": \"6a7bcfb7-49c9-4567-83ce-304476de0437\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"9cf17242-8ad5-4a92-b93c-2e1bdde9ead9\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"5f49cf41-62b9-4d99-8642-59eece7ecdc2\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-fields-helpers.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n            \"Name\": \"UiFormula\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 120074,\n                \"Version\": 13,\n                \"Guid\": \"ba7533db-4b2d-48fa-bbd1-56405b2f42a6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"Formula for a UI element\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p><a href=\\\"https://r.2sxc.org/formulas\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\"><img src=\\\"https://sources.2sxc.org/assets/v12/content-types/formulas-banner.svg?12.01\\\" height=\\\"100px\\\"></a></p>\\n<p>Use Formulas to calculate values or settings like visibility of fields. See <a href=\\\"https://r.2sxc.org/formulas\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">documentation</a>.</p>\\n<p><strong><span style=\\\"color: rgb(224, 62, 45);\\\">⚠️ Important: Do not edit the formulas here! ⚠️</span></strong></p>\\n<p>The formulas are stored here as simple data, but it's not the right place to edit them, unless you have to fix a formula that breaks your form.&nbsp;<a href=\\\"https://r.2sxc.org/formulas\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">The right place to edit formulas is directly in the Edit Form</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"UI Formula Σ\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"VarOverride\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167710,\n                    \"Version\": 3,\n                    \"Guid\": \"5996894a-ce5f-4ed7-94c8-e2486b44b5eb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"VarOverride\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167711,\n                    \"Version\": 2,\n                    \"Guid\": \"c36ae328-ccdd-42a9-bfdc-aa6e02359b5c\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Keep fields locked, as you shouldn't edit it here\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"I need to make some manual changes\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MessageDontDoThisHere\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183791,\n                    \"Version\": 4,\n                    \"Guid\": \"a45cd222-800b-4dc0-ba4e-9c7929b38a15\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Don't edit this here\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong><span style=\\\"color: rgb(224, 62, 45);\\\">⚠️ No seriously - you should not edit formulas here! ⚠️</span></strong></p>\\n<p>Please read the instructions above. It's much easier to edit formulas directly in the Edit UI.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"3ec13b90-fcb4-489e-b94d-b22f644f3330\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 120063,\n                    \"Version\": 7,\n                    \"Guid\": \"a5aca5c0-4e4f-41ff-b6f6-61d74d73c2ed\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The title is auto-generated, but you can add more text if you need to</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"d04909fa-1c34-4b2f-93cc-b680a3a2b756\",\n                            \"a17611a7-e0d7-4340-a73c-7e0fee146ded\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 130243,\n                    \"Version\": 5,\n                    \"Guid\": \"543dea87-6ebc-4bf4-9623-b801bf41ec1b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130244,\n                    \"Version\": 5,\n                    \"Guid\": \"f158d3d7-d401-4e63-be40-0cfd25feeae6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Target\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 120064,\n                    \"Version\": 16,\n                    \"Guid\": \"6e0db16d-261c-43d7-a9af-9801d11ccbc0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Field.Value\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Target\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The target is what will be updated. Choose a value or type your own key in advanced cases.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"eee175b1-cd81-4e85-a813-5be709ac612a\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 120067,\n                    \"Version\": 15,\n                    \"Guid\": \"1d4a41de-2b2d-4dd3-8c90-10c12d6b76e6\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 120068,\n                    \"Version\": 15,\n                    \"Guid\": \"c3a1471f-4c34-4cad-baf1-325b04f91287\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"Field.Value:Field Value\\nField.Settings.Name:Name (Title) of the Field\\nField.Settings.Notes:Notes / Help of the Field\\nField.Settings.Visible:Visible (show the Field)\\nField.Settings.Required:Required (must be filled in)\\nField.Settings.Disabled:Disabled (blocked, can't be edited)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Formula\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 120065,\n                    \"Version\": 16,\n                    \"Guid\": \"377a1d4e-5131-4ce4-904c-07ac0801fcf2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"v1(data, context) { return data.value; }\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Formula\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The formula - starting with v1(data, context) {...}.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"1c6def89-b2bc-42bb-a63f-53d0e5658b39\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 120069,\n                    \"Version\": 15,\n                    \"Guid\": \"17f5e665-ac5a-45d5-bb13-b2633302ef58\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 120070,\n                    \"Version\": 15,\n                    \"Guid\": \"aef05229-76ff-4ae6-955b-4c5adaec58cb\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Enabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130126,\n                    \"Version\": 4,\n                    \"Guid\": \"afe6ca1e-d1f8-4b2f-8c15-cbfa14fa7da8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Enabled\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130127,\n                    \"Version\": 3,\n                    \"Guid\": \"72946d4a-7cdc-45c7-8038-627ed4af792b\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Disable Formula\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Enable Formula\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VarShowNotes\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130129,\n                    \"Version\": 7,\n                    \"Guid\": \"134a5c7d-a1bb-4c7f-a519-53d1b0dbf64d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Show Notes\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"b1f61471-c6aa-4b7d-86a4-ca0d7eb3d526\",\n                            \"fc41eb73-7f0f-4507-8830-b487bc56c202\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"*\": true\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130130,\n                    \"Version\": 5,\n                    \"Guid\": \"27f21419-c0a3-4ca5-a9f9-000de0dc2554\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Hide notes\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"Show notes if it has any\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Show notes\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 120066,\n                    \"Version\": 7,\n                    \"Guid\": \"db877d55-b910-415c-bfda-a474178c3727\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Do not use this any more, please use <a href=\\\"https://r.2sxc.org/notes\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">notes</a> instead. This will be removed ca. 2023.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"9cffa304-1340-4531-83e5-ae01622ba0bb\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 120071,\n                    \"Version\": 6,\n                    \"Guid\": \"6f952f1c-289e-4aba-afa8-30cdfd0ff756\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 120072,\n                    \"Version\": 6,\n                    \"Guid\": \"1c339a04-2e98-4a54-b259-2c5ade275979\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        },\n                        \"WysiwygConfiguration\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 167712,\n              \"Version\": 1,\n              \"Guid\": \"d04909fa-1c34-4b2f-93cc-b680a3a2b756\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => {\\n  return !data.VarOverride;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Disabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130242,\n              \"Version\": 12,\n              \"Guid\": \"a17611a7-e0d7-4340-a73c-7e0fee146ded\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) {\\n  const value = data.value;\\n  const separator = ':';\\n  const prefix = data.Target.replace('Field.Settings.', 'Setting ').replace('Field.Value', 'Value');\\n  const prefixLight = prefix + separator;\\n  const prefixFull = prefixLight + ' ';\\n\\n  // Case 1: Empty or Whitespace only, use prefix\\n  if(value == '' || !/\\\\S/.test(value)) return prefix;\\n\\n  // Case 2: Already contains prefix, possibly with separator, no additional text\\n  if(value == prefix || value == prefixLight || value == prefixFull) return prefix;\\n\\n  // Case 3: Start with prefix and has more\\n  if(value.startsWith(prefixFull)) return value; \\n\\n  // case 4: Start with prefix but separator is incomplete\\n  if(value.startsWith(prefixLight)) return value.replace(prefixLight, prefixFull);\\n  if(value.startsWith(prefix)) return value.replace(prefix, prefixFull); \\n\\n  // case 5: No prefix yet, either missing or from previous setting\\n  const separatorPos = value.indexOf(separator);\\n  if(separatorPos == -1) return prefix;\\n\\n  return prefix + value.substring(separatorPos); \\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"<p>This looks complicated, but it just ensures that the title is automatically set to better ensure people use the right target.&nbsp;</p>\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value: based on target\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130128,\n              \"Version\": 6,\n              \"Guid\": \"eee175b1-cd81-4e85-a813-5be709ac612a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => {\\r\\n  const enabled = data.Enabled && data.VarOverride;\\r\\n  return !enabled;\\r\\n});\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Disabled: Disable if not enabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130132,\n              \"Version\": 7,\n              \"Guid\": \"1c6def89-b2bc-42bb-a63f-53d0e5658b39\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => {\\r\\n  const enabled = data.Enabled && data.VarOverride;\\r\\n  return !enabled;\\r\\n});\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Disabled: Disable if formula is not enabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130131,\n              \"Version\": 8,\n              \"Guid\": \"9cffa304-1340-4531-83e5-ae01622ba0bb\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) {\\n  return data.VarShowNotes;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show if set to show or has content\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130247,\n              \"Version\": 3,\n              \"Guid\": \"b1f61471-c6aa-4b7d-86a4-ca0d7eb3d526\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n\\n  // Init like this\\n  return data.Notes.length > 7; // min with p-tag\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value: if wysiwyg has contents\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130248,\n              \"Version\": 3,\n              \"Guid\": \"fc41eb73-7f0f-4507-8830-b487bc56c202\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !data.VarShowNotes; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: hide if true\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183792,\n              \"Version\": 1,\n              \"Guid\": \"3ec13b90-fcb4-489e-b94d-b22f644f3330\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => {\\n  return data.VarOverride;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"ContentType-InputType\",\n            \"Name\": \"ContentType-InputType\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53701,\n                \"Version\": 3,\n                \"Guid\": \"787d547a-85c0-485f-9f69-00570397e928\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Input type definition for a content-type\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>These objects must be attached to the content type to have an affect - so create them as metadata for a content type so they will be exported together with the content-type definition.&nbsp;</p>\\n<p>You only need to create this object for content-types which need extra configuration, so you won't find an input type in this list for every type which exists.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Custom InputType Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"<p>These objects must be attached to the content type to have an affect - so create them as metadata for a content type so they will be exported together with the content-type definition.&nbsp;</p>\\n<p>Note that the primary list for input-types is all global types with @ in front of the name, so you&nbsp;only need to create this object (as metadata) for content-types which need extra configuration. You won't find an input type in this list for every type which exists.&nbsp;</p>\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"ContentType-InputType\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Type\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45115,\n                    \"Version\": 1,\n                    \"Guid\": \"49c736a3-4103-4556-a0f1-588b613f1ce2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Type\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Label\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45116,\n                    \"Version\": 1,\n                    \"Guid\": \"55a65d8e-7978-4fdc-8394-405a2b006f97\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Label\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45117,\n                    \"Version\": 1,\n                    \"Guid\": \"b106e124-b054-4c76-bd14-ab0e57d83a2a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Description\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AngularGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 53675,\n                    \"Version\": 2,\n                    \"Guid\": \"3e4556ef-b52d-4080-a0ba-06a313320fd7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Angular Form Configuration\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>These are settings which apply to 2sxc 10</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53677,\n                    \"Version\": 1,\n                    \"Guid\": \"c5b45f7c-3e12-4b38-846e-ecaa097f9540\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DisableI18n\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 52202,\n                    \"Version\": 3,\n                    \"Guid\": \"11a0e6e2-c856-4a3d-86dd-572f477311b7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Disable Internationalization\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Don't allow this information to be translated - for example when the user presses translate-all</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 52203,\n                    \"Version\": 2,\n                    \"Guid\": \"b669c659-8956-4fcc-a23e-f4b385994ca1\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AngularAssets\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 53676,\n                    \"Version\": 3,\n                    \"Guid\": \"69d1698b-e8c5-4a80-b59a-a7dde42412dc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Assets\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>These assets are only for the new Angular form in 2sxc 10.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53678,\n                    \"Version\": 2,\n                    \"Guid\": \"9da27e0d-a5c5-49a8-9a65-cd12569939dc\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53679,\n                    \"Version\": 2,\n                    \"Guid\": \"902ad7b8-de5d-465f-b1f9-836201aefa81\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UseAdam\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 53686,\n                    \"Version\": 2,\n                    \"Guid\": \"b9a18505-0bac-4579-8e17-7466a8882176\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Use ADAM\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>When enabled, the various wrappers are ensured which provide ADAM functionality.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53687,\n                    \"Version\": 1,\n                    \"Guid\": \"6dcf4ef3-3228-4f65-bd76-b475dc9d230a\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupSpecialConfig\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182568,\n                    \"Version\": 4,\n                    \"Guid\": \"b9ecd6c9-4785-4c6a-9fda-0a0438c9b6b9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Custom Configuration of Input\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This will override the default behavior to determine which content-types are used to configure this input type (new v17).</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182570,\n                    \"Version\": 3,\n                    \"Guid\": \"f796d14c-996c-464b-b23c-984b8d90727d\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ConfigTypes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182569,\n                    \"Version\": 5,\n                    \"Guid\": \"6160ff26-0910-4649-860c-aae7dab1cd39\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Custom Configuration Types\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Select custom types to configure this input type.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182571,\n                    \"Version\": 4,\n                    \"Guid\": \"995d4aef-97a3-4871-9b29-286fe701df17\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182572,\n                    \"Version\": 4,\n                    \"Guid\": \"ec4933d4-2601-4642-a4f9-05a632a031b7\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"Scope=System.Fields\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"4a8eded3-727e-4990-b986-019d84b3d220\",\n            \"Name\": \"RegExCheck\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 63410,\n                \"Version\": 2,\n                \"Guid\": \"498f424b-db24-4a79-aab7-056ad5e410d6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Used to validate fields\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Configur a regular expression check here. It will usually be used in JavaScript, so make sure your RegEx adheres to the JavaScript RegEx standard. You can develop/test your regex in online tools like the <a href=\\\"https://regexr.com/\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">RegExr</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Regular Expression (BETA, not final)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"4a8eded3-727e-4990-b986-019d84b3d220\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63407,\n                    \"Version\": 2,\n                    \"Guid\": \"2e6fcfd2-9a79-4332-9c8b-e2722c6b63fd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Test for ...\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Just a nice title for your convenience, so you know what this regex is for.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63411,\n                    \"Version\": 1,\n                    \"Guid\": \"84e67299-b1cb-4713-935e-57e5d039df4c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63412,\n                    \"Version\": 1,\n                    \"Guid\": \"ffc53071-f755-4296-ab7d-d596a926ec01\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RegEx\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63408,\n                    \"Version\": 3,\n                    \"Guid\": \"c69b94bb-9421-425c-99be-806f03bc20ed\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"RegEx\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The Regular Expression in JS standard.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63413,\n                    \"Version\": 2,\n                    \"Guid\": \"75d70f0e-9e16-4f18-bfff-971695cb6473\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63414,\n                    \"Version\": 2,\n                    \"Guid\": \"957493e7-138b-43b7-8584-373b1054fedd\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Message\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63409,\n                    \"Version\": 2,\n                    \"Guid\": \"a1d9cc4f-ffb3-49af-8e1a-fb403984c7a9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Warning: field validation failed.\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Message\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Message to show to the user if the expression fails.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63415,\n                    \"Version\": 1,\n                    \"Guid\": \"3dd50a69-dc2b-4b7a-976e-aba713ff2ffa\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63416,\n                    \"Version\": 1,\n                    \"Guid\": \"5720d287-635c-4297-86fd-de40f4f190df\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"*\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"*\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Invert\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63417,\n                    \"Version\": 2,\n                    \"Guid\": \"7bde51e5-b169-4da3-b09d-56d150f93a05\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Invert Result\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Normally an expression is ok, if the regex matches the value found. In some cases, you would rather say \\\"it shouldn't match the expression\\\" for blacklisting certain things. So if you want the expression to&nbsp;<em>not match</em>, then activate this toggle.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-fields-pickers.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"@number-dropdown\",\n            \"Name\": \"@number-dropdown\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 131454,\n                \"Version\": 3,\n                \"Guid\": \"bd087f79-838b-4bab-92fb-382bfd53113b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Dropdown-Number Input configuration\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Read about Number-Dropdown fields in <a href=\\\"https://docs.2sxc.org/basics/data/fields/number-dropdown.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">the docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Dropdown (Number)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"https://docs.2sxc.org/basics/data/fields/number-dropdown.html\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@number-dropdown\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"DropdownValuesFormat\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 131460,\n                    \"Version\": 6,\n                    \"Guid\": \"39a04bbe-ac2a-49e2-a3d6-c61b8308f5f1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"value-label\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Dropdown Values Format\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131461,\n                    \"Version\": 5,\n                    \"Guid\": \"0b1b870d-be01-46df-929e-cb739d82f4a0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131462,\n                    \"Version\": 5,\n                    \"Guid\": \"c68320d9-3ff7-4bbe-a60f-0f71976cc5c4\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"Old - first Labels, then Values:\\nNew - first Values, then labels:value-label\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DropdownValues\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 131449,\n                    \"Version\": 2,\n                    \"Guid\": \"5bd40264-ef9e-4eab-b093-b3b620e8ac63\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \":Empty / no value\\n42:The meaning of life and everything\\n0.5625:Aspect ratio 16:9\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Values\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Type in the values, one per line and separate keys:values with a \\\":\\\". </p>\\n<p><strong>Example 1</strong><br />\\n(none):\\n<br />\\nLeft:l\\n<br />\\nRight:r\\n<br />\\nTop:t</p>\\n<p><strong>Example 2</strong><br />\\nMIT License:MIT<br />\\nGUN Licnese:GNU<br />\\nGPL-3 with mentioning of Author:GPL-3-BY</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131450,\n                    \"Version\": 2,\n                    \"Guid\": \"ef9d3d36-afdd-4994-be14-701d42f175c3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131451,\n                    \"Version\": 2,\n                    \"Guid\": \"ad7b7c85-4eee-400e-beda-a30befb455e4\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 12\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableTextEntry\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 131452,\n                    \"Version\": 5,\n                    \"Guid\": \"148087de-0e4a-4003-9909-ea4c548cfa74\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Enable Free Text\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Allow users to type other things than are in the drop-down. Two common situations for this:</p>\\n<ul>\\n<li>situations where the drop-down will suggest typical values, but others are also possible</li>\\n<li>Situations where you need tokens like [Parameter:Category] which will later be resolved to a real value</li>\\n</ul>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131453,\n                    \"Version\": 4,\n                    \"Guid\": \"8399706a-0a6c-4f58-b816-04a2272295f3\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@Entity\",\n            \"Name\": \"@Entity\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 52213,\n                \"Version\": 1,\n                \"Guid\": \"80bb6bfa-7a46-4f2b-a453-27648807c9a9\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Entity UI Definitions\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Entities / Relationships let the user pick other data. See <a href=\\\"https://github.com/2sic/2sxc/wiki/ui-field-entity\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">wiki</a> for more.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Entities or Relationships\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@Entity\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"EntityType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41690,\n                    \"Version\": 10,\n                    \"Guid\": \"e061de25-75e8-4408-bf19-397b72347fca\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Entity Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The type name of the entity to select. If empty, will return all entities (not usually a good idea). <br /><br />If you are using a query, this can still be usefull if you want to enable the users to create new items, as this type would be used.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41696,\n                    \"Version\": 5,\n                    \"Guid\": \"3f7376b2-03a6-42d0-bd21-7fc16c8e4d48\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41697,\n                    \"Version\": 1,\n                    \"Guid\": \"5ba8c909-5716-45a0-8575-616f332655c5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45200,\n                    \"Version\": 4,\n                    \"Guid\": \"8e5c63cb-aee2-4433-8139-e188ae15fa12\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"\"\n                        },\n                        \"Value\": {\n                          \"*\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 183980,\n                    \"Version\": 2,\n                    \"Guid\": \"5348b0a9-0816-4e18-8512-f8a3bef47a5f\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"39620e8d-dce6-4d8b-90e8-4ac4ec4ddde1\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupUiFeatures\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"f786e83a-12b8-4c76-8593-cc84e385ff1b\"\n                }\n              },\n              {\n                \"Name\": \"AllowMultiValue\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"faf06aa8-73cc-4cb0-baa5-da7a9e5d2203\"\n                }\n              },\n              {\n                \"Name\": \"EnableEdit\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"f09fbd6a-ba83-4023-a5b4-b82b6ef7e9ff\"\n                }\n              },\n              {\n                \"Name\": \"EnableCreate\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"916b17c1-f15d-4414-80e5-6d53b27ff463\"\n                }\n              },\n              {\n                \"Name\": \"EnableAddExisting\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0fc6d925-77df-4ccc-80dd-5d9ddaf003c9\"\n                }\n              },\n              {\n                \"Name\": \"EnableRemove\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"9f51cb28-eab4-4eb6-9b44-6246b55a7a52\"\n                }\n              },\n              {\n                \"Name\": \"EnableDelete\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"4274d627-fc80-412e-ad34-fa9ed21c6ba6\"\n                }\n              },\n              {\n                \"Name\": \"GroupExperimental\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 128428,\n                    \"Version\": 5,\n                    \"Guid\": \"487df46d-3ec2-4d53-87a7-c0e02a182340\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Experimental / Beta Features\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These features are not final, so you should only use them with caution and the way they are configured may still change.&nbsp;</p>\\n<p>We recommend that you use the entity-picker and that prefill instead.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"27ffdc8c-2054-4ec0-a4f6-14517d27b71c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 128429,\n                    \"Version\": 3,\n                    \"Guid\": \"a1db0df3-753a-4d72-888a-a99c53105b48\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Prefill\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 128425,\n                    \"Version\": 3,\n                    \"Guid\": \"fac91655-1777-4775-bdea-16b0c71e3ab6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Prefill (Beta)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is still a beta feature. Goal is that you can specify prefill-values for new entities generated through this. It's not documented, since it's still WIP and may change as we complete the implementation.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 128426,\n                    \"Version\": 2,\n                    \"Guid\": \"56b5211c-7067-4da2-a4f3-f308ebcd0311\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 128427,\n                    \"Version\": 2,\n                    \"Guid\": \"b649b222-9167-4b3a-961b-35b48c6d18c1\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183979,\n              \"Version\": 2,\n              \"Guid\": \"39620e8d-dce6-4d8b-90e8-4ac4ec4ddde1\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>Scope [Item:Scope] - internal ID ([Item:NameId])&nbsp;</p>\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Title\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.ContentTypes\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Entities - Content Types\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184083,\n              \"Version\": 2,\n              \"Guid\": \"27ffdc8c-2054-4ec0-a4f6-14517d27b71c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return context.debug;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@entity-default\",\n            \"Name\": \"@entity-default\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 52207,\n                \"Version\": 2,\n                \"Guid\": \"a71a80c1-1c62-40f7-a0d6-7dac593d9bb4\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"to choose one or more content items preserving the sorting-order\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Item/Entity Picker (default)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@entity-default\"\n                }\n              },\n              {\n                \"Id\": 52208,\n                \"Version\": 2,\n                \"Guid\": \"b4c4b321-1611-40cf-a1d8-b818f0076c39\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"standard single/multiple entity/item picker\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Entity / Item picker\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"entity-default\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": true\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@entity-default\"\n                }\n              },\n              {\n                \"Id\": 136790,\n                \"Version\": 1,\n                \"Guid\": \"c37e8485-69e6-4811-b6c6-6c93e91c8ca0\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@entity-default\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@entity-query\",\n            \"Name\": \"@entity-query\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 52212,\n                \"Version\": 2,\n                \"Guid\": \"c17b1bb9-7715-4eae-a8a3-18e0d110ce61\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"entity-picker with query configuration\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>In addition to the primary type, you can also use a query. This allows you to use different criterias for pre-filtering the data you want to allow, or to provide data from other apps. You can read more about this in the <a href=\\\"https://github.com/2sic/2sxc/wiki/ui-field-entity-query\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">wiki</a>.</p>\\n<p>Note that this is especially useful to select data from a query, where you want to save a relationship (like blog-post / tag, book/author, etc.).&nbsp;If you want to store a text-value, like a field-name, a value from SQL etc. you want to use the <a href=\\\"https://github.com/2sic/2sxc/wiki/ui-field-string-dropdown-query\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">string-dropdown-query</a> instead.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Query based item-picker\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"https://github.com/2sic/2sxc/wiki/ui-field-entity-query\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@entity-query\"\n                }\n              },\n              {\n                \"Id\": 52214,\n                \"Version\": 3,\n                \"Guid\": \"099ad0ba-f521-410b-a072-525d1acf5241\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"Select items/relationships based on visual queries.\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Query based entity/item-picker\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"entity-query\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": true\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@entity-query\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Query\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": true,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"1454db62-f29f-4471-b2a5-5bd82817580a\"\n                }\n              },\n              {\n                \"Name\": \"GroupMore\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130150,\n                    \"Version\": 2,\n                    \"Guid\": \"6ef796d0-8010-4920-9b9e-4421aba4c80d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"More Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8a7291bf-a93f-42be-be4d-eec4f53d4363\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130152,\n                    \"Version\": 1,\n                    \"Guid\": \"580371d2-aa02-4a14-8f71-17e6c6e45297\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"StreamName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\"\n                }\n              },\n              {\n                \"Name\": \"UrlParameters\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41705,\n                    \"Version\": 5,\n                    \"Guid\": \"0981c811-b101-424e-a2af-fc3d89796810\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Parameters\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If your query needs additional parameters in the URL, you can specify them here, in the same syntax as a url. For advanced scenarios you can also use field-names of this content-item to use as a query parameter.<br /><br /><strong>Examples</strong></p>\\n<ul>\\n<li>Category=27</li>\\n<li>Category=[Category]</li>\\n</ul>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41707,\n                    \"Version\": 4,\n                    \"Guid\": \"cdc65456-1b61-4741-8bb7-6064ce1cff19\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41708,\n                    \"Version\": 4,\n                    \"Guid\": \"3f8eb44f-334b-4d07-b11c-2530a76bcb8d\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130151,\n              \"Version\": 3,\n              \"Guid\": \"8a7291bf-a93f-42be-be4d-eec4f53d4363\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.Query; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show once Query is selected\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@string-dropdown\",\n            \"Name\": \"@string-dropdown\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53709,\n                \"Version\": 3,\n                \"Guid\": \"b0842c64-6260-4269-b891-0bc6e282b41e\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Dropdown string-input configuration\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>For more details about the dropdowns, see <a href=\\\"https://docs.2sxc.org/basics/data/fields/string-dropdown.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Dropdown (String/Text)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"https://docs.2sxc.org/basics/data/fields/string-dropdown.html\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-dropdown\"\n                }\n              },\n              {\n                \"Id\": 136472,\n                \"Version\": 1,\n                \"Guid\": \"7ddb0beb-84de-45db-95c8-acd513d5bf50\",\n                \"Type\": {\n                  \"Id\": \"c740085a-d548-41f3-8d06-0a48b8692345\",\n                  \"Name\": \"IsRecommendedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Message\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-dropdown\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"DropdownValuesFormat\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 131457,\n                    \"Version\": 7,\n                    \"Guid\": \"b50acc96-b176-4fbf-a631-bf36050ff69d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Dropdown Values Format\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"60e5fb78-89eb-4b3e-9104-3c3050f98cd8\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131458,\n                    \"Version\": 6,\n                    \"Guid\": \"8baaa324-e53d-4e13-b07c-11d52bfb8705\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131459,\n                    \"Version\": 6,\n                    \"Guid\": \"3b4c9db6-44d6-4a47-a814-60e339c448e0\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Old - first Labels, then Values\\nvalue-label:New - first Values, then labels (recommended)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DropdownValues\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41667,\n                    \"Version\": 5,\n                    \"Guid\": \"5bd40264-ef9e-4eab-b093-b3b620e8ac63\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Simple Value\\nAnother Value\\nl:Left (will store an l)\\nr:Right (will store an r)\\nc:Center (... c)\\nm:Middle\\nrandom:Random value\\nMIT:MIT License\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Values\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Type in the values, one per line and separate values and labels with a \\\":\\\".- see <a href=\\\"https://docs.2sxc.org/basics/data/fields/string-dropdown.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41668,\n                    \"Version\": 5,\n                    \"Guid\": \"ef9d3d36-afdd-4994-be14-701d42f175c3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41669,\n                    \"Version\": 5,\n                    \"Guid\": \"ad7b7c85-4eee-400e-beda-a30befb455e4\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 12\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableTextEntry\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41679,\n                    \"Version\": 5,\n                    \"Guid\": \"148087de-0e4a-4003-9909-ea4c548cfa74\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Enable Free Text\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Allow users to type other things than are in the drop-down. Two common situations for this:</p>\\n<ul>\\n<li>situations where the drop-down will suggest typical values, but others are also possible</li>\\n<li>Situations where you need tokens like [Parameter:Category] which will later be resolved to a real value</li>\\n</ul>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41682,\n                    \"Version\": 4,\n                    \"Guid\": \"8399706a-0a6c-4f58-b816-04a2272295f3\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 131469,\n              \"Version\": 2,\n              \"Guid\": \"60e5fb78-89eb-4b3e-9104-3c3050f98cd8\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n \\n  // on new entities - set it to the new mode\\n  if(context.target.entity.id == 0) return 'value-label';\\n  return data.value;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@string-dropdown-query\",\n            \"Name\": \"@string-dropdown-query\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53710,\n                \"Version\": 7,\n                \"Guid\": \"b9f7c48b-620f-40e3-9bb3-557e1b812d96\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Dropdown which receives data from a query\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure a dropdown which receives the options from a Visual Query.</p>\\n<p>Since this is a string-field, it will store the resulting data as a string, not as a relationship.</p>\\n<p>Note that this is especially useful to select data from a query, where you want to save a text-value (like a field-name, a value from SQL etc.). If you want to store a real relationship, you should use the entity-query field instead.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Dropdown from Query\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-dropdown-query\"\n                }\n              },\n              {\n                \"Id\": 183695,\n                \"Version\": 3,\n                \"Guid\": \"3c274d21-241c-4700-ad1a-97485aa191db\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"ConfigTypes\": {\n                      \"en-us\": \"@All,@string-dropdown-query\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"String Dropdown from Query\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"@string-dropdown-query\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": false\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-dropdown-query\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Query\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41724,\n                    \"Version\": 14,\n                    \"Guid\": \"ef0df2c9-dd1f-4ac9-b8db-e5edd3edc3e3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Query\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Pick the query which would be used to prepare the items a user can select. For very advanced scenarios you can also manually enter a special query.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41725,\n                    \"Version\": 8,\n                    \"Guid\": \"595aa647-1ee4-4c5e-a22c-0cb8de96b66a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41726,\n                    \"Version\": 1,\n                    \"Guid\": \"eb69a6f3-ebe7-44c7-a3fd-662bf06bce52\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42996,\n                    \"Version\": 7,\n                    \"Guid\": \"bdae88ba-d326-4b1c-b372-a3ba4e3be98d\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.Queries\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"\"\n                        },\n                        \"Value\": {\n                          \"*\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupMore\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130146,\n                    \"Version\": 3,\n                    \"Guid\": \"d62db9a1-e313-451b-a4e2-e169b2307d0d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"More Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"d84e7112-a89e-42d9-b966-a42af0cc077d\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130147,\n                    \"Version\": 2,\n                    \"Guid\": \"148d7ed3-ebd6-4238-a2f0-788ff848f256\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"StreamName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42362,\n                    \"Version\": 5,\n                    \"Guid\": \"83c25fc7-bf80-469f-8702-af1693158180\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Stream Name\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The Out-stream name on the query, usually \\\"Default\\\"</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42363,\n                    \"Version\": 3,\n                    \"Guid\": \"82b74d03-5fd8-42b1-8d38-e3a0ffb7a54c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42364,\n                    \"Version\": 1,\n                    \"Guid\": \"b7350212-ea1b-4c3a-adaa-9fc38d650265\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43002,\n                    \"Version\": 2,\n                    \"Guid\": \"008cc69c-bd91-4143-911a-b6cd3811f74c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Query\": {\n                          \"*\": \"System.QueryInfo\"\n                        },\n                        \"Separator\": {\n                          \"*\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"*\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"*\": \"QueryName=[Query]&StreamName=Default\"\n                        },\n                        \"Value\": {\n                          \"*\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableEdit\": {\n                          \"*\": false\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Value\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41712,\n                    \"Version\": 20,\n                    \"Guid\": \"d872b7c1-8902-4794-8bc1-65eb86855a20\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Value Field\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field of the items which will be stored as a value.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41717,\n                    \"Version\": 15,\n                    \"Guid\": \"18df3c8c-e0c3-4245-a21d-54282e4f4d0b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41718,\n                    \"Version\": 3,\n                    \"Guid\": \"9066a099-8063-4b0c-b386-2be00c737a57\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43000,\n                    \"Version\": 13,\n                    \"Guid\": \"a0b1a1dc-8878-49a6-b681-6505bfd3beb3\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.QueryInfo\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Attributes\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"QueryName=[Query]&StreamName=[StreamName]\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Label\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41713,\n                    \"Version\": 16,\n                    \"Guid\": \"5416a76a-99b7-4894-87c5-57e7b2834bc1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Label Field\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"The field which will be shown in the dropdown as the visible field for the user to select.\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41719,\n                    \"Version\": 14,\n                    \"Guid\": \"6088d6bb-0e91-4c32-9fe0-3e17bf458e74\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41720,\n                    \"Version\": 4,\n                    \"Guid\": \"3c39c80a-7d41-41c4-85c4-a622b546dbba\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43001,\n                    \"Version\": 10,\n                    \"Guid\": \"e23af53c-5b93-4dff-be00-26679e7387d8\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.QueryInfo\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Attributes\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"QueryName=[Query]&StreamName=[StreamName]\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MoreFields\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169126,\n                    \"Version\": 16,\n                    \"Guid\": \"b021c034-f018-4709-9ec0-99ad2d576f4f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"More Fields to retrieve (beta 15.04)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Additional fields can be used for tooltip, help or information.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"820ca909-c0d5-4905-9ba0-c0bc2ea8e506\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169127,\n                    \"Version\": 5,\n                    \"Guid\": \"ee679ab9-5f1f-4d64-a6b8-83c7b6de9719\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169128,\n                    \"Version\": 5,\n                    \"Guid\": \"e0fca792-aacc-47ef-8059-ad9f8536dee8\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.QueryInfo\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"QueryName=[Query]&StreamName=[StreamName]\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42570,\n                    \"Version\": 5,\n                    \"Guid\": \"f5cf7114-8285-4f91-9ac3-528e1ecd1429\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Advanced settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"In this section you can configure fairly advanced settings - use with care :)\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"33ca2eb9-b63c-48b5-bd81-ff32572e1ce1\",\n                            \"69cfc215-79f1-44ce-9e73-4c4e0b3e9694\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42571,\n                    \"Version\": 4,\n                    \"Guid\": \"44ebf48e-27af-4925-b870-685814c03f5b\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UrlParameters\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41711,\n                    \"Version\": 3,\n                    \"Guid\": \"051c2733-e788-4abf-8b70-b2a4b3bc92a6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Parameters\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If your query needs additional parameters in the URL, you can specify them here, in the same syntax as a url. For advanced scenarios you can also use field-names of this content-item to use as a query parameter.<br /><br /><strong>Examples</strong></p>\\n<ul>\\n<li>Category=27</li>\\n<li>Category=[Category]</li>\\n</ul>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41715,\n                    \"Version\": 2,\n                    \"Guid\": \"aa200ed5-1ae1-43a9-a27f-71795abe2095\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41716,\n                    \"Version\": 2,\n                    \"Guid\": \"ba52761a-4821-4852-9d5d-a4a081c311d7\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableTextEntry\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"c5825717-9c58-46d8-bafb-2bd8b3c2ec11\"\n                }\n              },\n              {\n                \"Name\": \"GroupUiFeatures\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 56931,\n                    \"Version\": 5,\n                    \"Guid\": \"2688bd00-2751-4025-94bd-dd7f76f4f716\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"UI Features of the Entity Picker\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"d25b73e0-faeb-454a-88e4-d929ba4abbb0\",\n                            \"a30c6445-4f7a-4f3f-8602-be7cd690f9a7\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 56934,\n                    \"Version\": 4,\n                    \"Guid\": \"24468710-9391-4210-9032-a7e5c3376cec\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableEdit\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"f09fbd6a-ba83-4023-a5b4-b82b6ef7e9ff\"\n                }\n              },\n              {\n                \"Name\": \"EnableRemove\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"9f51cb28-eab4-4eb6-9b44-6246b55a7a52\"\n                }\n              },\n              {\n                \"Name\": \"GroupMultiSelect\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42568,\n                    \"Version\": 5,\n                    \"Guid\": \"9756cd4e-5078-4276-873d-b96d1a00ba2b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Multi-Select Options\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Use these if you want to enable selecting multiple items\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"3ee655c2-17ec-4c7c-99d9-17e265fb2a07\",\n                            \"5a5ab2d8-4b48-4b20-9323-fe2ac96d45a3\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42569,\n                    \"Version\": 4,\n                    \"Guid\": \"32845684-2e3b-40a1-8140-fb2cc76b7613\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowMultiValue\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"faf06aa8-73cc-4cb0-baa5-da7a9e5d2203\"\n                }\n              },\n              {\n                \"Name\": \"Separator\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 42562,\n                    \"Version\": 7,\n                    \"Guid\": \"2671d0ea-9743-4503-920f-75470645dc9c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \",\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Separator\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If you want to support selecting multiple items, you'll need something to keep them separate. We recommend a comma, but maybe you want something different.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42563,\n                    \"Version\": 5,\n                    \"Guid\": \"160b7a1c-33db-46f1-a1b3-ef9892d30ec2\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42564,\n                    \"Version\": 2,\n                    \"Guid\": \"4a5500f2-d9ba-4ec6-9d8a-d7ccc0d67130\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 43003,\n                    \"Version\": 3,\n                    \"Guid\": \"dcecf7b1-4dbe-487c-ba0d-386da72b81d1\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \",\\n|\\n-\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130148,\n              \"Version\": 3,\n              \"Guid\": \"d84e7112-a89e-42d9-b966-a42af0cc077d\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {  return !!data.Query; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show once query is selected\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 169144,\n              \"Version\": 2,\n              \"Guid\": \"820ca909-c0d5-4905-9ba0-c0bc2ea8e506\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return context.debug; });\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130140,\n              \"Version\": 3,\n              \"Guid\": \"33ca2eb9-b63c-48b5-bd81-ff32572e1ce1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  return !!data.Query && !!data.StreamName;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide if query not set\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130425,\n              \"Version\": 2,\n              \"Guid\": \"69cfc215-79f1-44ce-9e73-4c4e0b3e9694\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.default + (data.UrlParameters ? ' ✅ (' + data.UrlParameters + ')' : ''); }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name: Show if something is configured\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130141,\n              \"Version\": 4,\n              \"Guid\": \"d25b73e0-faeb-454a-88e4-d929ba4abbb0\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!data.Query && !!data.StreamName; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide if query missing\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130427,\n              \"Version\": 1,\n              \"Guid\": \"a30c6445-4f7a-4f3f-8602-be7cd690f9a7\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.default + (data.EnableEdit || data.EnableRemove ? ' ✅' : ''); }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130142,\n              \"Version\": 3,\n              \"Guid\": \"3ee655c2-17ec-4c7c-99d9-17e265fb2a07\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return !!data.Query && !!data.StreamName; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide if query missing\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130426,\n              \"Version\": 2,\n              \"Guid\": \"5a5ab2d8-4b48-4b20-9323-fe2ac96d45a3\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.default + (data.AllowMultiValue ? ' ✅' : ''); }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name: if enabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@string-font-icon-picker\",\n            \"Name\": \"@string-font-icon-picker\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53711,\n                \"Version\": 1,\n                \"Guid\": \"1b956963-9c77-4c80-b525-60303138a108\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configure a font-icon picker\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Font-Icon Picker\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-font-icon-picker\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"CssPrefix\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41670,\n                    \"Version\": 3,\n                    \"Guid\": \"239d85c3-9d9c-43a5-963b-64188158b165\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \".icon-sxc\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Css Prefix\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The beginning of the CSS-information used to identify an&nbsp;icon - is used to find all classes that start with this. Common examples are \\\".icon-something-\\\"). find out more on <a href=\\\"//2sxc.org/help?tag=font-icon\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc.org/help?tag=font-icon</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41671,\n                    \"Version\": 3,\n                    \"Guid\": \"24e3cb2c-7c34-4da8-9ce7-66af403df526\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77268,\n                    \"Version\": 1,\n                    \"Guid\": \"a2308d31-ad20-4a4c-b790-af298a4699a1\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PreviewCss\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41672,\n                    \"Version\": 3,\n                    \"Guid\": \"a530f53e-b6fb-4804-b486-7c09116d86ab\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Preview Css Classes\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Additional CSS classes to apply to the preview tags. Leave blank for modern solutions like fontello, add the appropriate additonal classes like \\\"fa\\\" for font-awesome or \\\"glyphicons\\\" for glyphicons. find out more on <a href=\\\"//2sxc.org/help?tag=font-icon\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc.org/help?tag=font-icon</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41673,\n                    \"Version\": 3,\n                    \"Guid\": \"facbd263-8640-43cf-8e2d-33883b6e2b8a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77269,\n                    \"Version\": 1,\n                    \"Guid\": \"8bf516fb-16c3-4d6e-9775-849ffaf5321d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Files\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41674,\n                    \"Version\": 5,\n                    \"Guid\": \"c3d8fa4a-46d8-4df4-b7f6-7a14a4f0c029\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"[App:Path]/dist/custom-icons.css\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Files\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Files to load in this dialog - usually the list of CSS-files which would contain icon-definitions. You can also use the placeholder [App:Path] to inject the app, path, like&nbsp;<em>[App:Path]/dist/custom-icons.css</em>.</p>\\n<p>Remember that these styles will also affect the styling of the entire form, so&nbsp;try to include files which only include the icon-definitions. You could also create separate icon-definition files just for this icon picker.&nbsp; find out more on <a href=\\\"//2sxc.org/help?tag=font-icon\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc.org/help?tag=font-icon</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41675,\n                    \"Version\": 5,\n                    \"Guid\": \"df180d90-cb2b-49aa-99a3-ac05f2c14790\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": -1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77270,\n                    \"Version\": 3,\n                    \"Guid\": \"c8fcf7b4-e274-49a5-9296-f95a38c9d0a1\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ShowPrefix\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 77271,\n                    \"Version\": 3,\n                    \"Guid\": \"4d22a34d-58af-4773-bbb3-c435478f595d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Show Prefix\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Show or hide the prefix in the dropdown (like <strong>fa-</strong> in font-awesome)</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77272,\n                    \"Version\": 2,\n                    \"Guid\": \"5746d2c1-cc44-4852-816e-5b3b38c4320b\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Icon prefix is hidden\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"Icon prefix is default (hidden)\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Icon prefix is visible\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"88d60bbc-cc2a-4ef8-b430-ed41e3012240\",\n            \"Name\": \"UiPickerSourceCustomList\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 182278,\n                \"Version\": 1,\n                \"Guid\": \"0a97d73c-3fa8-4536-8d9d-01a78f407622\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Create a custom list of values to pick from, optionally with a different label.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"UI Picker Source - Custom List of Values\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"88d60bbc-cc2a-4ef8-b430-ed41e3012240\"\n                }\n              },\n              {\n                \"Id\": 183925,\n                \"Version\": 1,\n                \"Guid\": \"93e2a4c2-d2df-4c99-97b9-591b15e21346\",\n                \"Type\": {\n                  \"Id\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\",\n                  \"Name\": \"IsPickerSourceDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"88d60bbc-cc2a-4ef8-b430-ed41e3012240\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182272,\n                    \"Version\": 2,\n                    \"Guid\": \"4180a3c2-b1c1-45bd-b03f-b52c7035df8b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"List of Values for Picker\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Just a name so you can identify this picker source if you ever want to re-use it.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182274,\n                    \"Version\": 1,\n                    \"Guid\": \"ff99123e-0d78-49ef-a0c3-b702196e4322\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182275,\n                    \"Version\": 1,\n                    \"Guid\": \"e6224e79-15ec-46dc-860e-ef7dd0c852a3\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescription\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0046b3fd-b3ee-47ee-be29-1f0df071069a\"\n                }\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"970d9f99-9fc7-4ebb-b5c3-8ce1518a0bce\"\n                }\n              },\n              {\n                \"Name\": \"GroupDescriptionEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"ee7ba734-558a-4362-85a5-8ee9421b6118\"\n                }\n              },\n              {\n                \"Name\": \"Values\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182273,\n                    \"Version\": 3,\n                    \"Guid\": \"3e867069-68e0-4043-9297-0342592d5baa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Value without extra label\\nl:Left (will store an l)\\nr:Right (will store an r)\\nc:Center (... c)\\nm:Middle\\n27:Twenty Seven\\nrandom:Random value\\nMIT:MIT License\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Values\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Type in the values, one per line and separate values and labels with a \\\":\\\".- see <a href=\\\"https://docs.2sxc.org/basics/data/fields/string-dropdown.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182276,\n                    \"Version\": 2,\n                    \"Guid\": \"4a3a6cc6-a550-4828-acdd-cf9853838a21\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182277,\n                    \"Version\": 2,\n                    \"Guid\": \"d66b7475-2391-4565-92ff-c9e065d3bb7f\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupItemHelp\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"ea9c3f94-578f-4c5f-b721-767f38fea57d\"\n                }\n              },\n              {\n                \"Name\": \"MessageItemString\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183854,\n                    \"Version\": 2,\n                    \"Guid\": \"07155dba-0fb7-4bf6-8017-3fbdd3813049\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MessageItemString\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>For custom lists such as this one, the placeholders you can use are limited to the following:</p>\\n<ul>\\n<li>[Item:Value]</li>\\n<li>[Item:Title]</li>\\n</ul>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupHelpMessageUnlicensed\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"effab828-3273-497a-a7af-b93741fa25d5\"\n                }\n              },\n              {\n                \"Name\": \"ItemTooltip\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"49d939a6-b45c-405b-98e9-b7ee38a9c68a\"\n                }\n              },\n              {\n                \"Name\": \"ItemInformation\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"2cd90609-840f-4ccf-aed6-8c6e39ea067e\"\n                }\n              },\n              {\n                \"Name\": \"ItemLink\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"8a7dcb9e-f47b-4518-9519-f66db95f195e\"\n                }\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"f11f79a2-186b-49ec-89d6-be260698e371\",\n            \"Name\": \"UiPickerSourceEntity\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 182309,\n                \"Version\": 2,\n                \"Guid\": \"094a53b8-194c-4b6c-a076-89f883069af4\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Pick entities of a specific type.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"UI Picker Source - Entities\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"f11f79a2-186b-49ec-89d6-be260698e371\"\n                }\n              },\n              {\n                \"Id\": 183926,\n                \"Version\": 1,\n                \"Guid\": \"c4758063-0042-4f86-a3b5-ceb81d2bdea7\",\n                \"Type\": {\n                  \"Id\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\",\n                  \"Name\": \"IsPickerSourceDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"f11f79a2-186b-49ec-89d6-be260698e371\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182310,\n                    \"Version\": 2,\n                    \"Guid\": \"4c9d8eb7-248c-48e2-9bb7-c0e4860a0e04\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Picker Source - Entity\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>A title for you to identify this configuration in case you want to reuse it.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182311,\n                    \"Version\": 1,\n                    \"Guid\": \"d59fddb3-2ab0-4701-bb54-46df0dd5dca7\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182312,\n                    \"Version\": 1,\n                    \"Guid\": \"3a34dd00-ccc1-47d0-81e7-593f78d56b14\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescription\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0046b3fd-b3ee-47ee-be29-1f0df071069a\"\n                }\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"970d9f99-9fc7-4ebb-b5c3-8ce1518a0bce\"\n                }\n              },\n              {\n                \"Name\": \"GroupSettings\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183731,\n                    \"Version\": 3,\n                    \"Guid\": \"6c2a9dcd-553d-4cda-a4e7-7d987ada542b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"111ec6b8-449d-4dcb-ba53-4ca19a3a71f2\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183732,\n                    \"Version\": 1,\n                    \"Guid\": \"ce269ec9-6aec-4b1b-a3dd-07208d237dbc\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypeNames\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182565,\n                    \"Version\": 10,\n                    \"Guid\": \"4bedd5b6-2746-481f-b87b-b5eab5bf8915\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Types\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>One or more Content-Types to retrieve from the backend.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182566,\n                    \"Version\": 5,\n                    \"Guid\": \"6a0fdee0-5cc0-45c4-8e69-aabffd833083\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182567,\n                    \"Version\": 5,\n                    \"Guid\": \"a9dbc986-5ccd-453b-8f97-4d7ca812611c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"NameId\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183981,\n                    \"Version\": 3,\n                    \"Guid\": \"bb1f88da-de95-458d-934a-b186bcd3dec3\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"39620e8d-dce6-4d8b-90e8-4ac4ec4ddde1\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Number\": {\n                        \"AllowMultiMin\": {\n                          \"en-us\": 1\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183741,\n                    \"Version\": 4,\n                    \"Guid\": \"b35c7951-5585-4ee4-95da-3d52363f9f34\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"1734005c-1a57-4fa5-9113-73b5543bf6f6\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183750,\n                    \"Version\": 2,\n                    \"Guid\": \"ad93d564-782e-4c34-9cc4-18bbcec5c017\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CreateTypes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"3329843f-be88-47d2-a2c1-3c16724081d7\"\n                }\n              },\n              {\n                \"Name\": \"Value\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183742,\n                    \"Version\": 8,\n                    \"Guid\": \"cbaca63b-3042-48ed-b775-e144a3e39b89\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Guid\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Value\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field of the items which will be stored as a value.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183746,\n                    \"Version\": 6,\n                    \"Guid\": \"ee24debb-8866-4141-9b2e-8d3ac5045b33\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"0ff39e34-cee6-4ac1-b188-d6fbc6f0952d\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Label\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183743,\n                    \"Version\": 5,\n                    \"Guid\": \"44b2d850-5573-4fd3-8208-27e1b715c7c6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Label\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field which will be shown in the dropdown as the visible field for the user to select.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183747,\n                    \"Version\": 3,\n                    \"Guid\": \"cb82336a-0162-4418-a86c-a9eaf31afe3d\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"0ff39e34-cee6-4ac1-b188-d6fbc6f0952d\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MoreFields\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183692,\n                    \"Version\": 5,\n                    \"Guid\": \"b3a09f61-9df3-4bae-a8e1-cef9cd07b89e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"More Fields\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Additional fields can be used for tooltip, help or information.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183693,\n                    \"Version\": 1,\n                    \"Guid\": \"280a6f1f-5be9-4292-ab72-e2d819fc8279\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183748,\n                    \"Version\": 1,\n                    \"Guid\": \"8d2ce3c6-21d6-4b29-9f41-b9f4eb425e48\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"0ff39e34-cee6-4ac1-b188-d6fbc6f0952d\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupItemHelp\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"ea9c3f94-578f-4c5f-b721-767f38fea57d\"\n                }\n              },\n              {\n                \"Name\": \"GroupHelpMessageUnlicensed\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"effab828-3273-497a-a7af-b93741fa25d5\"\n                }\n              },\n              {\n                \"Name\": \"ItemTooltip\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"49d939a6-b45c-405b-98e9-b7ee38a9c68a\"\n                }\n              },\n              {\n                \"Name\": \"ItemInformation\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"2cd90609-840f-4ccf-aed6-8c6e39ea067e\"\n                }\n              },\n              {\n                \"Name\": \"ItemLink\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"8a7dcb9e-f47b-4518-9519-f66db95f195e\"\n                }\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183733,\n              \"Version\": 3,\n              \"Guid\": \"111ec6b8-449d-4dcb-ba53-4ca19a3a71f2\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return !!data.Title; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183749,\n              \"Version\": 1,\n              \"Guid\": \"1734005c-1a57-4fa5-9113-73b5543bf6f6\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return !!data.ContentTypeNames; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183744,\n              \"Version\": 3,\n              \"Guid\": \"0ff39e34-cee6-4ac1-b188-d6fbc6f0952d\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"<p>Will get the attributes for an Entity Picker.</p>\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Title\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.Attributes\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"ContentTypeName=[ContentTypeNames]\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Attributes for EntityPicker\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n            \"Name\": \"UiPickerSourceQuery\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 182308,\n                \"Version\": 1,\n                \"Guid\": \"67bd7eba-2ba9-4a8f-a505-58c0a2acb707\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure what query to use to get values to pick from.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"UI Picker Source - Query\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\"\n                }\n              },\n              {\n                \"Id\": 183927,\n                \"Version\": 1,\n                \"Guid\": \"58e60d38-d414-4658-accb-7c9466f52112\",\n                \"Type\": {\n                  \"Id\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\",\n                  \"Name\": \"IsPickerSourceDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182279,\n                    \"Version\": 2,\n                    \"Guid\": \"2cf607d1-1da7-4bc7-9c7f-7f1fb4fa2846\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Data from Query\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>A title to identify this configuration, in case you want to reuse it.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182306,\n                    \"Version\": 1,\n                    \"Guid\": \"239def94-12ac-4d8d-b2fb-a1f7ecdad607\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182307,\n                    \"Version\": 1,\n                    \"Guid\": \"20e3cebd-da40-499f-91ef-917e90850877\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescription\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0046b3fd-b3ee-47ee-be29-1f0df071069a\"\n                }\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"970d9f99-9fc7-4ebb-b5c3-8ce1518a0bce\"\n                }\n              },\n              {\n                \"Name\": \"GroupDescriptionEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"ee7ba734-558a-4362-85a5-8ee9421b6118\"\n                }\n              },\n              {\n                \"Name\": \"Query\",\n                \"Guid\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182280,\n                    \"Version\": 4,\n                    \"Guid\": \"578596e0-a154-4f72-925a-017e46d20d16\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Query\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Pick the query which would be used to prepare the items a user can select. For very advanced scenarios you can also manually enter a special query.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182291,\n                    \"Version\": 1,\n                    \"Guid\": \"dd93df45-8aff-4c02-ab4c-8114c9b2c78c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182292,\n                    \"Version\": 1,\n                    \"Guid\": \"c37ee3ca-4986-457f-b7d4-b6efc6a185a9\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Queries\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183974,\n                    \"Version\": 1,\n                    \"Guid\": \"d2aa9ceb-d0c6-4b90-b306-051cc4d26021\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"b96f7282-a854-4fa1-a091-9d18406bd2f9\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupMore\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182281,\n                    \"Version\": 3,\n                    \"Guid\": \"6598c731-836d-4e84-a957-f1fc22bb8442\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"More Settings eg. Different Value or Label\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"1a4863ce-fbb2-4c0b-a231-7ac719a619d8\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182293,\n                    \"Version\": 1,\n                    \"Guid\": \"c554a575-5e05-4430-9838-ba7863256ae0\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"StreamName\",\n                \"Guid\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182282,\n                    \"Version\": 6,\n                    \"Guid\": \"6025db5b-75e4-491f-9045-55224f31c6e8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"StreamName\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The Out-stream name on the query, usually \\\"Default\\\"</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182294,\n                    \"Version\": 2,\n                    \"Guid\": \"e1ac07ed-0396-4fa1-b99c-184efae2361b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182295,\n                    \"Version\": 3,\n                    \"Guid\": \"9d2ac197-62c4-4204-9c1b-bf0b0640ab43\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.QueryInfo\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"QueryName=[Query]&StreamName=Default\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Name\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183978,\n                    \"Version\": 1,\n                    \"Guid\": \"ecebbf4b-456b-435b-a805-2b3d0af8bf0b\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"eeaf0098-2cf7-4201-bb1d-a405717e9752\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Value\",\n                \"Guid\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182283,\n                    \"Version\": 8,\n                    \"Guid\": \"02109e16-a6ae-485f-ac61-81ac334cf81c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Value Field\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field of the items which will be stored as a value.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182296,\n                    \"Version\": 2,\n                    \"Guid\": \"1f2555e7-4af1-45d9-8219-91e4ae469066\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183968,\n                    \"Version\": 1,\n                    \"Guid\": \"d2f6e7f4-1ff9-44a0-babd-fee419272d5e\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"839f7aef-a5f2-4fa2-8065-30eb78e267ac\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Label\",\n                \"Guid\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182284,\n                    \"Version\": 6,\n                    \"Guid\": \"249b749f-ffe7-4448-b72e-5dca775fc828\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Label Field\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field which will be shown in the dropdown as the visible field for the user to select.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182298,\n                    \"Version\": 2,\n                    \"Guid\": \"7f0cd9b5-a673-444b-b203-6ec668be0048\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183969,\n                    \"Version\": 1,\n                    \"Guid\": \"c101c26e-b759-4256-987b-c6a712b8106f\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"839f7aef-a5f2-4fa2-8065-30eb78e267ac\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MoreFields\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182285,\n                    \"Version\": 8,\n                    \"Guid\": \"903997e4-8cdd-4503-8f3d-89546aef391f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"More Fields to retrieve\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Additional fields can be used for tooltip, help or information.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182300,\n                    \"Version\": 2,\n                    \"Guid\": \"0b254a51-48b0-45ed-bf93-3a720d00b112\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183970,\n                    \"Version\": 1,\n                    \"Guid\": \"dd1992f9-a98d-4e6d-9502-40466cc023b4\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"839f7aef-a5f2-4fa2-8065-30eb78e267ac\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182286,\n                    \"Version\": 4,\n                    \"Guid\": \"a9b8afcd-5819-4c26-aeb4-34b91fcc73c1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"2c7c12f3-70a5-461b-b17d-b56211ec0dfc\",\n                            \"f8a03d2b-9396-4f89-8111-e845946bee22\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183738,\n                    \"Version\": 1,\n                    \"Guid\": \"1f5c321b-39ae-47b6-9780-5f213c55f723\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"QueryParameters\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182287,\n                    \"Version\": 1,\n                    \"Guid\": \"3dbff41e-7b12-4ffb-a83f-2ec9a440d9db\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"QueryParameters\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CreateTypes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"3329843f-be88-47d2-a2c1-3c16724081d7\"\n                }\n              },\n              {\n                \"Name\": \"GroupItemHelp\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"ea9c3f94-578f-4c5f-b721-767f38fea57d\"\n                }\n              },\n              {\n                \"Name\": \"GroupHelpMessageUnlicensed\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"effab828-3273-497a-a7af-b93741fa25d5\"\n                }\n              },\n              {\n                \"Name\": \"ItemTooltip\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"49d939a6-b45c-405b-98e9-b7ee38a9c68a\"\n                }\n              },\n              {\n                \"Name\": \"ItemInformation\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"2cd90609-840f-4ccf-aed6-8c6e39ea067e\"\n                }\n              },\n              {\n                \"Name\": \"ItemLink\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"8a7dcb9e-f47b-4518-9519-f66db95f195e\"\n                }\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183972,\n              \"Version\": 1,\n              \"Guid\": \"b96f7282-a854-4fa1-a091-9d18406bd2f9\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Title]</p>\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Name\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.Queries\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Query - Query Picker\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182304,\n              \"Version\": 1,\n              \"Guid\": \"1a4863ce-fbb2-4c0b-a231-7ac719a619d8\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return !!data.Query; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183975,\n              \"Version\": 5,\n              \"Guid\": \"eeaf0098-2cf7-4201-bb1d-a405717e9752\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Name\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.QueryInfo\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"QueryName=[Query]&StreamName=Default&[QueryParameters]\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Query - StreamName\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183964,\n              \"Version\": 5,\n              \"Guid\": \"839f7aef-a5f2-4fa2-8065-30eb78e267ac\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Description]</p>\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Title\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.QueryInfo\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"QueryName=[Query]&StreamName=[StreamName]&[QueryParameters]\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Attributes\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Attributes for System.Query using QueryInfo\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183976,\n              \"Version\": 3,\n              \"Guid\": \"2c7c12f3-70a5-461b-b17d-b56211ec0dfc\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const params = data.QueryParameters;\\n  return data.default + (params ? ' ✅ (' + params + ')' : '');\\n})\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182305,\n              \"Version\": 2,\n              \"Guid\": \"f8a03d2b-9396-4f89-8111-e845946bee22\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return !!data.Query && !!data.StreamName; });\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"6fa7f390-7612-40c6-baff-2bcf6140a85f\",\n            \"Name\": \"@entity-picker\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 182380,\n                \"Version\": 10,\n                \"Guid\": \"cf832332-5f70-40af-ad1f-4399f294ac42\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure a Item (Entity) Picker. This is a new concept which is still in BETA ⚠️, so it may still change a bit.&nbsp;</p>\\n<p>The core idea is that you separate the UI (this configuration) from the Source Definition (see Source below). The Source can be reused in other pickers, and it allows many more features then were possible before.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Data Picker for Entity Field\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"6fa7f390-7612-40c6-baff-2bcf6140a85f\"\n                }\n              },\n              {\n                \"Id\": 182665,\n                \"Version\": 10,\n                \"Guid\": \"73bf2a9b-6d4c-4987-96d8-d421c586a888\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"ConfigTypes\": {\n                      \"en-us\": \"@All,@entity-picker\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"Item Picker for Entities (new v19)\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Data Picker Entity (new v19)\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"@entity-picker\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": true\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"6fa7f390-7612-40c6-baff-2bcf6140a85f\"\n                }\n              },\n              {\n                \"Id\": 184123,\n                \"Version\": 1,\n                \"Guid\": \"fe3b9d97-1076-4860-ad7f-7c80008428e7\",\n                \"Type\": {\n                  \"Id\": \"c740085a-d548-41f3-8d06-0a48b8692345\",\n                  \"Name\": \"IsRecommendedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Message\": {\n                      \"en-us\": \"new v19\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"6fa7f390-7612-40c6-baff-2bcf6140a85f\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"DataSources\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"5f7a115f-d935-4c77-8fc1-69024dd3828a\"\n                }\n              },\n              {\n                \"Name\": \"GroupUiFeatures\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": true,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"f786e83a-12b8-4c76-8593-cc84e385ff1b\"\n                }\n              },\n              {\n                \"Name\": \"EnableEdit\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"f09fbd6a-ba83-4023-a5b4-b82b6ef7e9ff\"\n                }\n              },\n              {\n                \"Name\": \"EnableCreate\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"916b17c1-f15d-4414-80e5-6d53b27ff463\"\n                }\n              },\n              {\n                \"Name\": \"EnableAddExisting\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0fc6d925-77df-4ccc-80dd-5d9ddaf003c9\"\n                }\n              },\n              {\n                \"Name\": \"EnableRemove\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"9f51cb28-eab4-4eb6-9b44-6246b55a7a52\"\n                }\n              },\n              {\n                \"Name\": \"EnableDelete\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"4274d627-fc80-412e-ad34-fa9ed21c6ba6\"\n                }\n              },\n              {\n                \"Name\": \"GroupMultiValue\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"3dcbb74e-44bc-4bb3-83c0-ac8243190696\"\n                }\n              },\n              {\n                \"Name\": \"AllowMultiValue\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"faf06aa8-73cc-4cb0-baa5-da7a9e5d2203\"\n                }\n              },\n              {\n                \"Name\": \"EnableReselect\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"6bb3b9ac-0008-477e-825c-7ce8f57e910d\"\n                }\n              },\n              {\n                \"Name\": \"AllowMultiMin\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"41f9d742-66fd-4729-8687-c9648d76d33a\"\n                }\n              },\n              {\n                \"Name\": \"AllowMultiMax\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"65e8eeaa-4914-449e-816d-31185f54e406\"\n                }\n              },\n              {\n                \"Name\": \"GroupDisplay\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"7c7c7fe3-57be-4d2f-9767-a0f3e3944bf1\"\n                }\n              },\n              {\n                \"Name\": \"PickerDisplayMode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"16057c04-0f49-4bd2-96e7-97d13bf3f8f5\"\n                }\n              },\n              {\n                \"Name\": \"PickerDisplayConfiguration\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"879356b3-0579-4fa1-b973-95c1b543c9db\"\n                }\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"bc89498a-6a98-4d7c-994f-4c04b8930154\"\n                }\n              },\n              {\n                \"Name\": \"CreatePrefill\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"594d3edf-5501-4ee5-8271-d216ceefac08\"\n                }\n              },\n              {\n                \"Name\": \"CreateParameters\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"c21252f1-6d64-4b59-91e0-5ce5a80c7bd4\"\n                }\n              },\n              {\n                \"Name\": \"EditParameters\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"46cb9c49-a1c8-4b5a-affe-32a7f6732dbd\"\n                }\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"2421dded-3aeb-47d2-ab9d-e2b72a2d821d\",\n            \"Name\": \"@number-picker\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 182381,\n                \"Version\": 8,\n                \"Guid\": \"df9485fb-10f6-4c1e-a19e-84b47b68955b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure a Number Picker. This is a new concept which is still in BETA ⚠️, so it may still change a bit.&nbsp;</p>\\n<p>The core idea is that you separate the UI (this configuration) from the Source Definition (see Source below). The Source can be reused in other pickers, and it allows many more features then were possible before.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Data Picker for Number Field\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"2421dded-3aeb-47d2-ab9d-e2b72a2d821d\"\n                }\n              },\n              {\n                \"Id\": 183771,\n                \"Version\": 3,\n                \"Guid\": \"65054dae-9f44-49cd-912f-4786bccabe04\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"ConfigTypes\": {\n                      \"en-us\": \"@All,@number-picker\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"Data Picker Number (new v19)\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Data Picker Number (new v19)\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"@number-picker\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": false\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"2421dded-3aeb-47d2-ab9d-e2b72a2d821d\"\n                }\n              },\n              {\n                \"Id\": 184124,\n                \"Version\": 1,\n                \"Guid\": \"1bdf0ff1-be37-40e1-b9c3-f3b4d6c062d9\",\n                \"Type\": {\n                  \"Id\": \"c740085a-d548-41f3-8d06-0a48b8692345\",\n                  \"Name\": \"IsRecommendedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Message\": {\n                      \"en-us\": \"new v19\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"2421dded-3aeb-47d2-ab9d-e2b72a2d821d\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"DataSources\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-picker\",\n                \"IsTitle\": true,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"5f7a115f-d935-4c77-8fc1-69024dd3828a\"\n                }\n              },\n              {\n                \"Name\": \"EnableTextEntry\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"c5825717-9c58-46d8-bafb-2bd8b3c2ec11\"\n                }\n              },\n              {\n                \"Name\": \"GroupDisplay\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"7c7c7fe3-57be-4d2f-9767-a0f3e3944bf1\"\n                }\n              },\n              {\n                \"Name\": \"PickerDisplayMode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"16057c04-0f49-4bd2-96e7-97d13bf3f8f5\"\n                }\n              },\n              {\n                \"Name\": \"PickerDisplayConfiguration\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"879356b3-0579-4fa1-b973-95c1b543c9db\"\n                }\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n            \"Name\": \"@string-picker\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 182382,\n                \"Version\": 8,\n                \"Guid\": \"dba24477-2502-42c2-8437-4c16934b9f5e\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure a String Picker. This is a new concept which is still in BETA ⚠️, so it may still change a bit.&nbsp;</p>\\n<p>The core idea is that you separate the UI (this configuration) from the Source Definition (see Source below). The Source can be reused in other pickers, and it allows many more features then were possible before.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Data Picker for Text/String Field\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"e64dd20e-0055-4410-87a1-1238fe44707f\"\n                }\n              },\n              {\n                \"Id\": 182573,\n                \"Version\": 7,\n                \"Guid\": \"ba6ce128-0a51-4047-8a40-bfff27658476\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"ConfigTypes\": {\n                      \"en-us\": \"@All,@string-picker\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"Data Picker for Text/String Field (new v19)\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Data Picker String (new v19)\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"@string-picker\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": false\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"e64dd20e-0055-4410-87a1-1238fe44707f\"\n                }\n              },\n              {\n                \"Id\": 184125,\n                \"Version\": 1,\n                \"Guid\": \"dce429d6-5813-435d-b46c-fb6d2ca6902d\",\n                \"Type\": {\n                  \"Id\": \"c740085a-d548-41f3-8d06-0a48b8692345\",\n                  \"Name\": \"IsRecommendedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Message\": {\n                      \"en-us\": \"new v19\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"e64dd20e-0055-4410-87a1-1238fe44707f\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"DataSources\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-picker\",\n                \"IsTitle\": true,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"5f7a115f-d935-4c77-8fc1-69024dd3828a\"\n                }\n              },\n              {\n                \"Name\": \"GroupUiFeatures\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"f786e83a-12b8-4c76-8593-cc84e385ff1b\"\n                }\n              },\n              {\n                \"Name\": \"EnableEdit\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"f09fbd6a-ba83-4023-a5b4-b82b6ef7e9ff\"\n                }\n              },\n              {\n                \"Name\": \"EnableCreate\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"916b17c1-f15d-4414-80e5-6d53b27ff463\"\n                }\n              },\n              {\n                \"Name\": \"EnableAddExisting\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0fc6d925-77df-4ccc-80dd-5d9ddaf003c9\"\n                }\n              },\n              {\n                \"Name\": \"EnableRemove\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"9f51cb28-eab4-4eb6-9b44-6246b55a7a52\"\n                }\n              },\n              {\n                \"Name\": \"EnableTextEntry\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"c5825717-9c58-46d8-bafb-2bd8b3c2ec11\"\n                }\n              },\n              {\n                \"Name\": \"GroupMultiSelect\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"3dcbb74e-44bc-4bb3-83c0-ac8243190696\"\n                }\n              },\n              {\n                \"Name\": \"AllowMultiValue\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"faf06aa8-73cc-4cb0-baa5-da7a9e5d2203\"\n                }\n              },\n              {\n                \"Name\": \"EnableReselect\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"6bb3b9ac-0008-477e-825c-7ce8f57e910d\"\n                }\n              },\n              {\n                \"Name\": \"Separator\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"844c1c0b-09c7-46b3-8541-e9eef134cd69\"\n                }\n              },\n              {\n                \"Name\": \"AllowMultiMin\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"41f9d742-66fd-4729-8687-c9648d76d33a\"\n                }\n              },\n              {\n                \"Name\": \"AllowMultiMax\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"65e8eeaa-4914-449e-816d-31185f54e406\"\n                }\n              },\n              {\n                \"Name\": \"GroupDisplay\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"7c7c7fe3-57be-4d2f-9767-a0f3e3944bf1\"\n                }\n              },\n              {\n                \"Name\": \"PickerDisplayMode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"16057c04-0f49-4bd2-96e7-97d13bf3f8f5\"\n                }\n              },\n              {\n                \"Name\": \"PickerDisplayConfiguration\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"879356b3-0579-4fa1-b973-95c1b543c9db\"\n                }\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"bc89498a-6a98-4d7c-994f-4c04b8930154\"\n                }\n              },\n              {\n                \"Name\": \"CreatePrefill\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"594d3edf-5501-4ee5-8271-d216ceefac08\"\n                }\n              },\n              {\n                \"Name\": \"CreateParameters\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"c21252f1-6d64-4b59-91e0-5ce5a80c7bd4\"\n                }\n              },\n              {\n                \"Name\": \"EditParameters\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"46cb9c49-a1c8-4b5a-affe-32a7f6732dbd\"\n                }\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"590d5961-c2d5-4f50-867a-5c609dd820c8\",\n            \"Name\": \"UiPickerModeTree\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182383,\n                    \"Version\": 2,\n                    \"Guid\": \"aed1fe52-d2f6-40c5-8bf4-6201190d61d4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Tree Picker Configuration\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>A title for this configuration, in case you want to reuse it.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182428,\n                    \"Version\": 1,\n                    \"Guid\": \"3cefd25a-0f43-4f05-a74b-7bd30848cb07\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182429,\n                    \"Version\": 1,\n                    \"Guid\": \"28f9ce11-a89e-4bb7-98d9-3b95790c76a3\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupRelationships\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182393,\n                    \"Version\": 1,\n                    \"Guid\": \"eae9f1e9-828d-422b-ac84-499fb1f95762\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupRelationships\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeRelationship\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182384,\n                    \"Version\": 2,\n                    \"Guid\": \"e2541b5c-45d3-4667-972b-60e7081215f4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"child-parent\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeRelationship\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182391,\n                    \"Version\": 1,\n                    \"Guid\": \"7d609426-ef83-4e01-b6e8-5b23a8d9fd42\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182392,\n                    \"Version\": 1,\n                    \"Guid\": \"35601351-aee0-4b67-aaf9-5099fb98c5b2\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"child-parent:Child has reference to Parent\\nparent-child:Parent has references to Children\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeBranchesStream\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182397,\n                    \"Version\": 2,\n                    \"Guid\": \"b765d306-2e2c-4217-a839-505e789e75eb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeBranchStream\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Which stream in the source should be used for branches / folders. Most sources only have a&nbsp;<em>Default.</em></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182399,\n                    \"Version\": 1,\n                    \"Guid\": \"2a1880ed-ddfc-4f0d-913e-23dbdbcbbbda\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182400,\n                    \"Version\": 1,\n                    \"Guid\": \"e48971da-addb-4731-a2ca-fe2f00836c7e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeLeavesStream\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182398,\n                    \"Version\": 3,\n                    \"Guid\": \"1e202275-a3a1-4c43-b339-c4090a9f7605\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeLeavesStream\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Which stream in the source should be used for leaves / files / lost-levers. Most sources only have a&nbsp;<em>Default.</em></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182401,\n                    \"Version\": 2,\n                    \"Guid\": \"cb33526c-69ff-416e-816f-6f7c66d5c23a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182402,\n                    \"Version\": 2,\n                    \"Guid\": \"62e139ef-f766-4e06-b635-3b336cd8c205\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeParentIdField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182385,\n                    \"Version\": 3,\n                    \"Guid\": \"d599da31-120a-4d4f-a444-db12a830ba85\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Id\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeParentIdField\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field on the parent which identifies it. Typically Id.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182395,\n                    \"Version\": 2,\n                    \"Guid\": \"55cd0993-3be4-4994-ba3c-d667046fb389\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182396,\n                    \"Version\": 2,\n                    \"Guid\": \"58c71cbf-bed2-4318-931d-075c2e1de13e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeChildIdField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182386,\n                    \"Version\": 3,\n                    \"Guid\": \"1472a482-192b-41e8-af8a-42463e131cf3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Id\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeChildIdField\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field on the child which identifies it. Typically Id.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182403,\n                    \"Version\": 2,\n                    \"Guid\": \"c1a7e876-06e2-4792-8ebe-9cddaa19c5e4\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182404,\n                    \"Version\": 2,\n                    \"Guid\": \"00306083-c3fe-4da5-a87b-cd3786e5ec21\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeParentChildRefField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182387,\n                    \"Version\": 2,\n                    \"Guid\": \"5f4af476-4b84-4db5-8b61-6b5720b7e7f9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Children\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeParentChildRefField\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field on the parent, which would contain references to the children (when using Parent-Child relationships).</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182405,\n                    \"Version\": 1,\n                    \"Guid\": \"80c22d8d-89b7-4240-8180-988bc9566fe6\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182406,\n                    \"Version\": 1,\n                    \"Guid\": \"b17f1483-8931-4a10-bd1c-ac2f2d72f186\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeChildParentRefField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182388,\n                    \"Version\": 2,\n                    \"Guid\": \"59a465be-901e-4f94-87fe-e9c6e49a4854\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Parent\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeChildParentRefField\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field on the child, which would contain a reference to the parent (when using Child-Parent relationships).</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182407,\n                    \"Version\": 1,\n                    \"Guid\": \"f9a473f8-b3ba-4fbe-878a-cad189bca27c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182408,\n                    \"Version\": 1,\n                    \"Guid\": \"d3a185e0-7ae5-4df5-9e3d-e9dba20c5582\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupShow\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182414,\n                    \"Version\": 1,\n                    \"Guid\": \"cf3fbd9b-0757-4858-ae8c-ee057f3ccddd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupShow\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeShowRoot\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182415,\n                    \"Version\": 2,\n                    \"Guid\": \"0ce5bfc3-8b32-4c17-8317-b6caf5b10d02\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeShowRoot\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If the root node(s) should be shown. Set to false, if you only have 1 root and it's not meant to be used.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182417,\n                    \"Version\": 1,\n                    \"Guid\": \"d95d1b9c-84bb-4575-a879-a6005f63666e\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeDepthMax\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182416,\n                    \"Version\": 2,\n                    \"Guid\": \"7183e6df-76dd-4ade-9d94-f86655ee30b2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"10\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeDepthMax\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Maximum Tree depth incl. root and leaves. This is to avoid infinite recursions etc.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182418,\n                    \"Version\": 1,\n                    \"Guid\": \"fcc6cb35-9886-4310-900f-cb46f5f5ccaa\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        },\n                        \"Max\": {\n                          \"en-us\": 25\n                        },\n                        \"Min\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupSelectability\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182394,\n                    \"Version\": 1,\n                    \"Guid\": \"00d0ce6d-df29-4728-b6ad-bbee6eba1054\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupSelectability\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeAllowSelectRoot\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182409,\n                    \"Version\": 2,\n                    \"Guid\": \"8800ebf1-6810-456b-ac18-7246909bb397\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeAllowSelectRoot\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow selecting the root node. You may want to disable this, if the root is always an object which you don't want selected.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182410,\n                    \"Version\": 1,\n                    \"Guid\": \"6c1c8b64-62ca-4935-b0c1-4b92a31cb2c2\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeAllowSelectBranch\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182389,\n                    \"Version\": 3,\n                    \"Guid\": \"f4dd8687-6168-42d1-89ba-5d70c4707cb5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeAllowSelectBranch\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow selecting any branch node. You may want to disable this, if you only want file-selects, but not folder-selects.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182411,\n                    \"Version\": 2,\n                    \"Guid\": \"c716d313-848d-4e2a-8542-888e75885277\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TreeAllowSelectLeaf\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182426,\n                    \"Version\": 2,\n                    \"Guid\": \"a751e853-23fd-4e8e-9978-ca6429174550\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TreeAllowSelectLeaf\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182427,\n                    \"Version\": 1,\n                    \"Guid\": \"e763900b-b827-45e7-b808-5db2b4409ea0\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"318133c2-1df8-4a0a-99dc-08abaae0ed53\",\n            \"Name\": \"SysPickerSharedFields\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [],\n            \"Attributes\": [\n              {\n                \"Name\": \"GroupDataSources\",\n                \"Guid\": \"76843959-1a40-4b92-9ac7-e14ae5525d42\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182466,\n                    \"Version\": 1,\n                    \"Guid\": \"6d6368c4-f3f6-4761-85be-2955ce52f7c4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupDataSources\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DataSources\",\n                \"Guid\": \"5f7a115f-d935-4c77-8fc1-69024dd3828a\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182467,\n                    \"Version\": 20,\n                    \"Guid\": \"6f08b256-40a8-4d12-8237-a76a2401f777\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Data Source Configuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Configure / Select DataSources for this Picker to provide choices.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183691,\n                    \"Version\": 2,\n                    \"Guid\": \"e35a3275-22bd-4306-a477-163fc6a4658f\",\n                    \"Type\": {\n                      \"Id\": \"6fa7f390-7612-40c6-baff-2bcf6140a85f\",\n                      \"Name\": \"@entity-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"a0a2db07-5d62-452c-b0a6-4708daee5380\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupUiFeatures\",\n                \"Guid\": \"f786e83a-12b8-4c76-8593-cc84e385ff1b\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": true,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182460,\n                    \"Version\": 7,\n                    \"Guid\": \"4bff4743-575f-4221-947a-5baad25276b9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"UI Features (buttons etc.)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"67f10945-8f58-47d5-86fb-7359fa58342e\",\n                            \"72214326-370f-41e2-8e68-39718d895f81\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182473,\n                    \"Version\": 4,\n                    \"Guid\": \"9a57c3ed-9c49-4670-8202-831e68253e58\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableEdit\",\n                \"Guid\": \"f09fbd6a-ba83-4023-a5b4-b82b6ef7e9ff\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182461,\n                    \"Version\": 8,\n                    \"Guid\": \"095ceb76-e05b-4655-ba6b-e60cf012f9c0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Enable Edit Items\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow user to edit the item in the list, usually by showing a pencil-icon.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182468,\n                    \"Version\": 6,\n                    \"Guid\": \"f168db44-4c78-48d3-a6b3-95cc1b97de86\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"edit items disabled \\uD83D\\uDD0F\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"automatically detect if edit is enabled\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"edit items enabled ✏️\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableCreate\",\n                \"Guid\": \"916b17c1-f15d-4414-80e5-6d53b27ff463\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182462,\n                    \"Version\": 8,\n                    \"Guid\": \"d5c87d5a-d241-49ba-9823-cfaf8d801051\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"EnableCreate\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow creating new items of the type(s) used in this list.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182469,\n                    \"Version\": 6,\n                    \"Guid\": \"f10a3743-1f41-40a9-a68b-fdb6406fc50c\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"create items disabled \\uD83D\\uDD12\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"automatically detect if create new is possible\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"create items enabled ⭐\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableAddExisting\",\n                \"Guid\": \"0fc6d925-77df-4ccc-80dd-5d9ddaf003c9\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182463,\n                    \"Version\": 8,\n                    \"Guid\": \"cba7c7df-977f-4b3f-ba7b-37ba8742a789\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"EnableAddExisting\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow the user to select the same item multiple times.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182470,\n                    \"Version\": 5,\n                    \"Guid\": \"68c54508-0af7-4499-b3a4-2bf969749ecd\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"add existing disabled \\uD83D\\uDD12\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"add existing enabled ➕\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableRemove\",\n                \"Guid\": \"9f51cb28-eab4-4eb6-9b44-6246b55a7a52\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182464,\n                    \"Version\": 6,\n                    \"Guid\": \"9420ea32-8570-403c-af05-1c8b7e183d7f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"EnableRemove\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow the user to remove an item in the list.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182471,\n                    \"Version\": 5,\n                    \"Guid\": \"ee7fb6ce-5577-409d-9dfd-b956c6ed1087\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"remove items disabled \\uD83D\\uDD12\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"remove item enabled ➖\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableDelete\",\n                \"Guid\": \"4274d627-fc80-412e-ad34-fa9ed21c6ba6\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182656,\n                    \"Version\": 8,\n                    \"Guid\": \"f3153679-0e0b-4b97-9cba-044ff5d36620\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"EnableDelete\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow the user to fully delete an item shown in the list.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182660,\n                    \"Version\": 7,\n                    \"Guid\": \"5c870c94-7c41-4590-97e9-e5fd024e2418\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"delete item disabled \\uD83D\\uDD12\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"delete item enabled \\uD83D\\uDDD1️\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableTextEntry\",\n                \"Guid\": \"c5825717-9c58-46d8-bafb-2bd8b3c2ec11\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182465,\n                    \"Version\": 7,\n                    \"Guid\": \"1d2c6ccd-7060-44f1-9740-7990e1689f9d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"EnableTextEntry\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow manually typing a value which may or may not be in the list. Two common situations for this:</p>\\n<ul>\\n<li>situations where the drop-down will suggest typical values, but others are also possible</li>\\n<li>Situations where you need tokens like [Parameter:Category] which will later be resolved to a real value</li>\\n</ul>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182472,\n                    \"Version\": 6,\n                    \"Guid\": \"fdb4f95b-73b0-4979-a3f0-2c34b209ef17\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"only allow values from list \\uD83D\\uDD22\\uD83D\\uDD12\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"enable free text entry by user ⌨️\\uD83D\\uDD13\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupMultiSelect\",\n                \"Guid\": \"3dcbb74e-44bc-4bb3-83c0-ac8243190696\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182479,\n                    \"Version\": 6,\n                    \"Guid\": \"7592ee8d-125d-4f48-aa8c-376662e4a731\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Select Multiple Values\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"5f17d5e2-fc51-4c6a-acd4-41f6c8de27f1\",\n                            \"8a74630d-e961-4130-9c22-31a9015bb83d\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182491,\n                    \"Version\": 3,\n                    \"Guid\": \"b0d5b79d-9fc4-4124-8711-cb0daf98834d\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowMultiValue\",\n                \"Guid\": \"faf06aa8-73cc-4cb0-baa5-da7a9e5d2203\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182480,\n                    \"Version\": 5,\n                    \"Guid\": \"9cd2974d-40f7-4279-810c-255b19e56878\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"AllowMultiValue\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Allow selecting multiple items (otherwise the user can only pick 1 item).</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182485,\n                    \"Version\": 4,\n                    \"Guid\": \"13ed6e7a-d6e2-4a1b-ba44-21827899e08b\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"only allow a single item 1️⃣\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"allow selecting multiple items ♾️\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableReselect\",\n                \"Guid\": \"6bb3b9ac-0008-477e-825c-7ce8f57e910d\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182481,\n                    \"Version\": 5,\n                    \"Guid\": \"8d91a38a-df11-49f8-b29c-33fdc13b6dc1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"EnableReselect\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>*Enable the user to select the same item multiple times in the list.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"b4e7a0b5-4102-49a8-9f62-70236d097a90\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182486,\n                    \"Version\": 3,\n                    \"Guid\": \"649364b0-fefd-4825-b034-bee8b9db2bb7\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"items can only be selected once 1️⃣ \"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"items can be selected again \\uD83D\\uDD01\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Separator\",\n                \"Guid\": \"844c1c0b-09c7-46b3-8541-e9eef134cd69\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182482,\n                    \"Version\": 8,\n                    \"Guid\": \"9a58bccc-650c-4926-a92b-69bf2c2a6479\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \",\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Separator\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If you want to support selecting multiple items, you'll need something to keep them separate. We recommend a comma or new-line, but maybe you want something different.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"ec85406a-ecaa-4027-a63c-7a568566da07\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182487,\n                    \"Version\": 6,\n                    \"Guid\": \"a570466a-0170-421c-aef0-f4673ee0d906\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182488,\n                    \"Version\": 6,\n                    \"Guid\": \"5228cb37-4015-44f3-ba87-7836e059aacd\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\\\\\\\\n:New Line / Enter (\\\\\\\\n)\\n,:Comma \\\",\\\"\\n|:Vertical Bar \\\"|\\\"\\n-:Dash \\\"-\\\"\\n;Semicolon \\\";\\\"\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowMultiMin\",\n                \"Guid\": \"41f9d742-66fd-4729-8687-c9648d76d33a\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182483,\n                    \"Version\": 5,\n                    \"Guid\": \"399cb29f-7635-4522-a6e2-57c90ef44bf7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Multi-Select Minimum Amount Required\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Define a minimum amount of item which <em>must</em> be picked.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"a8f0a31b-6360-4897-a7e6-279b0ca48237\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182489,\n                    \"Version\": 3,\n                    \"Guid\": \"ffaf539a-8012-4130-bbc9-718b68c15f5c\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowMultiMax\",\n                \"Guid\": \"65e8eeaa-4914-449e-816d-31185f54e406\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182484,\n                    \"Version\": 5,\n                    \"Guid\": \"1f5dc29f-190e-4227-b7df-b035ae64d5de\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Multi-Select Maximum Amount Allowed\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>When allowing multiple, max amount to allow.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"69f58d43-2c6f-49bf-a25d-bb33caebf947\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182490,\n                    \"Version\": 3,\n                    \"Guid\": \"383b2045-2b46-41bb-8777-22e2a0c83e87\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDisplay\",\n                \"Guid\": \"7c7c7fe3-57be-4d2f-9767-a0f3e3944bf1\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182498,\n                    \"Version\": 4,\n                    \"Guid\": \"30b66546-b066-43e0-bdca-3ca8c58aeb09\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Picker Display Configuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"6593add5-09d8-4bda-8229-0e6fc7e9cc0c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182514,\n                    \"Version\": 2,\n                    \"Guid\": \"4a3a35af-f216-4ec1-bb9a-5ad4e521c0ba\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PickerDisplayMode\",\n                \"Guid\": \"16057c04-0f49-4bd2-96e7-97d13bf3f8f5\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182499,\n                    \"Version\": 7,\n                    \"Guid\": \"6aa01f5c-ceae-44a7-80f3-85aa757a2271\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Picker Display Mode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Choose how the picker should be presented.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"bfc2786d-c211-4d74-8b58-621105cf3b27\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182505,\n                    \"Version\": 3,\n                    \"Guid\": \"4559dee6-0ff8-40c5-9718-303e77def461\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183895,\n                    \"Version\": 1,\n                    \"Guid\": \"d30201cc-f302-42e5-85d4-0f2866469ce2\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"b09500f5-0a16-4347-97d4-505bac83d0fc\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PickerDisplayConfiguration\",\n                \"Guid\": \"879356b3-0579-4fa1-b973-95c1b543c9db\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182500,\n                    \"Version\": 4,\n                    \"Guid\": \"b0449d6f-b226-4e6c-a60f-27347eeee463\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Picker Display Configuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>How the picker should be displayed, ATM only for special tree configurations.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182507,\n                    \"Version\": 3,\n                    \"Guid\": \"39631857-9d1b-4f08-8e65-50d26de3b870\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"UiPickerModeTree\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PreviewType\",\n                \"Guid\": \"2ca67f4b-7e68-4502-ac73-9c521fba2aaf\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183993,\n                    \"Version\": 6,\n                    \"Guid\": \"2533cf19-7597-46ad-bdda-19d7c693b0db\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Preview\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If the selected data can be previewed (like an icon), specify how.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183995,\n                    \"Version\": 5,\n                    \"Guid\": \"bce7becc-0db7-436f-a6c7-6694a45d9ef3\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"c37e1472-d258-4ce4-8733-d801a049f574\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupEditDialog\",\n                \"Guid\": \"bc89498a-6a98-4d7c-994f-4c04b8930154\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182501,\n                    \"Version\": 4,\n                    \"Guid\": \"a18c8bbe-6e2a-4453-896e-017c3b7e1ecf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Edit Items Configuration (Advanced)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Configure advanced settings when creating / editing items in this list.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"21e2f373-fbef-4196-9d4c-d3c8267c03c5\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182515,\n                    \"Version\": 2,\n                    \"Guid\": \"4b50469f-d229-40c2-8e51-9b2056f72e2e\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CreatePrefill\",\n                \"Guid\": \"594d3edf-5501-4ee5-8271-d216ceefac08\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182502,\n                    \"Version\": 4,\n                    \"Guid\": \"e8e416b4-a594-46ae-ab72-efcff879b7ef\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Create Item Prefill\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Prefill URL Parameters when creating a <em>new </em>item.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182508,\n                    \"Version\": 3,\n                    \"Guid\": \"97443bfd-5c19-4f2f-8be3-f520c0456e3d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182509,\n                    \"Version\": 3,\n                    \"Guid\": \"98b435ce-cea1-4510-87bc-2da0a9d70bf7\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CreateParameters\",\n                \"Guid\": \"c21252f1-6d64-4b59-91e0-5ce5a80c7bd4\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182503,\n                    \"Version\": 5,\n                    \"Guid\": \"f2710e88-e9ce-4e52-aff1-c5b823d50325\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Create Item - Form Parameters\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Form URL Parameters when creating a new item. Not for prefill, but to affect formulas which expect these parameters.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182510,\n                    \"Version\": 4,\n                    \"Guid\": \"ea046421-cf29-4efb-b500-9af6dedfae55\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182511,\n                    \"Version\": 4,\n                    \"Guid\": \"a20b9841-d4af-428b-a4c2-e9c8cf7c5464\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EditParameters\",\n                \"Guid\": \"46cb9c49-a1c8-4b5a-affe-32a7f6732dbd\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182504,\n                    \"Version\": 4,\n                    \"Guid\": \"c5ae0bc5-a476-432b-ac53-6ee638575b6a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Edit Item - Form Parameters\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Form URL Parameters when editing a new item. Not for prefill, but to affect formulas which expect these parameters.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182512,\n                    \"Version\": 3,\n                    \"Guid\": \"c46bc50f-c950-4b67-820f-7a5b555bb50c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182513,\n                    \"Version\": 3,\n                    \"Guid\": \"2398e456-0a07-4643-b8ba-129ff5d243c6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 182681,\n              \"Version\": 29,\n              \"Guid\": \"a0a2db07-5d62-452c-b0a6-4708daee5380\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"UiPickerSourceEntity\\nUiPickerSourceQuery\\nUiPickerSourceCustomList\\nUiPickerSourceCustomCsv\\nUiPickerSourceCss\\nUiPickerSourceAppAssets\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"<p>Get all Data Sources for UI Pickers.</p>\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[item:Description]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"[Item:Title] ([Item:Id])\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.UiPickers\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"System.UiPickers Data Source\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Guid\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182476,\n              \"Version\": 1,\n              \"Guid\": \"67f10945-8f58-47d5-86fb-7359fa58342e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => {\\n  return data.default + \\n    (data.EnableEdit ? \\\"✒️ \\\" : \\\"\\uD83D\\uDD0F \\\") +\\n    (data.EnableRemove ? '➖ ' : '\\uD83D\\uDD12 ') + \\n    (data.EnableCreate ? '⭐' : '\\uD83D\\uDD12');\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182475,\n              \"Version\": 3,\n              \"Guid\": \"72214326-370f-41e2-8e68-39718d895f81\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => {\\r\\n  // In normal picker setup, the field which must contain something is DataSources\\r\\n  // Since this group is also used in old Entity-Pickers, it would need to check the EntityType\\r\\n  if (!!data.DataSources && data.DataSources.length > 0)\\r\\n    return true;\\r\\n  if (!!data.EntityType)\\r\\n    return true;\\r\\n  return false;\\r\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182493,\n              \"Version\": 1,\n              \"Guid\": \"5f17d5e2-fc51-4c6a-acd4-41f6c8de27f1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.default + ' ' +\\n    (data.AllowMultiValue\\n      ? ('✅ ' + '\\\"' + data.Separator + '\\\"')\\n      : '1️⃣');\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182492,\n              \"Version\": 1,\n              \"Guid\": \"8a74630d-e961-4130-9c22-31a9015bb83d\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return !!data.DataSources && data.DataSources.length > 0; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182494,\n              \"Version\": 1,\n              \"Guid\": \"b4e7a0b5-4102-49a8-9f62-70236d097a90\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return data.AllowMultiValue; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182495,\n              \"Version\": 1,\n              \"Guid\": \"ec85406a-ecaa-4027-a63c-7a568566da07\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return data.AllowMultiValue; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182496,\n              \"Version\": 1,\n              \"Guid\": \"a8f0a31b-6360-4897-a7e6-279b0ca48237\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return data.AllowMultiValue; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182497,\n              \"Version\": 1,\n              \"Guid\": \"69f58d43-2c6f-49bf-a25d-bb33caebf947\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return data.AllowMultiValue; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182516,\n              \"Version\": 1,\n              \"Guid\": \"6593add5-09d8-4bda-8229-0e6fc7e9cc0c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return !!data.DataSources && data.DataSources.length > 0; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183903,\n              \"Version\": 15,\n              \"Guid\": \"bfc2786d-c211-4d74-8b58-621105cf3b27\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  let temp = 0;\\n  const options = data.optionsRaw.map(o => ({\\n    ...o,\\n    noSelect: o.data?.Disabled ?? false,\\n    // conditions: (++temp % 2) ? `warn=feature:PickerUiRadio` : null,\\n  }))\\n  console.log(options);\\n  return {\\n    options: options,\\n  };\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Options\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Options\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183894,\n              \"Version\": 16,\n              \"Guid\": \"b09500f5-0a16-4347-97d4-505bac83d0fc\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info,Disabled,Rules\\nlist,\\\"Default\\\",\\\"Dropdown with search. Opens dialog when more need to be selected.\\\",false\\n\\nauto-inline,\\\"Auto Radio/Checkbox\\\",\\\"Inline - automatically showing checkboxes or radio buttons, depending on the amount of items you can select\\\",false,\\\"warn-req=feature:PickerUiRadio;warn-req=feature:PickerUiCheckbox\\\"\\nradio,\\\"Inline Radio Buttons\\\",\\\"Inline radio button selection for single-item choices\\\",false,\\\"warn-req=feature:PickerUiRadio\\\"\\ncheckbox,\\\"Inline Checkboxes\\\",\\\"Inline checkbox list for multiple item selection\\\",false,\\\"warn-req=feature:PickerUiCheckbox\\\"\\n\\ntree,\\\"Tree structure (BETA)\\\",\\\"Requires more configuration (BETA, doesn't work yet)\\\",true\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PreviewType\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PreviewValue\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Picker Shared - DisplayMode\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183994,\n              \"Version\": 6,\n              \"Guid\": \"c37e1472-d258-4ce4-8733-d801a049f574\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\n,\\\"Not configured (default)\\\",\\\"No special preview, or use the preview-setting from the source - this is the default for normal values\\\"\\nicon-css,\\\"Icon from Font in CSS\\\",\\\"Show the value as an icon from an icon-font such as fontawesome, which is specified in the CSS - usually applied as a class.\\\"\\nicon-material,\\\"Icon Material (using font-symbols)\\\",\\\"Symbol icons use a text-name to specify that they should show\\\"\\nsvg,\\\"SVG preview\\\",\\\"Show an SVG file - typically an icon\\\"\\ntext-css,\\\"Text formatted by CSS\\\",\\\"Show some text to see how the text-formatting changes\\\"\\nimage,\\\"Image\\\",\\\"Show an image like png/jpg etc. which is specified by the data\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PreviewType\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PreviewValue\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Picker Shared - Preview Type\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182517,\n              \"Version\": 1,\n              \"Guid\": \"21e2f373-fbef-4196-9d4c-d3c8267c03c5\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return !!data.DataSources && data.DataSources.length > 0; });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"bee47d31-c425-421a-8520-292b11571179\",\n            \"Name\": \"SysPickerSourceSharedFields\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182666,\n                    \"Version\": 1,\n                    \"Guid\": \"36164d59-bddb-450e-b78b-f30db8e17147\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescription\",\n                \"Guid\": \"0046b3fd-b3ee-47ee-be29-1f0df071069a\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183727,\n                    \"Version\": 4,\n                    \"Guid\": \"178bfb2b-1123-4699-ad4b-c60d5a309b02\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Detailed Description\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Since this Data Source can be reused, it's helpful to provide a detailed description of what it does. This is optional.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"294f8671-40aa-4af3-a111-c53d00cb53be\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183728,\n                    \"Version\": 3,\n                    \"Guid\": \"6134ef41-2170-4c60-919d-ff77f8ddcbba\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Description\",\n                \"Guid\": \"970d9f99-9fc7-4ebb-b5c3-8ce1518a0bce\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183719,\n                    \"Version\": 4,\n                    \"Guid\": \"26f199b0-89a9-4cde-992e-f9660a40b97e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Description to help pick the right Data Source\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This will be shown on the info-button when picking data-sources, to better find this one.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183720,\n                    \"Version\": 3,\n                    \"Guid\": \"8ce7f15d-f797-40a2-8d7a-4815b00cfd74\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183721,\n                    \"Version\": 3,\n                    \"Guid\": \"8552b803-f493-43f4-a5ab-d96a66231f13\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"1\"\n                        },\n                        \"WysiwygConfiguration\": {\n                          \"en-us\": \"3e9dd123-ccef-4d81-80e7-4c6ae6f5ddc6\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescriptionEnd\",\n                \"Guid\": \"ee7ba734-558a-4362-85a5-8ee9421b6118\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183735,\n                    \"Version\": 1,\n                    \"Guid\": \"0fb3bd85-97b1-40f7-b738-425b71c40a09\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupDescriptionEnd\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupMore\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182667,\n                    \"Version\": 2,\n                    \"Guid\": \"cf55fc8f-9bfa-498b-973c-70e34d56a56c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"More Settings ✌️\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182670,\n                    \"Version\": 1,\n                    \"Guid\": \"10ff8d85-4aaa-4b22-973e-42bdab4059a3\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Label\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182668,\n                    \"Version\": 1,\n                    \"Guid\": \"d545e28c-5da2-45c2-83d6-6e0233f986bc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Label\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MoreFields\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182669,\n                    \"Version\": 1,\n                    \"Guid\": \"c445fae3-8975-4918-8f6a-ef5a2ce8ee7c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"*\": \"MoreFields\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182675,\n                    \"Version\": 1,\n                    \"Guid\": \"25fe04b5-a414-4c16-8e0f-9d9ba4dc3b36\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupAdvanced\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CreateTypes\",\n                \"Guid\": \"3329843f-be88-47d2-a2c1-3c16724081d7\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 182674,\n                    \"Version\": 7,\n                    \"Guid\": \"d444dc7d-15ac-4f46-b78a-6c9aca3fbc3f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Create Entity Types (for create new)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Specify one or more types - so the user can create new items.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182676,\n                    \"Version\": 5,\n                    \"Guid\": \"87b55ea6-abc3-458d-b967-4df2e2dd33bc\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"c6732c81-bfeb-4675-9a9d-611ad0289de2\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupItemHelp\",\n                \"Guid\": \"ea9c3f94-578f-4c5f-b721-767f38fea57d\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183696,\n                    \"Version\": 4,\n                    \"Guid\": \"2df2f3c0-f491-4c97-b658-aced8302db15\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Help on each Item\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Provide additional information to guide / help the user.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"e457872b-90e7-4041-a8de-07bb88ddd43e\",\n                            \"5a7bf19c-2be2-4310-b706-b888c89b8394\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183700,\n                    \"Version\": 3,\n                    \"Guid\": \"32653e1b-9a1f-4a10-86c5-d5b88e75a130\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupHelpMessageUnlicensed\",\n                \"Guid\": \"effab828-3273-497a-a7af-b93741fa25d5\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183910,\n                    \"Version\": 5,\n                    \"Guid\": \"a0b43b4f-6e3a-42ce-8fda-bb064665482c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"GroupHelpMessageUnlicensed\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Important: The feature <a href=\\\"https://patrons.2sxc.org/features/feat/PickerUiMoreInfo\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">PickerUiMoreInfo</a> is not enabled. You have filled in either the Info, Tooltip or Link, which require these features.&nbsp;</p>\\n<p>For you as a developer this feature will work, so you can develop it. Just remember that the end user will only benefit from this information if the feature is enabled on their system.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"1910fa85-fdb5-468d-a7cc-32f2a3a6695d\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemTooltip\",\n                \"Guid\": \"49d939a6-b45c-405b-98e9-b7ee38a9c68a\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183697,\n                    \"Version\": 3,\n                    \"Guid\": \"8d00a27b-2fcf-4fb8-b650-5674cffc8117\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Item Tooltip\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Show a rich tooltip on each item. You can use placeholders like [Item:FieldName].</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183701,\n                    \"Version\": 2,\n                    \"Guid\": \"fc1a712b-03fc-40ec-a8c5-580581bd7de3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183702,\n                    \"Version\": 2,\n                    \"Guid\": \"f0cd0c75-cb55-49b1-be75-29a283605a27\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"1\"\n                        },\n                        \"WysiwygConfiguration\": {\n                          \"en-us\": \"3e9dd123-ccef-4d81-80e7-4c6ae6f5ddc6\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemInformation\",\n                \"Guid\": \"2cd90609-840f-4ccf-aed6-8c6e39ea067e\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183698,\n                    \"Version\": 3,\n                    \"Guid\": \"3d356c88-e262-43e8-9737-a4bf4df6472e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Item Information Button\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Show information behind an ℹ️ icon on each item. You can use placeholders like [Item:FieldName].</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183703,\n                    \"Version\": 2,\n                    \"Guid\": \"05fbef7e-1393-4ddd-8642-584be2562175\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183704,\n                    \"Version\": 2,\n                    \"Guid\": \"a0417be5-9554-4dd5-9a6c-55a8874bf992\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"1\"\n                        },\n                        \"WysiwygConfiguration\": {\n                          \"en-us\": \"3e9dd123-ccef-4d81-80e7-4c6ae6f5ddc6\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemLink\",\n                \"Guid\": \"8a7dcb9e-f47b-4518-9519-f66db95f195e\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 183699,\n                    \"Version\": 3,\n                    \"Guid\": \"5dd99048-1e39-4759-9f63-f3bd8a3d2808\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Item Link\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Show a link to another page on each item. You can use placeholders like [Item:FieldName].</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183705,\n                    \"Version\": 2,\n                    \"Guid\": \"9a9c885b-e439-430f-8b6c-e76160f7c7da\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupPreview\",\n                \"Guid\": \"809f9514-13eb-4182-8a03-a010b93beaf7\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"Share\": true\n                },\n                \"Metadata\": [\n                  {\n                    \"Id\": 184000,\n                    \"Version\": 3,\n                    \"Guid\": \"731b5bbf-2f59-424f-9987-4c31d094f521\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Preview Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The following settings can adjust how the selected value is previewed.</p>\\n<p>For example, you can specify how a file such as an image/SVG is previewed, or how an icon-font will be displayed.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184001,\n                    \"Version\": 2,\n                    \"Guid\": \"2ddfec52-9e8a-4363-9efa-cbedc1fdef9d\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183740,\n              \"Version\": 1,\n              \"Guid\": \"294f8671-40aa-4af3-a111-c53d00cb53be\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data) => { return data.default + (!!data.Info ? '✅' : ''); });\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Name: Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 182677,\n              \"Version\": 2,\n              \"Guid\": \"c6732c81-bfeb-4675-9a9d-611ad0289de2\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"<p>Find all Content-Types</p>\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Title\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.ContentTypes\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"ContentTypes (all)\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"NameId\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183718,\n              \"Version\": 6,\n              \"Guid\": \"e457872b-90e7-4041-a8de-07bb88ddd43e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const typeName = context.target.entity.type.name;\\n  // For custom list, it can always be visible\\n  if (typeName == 'UiPickerSourceCustomList'\\n    || typeName == 'UiPickerSourceCustomCsv'\\n    || typeName == 'UiPickerSourceAppAssets'\\n  ) {\\n    return true;\\n  }\\n\\n  // For Entity Picker\\n  if (typeName == \\\"UiPickerSourceEntity\\\") {\\n    return data.ContentTypeNames.length > 0;\\n  }\\n\\n  if (typeName == \\\"UiPickerSourceQuery\\\") {\\n    return data.Query.length > 0;\\n  }\\n\\n  // Warn on unknown type, as it can't determine how to set visibility\\n  console.warn('formula for GroupItemHelp is running on an unexpected type, so it is not clear when to show/hide: ' + typeName);\\n  // console.log('2dm data', data, context);\\n  return data.value;\\n});\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible: Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183739,\n              \"Version\": 1,\n              \"Guid\": \"5a7bf19c-2be2-4310-b706-b888c89b8394\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const icons = [];\\n  if (!!data.ItemTooltip) icons.push('\\uD83D\\uDCA1');\\n  if (!!data.ItemInformation) icons.push('ℹ️');\\n  if (!!data.ItemHelpLink) icons.push('\\uD83D\\uDD17');\\n  const addOn = icons.length ? ' (' + icons.join(' ') + ')' : '';\\n  return data.default + addOn;\\n});\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Name: Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183912,\n              \"Version\": 3,\n              \"Guid\": \"1910fa85-fdb5-468d-a7cc-32f2a3a6695d\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const hasAny = !!data.ItemTooltip || !!data.ItemInformation || !!data.ItemLink;\\n  if (!hasAny) return hasAny;\\n  const enabled = context.features.isEnabled('PickerUiMoreInfo');\\n  return !enabled;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n            \"Name\": \"UiPickerSourceCustomCsv\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 183868,\n                \"Version\": 1,\n                \"Guid\": \"7953fd0e-61e8-4c07-a0c5-6998c908860a\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"UI Picker Source - Custom CSV\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"3a96ad21-027d-4679-8372-c39406ad1d11\"\n                }\n              },\n              {\n                \"Id\": 183924,\n                \"Version\": 1,\n                \"Guid\": \"72626777-5df3-4c13-b422-d14c4cb57d78\",\n                \"Type\": {\n                  \"Id\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\",\n                  \"Name\": \"IsPickerSourceDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"3a96ad21-027d-4679-8372-c39406ad1d11\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183855,\n                    \"Version\": 3,\n                    \"Guid\": \"84d21ca2-8dfb-4c25-941f-207975e43940\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"CSV Data Source\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>A simple name so you can identify this source when you re-use it.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183863,\n                    \"Version\": 2,\n                    \"Guid\": \"29181a04-8d2c-4e6a-8715-1f4b79a265e3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183864,\n                    \"Version\": 2,\n                    \"Guid\": \"7cb7ba37-131c-426e-a30e-72cf02cbea05\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PickerSourceCsvNotEnabledWarning\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183878,\n                    \"Version\": 6,\n                    \"Guid\": \"71fb0597-88bf-470c-9611-13058681c8ff\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"PickerSourceCsv FeatureNotEnabledWarning\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>Warning: </strong>You are configuring an new CSV source. It appears that this feature is not enabled. See <a href=\\\"https://patrons.2sxc.org/features/feat/PickerSourceCsv\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Picker Source CSV Source feature</a>.</p>\\n<p>✅ You can still use this source and everything will work, but it will show a warning that you're using an unlicensed feature.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"4250edc0-640c-47da-81d6-f947a691c3d4\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescription\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0046b3fd-b3ee-47ee-be29-1f0df071069a\"\n                }\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"970d9f99-9fc7-4ebb-b5c3-8ce1518a0bce\"\n                }\n              },\n              {\n                \"Name\": \"GroupCsvValues\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183870,\n                    \"Version\": 5,\n                    \"Guid\": \"93582c68-a89a-4134-8f3c-2cf0c199baea\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Comma Separated Values (BETA)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Create a mini-table with CSV. Note that as of now, the configuration is as follows:</p>\\n<ol>\\n<li>the first row must contain the column names, and must contain a&nbsp;<em>Value. </em>The&nbsp;<em>Title</em> is not required, but recommended.&nbsp;</li>\\n<li>spaces will be trimmed, so &lt;Value,Title&gt; and &lt;Value, Title&gt; are the same</li>\\n<li>empty lines will be skipped</li>\\n<li>delimiter will be guessed, we suggest you use a comma \\\",\\\"</li>\\n<li>if you have text containing the delimiter, best put it in quotes eg \\\"I think, therefore I am\\\"</li>\\n<li>numbers are not parsed, so make sure you use the neutral \\\".\\\" format like 42.27</li>\\n</ol>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183871,\n                    \"Version\": 4,\n                    \"Guid\": \"3952f26e-670c-46d3-90f4-f5d06863151d\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Csv\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183865,\n                    \"Version\": 7,\n                    \"Guid\": \"c085bf57-68cf-489b-9b1b-15ef8315dcb6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Value,Title,Info,Link\\n2sxc,2sxc CMS,the best plugin for Dnn and Oqtane,https://2sxc.org\\n2sic,2sic - makers of 2sxc,the creators of 2sxc,https://2sic.com\\nDescartes,René Descartes,\\\"I think, therefore I am\\\",\\\"https://en.wikipedia.org/wiki/Cogito,_ergo_sum\\\"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"CSV - Comma Separated Values\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183866,\n                    \"Version\": 6,\n                    \"Guid\": \"632f2213-7ee1-41bb-add4-79cb21e391e2\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183867,\n                    \"Version\": 6,\n                    \"Guid\": \"630ad0d7-8bbd-489e-9c89-607af64ef6b9\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"pre\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 20\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupPreview\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"809f9514-13eb-4182-8a03-a010b93beaf7\"\n                }\n              },\n              {\n                \"Name\": \"PreviewValue\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183999,\n                    \"Version\": 1,\n                    \"Guid\": \"2668c20e-aef8-40ce-9f6e-26b48f445189\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"ValuePreview\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PreviewType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"2ca67f4b-7e68-4502-ac73-9c521fba2aaf\"\n                }\n              },\n              {\n                \"Name\": \"GroupItemHelp\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"ea9c3f94-578f-4c5f-b721-767f38fea57d\"\n                }\n              },\n              {\n                \"Name\": \"GroupHelpMessageUnlicensed\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"effab828-3273-497a-a7af-b93741fa25d5\"\n                }\n              },\n              {\n                \"Name\": \"ItemTooltip\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"49d939a6-b45c-405b-98e9-b7ee38a9c68a\"\n                }\n              },\n              {\n                \"Name\": \"ItemInformation\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"2cd90609-840f-4ccf-aed6-8c6e39ea067e\"\n                }\n              },\n              {\n                \"Name\": \"ItemLink\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"8a7dcb9e-f47b-4518-9519-f66db95f195e\"\n                }\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183879,\n              \"Version\": 1,\n              \"Guid\": \"4250edc0-640c-47da-81d6-f947a691c3d4\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return !context.features.isEnabled('PickerSourceCsv'); });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"78451625-053f-4e23-b4e8-e95c3fcf3320\",\n            \"Name\": \"UiPickerSourceCss\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 183928,\n                \"Version\": 3,\n                \"Guid\": \"703be1a9-518b-4bdf-a98b-7a60ba3699cb\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"UI Picker Source - Css (for selecting icons or classes) BETA⚠️\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"78451625-053f-4e23-b4e8-e95c3fcf3320\"\n                }\n              },\n              {\n                \"Id\": 183952,\n                \"Version\": 1,\n                \"Guid\": \"01c78465-f078-4978-9eee-ec5d88599660\",\n                \"Type\": {\n                  \"Id\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\",\n                  \"Name\": \"IsPickerSourceDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"78451625-053f-4e23-b4e8-e95c3fcf3320\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183929,\n                    \"Version\": 2,\n                    \"Guid\": \"063d39d6-20ab-4426-bcb7-15fdd6fb9c1e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"CSS Data Source for Icons\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>A simple name so you can identify this source when you re-use it.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183930,\n                    \"Version\": 1,\n                    \"Guid\": \"9727cb6b-d6bd-4c1d-9f7c-ebee06b84731\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183931,\n                    \"Version\": 1,\n                    \"Guid\": \"9a273123-7ba7-419d-9a6f-701403f989a7\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescription\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0046b3fd-b3ee-47ee-be29-1f0df071069a\"\n                }\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"970d9f99-9fc7-4ebb-b5c3-8ce1518a0bce\"\n                }\n              },\n              {\n                \"Name\": \"GroupCssConfiguration\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183938,\n                    \"Version\": 2,\n                    \"Guid\": \"89044b7e-d98d-4d28-9b11-9066b0083b84\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Css Configuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Configure which CSS file to load, and what classes to select from it.</p>\\n<p>Note that the CSS file must come from the same domain, otherwise the browser will block access to the internal inspection, which must find the class names.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183941,\n                    \"Version\": 1,\n                    \"Guid\": \"1e24fbd7-e533-4303-87bf-9dbb6a99d568\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CssSourceFile\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183939,\n                    \"Version\": 5,\n                    \"Guid\": \"9c9cd7f9-16b9-4699-86cb-ce91ca4c4b8f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"[App:Path]/icons/fontawesome-nobrands.min.css\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"CSS Source File\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>File to load in this dialog - usually the CSS-file which would contain icon-definitions. You can also use the placeholder [App:Path] to inject the app, path, like</p>\\n<ul>\\n<li><em>[App:Path]/dist/custom-icons.css</em>.</li>\\n</ul>\\n<p>Remember that these styles will also affect the styling of the entire UI, so try to include files which only include the icon-definitions. You could also create separate icon-definition files just for this icon picker.</p>\\n<p>If you want to select icons and want a nice preview, make sure that the css file also loads the font you are using.</p>\\n<p>Find out more on <a href=\\\"//2sxc.org/help?tag=font-icon\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc.org/help?tag=font-icon</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183942,\n                    \"Version\": 4,\n                    \"Guid\": \"42470026-2c2c-40fa-9a82-2e227af1ce6c\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CssSelectorFilter\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183940,\n                    \"Version\": 4,\n                    \"Guid\": \"f7e752fe-b96d-4549-8cff-738ff77d740f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \".fa-\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Css Selector Filter\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The CSS could contain more rules (selectors) than you want, so to be sure we only show the desired ones, you can specify filters to limit what is used. You have 2 options:</p>\\n<ol>\\n<li>just use a string such as \\\".fa-\\\" (the typical prefix for FontAwesome) - this will filter/search for all selectors which start with this prefix</li>\\n<li>use a regular expression such as \\\"(\\\\.fa-|\\\\.fas-)\\\". Regular expressions must always be wrapped inside brackets (...) so that the search can tell the difference to normal string-start-with searches.</li>\\n</ol>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"A prefix or regular expression to select what CSS rules to use.\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183943,\n                    \"Version\": 3,\n                    \"Guid\": \"9d531a28-df89-44ba-ab8e-c7c2e32aeb8e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183944,\n                    \"Version\": 3,\n                    \"Guid\": \"1f5f925f-07ed-44d8-b472-fc986962d786\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Value\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183945,\n                    \"Version\": 2,\n                    \"Guid\": \"255db97a-79ca-481b-9258-007672fec2c8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Value (optional)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The value to store. If not specified, will just use the found selector without preceding dot, so \\\".address\\\" would become \\\"address\\\". Placeholders:</p>\\n<ol>\\n<li>[Item:Value] - the selector without leading \\\".\\\"</li>\\n<li>[Item:ValueRaw] - the selector with leading \\\".\\\"</li>\\n</ol>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183947,\n                    \"Version\": 1,\n                    \"Guid\": \"fa1a13a3-3658-4648-afea-b60714122861\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183948,\n                    \"Version\": 1,\n                    \"Guid\": \"2115f588-34ae-4d1d-a190-53ce1016b9f8\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupPreview\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"809f9514-13eb-4182-8a03-a010b93beaf7\"\n                }\n              },\n              {\n                \"Name\": \"PreviewType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184005,\n                    \"Version\": 3,\n                    \"Guid\": \"43f37c22-b262-4933-beed-a2d0d14068a3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"icon-css\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Preview Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If the selected data can be previewed (like an icon), specify how.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184006,\n                    \"Version\": 2,\n                    \"Guid\": \"f821a003-0b0d-44ee-9ece-6cb4f8692b51\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"radio\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"c37e1472-d258-4ce4-8733-d801a049f574\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PreviewValue\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183946,\n                    \"Version\": 4,\n                    \"Guid\": \"93e77f98-91ae-42ec-8e49-b890f2c375df\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"fas [Item:Value]\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Preview Value\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>CSS rule to use for the preview. Allows you to specify things such as prefixes (required for Font-Awesom, but not for newer If not specified, will just use the found selector with dot, so \\\".address\\\". Placeholders:</p>\\n<ol>\\n<li>[Item:Value] - the selector without leading \\\".\\\"</li>\\n<li>[Item:ValueRaw] - the selector with leading \\\".\\\"</li>\\n</ol>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183949,\n                    \"Version\": 3,\n                    \"Guid\": \"061e6f38-7e70-4420-8d93-e832f83d267e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183950,\n                    \"Version\": 3,\n                    \"Guid\": \"aca91517-1845-49e9-8b5e-056801366af5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupItemHelp\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"ea9c3f94-578f-4c5f-b721-767f38fea57d\"\n                }\n              },\n              {\n                \"Name\": \"ItemTooltip\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"49d939a6-b45c-405b-98e9-b7ee38a9c68a\"\n                }\n              },\n              {\n                \"Name\": \"ItemInformation\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"2cd90609-840f-4ccf-aed6-8c6e39ea067e\"\n                }\n              },\n              {\n                \"Name\": \"ItemLink\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"8a7dcb9e-f47b-4518-9519-f66db95f195e\"\n                }\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"5d139b94-70cd-45dd-97dd-0ea73d191791\",\n            \"Name\": \"UiPickerSourceAppAssets\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 184045,\n                \"Version\": 3,\n                \"Guid\": \"41643a23-8a35-42a2-89a4-b1ad208a8abe\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"UI Picker Source - App Assets (Files/Folders)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5d139b94-70cd-45dd-97dd-0ea73d191791\"\n                }\n              },\n              {\n                \"Id\": 184055,\n                \"Version\": 1,\n                \"Guid\": \"39456cc3-4416-4dab-89ed-7ad46164caf3\",\n                \"Type\": {\n                  \"Id\": \"bcce96be-a439-4f22-9d1e-a10487544fa5\",\n                  \"Name\": \"IsPickerSourceDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5d139b94-70cd-45dd-97dd-0ea73d191791\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184024,\n                    \"Version\": 2,\n                    \"Guid\": \"66cd66c1-e31f-43a3-8319-5c0e01104031\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Get App Files\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184043,\n                    \"Version\": 1,\n                    \"Guid\": \"992ee634-0e3a-4bd6-8b88-ae8d245e6b70\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184044,\n                    \"Version\": 1,\n                    \"Guid\": \"a5d42585-1668-444b-acd1-d37c6380a15e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PickerSourceAppFilesNotEnabledWarning\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184025,\n                    \"Version\": 4,\n                    \"Guid\": \"1f58aa88-4949-4478-a5d1-b5e815ed7c41\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"PickerSourceAppFilesNotEnabledWarning\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>Warning: </strong>You are configuring an new App Assets source. It appears that this feature is not enabled. See&nbsp;<a href=\\\"https://patrons.2sxc.org/features/feat/PickerSourceAppAssets\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Picker Source App Assets feature</a>.</p>\\n<p>✅ You can still use this source and everything will work, but it will show a warning that you're using an unlicensed feature.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"2576a1bb-76cc-464a-a7eb-d0e1eec4c373\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupDescription\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"0046b3fd-b3ee-47ee-be29-1f0df071069a\"\n                }\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"970d9f99-9fc7-4ebb-b5c3-8ce1518a0bce\"\n                }\n              },\n              {\n                \"Name\": \"GroupAppFiles\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184037,\n                    \"Version\": 2,\n                    \"Guid\": \"90d4b3a7-bf74-4e5b-b24f-eb56b99afa10\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"App Files\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184068,\n                    \"Version\": 1,\n                    \"Guid\": \"a5a9496b-9d92-470e-9a2d-82d7e0effa26\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AssetsRootFolder\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184026,\n                    \"Version\": 4,\n                    \"Guid\": \"aef9d6ca-4c86-488d-9b28-20716083b5e8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Root Folder\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Only retrieve things below this folder.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184039,\n                    \"Version\": 3,\n                    \"Guid\": \"c140bc7f-7958-442c-a0da-13dcfdcac4fa\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"e13e0514-2606-48ae-b77c-fd5ed9b9a602\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AssetsType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184049,\n                    \"Version\": 3,\n                    \"Guid\": \"e6e65889-3e45-4a00-ade0-9afc5adbe134\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"files\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"What to Retrieve\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Should the user be able to select files, folders or both?</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184051,\n                    \"Version\": 2,\n                    \"Guid\": \"cf5c7971-4209-4727-835c-adf26a9ce01a\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"radio\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"d8c9fc1c-7d81-4520-b6e9-8958f0b5429e\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AssetsFileFilter\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184027,\n                    \"Version\": 4,\n                    \"Guid\": \"3225f228-c9ac-4962-88f6-e4d9e26d7917\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"*.*\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"File Filter\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Only retrieve files matching this pattern.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184041,\n                    \"Version\": 3,\n                    \"Guid\": \"afd55f0c-6281-41e3-a837-ec326693cdd7\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"e5b1e2b4-a491-49d1-89da-3bbd91c087de\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupPreview\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"809f9514-13eb-4182-8a03-a010b93beaf7\"\n                }\n              },\n              {\n                \"Name\": \"Value\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184069,\n                    \"Version\": 7,\n                    \"Guid\": \"43fb0166-362c-4df0-86f6-9f4e7c9ec2c5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"FullName\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Value Field\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field of the items which will be stored as a value - typically the name with extension.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184071,\n                    \"Version\": 6,\n                    \"Guid\": \"57872556-a3d4-47e4-b2e5-a0c37e70b64e\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"a617f624-315d-41dc-b433-faf7924f64f1\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Label\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184072,\n                    \"Version\": 3,\n                    \"Guid\": \"37f09e7f-933e-4940-8995-0f1f8a27c94b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"FullName\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Label Field\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The field which will be shown in the dropdown as the visible field for the user to select.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184073,\n                    \"Version\": 2,\n                    \"Guid\": \"09aeafab-7083-4851-b2d8-9fe596d32309\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"a617f624-315d-41dc-b433-faf7924f64f1\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PreviewType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"2ca67f4b-7e68-4502-ac73-9c521fba2aaf\"\n                }\n              },\n              {\n                \"Name\": \"PreviewValue\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184056,\n                    \"Version\": 6,\n                    \"Guid\": \"abaf5be4-e2f4-4b62-876b-700db812ac6b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Url\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Preview Value (to be used in the special preview)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>We recommend the Url as it's the most likely option to work, but you can also use placeholders to create your own path to the preview.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"bd20b0d9-f99a-4fab-9af0-0fa431754383\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184074,\n                    \"Version\": 4,\n                    \"Guid\": \"764e0dd4-13fb-4044-9b67-15ae07758dc4\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"a617f624-315d-41dc-b433-faf7924f64f1\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupItemHelp\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"ea9c3f94-578f-4c5f-b721-767f38fea57d\"\n                }\n              },\n              {\n                \"Name\": \"GroupHelpMessageUnlicensed\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"effab828-3273-497a-a7af-b93741fa25d5\"\n                }\n              },\n              {\n                \"Name\": \"ItemTooltip\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"49d939a6-b45c-405b-98e9-b7ee38a9c68a\"\n                }\n              },\n              {\n                \"Name\": \"ItemInformation\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"2cd90609-840f-4ccf-aed6-8c6e39ea067e\"\n                }\n              },\n              {\n                \"Name\": \"ItemLink\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"SysSettings\": {\n                  \"InheritMetadataOf\": \"8a7dcb9e-f47b-4518-9519-f66db95f195e\"\n                }\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 184048,\n              \"Version\": 1,\n              \"Guid\": \"2576a1bb-76cc-464a-a7eb-d0e1eec4c373\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return !context.features.isEnabled('PickerSourceAppAssets'); });\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184038,\n              \"Version\": 5,\n              \"Guid\": \"e13e0514-2606-48ae-b77c-fd5ed9b9a602\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Path\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.AppAssets\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Folders\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"AppAssets - App Folders\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Path\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184050,\n              \"Version\": 4,\n              \"Guid\": \"d8c9fc1c-7d81-4520-b6e9-8958f0b5429e\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Icon\\n\\\"files\\\",\\\"Files\\\",file_copy\\n\\\"folders\\\",\\\"Folders\\\",folder_copy\\n\\\"all\\\",\\\"Files and Folders\\\",snippet_folder\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PreviewType\": {\n                    \"en-us\": \"icon-material\"\n                  },\n                  \"PreviewValue\": {\n                    \"en-us\": \"[Item:Icon]\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"App Assets - Asset Types\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184040,\n              \"Version\": 3,\n              \"Guid\": \"e5b1e2b4-a491-49d1-89da-3bbd91c087de\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\n\\\"*.*\\\",\\\"All Files\\\",\\\"Get all files\\\"\\n\\\"*.svg\\\",\\\"SVG Files\\\",\\\"Get all SVGs\\\"\\n\\\"*.txt\\\",\\\"TXT files\\\",\\\"Get all text files\\\"\\n\\\"todo\\\",\\\"Find all image files (not implemented!)\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PreviewType\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PreviewValue\": {\n                    \"en-us\": \"[Item:Title] ([Item:Value])\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"App Assets - File Filters\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184070,\n              \"Version\": 4,\n              \"Guid\": \"a617f624-315d-41dc-b433-faf7924f64f1\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Description]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Title\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.QueryInfo\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"QueryName=System.AppAssets&StreamName=Default\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Attributes\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"AppAssets - Fields of Query\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184075,\n              \"Version\": 1,\n              \"Guid\": \"bd20b0d9-f99a-4fab-9af0-0fa431754383\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return !!data.PreviewType;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-fields.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"@Boolean\",\n            \"Name\": \"@Boolean\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 136785,\n                \"Version\": 1,\n                \"Guid\": \"7d4a01de-e2e0-46cf-a6f4-b6b31dfaaa3d\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@Boolean\"\n                }\n              },\n              {\n                \"Id\": 137473,\n                \"Version\": 1,\n                \"Guid\": \"64e7dd21-ad14-4378-ac5a-e7a145f3a92c\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Boolean UI Definitions\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Boolean (Yes/No)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@Boolean\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"TitleTrue\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 75059,\n                    \"Version\": 5,\n                    \"Guid\": \"0e69e4e5-1229-4ac2-a954-2e173d19479b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title when True\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75061,\n                    \"Version\": 4,\n                    \"Guid\": \"d0dfae35-7a3d-4400-8ed6-d3b4879224a0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75062,\n                    \"Version\": 4,\n                    \"Guid\": \"46095a91-2c58-43b4-a4d3-d9ac5cf15eb8\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TitleFalse\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 75060,\n                    \"Version\": 6,\n                    \"Guid\": \"bbc06875-6163-4fd6-9d02-4a4ee933e26d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title when False\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75063,\n                    \"Version\": 5,\n                    \"Guid\": \"33bf0ebe-6081-47dc-960d-4c250ea48145\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75064,\n                    \"Version\": 5,\n                    \"Guid\": \"13c6e203-fd2f-4321-a753-eaa093f8836e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TitleIndeterminate\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 75066,\n                    \"Version\": 5,\n                    \"Guid\": \"337f220b-5b35-4899-9916-767f722a83e4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title when Indeterminate\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is shown when the field has no value - so it's only relevant for boolean input fields which have 3 states.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"ae75440d-d7d7-46c9-b405-9508603322ea\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75067,\n                    \"Version\": 4,\n                    \"Guid\": \"43472eaa-d4b6-41a7-8d9a-d4cb5b490407\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75068,\n                    \"Version\": 4,\n                    \"Guid\": \"eb953a6e-f9e6-47c3-ad07-7903846bc9c6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ReverseToggle\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130138,\n                    \"Version\": 7,\n                    \"Guid\": \"116195e5-3f33-4bf3-adbd-155bea2ea818\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Reverse Toggle\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Sometimes you're storing a negative-named-value like <em>Disable.</em> But you want to show the user <strong>Enabled</strong> when the value is <em>false</em>, showing an active toggle. This reverses what the toggle visual shows.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130139,\n                    \"Version\": 6,\n                    \"Guid\": \"59b42099-e4b2-44ce-845a-53f175bd005e\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Normal Toggle: true shows the active toggle\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"Default Toggle: true shows the active toggle\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Reverse Toggle: false shows the active toggle\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130495,\n              \"Version\": 5,\n              \"Guid\": \"ae75440d-d7d7-46c9-b405-9508603322ea\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  var isTristate = context.entities.getOfType('@boolean-tristate');\\n  return !!isTristate;\\n})\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible: Tristate only\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@boolean-tristate\",\n            \"Name\": \"@boolean-tristate\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 74296,\n                \"Version\": 1,\n                \"Guid\": \"297aa555-3867-4a32-b820-946d34315230\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Boolean that also has a null\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Tristate\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@boolean-tristate\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@boolean-default\",\n            \"Name\": \"@boolean-default\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 131475,\n                \"Version\": 2,\n                \"Guid\": \"dd4579e4-ef8a-49bd-b3c9-e1a147f89e9a\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"for yes/no values (actually true/false) - shows a slider in the UI\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>The boolean-default field has no settings.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Boolean (yes/no slider)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@boolean-default\"\n                }\n              },\n              {\n                \"Id\": 136788,\n                \"Version\": 1,\n                \"Guid\": \"a7c0eac2-f6fb-4452-a50b-0cadb2a289d1\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@boolean-default\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@All\",\n            \"Name\": \"@All\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 84733,\n                \"Version\": 2,\n                \"Guid\": \"0bab4be8-e795-4d9f-b50e-f7ec161ed8cb\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"the fields used on all input types\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"General Field Settings\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@All\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Name\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41572,\n                    \"Version\": 5,\n                    \"Guid\": \"7a234b4b-7ede-4f84-a6e1-6e79783842e0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"The field label as shown in the edit form\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 56937,\n                    \"Version\": 3,\n                    \"Guid\": \"5c46175d-2b00-459f-8c2f-a904871e391b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 56938,\n                    \"Version\": 3,\n                    \"Guid\": \"289310e5-adc1-4493-8f90-ddfaeb1da0f5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"InputType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41583,\n                    \"Version\": 6,\n                    \"Guid\": \"e3449540-fdc5-49ab-ab67-aa5a86eb3ffe\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Input Type\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Hidden field which tells the UI what input-type to use in a dynamic form</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42575,\n                    \"Version\": 4,\n                    \"Guid\": \"aca2720d-2df6-4028-a716-8378f12036f2\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42576,\n                    \"Version\": 4,\n                    \"Guid\": \"c7481400-af83-43ea-a186-933d68aee54e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DefaultValue\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41580,\n                    \"Version\": 6,\n                    \"Guid\": \"a7fd8fdb-676d-45e9-85b3-19b7b0eb1215\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Default Value\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p><em>Note that you can also set the default value of a drop-down, just remember to use the Key of the drop-down, not the displayed text.</em></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"Default value for this field - used when this field is first filled in\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41683,\n                    \"Version\": 4,\n                    \"Guid\": \"b0b97f60-a550-48eb-98a0-bb6dfd1aa100\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41684,\n                    \"Version\": 4,\n                    \"Guid\": \"eaa1a860-527f-4ecb-92c0-dbeaf4aa096a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 2\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"HelpGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 75071,\n                    \"Version\": 4,\n                    \"Guid\": \"0ec1f933-c721-4506-b3eb-397c48ee1910\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Help / Instructions\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75072,\n                    \"Version\": 3,\n                    \"Guid\": \"449e6709-2a66-4327-ba32-51a33f95074a\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Placeholder\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 75073,\n                    \"Version\": 3,\n                    \"Guid\": \"0a01881f-4fe4-4a29-8a99-ee9764c0b827\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Placeholder\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>We recommend to use this for quick hints, as it's only visible when the field is empty and will not clutter as the form is filled up.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"This text will appear in the background of empty fields\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75074,\n                    \"Version\": 2,\n                    \"Guid\": \"d6a0d467-f4a0-4117-854a-9ea35d55b318\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75075,\n                    \"Version\": 2,\n                    \"Guid\": \"ab642d12-39a8-48f5-8d1d-f113e5c009bd\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41574,\n                    \"Version\": 7,\n                    \"Guid\": \"57004e54-c530-4777-ba86-f0eb0eafe729\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Add notes / helpful comments to aid the editor in adding his information. Note that you have a WYSIWYG for this field, but be careful to KISS.</p>\\n<p>You can also add helpful links like <a href=\\\"https://www.2sxc.org\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">www.2sxc.org</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 56935,\n                    \"Version\": 4,\n                    \"Guid\": \"22b951f5-4029-4f21-990c-99e809baaffd\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 56936,\n                    \"Version\": 4,\n                    \"Guid\": \"c1885242-dc2a-4fb5-8793-5c4ed776e85e\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"inline\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        },\n                        \"WysiwygConfiguration\": {\n                          \"en-us\": \"d3dde02f-c1dc-43b8-a8b7-4be3c43eadd0\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"UiGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63427,\n                    \"Version\": 5,\n                    \"Guid\": \"04019772-2133-4513-8f0f-408082b70534\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"User Interface (UI) Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Configure how this field behaves in the input form.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"859a787b-f9d4-4069-89de-4e51d2a21bd2\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63428,\n                    \"Version\": 4,\n                    \"Guid\": \"c4519a06-85f3-4661-bc76-292c9721083a\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VisibleInEditUI\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41576,\n                    \"Version\": 5,\n                    \"Guid\": \"750f4dfc-c243-4076-bb03-c0733dae7758\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Visible In Edit UI\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If true (the common value) this input field is visible.</p>\\n<p>There are only a few cases, where an invisible field makes sense, but we won't tell you about these yet. It's for a future feature :).</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42579,\n                    \"Version\": 3,\n                    \"Guid\": \"dd45ee54-6b30-4808-9022-46cc31ec5b86\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Invisible\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Visible\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Disabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41581,\n                    \"Version\": 7,\n                    \"Guid\": \"0b34ba0a-ff14-4dca-91ba-a65519dc824f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"False\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Disabled\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Will permanently disable a field in the UI - so the user can see the value but not change it. You'll be able to change it using code or by prefilling it.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"44719726-8365-49b1-96f3-4b97ae608b2a\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77283,\n                    \"Version\": 5,\n                    \"Guid\": \"d5c8dbdb-acfd-4d6d-8193-89c62cd30016\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Enabled so user can edit\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Disabled so user cannot edit\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Required\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41578,\n                    \"Version\": 7,\n                    \"Guid\": \"24c5a584-6344-42f4-b794-9e8e91fa2d78\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Required\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If this field is required. The Edit-UI won't allow saving if a required field is blank.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"1eb95148-7cd6-4e1a-b32e-ce748891dfb1\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77282,\n                    \"Version\": 5,\n                    \"Guid\": \"4c5d739e-ec96-42ac-844a-2cf8e634eb22\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Optional\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Required\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DisableTranslation\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 75058,\n                    \"Version\": 5,\n                    \"Guid\": \"3883142a-c7f1-4ce2-b724-06fa52579cbc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Disable Translation\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If enabled, will only be editable in the primary language.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"32921231-379e-4819-8977-351a4e2d098b\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77284,\n                    \"Version\": 3,\n                    \"Guid\": \"e6061a08-85bb-4f96-bfd9-57d88369f421\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Translatable\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Not translatable\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DisableAutoTranslation\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166025,\n                    \"Version\": 8,\n                    \"Guid\": \"9a9658f0-6226-48af-8985-0832f96efede\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"DisableAutoTranslation\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"f76bfadf-be8a-4703-a94e-66b25a3f37f4\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"DisableAutoTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166026,\n                    \"Version\": 5,\n                    \"Guid\": \"ab38e5e8-eae7-40b2-898f-8879509bb87d\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Auto-Translate will try to translate this and unlock the field for editing\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"Auto-Translate Default (most text fields are auto-translated, other fields not)\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Auto-Translate will skip this (recommended for name fields etc.)\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IsEphemeral\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130160,\n                    \"Version\": 8,\n                    \"Guid\": \"7ea452dc-12f0-4e85-9320-99cb98e57dfa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Ephemeral / Temporary\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>See docs for <a href=\\\"https://r.2sxc.org/ephemeral\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">ephemeral / variable / temporary fields</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130161,\n                    \"Version\": 7,\n                    \"Guid\": \"bc488257-42aa-40dc-b066-ea9ff01b4cab\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Save Values\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"Save Values (default)\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Don't save value (ephemeral) - will treat this as a temporary variable in the UI\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ValidationGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63418,\n                    \"Version\": 7,\n                    \"Guid\": \"69cf3253-e0d6-4394-9fb3-eb8945392cb8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Field Validations\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Configure validation settings here to ensure that the field is ok to save or show warnings only. Read more about <a href=\\\"https://r.2sxc.org/FieldValidation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Field Validation in the docs</a>.</p>\\n<p>Note that these are work-in-progress and not final yet.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63419,\n                    \"Version\": 6,\n                    \"Guid\": \"1c78d23c-098c-4692-b078-32f9c7c42da5\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Errors\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63423,\n                    \"Version\": 3,\n                    \"Guid\": \"69f44c1b-bb08-416c-8b68-41388d6ba734\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Errors\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>These regular expressions will be used to check if the field is ok. If not valid, will prevent the form from saving. Read more about <a href=\\\"https://r.2sxc.org/FieldValidation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Field Validation in the docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"58739790-70e1-4df3-a98a-0cc69a260e68\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63426,\n                    \"Version\": 2,\n                    \"Guid\": \"b452fa04-e347-4ab7-ba4c-e9ab53ab9e8c\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"RegExCheck\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": false\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": true\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Warnings\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63420,\n                    \"Version\": 5,\n                    \"Guid\": \"7ec70497-a426-448a-a730-ce79f35dd47b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Warnings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>These regular expressions will be used to check if the field is ok, but only show warnings if they fail. So the user can still store the data, but he'll be notified that something might be wrong. Read more about <a href=\\\"https://r.2sxc.org/FieldValidation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Field Validation in the docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"e9def33a-148f-4dd1-975c-9422baf6bc94\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63421,\n                    \"Version\": 4,\n                    \"Guid\": \"39f71721-57b4-4a69-9a3b-261f4b694961\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"RegExCheck\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": false\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": true\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ValidationRegExJavaScript\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41585,\n                    \"Version\": 4,\n                    \"Guid\": \"fd6326de-4ffe-4f77-8580-436ec502ae4c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Validation RegEx JavaScript\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>OLD feature: Help text: regular expression to validate the input - the UI will not allow saving if this condition is not met - see <a href=\\\"https://2sxc.org/help?tag=validation\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">help with tag validation</a> for more infos. We're working on a new improved feature.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63424,\n                    \"Version\": 2,\n                    \"Guid\": \"890ee484-9888-4ed6-9c03-0ee03bea1617\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63425,\n                    \"Version\": 2,\n                    \"Guid\": \"4530d30b-db0e-4541-8cab-08363eb03fe6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CustomJavaScript\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41587,\n                    \"Version\": 3,\n                    \"Guid\": \"53550e09-cf1b-48bc-a78a-93c98d546bdb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Custom JavaScript\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Execute custom javascript in the edit-form. Use with extreme caution. Read more on <a href=\\\"http://2sxc.org/en/help?tag=edit-form-development\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc.org/en/help?tag=edit-form-development</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42577,\n                    \"Version\": 2,\n                    \"Guid\": \"d4325442-173f-4b41-8c79-5af13b51d41c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 42578,\n                    \"Version\": 2,\n                    \"Guid\": \"2b3ee05b-91c5-4b79-8d75-211ec1445a39\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 12\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupFormulas\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 120060,\n                    \"Version\": 16,\n                    \"Guid\": \"ed7aea66-7a76-4c72-9f5f-23a1f1c882c0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Formulas Σ\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><a href=\\\"https://r.2sxc.org/formulas\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\"><img style=\\\"float: right; width: 25%;\\\" src=\\\"https://sources.2sxc.org/assets/v12/content-types/formulas-banner.svg?12.01\\\"></a>Formulas can change value, visibility etc. You should edit them in the edit UI using the developer mode. Use this section to manually delete or fix formulas in emergencies. See <a href=\\\"https://r.2sxc.org/formulas\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Formulas Documentation</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"92c9f03c-31da-4288-91ed-780503438983\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"EnableExperimental\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 120062,\n                    \"Version\": 15,\n                    \"Guid\": \"6cc95e17-0baf-46db-a20c-9031135cc53a\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Formulas\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 120061,\n                    \"Version\": 4,\n                    \"Guid\": \"822c72d5-d864-4e2c-ba28-63117973a1d5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Formulas / Calculations\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 120073,\n                    \"Version\": 3,\n                    \"Guid\": \"0e862ce8-c341-4c5a-937f-09e37a5f5677\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"UiFormula\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": false\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": true\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130246,\n                    \"Version\": 1,\n                    \"Guid\": \"8fe736ac-91b2-416e-a5f2-0ca4e7979138\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"GroupEnd\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableExperimental\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130155,\n                    \"Version\": 4,\n                    \"Guid\": \"94277a9d-d94c-46f4-abed-eb3276321f57\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Enable Experimental Features\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130156,\n                    \"Version\": 3,\n                    \"Guid\": \"ef92527f-ec0e-4e09-af98-103b41881912\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Hide experimental settings\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"Don't show experimental settings (default)\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Show experimental settings\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130494,\n              \"Version\": 4,\n              \"Guid\": \"859a787b-f9d4-4069-89de-4e51d2a21bd2\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  var hints = [];\\n  if(!data.VisibleInEditUI) hints.push('\\uD83E\\uDD77\\uD83C\\uDFFD');\\n  if(data.Disabled) hints.push('\\uD83D\\uDD12');\\n  if(data.Required) hints.push('✅');\\n  if(data.DisableTranslation) hints.push('no \\uD83C\\uDF10');\\n  if(data.DisableAutoTranslation === false) hints.push('auto-\\uD83C\\uDF10');\\n  if(data.DisableAutoTranslation === true) hints.push('no auto-\\uD83C\\uDF10');\\n  if(data.IsEphemeral) hints.push('no \\uD83D\\uDCBE');\\n  var hint = hints.length ? ' (' + hints.join(', ') + ')' : '';\\n  return data.default + hint; \\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130135,\n              \"Version\": 3,\n              \"Guid\": \"44719726-8365-49b1-96f3-4b97ae608b2a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.VisibleInEditUI; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide option if it's not visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130125,\n              \"Version\": 6,\n              \"Guid\": \"1eb95148-7cd6-4e1a-b32e-ce748891dfb1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.VisibleInEditUI && !data.Disabled; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide if not visible or not enabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130137,\n              \"Version\": 3,\n              \"Guid\": \"32921231-379e-4819-8977-351a4e2d098b\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.VisibleInEditUI && !data.Disabled; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Hide if not visible in UI\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 166032,\n              \"Version\": 2,\n              \"Guid\": \"f76bfadf-be8a-4703-a94e-66b25a3f37f4\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return !data.DisableTranslation; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130157,\n              \"Version\": 3,\n              \"Guid\": \"58739790-70e1-4df3-a98a-0cc69a260e68\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.EnableExperimental; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show if experimental\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130158,\n              \"Version\": 3,\n              \"Guid\": \"e9def33a-148f-4dd1-975c-9422baf6bc94\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return !!data.EnableExperimental; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show if experimental\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130254,\n              \"Version\": 2,\n              \"Guid\": \"92c9f03c-31da-4288-91ed-780503438983\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.default + (data.Formulas.length ? ' (' + data.Formulas.length + ')' : ''); }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@Number\",\n            \"Name\": \"@Number\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53707,\n                \"Version\": 1,\n                \"Guid\": \"1e8276d5-efa9-4093-9ab1-f64a3e12de40\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configuration for a number field\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Number\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@Number\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Decimals\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41638,\n                    \"Version\": 3,\n                    \"Guid\": \"b0a8094d-e970-4bdb-9b52-de2c36b5e08b\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"*\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41639,\n                    \"Version\": 2,\n                    \"Guid\": \"159215ba-de96-474c-80dd-5235457dbb02\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"0\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Number of Decimals\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Typically 0 (then only integers ergo whole numbers allowed)</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Min\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41640,\n                    \"Version\": 2,\n                    \"Guid\": \"cf6bd802-5692-4c8b-9530-220f4ce93c72\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41641,\n                    \"Version\": 1,\n                    \"Guid\": \"13cab28e-d270-4e41-ba08-35dad6842c64\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Minimum\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Minimum value. Used if you want to ensure that a number is between two values. Leave blank if not needed.\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Max\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41642,\n                    \"Version\": 1,\n                    \"Guid\": \"16b2f6b6-4136-4e83-9560-f7a3e4862f0d\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41643,\n                    \"Version\": 1,\n                    \"Guid\": \"b2f14ccc-80df-42a9-848e-4f54fedb31fc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Maximum\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Maximum value. Used if you want to ensure that a number is between two values. Leave blank if not needed.\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@number-default\",\n            \"Name\": \"@number-default\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 131474,\n                \"Version\": 4,\n                \"Guid\": \"bf1ee3eb-5878-4f5e-94ad-b5b6d4d2d3fe\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"standard number input field with 0 or more decimals\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>The number-default field has no settings.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Basic Number Input\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@number-default\"\n                }\n              },\n              {\n                \"Id\": 136792,\n                \"Version\": 1,\n                \"Guid\": \"e2410590-f90f-44f8-a951-4274bc807891\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@number-default\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@DateTime\",\n            \"Name\": \"@DateTime\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53705,\n                \"Version\": 1,\n                \"Guid\": \"dac48bd5-7c9b-4e7a-b438-4718f70e4636\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"DateTime UI Definitions\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Date and Time\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@DateTime\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"UseTimePicker\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41598,\n                    \"Version\": 2,\n                    \"Guid\": \"802ca6c7-3dee-4105-8e6d-47621ac3683e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Use Time-Picker\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If activated, the picker also enables a time-choice.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77273,\n                    \"Version\": 1,\n                    \"Guid\": \"ae3dc872-f0b4-401e-a779-7c1365a9202e\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@datetime-default\",\n            \"Name\": \"@datetime-default\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 131473,\n                \"Version\": 3,\n                \"Guid\": \"4a073785-b7fb-4b37-81bf-19fdbe40a010\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"for normal date / time selections\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>The datetime-default field has no settings.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Date/time picker\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@datetime-default\"\n                }\n              },\n              {\n                \"Id\": 136787,\n                \"Version\": 1,\n                \"Guid\": \"5188fb5d-b8f0-4a6a-88f8-5ae8b2c6d545\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@datetime-default\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@entity-content-blocks\",\n            \"Name\": \"@entity-content-blocks\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 52210,\n                \"Version\": 1,\n                \"Guid\": \"942f090c-9daf-44de-8539-4f8d604cf78d\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Container for inner-content references\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Content-Blocks Container\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@entity-content-blocks\"\n                }\n              },\n              {\n                \"Id\": 52211,\n                \"Version\": 2,\n                \"Guid\": \"c546fe23-367e-4ea3-99e6-90e53c2ef570\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"Use this to manage inner content-blocks - discover more on 2sxc.org/help?tag=content-blocks\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Inner Content Items\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"entity-content-blocks\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": true\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@entity-content-blocks\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@hyperlink-default\",\n            \"Name\": \"@hyperlink-default\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53715,\n                \"Version\": 2,\n                \"Guid\": \"dbb9a27b-210c-4f82-88cc-66742b607188\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"use to refer to a page, image, document, whatever\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Link to Url, File or Page \"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"hyperlink-default\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": false\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": true\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@hyperlink-default\"\n                }\n              },\n              {\n                \"Id\": 131476,\n                \"Version\": 1,\n                \"Guid\": \"fca9b122-b3b2-4c46-8840-7f0ef2380dd0\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"use to refer to a page, image, document, whatever\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>The hyperlink-default field has no settings.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"default (link, page, file, ...)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@hyperlink-default\"\n                }\n              },\n              {\n                \"Id\": 136791,\n                \"Version\": 1,\n                \"Guid\": \"2734ffe4-8992-45d4-a593-095571bab6c3\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@hyperlink-default\"\n                }\n              },\n              {\n                \"Id\": 183847,\n                \"Version\": 1,\n                \"Guid\": \"1b115da0-7fce-49a2-ad45-71ae62348765\",\n                \"Type\": {\n                  \"Id\": \"c490b369-9cd2-4298-af74-19c1e438cdfc\",\n                  \"Name\": \"MetadataExpectedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"MetadataTypes\": {\n                      \"en-us\": \"ImageDecorator\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Links / Images expect Image Decorator Metadata\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 2\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@hyperlink-default\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@hyperlink-library\",\n            \"Name\": \"@hyperlink-library\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 52206,\n                \"Version\": 2,\n                \"Guid\": \"baf97dd4-5f6e-466a-b7b2-b2ed0cda2ac6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configure a file-library field containing folders, files and more.\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Many files, optionally in folders - just for this field. Ideal for galeries and more. Each file and folder can also have additional metadata if configured.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"File Library\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@hyperlink-library\"\n                }\n              },\n              {\n                \"Id\": 52209,\n                \"Version\": 2,\n                \"Guid\": \"2dc2667a-4eb8-4f27-bc41-2730d92f7987\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"*\": \"\"\n                    },\n                    \"Description\": {\n                      \"*\": \"Library of files, optionally with folders and file/folder metadata\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Library of files\"\n                    },\n                    \"Type\": {\n                      \"*\": \"hyperlink-library\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"*\": true\n                    },\n                    \"UseAdam\": {\n                      \"*\": true\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@hyperlink-library\"\n                }\n              },\n              {\n                \"Id\": 183848,\n                \"Version\": 1,\n                \"Guid\": \"576d2631-c274-4acb-b42b-c7dd40913be3\",\n                \"Type\": {\n                  \"Id\": \"c490b369-9cd2-4298-af74-19c1e438cdfc\",\n                  \"Name\": \"MetadataExpectedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"MetadataTypes\": {\n                      \"en-us\": \"ImageDecorator\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Link Libraries / Albums expect ImageDecorator Metadata\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 2\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@hyperlink-library\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"FolderDepth\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41631,\n                    \"Version\": 2,\n                    \"Guid\": \"6f3a3dcf-f69c-4660-88f8-ce2e1438c9fa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"2\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Folder Depth\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If sub folders are allowed and how deply they may be nested. Use 0 for no sub folders, 1 for 1 level only, 2 for 2 levels (like /gallery/subgallery) etc. Use a large number like 100 for practically unlimited sub folders, but not recommended for realistic use cases.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77276,\n                    \"Version\": 1,\n                    \"Guid\": \"9dc62cf8-db94-46a3-b309-98c58b19f552\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"*\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowAssetsInRoot\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41633,\n                    \"Version\": 2,\n                    \"Guid\": \"8f991906-39b3-437e-9bf5-09730b47dfe2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Allow Assets In Root Folder\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Specifies if files may be placed in the core / root container, or if the user is required to create sub folders. This would be the case if you expect multiple groups of files, but never a top-level list.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41634,\n                    \"Version\": 2,\n                    \"Guid\": \"d42769f3-a31f-4f5b-95d0-6100314a082b\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MetadataContentTypes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41635,\n                    \"Version\": 4,\n                    \"Guid\": \"050e4c5a-24b8-4fec-b064-2c536f5cbb54\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Metadata Content Types\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The content-type (or types) to be used for assets in this library. To use this, first create a content-type (like DownloadMetadata or MugshotMetadata) and type the name of the content type into this field. Advanced configuration is possible, discover on <a href=\\\"https://2sxc.org/help?tag=adam\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">2sxc.org/help?tag=adam</a></p>\\n<p>&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46370,\n                    \"Version\": 3,\n                    \"Guid\": \"a0b102c2-c358-44a7-91e1-d5e0e781b704\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46371,\n                    \"Version\": 3,\n                    \"Guid\": \"4269904d-d80f-4ea7-b0c3-5815911d9e08\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@Hyperlink\",\n            \"Name\": \"@Hyperlink\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53706,\n                \"Version\": 1,\n                \"Guid\": \"386c8195-d911-4dd9-9ce2-f90c9f48e6c4\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"File UI Definitions\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Hyperlink (link or file)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@Hyperlink\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"FileFilter\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41611,\n                    \"Version\": 5,\n                    \"Guid\": \"f3c22555-bb82-4bb5-93a8-0cdfbb392f50\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Custom File Extensions\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Enter the allowed file extensions, comma-separated. Example: \\\"*.jpg,*.bmp,*.png,*.gif\\\" or you can also do \\\"jpg,png,doc\\\" or use regex like \\\"[0-9]{2}.*\\\\.(jpg|png)\\\"</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46393,\n                    \"Version\": 3,\n                    \"Guid\": \"d3597846-0b56-480b-a61a-0c95cc156d0e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46394,\n                    \"Version\": 3,\n                    \"Guid\": \"17f774d8-fdbb-4624-9cac-5ba196b1c559\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupButtons\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130226,\n                    \"Version\": 2,\n                    \"Guid\": \"15b0b2c7-da26-4947-8ff3-0f75096de205\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Buttons to the Side of the Input Field\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130227,\n                    \"Version\": 1,\n                    \"Guid\": \"f6f8afa5-8ec7-465b-84d6-bf4b226cf4bf\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Buttons\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41628,\n                    \"Version\": 6,\n                    \"Guid\": \"78c9cad8-4882-42af-a7a7-6dcc9efaa76d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"adam,more\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Buttons\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Buttons to show directly at the input-field. Use combinations of <em>adam</em>, <em>page </em>and <em>more. </em>More <a href=\\\"https://2sxc.org/help?tag=field-hyperlink\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">help here</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53737,\n                    \"Version\": 4,\n                    \"Guid\": \"e1c2e9c2-d823-4fa2-a8ed-61e6ceb67eef\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53738,\n                    \"Version\": 4,\n                    \"Guid\": \"88b19925-1986-43cf-b506-9dba9e3c0ab0\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupButtonsEllipsis\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46389,\n                    \"Version\": 4,\n                    \"Guid\": \"14ceb15b-8890-4d30-bd93-bdefe6c536b2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Buttons in the Dialog Ellipsis\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>These are the buttons you can show in the large dialog, in the more \\\"&hellip;\\\" button.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46392,\n                    \"Version\": 3,\n                    \"Guid\": \"61ea8550-b7f8-4a78-9b66-27bebda96789\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DefaultDialog\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41618,\n                    \"Version\": 5,\n                    \"Guid\": \"67fa4342-dd9b-4a04-ac66-071330f1ac0b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Default Dialog\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46368,\n                    \"Version\": 3,\n                    \"Guid\": \"c09560e6-8c8a-4140-b4fc-b70c6d1e176e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46369,\n                    \"Version\": 3,\n                    \"Guid\": \"117dd404-d80b-42b2-9a38-aa5132ef4568\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"None:None\\nAutomatic Data Asset Manager (ADAM):Adam\\nPage Picker:PagePicker\\nImage Manager:ImageManager\\nFile Manager:FileManager\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ShowPagePicker\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41620,\n                    \"Version\": 9,\n                    \"Guid\": \"be42e432-084c-43a8-861e-bfec222f041a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Show Page Picker\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41621,\n                    \"Version\": 9,\n                    \"Guid\": \"a88187b4-af71-423c-8348-f565271e20fc\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Hide Page Picker\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Show Page Picker in Menu\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ShowImageManager\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41622,\n                    \"Version\": 8,\n                    \"Guid\": \"95ae3c5e-aa0c-4720-9683-9ff596432c82\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Show Image Manager\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41623,\n                    \"Version\": 8,\n                    \"Guid\": \"e2ca89fd-ffc2-48a9-9878-ba08f284a144\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Hide Site Images in Menu\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Show Site Images in Menu\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ShowFileManager\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41624,\n                    \"Version\": 5,\n                    \"Guid\": \"1569a887-2d5d-4584-ac97-deee187647c8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Show File Manager\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41625,\n                    \"Version\": 5,\n                    \"Guid\": \"3ff12832-e891-45f7-b788-bd7e8fb27c46\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Hide Site Files Picker\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Site Site Files Picker in Menu\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ShowAdam\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41626,\n                    \"Version\": 4,\n                    \"Guid\": \"ae19ed2d-27ac-4f9f-a0cb-d91715e7dbf1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Show Adam\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Shows the Automatic Digital Asset Manager in the menu</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41627,\n                    \"Version\": 4,\n                    \"Guid\": \"6996d7d8-bda3-48ce-a1e2-84db0e426949\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Hide ADAM in the Menu\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Show ADAM in the Menu\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EnableImageConfiguration\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144407,\n                    \"Version\": 7,\n                    \"Guid\": \"51690ebc-e20f-4a4c-9c13-eefb465a20d5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Enable Image Config \\uD83C\\uDFAF\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144408,\n                    \"Version\": 6,\n                    \"Guid\": \"16e1571f-6f80-40d5-8546-a78ec480e541\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Disable image configuration\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"Enable image configuration (default)\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Enable image configuration if the file is an image \\uD83C\\uDFAF\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AdvancedGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46390,\n                    \"Version\": 2,\n                    \"Guid\": \"c1bb7cbb-c698-4b58-a7f1-edd9c4dbaee4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Advanced Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46391,\n                    \"Version\": 1,\n                    \"Guid\": \"a1167733-9f5d-4135-b6ba-5f769ba5708d\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Paths\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41614,\n                    \"Version\": 4,\n                    \"Guid\": \"bbb7180b-1389-46c0-a3f6-c18aa88bd749\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Paths\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is only needed if you use the old file pickers (not ADAM). Specify an&nbsp;<em>existing </em>folder and that will be the root for the file pickers. If you're unsure, best to leave it empty. More <a href=\\\"http://2sxc.org/help?tag=field-hyperlink\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">help here</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8616c87b-9fc2-4f72-9e6e-71ebe1f8d563\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77277,\n                    \"Version\": 2,\n                    \"Guid\": \"f9b3a532-0330-4881-be16-5c30fc224c79\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77278,\n                    \"Version\": 2,\n                    \"Guid\": \"a6e1725a-e3a4-4f7c-9f1d-bf5d7e239f5b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ServerResourceMapping\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46386,\n                    \"Version\": 3,\n                    \"Guid\": \"6965dd64-29a0-4e65-ab75-70a14bd4e0dc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Server Resource References\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>determine how server resources should be references - the default mode will create links like file:17, the other mode will use /path/file.name</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46387,\n                    \"Version\": 2,\n                    \"Guid\": \"de32521f-e3a1-410d-9c5c-37245532b9b8\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46388,\n                    \"Version\": 2,\n                    \"Guid\": \"1e3b8c8f-a5e1-4bb8-b419-8b88bbf67fc0\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"Default (let server manage):\\nLet server manage the link and just use ID:id\\nLink directly and use url:url\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130145,\n              \"Version\": 3,\n              \"Guid\": \"8616c87b-9fc2-4f72-9e6e-71ebe1f8d563\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) {\\n  return !!(data.ShowFileManager || data.ShowImageManager);\\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible: InEditUI: Show only if site files are used\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@empty-end\",\n            \"Name\": \"@empty-end\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 130231,\n                \"Version\": 2,\n                \"Guid\": \"d25ca4ed-ed46-4447-a9f4-9c5bcd83d1e5\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Close a field group\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>This closes a field-group and doesn't have any settings.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Field-Group End\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@empty-end\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@empty-default\",\n            \"Name\": \"@empty-default\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 52204,\n                \"Version\": 4,\n                \"Guid\": \"12297a3a-1e70-4a76-bd70-f9cca8fc185d\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"An empty field (will not store data) for Headings/Groups\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Field Group Header\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"empty-default\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": true\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@empty-default\"\n                }\n              },\n              {\n                \"Id\": 52205,\n                \"Version\": 6,\n                \"Guid\": \"d7df774a-6a29-4db9-8352-d44e25266916\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configuration of the Field-Groups\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Empty fields don't get saved but are used to structure the input form.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Groups, Titles and Instructions\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@empty-default\"\n                }\n              },\n              {\n                \"Id\": 136789,\n                \"Version\": 1,\n                \"Guid\": \"51dd473d-e3fd-4c1c-b4e6-d47247a6a66d\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@empty-default\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"DefaultCollapsed\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41599,\n                    \"Version\": 4,\n                    \"Guid\": \"b1686959-5bd6-41f4-81a8-0fcc91962e59\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Collapsed by default\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If set to true, then the field group is collapsed by default.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41600,\n                    \"Version\": 4,\n                    \"Guid\": \"7fae583e-963b-42a3-8b71-cf7628b518a9\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Open when dialog loads\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Collapsed when the dialog loads\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@empty-message\",\n            \"Name\": \"@empty-message\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 131463,\n                \"Version\": 3,\n                \"Guid\": \"0ec288b3-3ce3-41c6-be6f-02f06e08f45a\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Just show a message\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This will just show a message in the edit form.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Message\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@empty-message\"\n                }\n              }\n            ],\n            \"Attributes\": []\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@string-json\",\n            \"Name\": \"@string-json\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 135589,\n                \"Version\": 1,\n                \"Guid\": \"73ebb249-2c4e-4234-bf91-3b056742f23e\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Configuration for a json-editor field\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"JSON editor\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-json\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Rows\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135569,\n                    \"Version\": 3,\n                    \"Guid\": \"095e1da5-4597-41b9-a15c-0f8619dba10c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"10\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Rows\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135570,\n                    \"Version\": 2,\n                    \"Guid\": \"ade6d28c-64ea-41eb-89eb-2f1be6ac4c18\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"*\": 0.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonValidation\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135571,\n                    \"Version\": 5,\n                    \"Guid\": \"4dc0536d-f22b-431b-b39d-5a771501b750\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"strict\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"JSON Validation\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135572,\n                    \"Version\": 3,\n                    \"Guid\": \"0444cf6c-0779-4e97-b057-7dced86a3a98\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183877,\n                    \"Version\": 3,\n                    \"Guid\": \"f74b1720-bb48-4ede-91ce-b74e91f7e885\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"f57b953e-9caf-4bf8-bbf8-51d2479835f5\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonSchemaMode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135574,\n                    \"Version\": 10,\n                    \"Guid\": \"c0c26653-22ee-4ccf-80b9-61c68466725b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"none\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"JSON Schema Mode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>JSONs can validate using a <a href=\\\"https://json-schema.org/\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">schema</a>.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135575,\n                    \"Version\": 4,\n                    \"Guid\": \"0b972173-a209-435b-aa98-6e1d5ad7116c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183882,\n                    \"Version\": 8,\n                    \"Guid\": \"3a7d4165-b25e-40d2-ab8c-953de56532e8\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"a4800b93-f69b-419c-bfa9-7eadbf1a9bfc\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonSchemaSource\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135577,\n                    \"Version\": 5,\n                    \"Guid\": \"7c8e0a6d-4665-4d19-ada6-a37acb28b325\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Schema Source\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"c00d685b-568a-45dc-b43a-92a32ed40b36\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135578,\n                    \"Version\": 2,\n                    \"Guid\": \"4af56eba-bdbb-44c4-813e-a16d39568d21\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183884,\n                    \"Version\": 2,\n                    \"Guid\": \"b30d51f3-2a2a-4aba-b8ed-cacff7bdc848\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"2705cd61-c736-41f6-8d85-f717597924ea\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonSchemaUrl\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135580,\n                    \"Version\": 2,\n                    \"Guid\": \"ec9a800d-9976-404f-a057-37a5521c060f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Schema Url\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Many common schemas are available on <a href=\\\"https://www.schemastore.org/json/\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">SchemaStore</a> or you can specify other URLs.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"78ec0298-216e-4fad-bb9e-7dd465d82952\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135581,\n                    \"Version\": 2,\n                    \"Guid\": \"be1342ac-5da9-4aa4-b09c-7a72729b06f5\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"*.json\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": true\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonSchemaRaw\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-json\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135931,\n                    \"Version\": 5,\n                    \"Guid\": \"32dba462-d65c-4aa9-8a99-46ecc3d05a2d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-json\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Raw JSON Schema\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Custom schemas must adhere to the latest <a href=\\\"https://json-schema.org/draft/2019-09/schema\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Draft 8</a> <a href=\\\"https://json-schema.org/specification.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">specs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"5b934578-e633-4bcd-86b3-217c61337d4e\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135932,\n                    \"Version\": 4,\n                    \"Guid\": \"fe42f234-acfb-4810-9ceb-5d14e52faa3f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135933,\n                    \"Version\": 4,\n                    \"Guid\": \"544bfcfb-3fb2-4eef-b71f-d4736727b277\",\n                    \"Type\": {\n                      \"Id\": \"@string-json\",\n                      \"Name\": \"@string-json\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"JsonSchemaMode\": {\n                          \"en-us\": \"strict\"\n                        },\n                        \"JsonSchemaRaw\": {\n                          \"en-us\": \"\"\n                        },\n                        \"JsonSchemaSource\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"JsonValidation\": {\n                          \"en-us\": \"strict\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"JsonSchemaUrl\": {\n                          \"en-us\": \"https://json-schema.org/draft/2019-09/schema\"\n                        }\n                      },\n                      \"Number\": {\n                        \"Rows\": {\n                          \"en-us\": 25\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonCommentsAllowed\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144393,\n                    \"Version\": 3,\n                    \"Guid\": \"6a620b1e-0cf7-417f-8770-8ad7ab93dfa8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"JsonCommentsAllowed\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144394,\n                    \"Version\": 2,\n                    \"Guid\": \"c7f62557-5854-4a3b-b938-3450a577399e\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Show warning if user adds comments\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"JSON comments - use defaults (show warning)\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Allow comments in JSON\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183875,\n              \"Version\": 2,\n              \"Guid\": \"f57b953e-9caf-4bf8-bbf8-51d2479835f5\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Tooltip\\nstrict,JSON must be valid (default),The JSON must be valid and can't be saved if it isn't.\\nlight,Show warning on invalid JSON,The JSON should be valid, but save is still allowed if not.\\nnone,JSON can be anything (not recommended),Allow any input, incl. text and invalid JSON.\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Tooltip]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Tooltip]</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Custom JSON - JSON Validation\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183881,\n              \"Version\": 7,\n              \"Guid\": \"a4800b93-f69b-419c-bfa9-7eadbf1a9bfc\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\nnone,No Schema (default),\\\"Don't use a JSON Schema\\\"\\nstrict,Enforce (recommended),\\\"You can provide a real JSON Schema which will be checked and enforced.\\\"\\nlight,Suggest,\\\"Use a JSON Schema to help editing, but don't enforce\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Json Picker - Json Schema\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"https://json-schema.org/\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 135938,\n              \"Version\": 1,\n              \"Guid\": \"c00d685b-568a-45dc-b43a-92a32ed40b36\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.JsonSchemaMode != 'none'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183883,\n              \"Version\": 1,\n              \"Guid\": \"2705cd61-c736-41f6-8d85-f717597924ea\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\nlink,Link / URL,\\\"Use a link to a Schema in the internet or on your site\\\"\\nraw,Manual,\\\"Add Schema manually as JSON below\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"JSON Editor - Schema Source\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 135939,\n              \"Version\": 1,\n              \"Guid\": \"78ec0298-216e-4fad-bb9e-7dd465d82952\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return data.JsonSchemaMode != 'none' && data.JsonSchemaSource == 'link';\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 135936,\n              \"Version\": 1,\n              \"Guid\": \"5b934578-e633-4bcd-86b3-217c61337d4e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return data.JsonSchemaMode != 'none' && data.JsonSchemaSource == 'raw';\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@String\",\n            \"Name\": \"@String\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 46433,\n                \"Version\": 4,\n                \"Guid\": \"605214b9-4de7-448d-8db4-deefa46680f6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"String UI Definitions - only included for compatibility to old app-imports\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Strings don't have any own settings - all string settings are at the specific input-element.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"String (Text)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@String\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"InputType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46498,\n                    \"Version\": 3,\n                    \"Guid\": \"c424fd63-3ed9-4cc2-8394-397fd6ec6add\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Input Type (old / deprecated)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"This was an older implementation - do not use any more. It's only included so that old data will still work.\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46499,\n                    \"Version\": 2,\n                    \"Guid\": \"e63bb057-e819-49dc-8dc7-d3dfb804b33f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46500,\n                    \"Version\": 2,\n                    \"Guid\": \"7e2d05df-8c51-41d4-8b0b-af258792fa04\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupOldDropdown\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130437,\n                    \"Version\": 8,\n                    \"Guid\": \"d91897bf-1bcf-4df7-aaeb-893dcc94c3eb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Old Settings - Please Migrate Manually\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Previously the dropdown values were configured here. This was an older implementation - do not use any more. It's only included so that old data will still work.&nbsp;</p>\\n<p style=\\\"text-align: center;\\\"><span style=\\\"color: #e03e2d;\\\"><strong>Please configure this field to be a string-dropdown and move the values to there.</strong></span></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"f670e444-96a8-4a00-b588-70a6f8d879ef\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130438,\n                    \"Version\": 7,\n                    \"Guid\": \"2c56b45a-4758-4d26-be47-56f30375602a\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DropdownValues\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46502,\n                    \"Version\": 14,\n                    \"Guid\": \"884665fa-858e-4f29-b008-a8c358a26604\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Old Dropdown Values\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"9841f99d-f188-4fb6-b8e0-05890cf288ae\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46504,\n                    \"Version\": 13,\n                    \"Guid\": \"c43bbdf6-c699-4a3d-9e2b-32c56783209c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46505,\n                    \"Version\": 13,\n                    \"Guid\": \"00c86c88-f991-4b1f-989e-de87e3886350\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RowCount\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46501,\n                    \"Version\": 7,\n                    \"Guid\": \"e9353448-5f32-483f-b6f2-506694f247fe\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Old Row Count\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"This was an older implementation - do not use any more. It's only included so that old data will still work.\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"b8083a65-c590-48d8-a278-d96e180db82b\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46503,\n                    \"Version\": 6,\n                    \"Guid\": \"bc63f8d1-3886-424f-bbb3-d8dbac21d7df\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"*\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"BtnFlushValues\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130440,\n                    \"Version\": 3,\n                    \"Guid\": \"f3ee9289-df63-4cda-92a7-e9037230b681\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Flush Old Values (toggle this after moving the values to the new location)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"IsEphemeral\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130441,\n                    \"Version\": 2,\n                    \"Guid\": \"b947dac0-8c4c-4639-8e25-fb45105d2cc4\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130439,\n              \"Version\": 4,\n              \"Guid\": \"f670e444-96a8-4a00-b588-70a6f8d879ef\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  if(context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n  return !!data.DropdownValues;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130442,\n              \"Version\": 4,\n              \"Guid\": \"9841f99d-f188-4fb6-b8e0-05890cf288ae\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.BtnFlushValues ? '' : data.initial; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value: Reset if Flush\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130443,\n              \"Version\": 1,\n              \"Guid\": \"b8083a65-c590-48d8-a278-d96e180db82b\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.BtnFlushValues ? '' : data.initial; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@string-default\",\n            \"Name\": \"@string-default\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53708,\n                \"Version\": 1,\n                \"Guid\": \"7987fc75-68b0-4e00-81fc-1ed91a36c5fe\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Default single or multi-line string input\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"String / Text (basic)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-default\"\n                }\n              },\n              {\n                \"Id\": 136470,\n                \"Version\": 1,\n                \"Guid\": \"c3e3ebec-4144-4e36-9572-b0ecf45fd8f8\",\n                \"Type\": {\n                  \"Id\": \"c740085a-d548-41f3-8d06-0a48b8692345\",\n                  \"Name\": \"IsRecommendedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Message\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-default\"\n                }\n              },\n              {\n                \"Id\": 136479,\n                \"Version\": 1,\n                \"Guid\": \"ba5c21e9-4d50-4b6e-83f1-d5439de151ad\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-default\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"RowCount\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41666,\n                    \"Version\": 3,\n                    \"Guid\": \"cc578b17-8d1c-4b3d-ad32-15ae128db466\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Rows\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77279,\n                    \"Version\": 2,\n                    \"Guid\": \"057ed9d6-679a-437c-b87c-5b2ebbc22933\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"*\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"InputFontFamily\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130496,\n                    \"Version\": 5,\n                    \"Guid\": \"41af71f5-a567-4773-9a53-a23dda4caa88\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Font Family\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130497,\n                    \"Version\": 2,\n                    \"Guid\": \"b2be2a5a-7c9b-48d2-859e-064e08ab3e80\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183889,\n                    \"Version\": 1,\n                    \"Guid\": \"83a04b12-0c9c-4e0a-9429-f22fa099d4c0\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"6625ab49-7a69-45b0-be1e-f4a2e4cd1bf2\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TextWrapping\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183872,\n                    \"Version\": 7,\n                    \"Guid\": \"2be027ec-ebaf-4e69-acba-ac65eed2c08f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Text Wrapping on White Space\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Determines how text will wrap if it's longer than the width of the input.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183873,\n                    \"Version\": 2,\n                    \"Guid\": \"3a02e478-bfaa-4949-ab08-c01c0665cb16\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183891,\n                    \"Version\": 3,\n                    \"Guid\": \"21621aeb-54cf-4710-9f84-f38b5b73dce4\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"397911a4-839e-4c7e-9e20-deb26335aa3a\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183888,\n              \"Version\": 4,\n              \"Guid\": \"6625ab49-7a69-45b0-be1e-f4a2e4cd1bf2\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\n,\\\"Standard\\\",\\\"The same standard font as everywhere (default)\\\"\\nmonospace,\\\"Monospace (code-style)\\\",\\\"Font where every character has the same width - usually Courier.<br><br>This is for code-style inputs\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"String-Default Input-Font-Family\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183890,\n              \"Version\": 5,\n              \"Guid\": \"397911a4-839e-4c7e-9e20-deb26335aa3a\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info,Css\\n,Automatic (default),\\\"Text will wrap\\\",normal\\npre,Manual (only on new-line),\\\"No line wrapping unless manually adding an enter\\\",pre\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\\n<p>&nbsp;</p>\\n<p>In CSS this is \\\"<strong>[Item:Css]</strong>\\\"</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"String-Default - Text Wrapping Options\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@string-url-path\",\n            \"Name\": \"@string-url-path\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53712,\n                \"Version\": 2,\n                \"Guid\": \"95489982-4260-446b-9289-839cb132feb4\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Configuration for a string-url-path field\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Allows text-input, but only for url-valid characters. Ideal to auto-generate path-parts based on other fields like the title.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Url-Path or Path-Part\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-url-path\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"AutoGenerateMask\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41676,\n                    \"Version\": 2,\n                    \"Guid\": \"7c760382-9abe-47d7-9cfe-72dc9c86e34d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"[Title]\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Auto Generate Path Mask\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Will let you automatically pick up a value - like the item-title - and use it to generate the initial path. Default is [Title] which would use the title-field.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 41677,\n                    \"Version\": 2,\n                    \"Guid\": \"a2b35c49-0b18-4484-9bf9-1298cb682de8\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77281,\n                    \"Version\": 1,\n                    \"Guid\": \"00171650-ff77-4e6b-98e1-af546b29c807\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowSlashes\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41678,\n                    \"Version\": 3,\n                    \"Guid\": \"2884dc70-332b-4cb9-8d76-186506977d5a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Allow Slashes inside Path\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This would allow path-parts with slashes inside the path - so word1/word2 would be allowed. Usually you don't want this, because in most cases you will want to have only non-slash words in this url-part.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 77280,\n                    \"Version\": 2,\n                    \"Guid\": \"9520913a-714e-4d6a-81a9-d231e03ff567\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No slashes allowed in this field\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Slashes allowed in this field\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@string-wysiwyg\",\n            \"Name\": \"@string-wysiwyg\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 53697,\n                \"Version\": 10,\n                \"Guid\": \"7c8aad9f-40a8-4756-94fb-2c3e58e8a2f6\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"[system:path]/extensions/field-string-wysiwyg/index.js\"\n                    },\n                    \"ConfigTypes\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"light wysiwyg-editor (recommended) - without images or advanced formating, as is usually the case in professional content-templates.\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"WYSIWYG editor (default)\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"string-wysiwyg\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": false\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": true\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-wysiwyg\"\n                }\n              },\n              {\n                \"Id\": 53713,\n                \"Version\": 4,\n                \"Guid\": \"c9da1ed4-42ab-4947-957d-7f40c0c44a94\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Edit text like using word with the tiny-mce rich-text editor\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Configure settings for the default Wysiwyg editor. For more advanced customizations you need to create a <a href=\\\"https://r.2sxc.org/field-wysiwyg\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">custom Wysiwyg WebComponent</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"WYSIWYG (default)\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-wysiwyg\"\n                }\n              },\n              {\n                \"Id\": 136473,\n                \"Version\": 1,\n                \"Guid\": \"9f594e21-94c8-4983-a63e-d8038b1f20c1\",\n                \"Type\": {\n                  \"Id\": \"c740085a-d548-41f3-8d06-0a48b8692345\",\n                  \"Name\": \"IsRecommendedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Message\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-wysiwyg\"\n                }\n              },\n              {\n                \"Id\": 183845,\n                \"Version\": 2,\n                \"Guid\": \"746882b7-96af-4903-9ee7-da6fe2b3a42e\",\n                \"Type\": {\n                  \"Id\": \"c490b369-9cd2-4298-af74-19c1e438cdfc\",\n                  \"Name\": \"MetadataExpectedDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"\"\n                    },\n                    \"MetadataTypes\": {\n                      \"en-us\": \"ImageDecorator\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Wysiwyg expects Image Decorator Metadata\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 2\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@string-wysiwyg\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"WysiwygConfiguration\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166491,\n                    \"Version\": 12,\n                    \"Guid\": \"b6b90707-fe77-4806-b4ce-ba3a6274ae7a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"d3dde02f-c1dc-43b8-a8b7-4be3c43eadd0\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Configuration / Presets\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>New v15.04 - see <a href=\\\"https://r.2sxc.org/string-wyswiyg\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"Default mode\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166504,\n                    \"Version\": 10,\n                    \"Guid\": \"d9a71337-e54b-41bc-b051-cc93b09a8f33\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166505,\n                    \"Version\": 11,\n                    \"Guid\": \"81e6ae95-754e-42d6-9fcb-6deb20e52668\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.SettingsEntities\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"ContentType=StringWysiwygConfiguration\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Guid\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupOverrideSettings\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 167718,\n                    \"Version\": 2,\n                    \"Guid\": \"ab4df5d5-0c62-44b8-8ca3-a598aa98abaa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Override Settings from the Configuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 167719,\n                    \"Version\": 1,\n                    \"Guid\": \"d70eab19-4d4f-4ca4-a661-9b8426b6f9e2\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Dialog\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 53794,\n                    \"Version\": 10,\n                    \"Guid\": \"5408022f-dfc2-4989-b645-1be76bb6d89b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Dialog Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Determines if the wysiwyg is opened in a dialog (default behaviour in 2sxc 10).</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53797,\n                    \"Version\": 5,\n                    \"Guid\": \"041334ae-0ec1-4373-b92b-2f7a74dd5a9b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 183898,\n                    \"Version\": 3,\n                    \"Guid\": \"8536c409-feac-4c30-9629-eb842076552c\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"28e7b048-6967-4abf-bf84-4b09e5c45843\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"InlineInitialHeight\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 142600,\n                    \"Version\": 7,\n                    \"Guid\": \"299a0045-1ff2-45d4-9351-d7863ca2a208\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Inline Editor - Initial Height\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"18da7984-28c7-4c22-9c30-c7d698808c15\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 142601,\n                    \"Version\": 4,\n                    \"Guid\": \"262c1a72-0d37-4eb6-ace1-3b6cf35f57fa\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183900,\n                    \"Version\": 1,\n                    \"Guid\": \"3eba4b81-de2a-48e8-a5b3-5f6076625209\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"43c38be0-097c-4c0d-8860-7a530e1f4c7a\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MsgEnhanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164913,\n                    \"Version\": 6,\n                    \"Guid\": \"8eac2cf4-3544-4278-978f-b2796fbfa656\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MsgEnhanced\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Important: <strong>Enhanced mode </strong>allows editors to better align images / content in the post, but it changes how image alignment happens. This requires the page to also include some CSS to make it look good. See docs [TODO]</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"c1f607b3-6cc1-4797-a75b-b46555f512cf\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentCss\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 75079,\n                    \"Version\": 3,\n                    \"Guid\": \"e6c3af21-b3f4-449b-90fd-60ff5529b8fe\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content Css File\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"additional css file to load into the wysiwyg\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 75080,\n                    \"Version\": 2,\n                    \"Guid\": \"271f2b0d-865f-42b0-b711-69c4e53226af\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"*\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"*\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"*\": \"\"\n                        },\n                        \"Paths\": {\n                          \"*\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"*\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"*\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"*\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupButtons\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 53799,\n                    \"Version\": 3,\n                    \"Guid\": \"4ef2a9ce-1362-4b26-8503-d077f47d7a6f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Override Show/Hide of Special Buttons\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"325f68ef-247c-446c-bbe2-30cf32ea437a\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 142605,\n                    \"Version\": 2,\n                    \"Guid\": \"9a287e0d-3692-4a03-b340-490c0d814ad8\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ButtonSource\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 53795,\n                    \"Version\": 10,\n                    \"Guid\": \"54e74c8d-9539-44ba-9ce0-025db7a42e0c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"HTML Source\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The button to access the HTML source code.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53800,\n                    \"Version\": 5,\n                    \"Guid\": \"464233ce-8364-4b2f-b8fc-8c3591ada33e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 183905,\n                    \"Version\": 3,\n                    \"Guid\": \"4e86b58c-6c66-4ff9-acb5-d58cd335e7ec\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"7a6b443a-6d23-45b2-9499-35743cf7d924\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ButtonAdvanced\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 53796,\n                    \"Version\": 9,\n                    \"Guid\": \"2e4375c3-f594-44f8-b8d6-bf1d2f61bd1b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The button to access advanced features such as formatting and tables.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53802,\n                    \"Version\": 5,\n                    \"Guid\": \"ebacf837-1ae9-4c8a-b8f3-70a40b4daec6\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 183907,\n                    \"Version\": 2,\n                    \"Guid\": \"b3eaf477-32ab-47aa-99ea-ada8a97b2d0e\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"4e5df6de-0980-48f3-8ad4-3e405fe67138\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupFeatures\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 160369,\n                    \"Version\": 6,\n                    \"Guid\": \"fed70eee-17b9-428b-99df-bae94935901d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Features (experimental /WIP v15)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 160371,\n                    \"Version\": 4,\n                    \"Guid\": \"5211c30f-484a-4cf1-93f8-c966ba6040cd\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183897,\n              \"Version\": 3,\n              \"Guid\": \"28e7b048-6967-4abf-bf84-4b09e5c45843\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\n,\\\"Default (inline editor)\\\",\\\"Will put the WYSIWYG into the form and usually allow opening a larger dialog when working on a lot of content\\\"\\ndialog,\\\"Dialog only\\\",\\\"Only show a brief preview of the HTML, then use the dialog for editing\\\"\\ninline,\\\"Inline without dialog\\\",\\\"Place inline in form without dialog\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"String-WYSIWYG Dialog Type\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 142603,\n              \"Version\": 4,\n              \"Guid\": \"18da7984-28c7-4c22-9c30-c7d698808c15\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return data.Dialog != 'dialog';\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183899,\n              \"Version\": 5,\n              \"Guid\": \"43c38be0-097c-4c0d-8860-7a530e1f4c7a\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\n,\\\"Default (narrow)\\\",\\\"Default is narrow, but visibly multi-line with ca. 3 lines of text\\\"\\n1,\\\"Minimum\\\",\\\"As narrow as possible, so the user will usually not type much, and it doesn't take much screen space\\\"\\n3,\\\"Narrow\\\",\\\"Narrow, but visibly multi-line\\\"\\n5,\\\"Medium\\\",\\\"Medium size\\\"\\n10,\\\"Large\\\",\\\"Large so it's clearly meant for a lot of text. Only do this if the user should write a lot\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\\n<p>ca. [Item:Value] lines</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\\n<p>ca. [Item:Value] lines</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"String-WYSIWYG - Inline Initial Height\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 164914,\n              \"Version\": 3,\n              \"Guid\": \"c1f607b3-6cc1-4797-a75b-b46555f512cf\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.WysiwygMode === 'enhanced'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 142604,\n              \"Version\": 3,\n              \"Guid\": \"325f68ef-247c-446c-bbe2-30cf32ea437a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  // only run in the beginning\\n  if (context.cache.alreadyRun) return data.value;\\n  context.cache.alreadyRun = true;\\n  return data.ButtonSource == '' && data.ButtonAdvanced == '';\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Collapsed\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Collapsed\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183904,\n              \"Version\": 1,\n              \"Guid\": \"7a6b443a-6d23-45b2-9499-35743cf7d924\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\n,\\\"Default\\\",\\\"In default mode the button is disabled in the small editor, but enabled in the popup Dialog\\\"\\ntrue,\\\"Always Enable\\\",\\\"Enable the button in both the small editor as well as the popup dialog\\\"\\nfalse,\\\"Always Disable\\\",\\\"Disable the button in both the small editor as well as the popup dialog\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"String-WYSIWyG Button Source\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 183906,\n              \"Version\": 2,\n              \"Guid\": \"4e5df6de-0980-48f3-8ad4-3e405fe67138\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\n,\\\"Default\\\",\\\"Disabled in the small editor, enabled in the popup Dialog\\\"\\ntrue,\\\"Always Enable\\\",\\\"Always enable in all editors\\\"\\nfalse,\\\"Always Disable\\\",\\\"Always disable in all editors\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"String-WYSIWYG - Button Advanced\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@custom-gps\",\n            \"Name\": \"@custom-gps\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 46512,\n                \"Version\": 9,\n                \"Guid\": \"e0342e24-fca1-412c-8b72-7220833a1410\",\n                \"Type\": {\n                  \"Id\": \"ContentType-InputType\",\n                  \"Name\": \"ContentType-InputType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AngularAssets\": {\n                      \"en-us\": \"[system:path]/extensions/field-custom-gps/index.js\"\n                    },\n                    \"ConfigTypes\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"to pick a location with a map - can also store the values in separate number fields and auto-find an address based on values in the form\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"GPS Picker\"\n                    },\n                    \"Type\": {\n                      \"en-us\": \"custom-gps\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"DisableI18n\": {\n                      \"en-us\": false\n                    },\n                    \"UseAdam\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@custom-gps\"\n                }\n              },\n              {\n                \"Id\": 53674,\n                \"Version\": 1,\n                \"Guid\": \"b97ce122-71d1-41a7-b9f1-6f122023cfbe\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Configure the input for gps selection\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Custom GPS\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@custom-gps\"\n                }\n              },\n              {\n                \"Id\": 136786,\n                \"Version\": 1,\n                \"Guid\": \"2f1defcf-be98-4ebd-8ced-6737d67bb39c\",\n                \"Type\": {\n                  \"Id\": \"529ba3a2-d7d4-4f40-a81b-ff819de03a9e\",\n                  \"Name\": \"IsDefaultDecorator\"\n                },\n                \"Attributes\": {},\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@custom-gps\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"AddressMask\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41596,\n                    \"Version\": 2,\n                    \"Guid\": \"6a21874b-9f74-4248-8d4f-6ce8b0c4b0ba\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Address Mask\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"An initial address to search for or better - tokens of form-fields to find an address in the map. example (spaces intended): [Address] [Zip] [City]\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46496,\n                    \"Version\": 1,\n                    \"Guid\": \"3d54b676-c483-4f1c-b957-2f13b1933c1c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46497,\n                    \"Version\": 1,\n                    \"Guid\": \"fd224683-eff9-4131-a2d9-5de283b81a79\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Address Mask\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41590,\n                    \"Version\": 2,\n                    \"Guid\": \"6e192b44-91bc-44fa-89fb-521395fb2d43\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Address Mask\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Old field - do not use any more. Only kept here for compatibility because old data already uses this field.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 130222,\n                    \"Version\": 1,\n                    \"Guid\": \"b60c4562-efc0-4201-b2ab-411efb36a7ba\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130223,\n                    \"Version\": 1,\n                    \"Guid\": \"92328388-990f-4835-afd3-4601e0d39a06\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupOldFields\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130224,\n                    \"Version\": 2,\n                    \"Guid\": \"c6dfdfd8-7d60-4a2f-a110-7314ad310056\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Old Settings (not recommended)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>These two fields were an older way of passing on the numbers from the GPS picker to other number fields. Please don't use any more, as you can now simply use the GPS field itself using <a href=\\\"https://docs.2sxc.org/net-code/dynamic-code/as-dynamic-string.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">AsDynamic(...)</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130225,\n                    \"Version\": 1,\n                    \"Guid\": \"1c3727d5-1b3d-4649-a664-f06ba10546a8\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"LatField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41592,\n                    \"Version\": 1,\n                    \"Guid\": \"f7c19c8a-29b4-4d8e-87cb-1083780b83ca\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"LatField\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"An optional field in the form into which the lat-coordinate would be copied automatically by this UI. Example: GPSLat\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"LongField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 41594,\n                    \"Version\": 1,\n                    \"Guid\": \"b6c71a10-fde7-43ed-adc5-16ef4ce8912f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"LongField\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"An optional field in the form into which the lat-coordinate would be copied automatically by this UI. Example: GPSLong\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"@custom-json-editor\",\n            \"Name\": \"@custom-json-editor\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 48236,\n                \"Version\": 6,\n                \"Guid\": \"1c3a6fe6-3318-4308-b063-0716d8de472d\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Configuration for a string-json field\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Custom JSON editor\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"<p>Note that this is a&nbsp;<em>Custom</em> type, we recommend you use the&nbsp;<em>String</em> json instead.&nbsp;</p>\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@custom-json-editor\"\n                }\n              },\n              {\n                \"Id\": 136467,\n                \"Version\": 1,\n                \"Guid\": \"f48cfda7-274a-4e44-9a70-1da3e5c92338\",\n                \"Type\": {\n                  \"Id\": \"852fe15e-bf23-44e6-a856-0a130203496c\",\n                  \"Name\": \"IsObsoleteDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Message\": {\n                      \"en-us\": \"This is an older type - we recommend that you use the String implementation instead. \"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"@custom-json-editor\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Rows\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 48235,\n                    \"Version\": 3,\n                    \"Guid\": \"992553d3-8e76-4177-96b9-e25e3f08f930\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"10\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Rows\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 74864,\n                    \"Version\": 2,\n                    \"Guid\": \"a3cec011-c44e-4c8a-8131-74067976b472\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"*\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonValidation\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 133274,\n                    \"Version\": 8,\n                    \"Guid\": \"05edcd7a-4557-4b97-8505-3513cc372b33\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"strict\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"JSON Validation\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 133275,\n                    \"Version\": 3,\n                    \"Guid\": \"428437ae-e7d7-4cd3-a339-879174513de1\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 133276,\n                    \"Version\": 3,\n                    \"Guid\": \"d84e983c-9e0a-4926-8590-fc9c79614cfd\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"strict:JSON must be valid (default)\\nlight:Show warning on invalid JSON but allow Save\\nnone:JSON can be any text and also invalid JSON (not recommended)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183876,\n                    \"Version\": 1,\n                    \"Guid\": \"99cdc772-db96-4d00-b8be-f2666350814a\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"checkbox\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \"\\\\n\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"f57b953e-9caf-4bf8-bbf8-51d2479835f5\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonSchemaMode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 133277,\n                    \"Version\": 5,\n                    \"Guid\": \"eaa0f5d5-2f50-41f3-b10c-faf931d0ee0c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"none\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"JSON Schema Mode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>JSONs can validate using a <a href=\\\"https://json-schema.org/\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">schema</a>. This can be activated.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 133278,\n                    \"Version\": 4,\n                    \"Guid\": \"76b6560c-d8cd-4c2a-a84b-8e7b80ed5ca5\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 133279,\n                    \"Version\": 4,\n                    \"Guid\": \"03362486-8d56-4380-89f8-0063b8914237\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"none:Don't use a JSON Schema (default)\\nstrict:Enforce a JSON Schema\\nlight:Use a JSON Schema to help editing, but don't enforce\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonSchemaSource\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 133287,\n                    \"Version\": 4,\n                    \"Guid\": \"a824446a-0af8-452c-8016-bd25c35e1b29\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Schema Source\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"196e4c5d-2c45-4908-bd3f-e9ae6d3eb8e0\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 133288,\n                    \"Version\": 3,\n                    \"Guid\": \"265bad65-1cd1-49a9-bf87-02ac1be42d81\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 133289,\n                    \"Version\": 3,\n                    \"Guid\": \"c7f8b05b-c400-4c23-b3c6-92a8ff0625da\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"link:Link to a Schema\\nraw:Add Schema manually as JSON\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonSchemaUrl\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 133266,\n                    \"Version\": 5,\n                    \"Guid\": \"0ce7a189-a2ab-40e5-93c5-082e5bb3b3ff\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Schema Url\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Many common schemas are available on <a href=\\\"https://www.schemastore.org/json/\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">SchemaStore</a> or you can specify other URLs.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"91e53b6e-50cf-4da0-a641-87cf17aa4813\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 133280,\n                    \"Version\": 4,\n                    \"Guid\": \"2bec1394-4e83-40c4-a3fa-6d8277d80d85\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"*.json\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": true\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"JsonSchemaRaw\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-json\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135930,\n                    \"Version\": 4,\n                    \"Guid\": \"e75a881d-c31d-49db-a716-2e7618ef4048\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-json\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Raw JSON Schema\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Custom schemas must adhere to the latest <a href=\\\"https://json-schema.org/draft/2019-09/schema\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Draft 8</a> <a href=\\\"https://json-schema.org/specification.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">specs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"0dc4f1a4-caaf-4caf-8449-cd18e751e27d\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135934,\n                    \"Version\": 3,\n                    \"Guid\": \"b70132e6-0f9c-45a0-82dc-8351257c06a0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135935,\n                    \"Version\": 3,\n                    \"Guid\": \"4fbe9bb9-1196-4997-a5e2-0ed10dd9d171\",\n                    \"Type\": {\n                      \"Id\": \"@string-json\",\n                      \"Name\": \"@string-json\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"JsonSchemaMode\": {\n                          \"en-us\": \"strict\"\n                        },\n                        \"JsonSchemaRaw\": {\n                          \"en-us\": \"\"\n                        },\n                        \"JsonSchemaSource\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"JsonValidation\": {\n                          \"en-us\": \"strict\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"JsonSchemaUrl\": {\n                          \"en-us\": \"https://json-schema.org/draft/2019-09/schema\"\n                        }\n                      },\n                      \"Number\": {\n                        \"Rows\": {\n                          \"en-us\": 25\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 133290,\n              \"Version\": 2,\n              \"Guid\": \"196e4c5d-2c45-4908-bd3f-e9ae6d3eb8e0\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.JsonSchemaMode != 'none'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 133281,\n              \"Version\": 6,\n              \"Guid\": \"91e53b6e-50cf-4da0-a641-87cf17aa4813\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return data.JsonSchemaMode != 'none' && data.JsonSchemaSource == 'link';\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 135937,\n              \"Version\": 1,\n              \"Guid\": \"0dc4f1a4-caaf-4caf-8449-cd18e751e27d\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return data.JsonSchemaMode != 'none' && data.JsonSchemaSource == 'raw';\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-queries.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"Entities\": [\n        {\n          \"Id\": 42901,\n          \"Version\": 27,\n          \"Guid\": \"d680fba2-9ab7-417a-8821-db23c15f4a2e\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get all apps of a zone (site)\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Apps\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"ListContent,Default\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"3e0daa8d-2c13-4b73-94f9-cae9d1c412e8:Default>666576b7-65f7-4d93-96ca-238ef1d336dd:Default\\r\\n666576b7-65f7-4d93-96ca-238ef1d336dd:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:ZoneId]=2\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=1\",\n          \"Metadata\": [\n            {\n              \"Id\": 42968,\n              \"Version\": 7,\n              \"Guid\": \"3e0daa8d-2c13-4b73-94f9-cae9d1c412e8\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Apps\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.System.Apps, ToSic.Eav.Apps\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 480,\\r\\n  \\\"Left\\\": 440\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"d680fba2-9ab7-417a-8821-db23c15f4a2e\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 42969,\n                  \"Version\": 2,\n                  \"Guid\": \"ead6c3a7-cd8f-433d-bee0-c1fd40d9802e\",\n                  \"Type\": {\n                    \"Id\": \"fabc849e-b426-42ea-8e1c-c04e69facd9b\",\n                    \"Name\": \"ToSic.Eav.DataSources.Apps\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"Title\": {\n                        \"*\": \"\"\n                      },\n                      \"ZoneId\": {\n                        \"*\": \"[QueryString:ZoneId]\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=1\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"3e0daa8d-2c13-4b73-94f9-cae9d1c412e8\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 42970,\n              \"Version\": 5,\n              \"Guid\": \"666576b7-65f7-4d93-96ca-238ef1d336dd\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"ValueSort\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.ValueSort, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 240,\\r\\n  \\\"Left\\\": 440\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"d680fba2-9ab7-417a-8821-db23c15f4a2e\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 42971,\n                  \"Version\": 1,\n                  \"Guid\": \"bdda4bef-cee9-439a-b92b-622472bf5a01\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.ValueSort\",\n                    \"Name\": \"ToSic.Eav.DataSources.ValueSort\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"Attributes\": {\n                        \"*\": \"Name\"\n                      },\n                      \"Directions\": {\n                        \"*\": \"Asc\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=1\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"666576b7-65f7-4d93-96ca-238ef1d336dd\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 166436,\n              \"Version\": 1,\n              \"Guid\": \"1c219107-bc74-492f-8bc3-131a18e631b1\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"d680fba2-9ab7-417a-8821-db23c15f4a2e\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 42938,\n          \"Version\": 19,\n          \"Guid\": \"95041b6d-8669-4941-a516-47725acfe6ec\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get all attributes of a content-type\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Attributes\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"ListContent,Default\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"018a942b-1bad-4124-978c-0d0c35633be1:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:ContentTypeName]=@All,@Entity\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=1\",\n          \"Metadata\": [\n            {\n              \"Id\": 42980,\n              \"Version\": 9,\n              \"Guid\": \"018a942b-1bad-4124-978c-0d0c35633be1\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Attributes\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.System.Attributes, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 354,\\r\\n  \\\"Left\\\": 400\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"95041b6d-8669-4941-a516-47725acfe6ec\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 43014,\n                  \"Version\": 1,\n                  \"Guid\": \"788a504a-9636-4b1b-9620-db2dcf612fa5\",\n                  \"Type\": {\n                    \"Id\": \"5461d34d-7dc6-4d38-9250-a0729cc8ead3\",\n                    \"Name\": \"ToSic.Eav.DataSources.Attributes\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"ContentTypeName\": {\n                        \"*\": \"[QueryString:ContentTypeName]\"\n                      },\n                      \"Title\": {\n                        \"*\": \"\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=1\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"018a942b-1bad-4124-978c-0d0c35633be1\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 166437,\n              \"Version\": 1,\n              \"Guid\": \"d06b4574-0b8b-41a9-87c2-57610f505ae2\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"95041b6d-8669-4941-a516-47725acfe6ec\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 42937,\n          \"Version\": 33,\n          \"Guid\": \"ede9fc6f-34bb-4a1f-8482-6dd0742e365f\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"*\": \"Retrieve the content-types of an app\"\n              },\n              \"Name\": {\n                \"*\": \"System.ContentTypes\"\n              },\n              \"Params\": {\n                \"*\": \"AppId=[QueryString:AppId]\\nScope=[QueryString:Scope]\"\n              },\n              \"StreamsOut\": {\n                \"*\": \"ListContent,Default\"\n              },\n              \"StreamWiring\": {\n                \"*\": \"db8515d1-e8c9-4e84-a1ec-970376ea9922:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"*\": \"[QueryString:AppId]=\\n[QueryString:Scope]=\"\n              },\n              \"VisualDesignerData\": {\n                \"*\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"*\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"*\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=1\",\n          \"Metadata\": [\n            {\n              \"Id\": 42978,\n              \"Version\": 14,\n              \"Guid\": \"db8515d1-e8c9-4e84-a1ec-970376ea9922\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"ContentTypes\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.System.ContentTypes, ToSic.Eav.Apps\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 400,\\r\\n  \\\"Left\\\": 460\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"ede9fc6f-34bb-4a1f-8482-6dd0742e365f\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 42979,\n                  \"Version\": 3,\n                  \"Guid\": \"d0ef68cc-151d-4cc5-bb57-1b424c9f7d19\",\n                  \"Type\": {\n                    \"Id\": \"37b25044-29bb-4c78-85e4-7b89f0abaa2c\",\n                    \"Name\": \"ToSic.Eav.DataSources.ContentTypes\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"AppId\": {\n                        \"en-us\": \"[Params:AppId]\"\n                      },\n                      \"Scope\": {\n                        \"en-us\": \"[Params:Scope]\"\n                      },\n                      \"Title\": {\n                        \"en-us\": \"\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=1\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"db8515d1-e8c9-4e84-a1ec-970376ea9922\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 166438,\n              \"Version\": 1,\n              \"Guid\": \"5a87e94f-a3f2-4809-9aa4-7386d1ecc907\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"ede9fc6f-34bb-4a1f-8482-6dd0742e365f\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 129754,\n          \"Version\": 22,\n          \"Guid\": \"34acb79b-21e1-423e-bdec-b67f4a5c8c85\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get all pages of the current site. \"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Pages\"\n              },\n              \"Params\": {\n                \"en-us\": \"IncludeHidden=[QueryString:IncludeHidden]\\nIncludeLinks=[QueryString:IncludeLinks]\\nIncludeDeleted=[QueryString:IncludeDeleted]\\nIncludeAdmin=[QueryString:IncludeAdmin]\\nIncludeSystem=[QueryString:IncludeSystem]\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"b1fa7bee-c137-4e60-b8b5-3588b9c16b9a:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:IncludeHidden]=true\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 129756,\n              \"Version\": 13,\n              \"Guid\": \"b1fa7bee-c137-4e60-b8b5-3588b9c16b9a\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Pages\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"e35031b2-3e99-41fe-a5ac-b79f447d5800\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 280,\\r\\n  \\\"Left\\\": 420\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"34acb79b-21e1-423e-bdec-b67f4a5c8c85\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 169984,\n                  \"Version\": 2,\n                  \"Guid\": \"fb4d8d0d-9eef-4a95-acd0-0d9843b432e7\",\n                  \"Type\": {\n                    \"Id\": \"3d970d2b-32cb-4ecb-aeaf-c49fbcc678a5\",\n                    \"Name\": \"PagesDataSourceConfig\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"IncludeAdmin\": {\n                        \"en-us\": \"[Params:IncludeAdmin||false]\"\n                      },\n                      \"IncludeDeleted\": {\n                        \"en-us\": \"[Params:IncludeDeleted||false]\"\n                      },\n                      \"IncludeHidden\": {\n                        \"en-us\": \"[Params:IncludeHidden||false]\"\n                      },\n                      \"IncludeLinks\": {\n                        \"en-us\": \"[Params:IncludeLinks||true]\"\n                      },\n                      \"IncludeSystem\": {\n                        \"en-us\": \"[Params:IncludeSystem||false]\"\n                      },\n                      \"RequireEditPermissions\": {\n                        \"en-us\": \"false\"\n                      },\n                      \"RequireViewPermissions\": {\n                        \"en-us\": \"true\"\n                      },\n                      \"Title\": {\n                        \"en-us\": \"Pages Configuration\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"b1fa7bee-c137-4e60-b8b5-3588b9c16b9a\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 129760,\n              \"Version\": 1,\n              \"Guid\": \"d540eb1f-f7f9-45cb-8651-8daf71b1bffb\",\n              \"Type\": {\n                \"Id\": \"PermissionConfiguration\",\n                \"Name\": \"PermissionConfiguration\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Condition\": {\n                    \"*\": \"SecurityAccessLevel.Edit\"\n                  },\n                  \"Grant\": {\n                    \"*\": \"r\"\n                  },\n                  \"Identity\": {\n                    \"*\": \"\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Accessible for content editors\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"34acb79b-21e1-423e-bdec-b67f4a5c8c85\"\n              }\n            },\n            {\n              \"Id\": 166439,\n              \"Version\": 1,\n              \"Guid\": \"02d62934-cca2-4c75-bfcb-079297f458ad\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"34acb79b-21e1-423e-bdec-b67f4a5c8c85\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 42915,\n          \"Version\": 20,\n          \"Guid\": \"e57cfebc-2c9f-4feb-95e0-9362049b7502\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Retrieves the queries of the current app (usually for drop-downs)\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Queries\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"89b3116e-efab-4fee-8a7c-afe1e28825d2:DataPipeline>3d48f6fe-81dd-4cef-8717-45ab3c786625:Default\\r\\n3b01ba93-62ea-4f73-b150-c8129eb82cab:Default>40460932-1d32-4005-8bd1-c45f8599da24:Default\\r\\n40460932-1d32-4005-8bd1-c45f8599da24:Default>Out:Default\\r\\n3d48f6fe-81dd-4cef-8717-45ab3c786625:Default>3b01ba93-62ea-4f73-b150-c8129eb82cab:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=1\",\n          \"Metadata\": [\n            {\n              \"Id\": 42916,\n              \"Version\": 14,\n              \"Guid\": \"89b3116e-efab-4fee-8a7c-afe1e28825d2\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"App\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.App, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 840,\\r\\n  \\\"Left\\\": 420\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e57cfebc-2c9f-4feb-95e0-9362049b7502\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 169176,\n                  \"Version\": 1,\n                  \"Guid\": \"8e81803b-1701-4417-85d9-1c9ad1caf422\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.App\",\n                    \"Name\": \"ToSic.Eav.DataSources.App\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"AppSwitch\": {\n                        \"en-us\": \"\"\n                      },\n                      \"WithAncestors\": {\n                        \"en-us\": \"true\"\n                      },\n                      \"ZoneSwitch\": {\n                        \"en-us\": \"\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"89b3116e-efab-4fee-8a7c-afe1e28825d2\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 42917,\n              \"Version\": 11,\n              \"Guid\": \"3b01ba93-62ea-4f73-b150-c8129eb82cab\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"AttributeFilter\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.AttributeFilter, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 460,\\r\\n  \\\"Left\\\": 420\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e57cfebc-2c9f-4feb-95e0-9362049b7502\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 42918,\n                  \"Version\": 2,\n                  \"Guid\": \"33ab87f2-ae04-4b2f-a80c-664d0a87a96e\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.AttributeFilter\",\n                    \"Name\": \"ToSic.Eav.DataSources.AttributeFilter\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"AttributeNames\": {\n                        \"*\": \"Name,Id,Guid\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=1\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"3b01ba93-62ea-4f73-b150-c8129eb82cab\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 42919,\n              \"Version\": 7,\n              \"Guid\": \"40460932-1d32-4005-8bd1-c45f8599da24\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"ValueSort\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.ValueSort, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 220,\\r\\n  \\\"Left\\\": 420\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e57cfebc-2c9f-4feb-95e0-9362049b7502\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 42920,\n                  \"Version\": 2,\n                  \"Guid\": \"f0034b9d-9255-4cb1-906a-33081a79bca3\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.ValueSort\",\n                    \"Name\": \"ToSic.Eav.DataSources.ValueSort\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"Attributes\": {\n                        \"en-us\": \"AppId,Name\"\n                      },\n                      \"Directions\": {\n                        \"en-us\": \"Desc,Asc\"\n                      },\n                      \"Languages\": {\n                        \"en-us\": \"\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=1\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"40460932-1d32-4005-8bd1-c45f8599da24\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 42926,\n              \"Version\": 1,\n              \"Guid\": \"6f0a476e-9b25-4a41-9aed-71711b3e46f3\",\n              \"Type\": {\n                \"Id\": \"PermissionConfiguration\",\n                \"Name\": \"PermissionConfiguration\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Condition\": {\n                    \"*\": \"SecurityAccessLevel.Admin\"\n                  },\n                  \"Grant\": {\n                    \"*\": \"r\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Security Rule\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e57cfebc-2c9f-4feb-95e0-9362049b7502\"\n              }\n            },\n            {\n              \"Id\": 166440,\n              \"Version\": 1,\n              \"Guid\": \"dcbe1853-edb8-4433-80e8-d9a5d51182f7\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e57cfebc-2c9f-4feb-95e0-9362049b7502\"\n              }\n            },\n            {\n              \"Id\": 169180,\n              \"Version\": 2,\n              \"Guid\": \"3d48f6fe-81dd-4cef-8717-45ab3c786625\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Value Filter\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.ValueFilter, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 660,\\r\\n  \\\"Left\\\": 420\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e57cfebc-2c9f-4feb-95e0-9362049b7502\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 169181,\n                  \"Version\": 1,\n                  \"Guid\": \"4667674d-dbdf-4a0d-a184-8d37f09373c3\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.ValueFilter\",\n                    \"Name\": \"ToSic.Eav.DataSources.ValueFilter\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"Attribute\": {\n                        \"en-us\": \"HiddenInQueryPicker\"\n                      },\n                      \"Languages\": {\n                        \"en-us\": \"\"\n                      },\n                      \"Operator\": {\n                        \"en-us\": \"!=\"\n                      },\n                      \"Take\": {\n                        \"en-us\": \"\"\n                      },\n                      \"Value\": {\n                        \"en-us\": \"true\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"3d48f6fe-81dd-4cef-8717-45ab3c786625\"\n                  }\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"Id\": 42946,\n          \"Version\": 39,\n          \"Guid\": \"2889c62f-9c07-4027-b85e-af7ddf55f44f\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Retrieve streams and fields of a query. \"\n              },\n              \"Name\": {\n                \"en-us\": \"System.QueryInfo\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"ListContent,Default,Attributes\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"c11d7835-035d-441c-8cbc-287aaecbea81:Attributes>Out:Attributes\\r\\nc11d7835-035d-441c-8cbc-287aaecbea81:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:QueryName]=System.Apps\\n[QueryString:StreamName]=Default\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=1\",\n          \"Metadata\": [\n            {\n              \"Id\": 42976,\n              \"Version\": 12,\n              \"Guid\": \"c11d7835-035d-441c-8cbc-287aaecbea81\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"QueryInfo\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.System.QueryInfo, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 340,\\r\\n  \\\"Left\\\": 427\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"2889c62f-9c07-4027-b85e-af7ddf55f44f\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 42977,\n                  \"Version\": 1,\n                  \"Guid\": \"beaa3575-01f6-4730-9232-3b29a8287e1d\",\n                  \"Type\": {\n                    \"Id\": \"4638668f-d506-4f5c-ae37-aa7fdbbb5540\",\n                    \"Name\": \"ToSic.Eav.DataSources.QueryInfo\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"QueryName\": {\n                        \"*\": \"[QueryString:QueryName]\"\n                      },\n                      \"StreamName\": {\n                        \"*\": \"[QueryString:StreamName]\"\n                      },\n                      \"Title\": {\n                        \"*\": \"\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=1\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"c11d7835-035d-441c-8cbc-287aaecbea81\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 166441,\n              \"Version\": 1,\n              \"Guid\": \"cf5ae7aa-f70e-42e0-ad42-83d6398c0cc8\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"2889c62f-9c07-4027-b85e-af7ddf55f44f\"\n              }\n            },\n            {\n              \"Id\": 169163,\n              \"Version\": 2,\n              \"Guid\": \"f61dbc48-f992-41c2-9d04-f6aa0d6342fa\",\n              \"Type\": {\n                \"Id\": \"5e958dc6-2922-4d68-835c-7b9711538b12\",\n                \"Name\": \"NoteDecorator\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Note\": {\n                    \"en-us\": \"<p>IMPORTANT: The test-values should not be changed - they must be [QueryString:QueryName]=System.Apps and [QueryString:StreamName]=Default</p>\"\n                  },\n                  \"NoteType\": {\n                    \"en-us\": \"warning\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"IMPORTANT: The test-values sho...\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"2889c62f-9c07-4027-b85e-af7ddf55f44f\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 42900,\n          \"Version\": 20,\n          \"Guid\": \"e8a702d2-eccd-4b0f-83bd-600d8a8449d9\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Retrieve full list of all zones\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Zones\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"ListContent,Default\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"a942aaca-088c-41f4-b938-f625a5170ab0:Default>Out:Default\\r\\ne60248e9-4dce-475a-a99d-61d11a6fb1cc:Default>a942aaca-088c-41f4-b938-f625a5170ab0:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=1\",\n          \"Metadata\": [\n            {\n              \"Id\": 42948,\n              \"Version\": 9,\n              \"Guid\": \"a942aaca-088c-41f4-b938-f625a5170ab0\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Sort by Tenant Name\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.ValueSort, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 226,\\r\\n  \\\"Left\\\": 466\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e8a702d2-eccd-4b0f-83bd-600d8a8449d9\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 42949,\n                  \"Version\": 3,\n                  \"Guid\": \"b47783df-02fd-482f-9548-a231d79a702e\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.ValueSort\",\n                    \"Name\": \"ToSic.Eav.DataSources.ValueSort\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"Attributes\": {\n                        \"*\": \"TenantName\"\n                      },\n                      \"Directions\": {\n                        \"*\": \"Asc\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=1\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"a942aaca-088c-41f4-b938-f625a5170ab0\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 42967,\n              \"Version\": 3,\n              \"Guid\": \"e60248e9-4dce-475a-a99d-61d11a6fb1cc\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Zones\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.System.Zones, ToSic.Eav.Apps\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 400,\\r\\n  \\\"Left\\\": 469\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=1\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e8a702d2-eccd-4b0f-83bd-600d8a8449d9\"\n              }\n            },\n            {\n              \"Id\": 166442,\n              \"Version\": 1,\n              \"Guid\": \"4a5b205b-9b1f-4a24-bb71-e880dc74b73f\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e8a702d2-eccd-4b0f-83bd-600d8a8449d9\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 160746,\n          \"Version\": 23,\n          \"Guid\": \"f54e66aa-0ed1-47ca-b15d-774f3a5d60ca\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Retrieve all roles of the current site.\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.UserRoles\"\n              },\n              \"Params\": {\n                \"en-us\": \"RoleIds=[QueryString:RoleIds]\\nExcludeRoleIds=[QueryString:ExcludeRoleIds]\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"e5837542-beeb-4528-829b-2983d11e566a:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[Params:ExcludeRoleIds]=351\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 160751,\n              \"Version\": 9,\n              \"Guid\": \"e5837542-beeb-4528-829b-2983d11e566a\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Roles\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"eee54266-d7ad-4f5e-9422-2d00c8f93b45\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 440,\\r\\n  \\\"Left\\\": 440\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"f54e66aa-0ed1-47ca-b15d-774f3a5d60ca\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 160759,\n                  \"Version\": 3,\n                  \"Guid\": \"68bac4d0-8a56-4cbd-b7fd-c656c290b062\",\n                  \"Type\": {\n                    \"Id\": \"1b9fd9d1-dde0-40ad-bb66-5cd7f30de18d\",\n                    \"Name\": \"RolesDataSourceConfig\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"ExcludeRoleIds\": {\n                        \"en-us\": \"[Params:ExcludeRoleIds]\"\n                      },\n                      \"RoleIds\": {\n                        \"en-us\": \"[Params:RoleIds]\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"e5837542-beeb-4528-829b-2983d11e566a\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 166443,\n              \"Version\": 1,\n              \"Guid\": \"140ce9e2-6018-4fdb-b9ec-dab072f6a38a\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"f54e66aa-0ed1-47ca-b15d-774f3a5d60ca\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 160760,\n          \"Version\": 27,\n          \"Guid\": \"dd3021bf-1b9a-4d10-8dde-12efe9832f47\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get users of this site.\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Users\"\n              },\n              \"Params\": {\n                \"en-us\": \"UserIds=[QueryString:UserIds]\\nExcludeUserIds=[QueryString:ExcludeUserIds]\\nRoleIds=[QueryString:RoleIds]\\nExcludeRoleIds=[QueryString:ExcludeRoleIds]\\nIncludeSystemAdmins=[QueryString:IncludeSystemAdmins]\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header,Roles\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"71a257cd-cebf-4c3c-a588-c46e9244a398:Default>Out:Default\\r\\n71a257cd-cebf-4c3c-a588-c46e9244a398:Roles>Out:Roles\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:IncludeSystemAdmins]=false\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 160762,\n              \"Version\": 15,\n              \"Guid\": \"71a257cd-cebf-4c3c-a588-c46e9244a398\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Users\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"93ac53c6-adc6-4218-b979-48d1071a5765\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 380,\\r\\n  \\\"Left\\\": 380\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"dd3021bf-1b9a-4d10-8dde-12efe9832f47\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 160780,\n                  \"Version\": 6,\n                  \"Guid\": \"580dc00d-497c-45b4-9422-c8e426d34e4a\",\n                  \"Type\": {\n                    \"Id\": \"ac11fae7-1916-4d2d-8583-09872e1e6966\",\n                    \"Name\": \"UsersDataSourceConfig\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"AddRoles\": {\n                        \"en-us\": \"true\"\n                      },\n                      \"ExcludeRoleIds\": {\n                        \"en-us\": \"[Params:ExcludeRoleIds]\"\n                      },\n                      \"ExcludeUserIds\": {\n                        \"en-us\": \"[Params:ExcludeUserIds]\"\n                      },\n                      \"IncludeSystemAdmins\": {\n                        \"en-us\": \"[Params:IncludeSystemAdmins]\"\n                      },\n                      \"RoleIds\": {\n                        \"en-us\": \"[Params:RoleIds]\"\n                      },\n                      \"UserIds\": {\n                        \"en-us\": \"[Params:UserIds]\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"71a257cd-cebf-4c3c-a588-c46e9244a398\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 166444,\n              \"Version\": 1,\n              \"Guid\": \"2d383a38-e609-4edc-b925-1573a4d0c677\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"dd3021bf-1b9a-4d10-8dde-12efe9832f47\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 166473,\n          \"Version\": 7,\n          \"Guid\": \"34693704-fa1f-48bd-a5d7-0ace93d1ee3e\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get all the data scopes of the current App (like folders to organize content-types)\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Scopes\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"0d20bfd8-52c8-411a-bf78-fc6908c70ad1:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166475,\n              \"Version\": 2,\n              \"Guid\": \"0d20bfd8-52c8-411a-bf78-fc6908c70ad1\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Scopes\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"f134e3c1-f09f-4fbc-85be-de43a64c6eed\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 320,\\r\\n  \\\"Left\\\": 480\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"34693704-fa1f-48bd-a5d7-0ace93d1ee3e\"\n              }\n            },\n            {\n              \"Id\": 166476,\n              \"Version\": 1,\n              \"Guid\": \"7288dd48-5fbd-455e-9610-f2f7fbf50c33\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"34693704-fa1f-48bd-a5d7-0ace93d1ee3e\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 166484,\n          \"Version\": 36,\n          \"Guid\": \"05ab1404-55f3-45f4-8252-a3c9bd59d6f6\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Retrieve settings entities from global App and from current App.\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.SettingsEntities\"\n              },\n              \"Params\": {\n                \"en-us\": \"ContentType=[QueryString:ContentType]\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"706d272f-9cd5-4c10-80a7-cfa4128a8e7b:Default>Out:Default\\r\\n2a723149-7dee-407d-8831-14180e294705:Default>425988c7-0851-47f5-8955-9949b52cfa3e:Default\\r\\n425988c7-0851-47f5-8955-9949b52cfa3e:Default>706d272f-9cd5-4c10-80a7-cfa4128a8e7b:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:ContentType]=⚙️Image\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166503,\n              \"Version\": 1,\n              \"Guid\": \"d41628cd-68af-45ac-9350-6158dc989904\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"05ab1404-55f3-45f4-8252-a3c9bd59d6f6\"\n              }\n            },\n            {\n              \"Id\": 166533,\n              \"Version\": 12,\n              \"Guid\": \"706d272f-9cd5-4c10-80a7-cfa4128a8e7b\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Serialization Configuration\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"2952e680-4aaa-4a12-adf7-325cb2854358\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 180,\\r\\n  \\\"Left\\\": 320\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"05ab1404-55f3-45f4-8252-a3c9bd59d6f6\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 166534,\n                  \"Version\": 1,\n                  \"Guid\": \"75ac5a8d-c218-453e-954c-55fa4a1c1d72\",\n                  \"Type\": {\n                    \"Id\": \"5c84cd3f-f853-40b3-81cf-dee6a07dc411\",\n                    \"Name\": \"DsSerializationConfiguration\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"IncludeAppId\": {\n                        \"en-us\": \"true\"\n                      },\n                      \"IncludeCreated\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeGuid\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadata\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataFor\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataForId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataForType\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataGuid\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataTitle\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeModified\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationshipGuid\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationshipId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationships\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationshipTitle\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeTitle\": {\n                        \"en-us\": \"\"\n                      },\n                      \"Notes\": {\n                        \"en-us\": \"\"\n                      },\n                      \"RemoveEmptyStringValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"RemoveFalseValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"RemoveNullValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"RemoveZeroValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"Title\": {\n                        \"en-us\": \"Serialization Configuration - include AppId\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"706d272f-9cd5-4c10-80a7-cfa4128a8e7b\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 169174,\n              \"Version\": 10,\n              \"Guid\": \"2a723149-7dee-407d-8831-14180e294705\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"App\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.App, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 600,\\r\\n  \\\"Left\\\": 320\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"05ab1404-55f3-45f4-8252-a3c9bd59d6f6\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 169175,\n                  \"Version\": 1,\n                  \"Guid\": \"10e5c50a-439a-4264-9ecc-dddb812a633a\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.App\",\n                    \"Name\": \"ToSic.Eav.DataSources.App\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"AppSwitch\": {\n                        \"en-us\": \"\"\n                      },\n                      \"WithAncestors\": {\n                        \"en-us\": \"true\"\n                      },\n                      \"ZoneSwitch\": {\n                        \"en-us\": \"\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"2a723149-7dee-407d-8831-14180e294705\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 183840,\n              \"Version\": 4,\n              \"Guid\": \"425988c7-0851-47f5-8955-9949b52cfa3e\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Type-Filter\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.EntityTypeFilter, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 380,\\r\\n  \\\"Left\\\": 300\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"05ab1404-55f3-45f4-8252-a3c9bd59d6f6\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 183841,\n                  \"Version\": 1,\n                  \"Guid\": \"b3b9d389-d9a9-4bbc-9d58-23fc43ac16d4\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.EntityTypeFilter\",\n                    \"Name\": \"ToSic.Eav.DataSources.EntityTypeFilter\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"TypeName\": {\n                        \"en-us\": \"[Params:ContentType||error-no-type-should-be-used]\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"425988c7-0851-47f5-8955-9949b52cfa3e\"\n                  }\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"Id\": 166506,\n          \"Version\": 6,\n          \"Guid\": \"9e0c28ce-e4fe-4fe4-8cac-35fa6dad5df5\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"List of Metadata TargetTypes, which determine what kind of target the metadata is for.\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.MetadataTargetTypes\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"67cc45e2-fe12-4161-8181-930777d46e53:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166508,\n              \"Version\": 2,\n              \"Guid\": \"67cc45e2-fe12-4161-8181-930777d46e53\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Metadata Target Types\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"fba0d40d-f6af-4593-9ccb-54cfd73d8217\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 360,\\r\\n  \\\"Left\\\": 420\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"9e0c28ce-e4fe-4fe4-8cac-35fa6dad5df5\"\n              }\n            },\n            {\n              \"Id\": 166509,\n              \"Version\": 1,\n              \"Guid\": \"08dad3ad-1002-4cc3-9bb4-09999db29ca3\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"9e0c28ce-e4fe-4fe4-8cac-35fa6dad5df5\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 166627,\n          \"Version\": 5,\n          \"Guid\": \"1e8d613c-e68b-471a-a438-c9325e53f003\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get a list of all licenses in the system.\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Licenses\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"70cab874-14f8-41b1-8991-def591ae0de8:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166629,\n              \"Version\": 2,\n              \"Guid\": \"70cab874-14f8-41b1-8991-def591ae0de8\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Licenses\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"402fa226-5584-46d1-a763-e63ba0774c31\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 300,\\r\\n  \\\"Left\\\": 400\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"1e8d613c-e68b-471a-a438-c9325e53f003\"\n              }\n            },\n            {\n              \"Id\": 166633,\n              \"Version\": 1,\n              \"Guid\": \"d22b716c-f4e4-4090-8a42-8ad6763d006f\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"1e8d613c-e68b-471a-a438-c9325e53f003\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 166630,\n          \"Version\": 6,\n          \"Guid\": \"abb9d5ee-3333-4a15-9539-36e1e0f00953\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Retrieve a list of all features and their state.\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Features\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"200e0670-301e-4cb7-b0b3-da6344894fcc:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166632,\n              \"Version\": 2,\n              \"Guid\": \"200e0670-301e-4cb7-b0b3-da6344894fcc\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Features\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"398d0b9f-044f-48f7-83ef-307872f7ed93\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 260,\\r\\n  \\\"Left\\\": 440\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"abb9d5ee-3333-4a15-9539-36e1e0f00953\"\n              }\n            },\n            {\n              \"Id\": 166634,\n              \"Version\": 1,\n              \"Guid\": \"6f8ba371-8e2b-4148-aeaa-815519ff6549\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"abb9d5ee-3333-4a15-9539-36e1e0f00953\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 166646,\n          \"Version\": 8,\n          \"Guid\": \"310cc86c-2281-4614-8605-a423c87105e9\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get all the sites in the system.\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Sites\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"39f544b2-45a2-4229-9e26-1f95c950f8f6:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166648,\n              \"Version\": 3,\n              \"Guid\": \"39f544b2-45a2-4229-9e26-1f95c950f8f6\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Sites\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"a11c28fb-7d8d-40a2-a22c-50beaa019e41\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 320,\\r\\n  \\\"Left\\\": 400\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"310cc86c-2281-4614-8605-a423c87105e9\"\n              }\n            },\n            {\n              \"Id\": 166649,\n              \"Version\": 1,\n              \"Guid\": \"71f07571-ac86-46b3-ab6e-a840d39177b6\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"310cc86c-2281-4614-8605-a423c87105e9\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 169100,\n          \"Version\": 9,\n          \"Guid\": \"2317bfff-79bc-4812-89dd-0e0b9cba1cb9\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get all settings of the current app incl. global and preset settings.\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.Settings\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"b897b9c9-4dc2-4c2e-959b-eca18871b062:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 169102,\n              \"Version\": 2,\n              \"Guid\": \"b897b9c9-4dc2-4c2e-959b-eca18871b062\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"App Stack\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"60806cb1-0c76-4c1e-8dfe-dcec94726f8d\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 300,\\r\\n  \\\"Left\\\": 460\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"2317bfff-79bc-4812-89dd-0e0b9cba1cb9\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 169115,\n                  \"Version\": 2,\n                  \"Guid\": \"a84c055f-55e1-4faa-a5d7-e49f118bcdb6\",\n                  \"Type\": {\n                    \"Id\": \"f9aca0f0-1b1b-4414-b42e-b337de124124\",\n                    \"Name\": \"SystemStackConfig\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"AddValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"StackNames\": {\n                        \"en-us\": \"Settings\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"b897b9c9-4dc2-4c2e-959b-eca18871b062\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 169103,\n              \"Version\": 1,\n              \"Guid\": \"97754be9-8b32-483b-8dea-a36cc17ef0c3\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"2317bfff-79bc-4812-89dd-0e0b9cba1cb9\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 182360,\n          \"Version\": 13,\n          \"Guid\": \"68af1a61-9362-4cc5-8e60-cd9c37fe88c3\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"*\": \"Retrieve all Picker Sources to reuse in pickers.\"\n              },\n              \"Name\": {\n                \"*\": \"System.UiPickers\"\n              },\n              \"Params\": {\n                \"*\": \"\"\n              },\n              \"StreamsOut\": {\n                \"*\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"*\": \"6c04fa59-082e-428c-9a1f-ac511e3d04b6:UiPickerSourceCustomList>e73021f3-b121-4fc0-81c3-a8800bbd14d9:CustomList\\r\\n6c04fa59-082e-428c-9a1f-ac511e3d04b6:UiPickerSourceEntity>e73021f3-b121-4fc0-81c3-a8800bbd14d9:Entity\\r\\n6c04fa59-082e-428c-9a1f-ac511e3d04b6:UiPickerSourceQuery>e73021f3-b121-4fc0-81c3-a8800bbd14d9:Query\\r\\ne73021f3-b121-4fc0-81c3-a8800bbd14d9:Default>Out:Default\\r\\n6c04fa59-082e-428c-9a1f-ac511e3d04b6:UiPickerSourceCustomCsv>e73021f3-b121-4fc0-81c3-a8800bbd14d9:Default\\r\\n6c04fa59-082e-428c-9a1f-ac511e3d04b6:UiPickerSourceCss>e73021f3-b121-4fc0-81c3-a8800bbd14d9:UiPickerSourceCss\\r\\n6c04fa59-082e-428c-9a1f-ac511e3d04b6:UiPickerSourceAppAssets>e73021f3-b121-4fc0-81c3-a8800bbd14d9:UiPickerSourceAppAssets\"\n              },\n              \"TestParameters\": {\n                \"*\": \"\"\n              },\n              \"VisualDesignerData\": {\n                \"*\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"*\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"*\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 182362,\n              \"Version\": 11,\n              \"Guid\": \"6c04fa59-082e-428c-9a1f-ac511e3d04b6\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"App\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.App, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 480,\\r\\n  \\\"Left\\\": 420\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"68af1a61-9362-4cc5-8e60-cd9c37fe88c3\"\n              }\n            },\n            {\n              \"Id\": 182363,\n              \"Version\": 9,\n              \"Guid\": \"e73021f3-b121-4fc0-81c3-a8800bbd14d9\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Merge Streams\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.StreamMerge, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 200,\\r\\n  \\\"Left\\\": 400\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"68af1a61-9362-4cc5-8e60-cd9c37fe88c3\"\n              }\n            },\n            {\n              \"Id\": 182365,\n              \"Version\": 2,\n              \"Guid\": \"acba9b5f-fead-4181-8a36-e39281fc7288\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"68af1a61-9362-4cc5-8e60-cd9c37fe88c3\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 182535,\n          \"Version\": 14,\n          \"Guid\": \"ca79c11d-0c2e-422a-8bcb-0a89d493ecc0\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Entity picker for UI with special security, as security is handled in the data source. \"\n              },\n              \"Name\": {\n                \"en-us\": \"System.EntityPicker\"\n              },\n              \"Params\": {\n                \"en-us\": \"\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"d0fac9fe-78ce-464a-8696-57fb5f69646d:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:TypeNames]=SystemExportDecorator,@All\\n[QueryString:xx-ItemIds]=42930,42931\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 182537,\n              \"Version\": 7,\n              \"Guid\": \"d0fac9fe-78ce-464a-8696-57fb5f69646d\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Entity-Picker (internal)\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"32369814-8f6d-47d8-a648-ce5372de78a8\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 220,\\r\\n  \\\"Left\\\": 440\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"ca79c11d-0c2e-422a-8bcb-0a89d493ecc0\"\n              }\n            },\n            {\n              \"Id\": 182538,\n              \"Version\": 1,\n              \"Guid\": \"d65d5b41-6770-447b-895d-fc449a6b2545\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"ca79c11d-0c2e-422a-8bcb-0a89d493ecc0\"\n              }\n            },\n            {\n              \"Id\": 183752,\n              \"Version\": 1,\n              \"Guid\": \"c324500c-8dd9-41ec-a7ae-b30809384e2f\",\n              \"Type\": {\n                \"Id\": \"PermissionConfiguration\",\n                \"Name\": \"PermissionConfiguration\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Condition\": {\n                    \"en-us\": \"SecurityAccessLevel.View\"\n                  },\n                  \"Grant\": {\n                    \"en-us\": \"r\"\n                  },\n                  \"Identity\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PermissionType\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Allow Anonymous Access with View Permission\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"ca79c11d-0c2e-422a-8bcb-0a89d493ecc0\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 167720,\n          \"Version\": 26,\n          \"Guid\": \"952633f8-c04b-4592-9db9-a3e6ecf2dbb5\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get all the files / folders from an App (new v18.02)\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.AppAssets\"\n              },\n              \"Params\": {\n                \"en-us\": \"RootFolder=[QueryString:RootFolder||/]\\nFileFilter=[QueryString:FileFilter||*.*]\\nSearchSubfolders=[QueryString:SearchSubfolders||false]\\nAssetType=[QueryString:AssetType||Files]\\n\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header,Files,Folders,All\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"da65ba2b-ae16-4446-84f7-90d76c98c513:Files>Out:Files\\r\\nda65ba2b-ae16-4446-84f7-90d76c98c513:Folders>Out:Folders\\r\\nda65ba2b-ae16-4446-84f7-90d76c98c513:All>Out:All\\r\\nda65ba2b-ae16-4446-84f7-90d76c98c513:Files>0ccade9c-343a-4d4f-b037-66ed381d8cee:Files\\r\\nda65ba2b-ae16-4446-84f7-90d76c98c513:Folders>0ccade9c-343a-4d4f-b037-66ed381d8cee:Folders\\r\\nda65ba2b-ae16-4446-84f7-90d76c98c513:All>0ccade9c-343a-4d4f-b037-66ed381d8cee:All\\r\\n0ccade9c-343a-4d4f-b037-66ed381d8cee:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:RootFolder]=/\\n[QueryString:FileFilter]=*.*\\n[QueryString:SearchSubfolders]=false\\n[QueryString:AssetType]=Folders\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 167722,\n              \"Version\": 15,\n              \"Guid\": \"da65ba2b-ae16-4446-84f7-90d76c98c513\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"AppFiles\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"3fe6c215-4c37-45c1-8883-b4b2a47162a7\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 520,\\r\\n  \\\"Left\\\": 200\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"952633f8-c04b-4592-9db9-a3e6ecf2dbb5\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 184022,\n                  \"Version\": 4,\n                  \"Guid\": \"6059b2f9-28d6-4673-b165-540c6d85828b\",\n                  \"Type\": {\n                    \"Id\": \"477d5de4-5ffa-43ef-8553-37354cb27660\",\n                    \"Name\": \"AppFilesDataSourceConfig\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"FileFilter\": {\n                        \"en-us\": \"[Params:FileFilter]\"\n                      },\n                      \"RootFolder\": {\n                        \"en-us\": \"[Params:RootFolder]\"\n                      },\n                      \"SearchSubfolders\": {\n                        \"en-us\": \"[Params:SearchSubfolders]\"\n                      },\n                      \"Title\": {\n                        \"en-us\": \"App Files\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"da65ba2b-ae16-4446-84f7-90d76c98c513\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 184023,\n              \"Version\": 1,\n              \"Guid\": \"72559058-b7e0-4be1-bca6-ecf809c55b14\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"952633f8-c04b-4592-9db9-a3e6ecf2dbb5\"\n              }\n            },\n            {\n              \"Id\": 184053,\n              \"Version\": 6,\n              \"Guid\": \"0ccade9c-343a-4d4f-b037-66ed381d8cee\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Pick Stream\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.StreamPick, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 260,\\r\\n  \\\"Left\\\": 540\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"952633f8-c04b-4592-9db9-a3e6ecf2dbb5\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 184054,\n                  \"Version\": 1,\n                  \"Guid\": \"cb686948-965b-4b9b-a14a-920c0594b48c\",\n                  \"Type\": {\n                    \"Id\": \"67b19864-df6d-400b-9f37-f41f1dd69c4a\",\n                    \"Name\": \"StreamPick\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"StreamName\": {\n                        \"en-us\": \"[Params:AssetType]\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"0ccade9c-343a-4d4f-b037-66ed381d8cee\"\n                  }\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"Id\": 184091,\n          \"Version\": 34,\n          \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"en-us\": \"Get everything with a specific Metadata - for now Entities & ContentTypes\"\n              },\n              \"Name\": {\n                \"en-us\": \"System.BundleDetails\"\n              },\n              \"Params\": {\n                \"en-us\": \"ConfigurationGuid=[QueryString:ConfigurationGuid]\"\n              },\n              \"StreamsOut\": {\n                \"en-us\": \"Default,Header,PleaseRename54247\"\n              },\n              \"StreamWiring\": {\n                \"en-us\": \"29f1a49c-aad2-46b7-adcc-4de99b5a4e54:Default>7e8e2c29-d170-4738-b99d-5bcfdcfdafb3:Default\\r\\nac245cea-8418-4a29-8ef7-76062b006c49:Default>0f5703bc-6e2f-4e02-b864-191aaf76d1d2:Default\\r\\n7e8e2c29-d170-4738-b99d-5bcfdcfdafb3:Default>1cdab8ab-f4ff-4965-a8bc-acdbbfafd015:Default\\r\\n1cdab8ab-f4ff-4965-a8bc-acdbbfafd015:Default>ac245cea-8418-4a29-8ef7-76062b006c49:Default\\r\\n0f5703bc-6e2f-4e02-b864-191aaf76d1d2:Default>dd5fafd6-7b3e-4fe5-874e-330381df561d:Default\\r\\ndd5fafd6-7b3e-4fe5-874e-330381df561d:Default>Out:Default\"\n              },\n              \"TestParameters\": {\n                \"en-us\": \"[QueryString:ConfigurationGuid]=1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n              },\n              \"VisualDesignerData\": {\n                \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"en-us\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 184093,\n              \"Version\": 26,\n              \"Guid\": \"29f1a49c-aad2-46b7-adcc-4de99b5a4e54\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"App\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.App, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 820,\\r\\n  \\\"Left\\\": 120\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 184096,\n                  \"Version\": 2,\n                  \"Guid\": \"900c5376-38e3-41d3-be5a-953ef8d37b91\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.App\",\n                    \"Name\": \"ToSic.Eav.DataSources.App\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"AppSwitch\": {\n                        \"en-us\": \"\"\n                      },\n                      \"WithAncestors\": {\n                        \"en-us\": \"\"\n                      },\n                      \"ZoneSwitch\": {\n                        \"en-us\": \"\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"29f1a49c-aad2-46b7-adcc-4de99b5a4e54\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 184094,\n              \"Version\": 25,\n              \"Guid\": \"7e8e2c29-d170-4738-b99d-5bcfdcfdafb3\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Type-Filter Export Config\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.EntityTypeFilter, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 680,\\r\\n  \\\"Left\\\": 340\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 184095,\n                  \"Version\": 2,\n                  \"Guid\": \"a2fac7d0-825a-45e3-a39b-6cfd19840d17\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.EntityTypeFilter\",\n                    \"Name\": \"ToSic.Eav.DataSources.EntityTypeFilter\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"TypeName\": {\n                        \"en-us\": \"d7f2e4fa-5306-41bb-a3cd-d9529c838879\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"7e8e2c29-d170-4738-b99d-5bcfdcfdafb3\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 184097,\n              \"Version\": 1,\n              \"Guid\": \"503a3137-d447-49db-acd7-581536da1cad\",\n              \"Type\": {\n                \"Id\": \"5e958dc6-2922-4d68-835c-7b9711538b12\",\n                \"Name\": \"NoteDecorator\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Note\": {\n                    \"en-us\": \"<p>The test data guid \\\"d7f2e4fa-5306-41bb-a3cd-d9529c838879\\\" is the export-decorator used in the system-queries app.</p>\"\n                  },\n                  \"NoteType\": {\n                    \"en-us\": \"note\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"The test data guid \\\"d7f2e4fa-5...\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\"\n              }\n            },\n            {\n              \"Id\": 184098,\n              \"Version\": 21,\n              \"Guid\": \"0f5703bc-6e2f-4e02-b864-191aaf76d1d2\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Metadata Targets\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"afaf73d9-775c-4932-aebd-23e898b1643e\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 300,\\r\\n  \\\"Left\\\": 580\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\"\n              }\n            },\n            {\n              \"Id\": 184099,\n              \"Version\": 19,\n              \"Guid\": \"ac245cea-8418-4a29-8ef7-76062b006c49\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Parents - Decorators for this Config\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"915217e5-7957-4303-a19c-a15505f2ad1d\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 380,\\r\\n  \\\"Left\\\": 100\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 184100,\n                  \"Version\": 1,\n                  \"Guid\": \"f2afd28f-4115-4fe2-b3e5-c0fae23390dc\",\n                  \"Type\": {\n                    \"Id\": \"a72cb2f4-52bb-41e6-9281-10e69aeb0310\",\n                    \"Name\": \"ParentsDataSourceConfig\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"ContentTypeName\": {\n                        \"en-us\": \"32698880-1c2e-41ab-bcfc-420091d3263f\"\n                      },\n                      \"FieldName\": {\n                        \"en-us\": \"Configuration\"\n                      },\n                      \"FilterDuplicates\": {\n                        \"en-us\": \"true\"\n                      },\n                      \"Title\": {\n                        \"en-us\": \"Get Parent Items\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"ac245cea-8418-4a29-8ef7-76062b006c49\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 184103,\n              \"Version\": 12,\n              \"Guid\": \"1cdab8ab-f4ff-4965-a8bc-acdbbfafd015\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Filter desired Config\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"ToSic.Eav.DataSources.ValueFilter, ToSic.Eav.DataSources\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 520,\\r\\n  \\\"Left\\\": 600\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 184104,\n                  \"Version\": 3,\n                  \"Guid\": \"df250d6f-11db-45ee-afd9-85cc34352688\",\n                  \"Type\": {\n                    \"Id\": \"|Config ToSic.Eav.DataSources.ValueFilter\",\n                    \"Name\": \"ToSic.Eav.DataSources.ValueFilter\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"Attribute\": {\n                        \"en-us\": \"EntityGuid\"\n                      },\n                      \"Languages\": {\n                        \"en-us\": \"\"\n                      },\n                      \"Operator\": {\n                        \"en-us\": \"==\"\n                      },\n                      \"Take\": {\n                        \"en-us\": \"\"\n                      },\n                      \"Value\": {\n                        \"en-us\": \"[Params:ConfigurationGuid]\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"1cdab8ab-f4ff-4965-a8bc-acdbbfafd015\"\n                  }\n                }\n              ]\n            },\n            {\n              \"Id\": 184105,\n              \"Version\": 1,\n              \"Guid\": \"aa4ebca9-5bf0-4f73-accc-9c0ae788698a\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\"\n              }\n            },\n            {\n              \"Id\": 184121,\n              \"Version\": 3,\n              \"Guid\": \"dd5fafd6-7b3e-4fe5-874e-330381df561d\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"Serialization Configuration\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"2952e680-4aaa-4a12-adf7-325cb2854358\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 120,\\r\\n  \\\"Left\\\": 380\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3d492956-301c-4ad9-afce-085b41661035\"\n              },\n              \"Metadata\": [\n                {\n                  \"Id\": 184122,\n                  \"Version\": 2,\n                  \"Guid\": \"29c21925-dc7c-454a-8b46-c6287aafcf64\",\n                  \"Type\": {\n                    \"Id\": \"5c84cd3f-f853-40b3-81cf-dee6a07dc411\",\n                    \"Name\": \"DsSerializationConfiguration\"\n                  },\n                  \"Attributes\": {\n                    \"String\": {\n                      \"IncludeAppId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeCreated\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeGuid\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadata\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataFor\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataForId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataForType\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataGuid\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeMetadataTitle\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeModified\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationshipGuid\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationshipId\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationships\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationshipsAsCsv\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeRelationshipTitle\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeTitle\": {\n                        \"en-us\": \"\"\n                      },\n                      \"IncludeTypeAs\": {\n                        \"en-us\": \"flat\"\n                      },\n                      \"IncludeTypeId\": {\n                        \"en-us\": \"false\"\n                      },\n                      \"IncludeTypeName\": {\n                        \"en-us\": \"true\"\n                      },\n                      \"Notes\": {\n                        \"en-us\": \"\"\n                      },\n                      \"RemoveEmptyStringValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"RemoveFalseValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"RemoveNullValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"RemoveZeroValues\": {\n                        \"en-us\": \"\"\n                      },\n                      \"Title\": {\n                        \"en-us\": \"Serialization Configuration\"\n                      },\n                      \"TypePropertyNames\": {\n                        \"en-us\": \"Type\"\n                      }\n                    }\n                  },\n                  \"Owner\": \"dnn:userid=41\",\n                  \"For\": {\n                    \"Target\": \"Entity\",\n                    \"TargetType\": 4,\n                    \"Guid\": \"dd5fafd6-7b3e-4fe5-874e-330381df561d\"\n                  }\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"Id\": 185367,\n          \"Version\": 43,\n          \"Guid\": \"4570a596-5020-4111-b494-3e510f778c6e\",\n          \"Type\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Description\": {\n                \"*\": \"Retrieve data from the backend - basically any other DataSource.\"\n              },\n              \"Name\": {\n                \"*\": \"System.SysData\"\n              },\n              \"Params\": {\n                \"*\": \"SysDataSource=[QueryString:SysDataSource]\\nSysDataStream=[QueryString:SysDataStream||Default]\"\n              },\n              \"StreamsOut\": {\n                \"*\": \"*,Header\"\n              },\n              \"StreamWiring\": {\n                \"*\": \"9ca272fb-3778-4ade-bc11-9687ab5d3995:Default>Out:*\"\n              },\n              \"TestParameters\": {\n                \"*\": \"[QueryString:SysDataSource_Metadata]=fba0d40d-f6af-4593-9ccb-54cfd73d8217\\n[Params:SysDataSource_Scopes]=f134e3c1-f09f-4fbc-85be-de43a64c6eed\\n[QueryString:SysDataSource]=ToSic.Eav.DataSources.System.Attributes, ToSic.Eav.DataSources\\n[Params:SysDataSource_Never]=398d0b9f-044f-48f7-83ef-307872f7ed93\\n[Params:SysDataStream_xx]=Default\\n[QueryString:ContentTypeName]=Test\"\n              },\n              \"VisualDesignerData\": {\n                \"*\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n              }\n            },\n            \"Boolean\": {\n              \"AllowEdit\": {\n                \"*\": true\n              },\n              \"HiddenInQueryPicker\": {\n                \"*\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 185369,\n              \"Version\": 20,\n              \"Guid\": \"9ca272fb-3778-4ade-bc11-9687ab5d3995\",\n              \"Type\": {\n                \"Id\": \"DataPipelinePart\",\n                \"Name\": \"DataPipelinePart\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Description\": {\n                    \"*\": \"\"\n                  },\n                  \"Name\": {\n                    \"*\": \"System Data\"\n                  },\n                  \"PartAssemblyAndType\": {\n                    \"*\": \"37cf83f7-5e57-4c4a-9798-a7e1440f99b3\"\n                  },\n                  \"VisualDesignerData\": {\n                    \"*\": \"{\\r\\n  \\\"Top\\\": 240,\\r\\n  \\\"Left\\\": 440\\r\\n}\"\n                  }\n                }\n              },\n              \"Owner\": \"unknown\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"4570a596-5020-4111-b494-3e510f778c6e\"\n              }\n            },\n            {\n              \"Id\": 185370,\n              \"Version\": 1,\n              \"Guid\": \"d1d0e574-0f40-431f-9255-3b0e3c77317e\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1fac6138-39c7-4ab6-9c54-9cf3e4ffd5ed\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"4570a596-5020-4111-b494-3e510f778c6e\"\n              }\n            },\n            {\n              \"Id\": 185371,\n              \"Version\": 1,\n              \"Guid\": \"c9c3cb1e-b4bf-4a30-a578-06b2d95e2d1d\",\n              \"Type\": {\n                \"Id\": \"PermissionConfiguration\",\n                \"Name\": \"PermissionConfiguration\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Condition\": {\n                    \"en-us\": \"SecurityAccessLevel.Admin\"\n                  },\n                  \"Grant\": {\n                    \"en-us\": \"r\"\n                  },\n                  \"Identity\": {\n                    \"en-us\": \"\"\n                  },\n                  \"PermissionType\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Allow admins - but internal security checks will restrict it more\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"4570a596-5020-4111-b494-3e510f778c6e\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-query.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"DataPipeline\",\n            \"Name\": \"DataPipeline\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 45145,\n                \"Version\": 2,\n                \"Guid\": \"b48d7594-b48d-4412-8450-0080a1f3327b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Describes a set of data sources and how they are interconnected.\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>A Query (DataPipeline) is the definition type of a Visual-Query, containing title, description and hidden information like wiring between the parts.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Query\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"DataPipeline\"\n                }\n              },\n              {\n                \"Id\": 137453,\n                \"Version\": 1,\n                \"Guid\": \"01a3080f-1409-4760-84ee-632fe76142f7\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"DataPipeline\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Name\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45120,\n                    \"Version\": 4,\n                    \"Guid\": \"8d83d13c-916f-4594-9ae9-aa1f5c0fe24f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Query Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"Descriptive Name\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45121,\n                    \"Version\": 3,\n                    \"Guid\": \"f6dabb9c-1f12-4443-9783-70f691d6e7b2\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45150,\n                    \"Version\": 2,\n                    \"Guid\": \"f23e2e7e-aa81-405f-b129-22e2816240df\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45122,\n                    \"Version\": 2,\n                    \"Guid\": \"41533565-885e-4c33-9bfb-8e208ed8d8ee\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Description\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Short info about this pipeline, what it's for\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45123,\n                    \"Version\": 3,\n                    \"Guid\": \"009d0843-b009-41ae-9237-e22b465316e8\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45151,\n                    \"Version\": 2,\n                    \"Guid\": \"a2cb52c2-3c1b-4486-8222-4aadcf9840f0\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowEdit\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45124,\n                    \"Version\": 3,\n                    \"Guid\": \"ea3d9f87-c42b-46c9-8ddd-9c073f09c0fe\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"True\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Allow Edit\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"If set to false, the pipeline-system will only show this pipeline but not allow changes.\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 169179,\n                    \"Version\": 1,\n                    \"Guid\": \"b8ac5fc0-85c5-4146-ba33-e897e932c857\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Read-only - editing not allowed\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Allow Edit\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"HiddenInQueryPicker\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169177,\n                    \"Version\": 3,\n                    \"Guid\": \"d94606d0-72d5-4f65-a1aa-ecea3fa4f049\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"HiddenInQueryPicker\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Hide this query from users who pick a query in a query picker.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169178,\n                    \"Version\": 2,\n                    \"Guid\": \"297811b1-d326-4600-8700-d789e366c3fc\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Visible in Query Picker (default)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Hidden in Query Picker\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ParametersGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63402,\n                    \"Version\": 3,\n                    \"Guid\": \"fdcb6b4a-f22d-45ca-817e-c14b68a03828\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Parameters for Testing and Runtime\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The <strong>Test Parameters</strong> are for testing only, while the <strong>Parameters</strong> are used for the Params LookUp - for tokens like [Params:Id]. Read more about <a href=\\\"https://r.2sxc.org/QueryParams\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Query Params in the docs</a>.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63404,\n                    \"Version\": 2,\n                    \"Guid\": \"5d34f96d-02db-4858-959e-80870dda0708\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Params\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63403,\n                    \"Version\": 9,\n                    \"Guid\": \"a67f614b-d57a-48f7-bfd8-05604fa88725\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"ReplaceThis=27\\nReplaceThisAsWell=[QueryString:Id]\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Parameters\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Parameters used in this query. One on each line. Format like Key=Value. Examples:&nbsp;</p>\\n<ul>\\n<li>Id=27</li>\\n<li>Id=[QueryString:Id]</li>\\n<li>Id=[QueryString:Id||27]</li>\\n</ul>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63405,\n                    \"Version\": 8,\n                    \"Guid\": \"86929de5-86c8-4a85-8854-7cedaaa3693a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63406,\n                    \"Version\": 8,\n                    \"Guid\": \"81f36eff-3f91-4a23-9b90-13a3137e08c1\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TestParameters\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 63461,\n                    \"Version\": 3,\n                    \"Guid\": \"56ada5ea-e4ff-4bba-80bd-5dfb27d044e5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Test Parameters\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Test parameters, one per line. See <a href=\\\"https://r.2sxc.org/QueryParams\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>. Syntax is</p>\\n<ul>\\n<li>[source:property]=value</li>\\n<li>[source:property]=[othersource:property]</li>\\n</ul>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63462,\n                    \"Version\": 2,\n                    \"Guid\": \"c3bc760d-e33f-45b4-987c-cb8854192aa3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 63463,\n                    \"Version\": 2,\n                    \"Guid\": \"b003c249-537f-4ab3-a0a3-09b12336e01a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 5\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135947,\n                    \"Version\": 5,\n                    \"Guid\": \"c7be53d6-3fe2-43c4-8a3c-fd94bf4c4bd8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced Settings ⚠️\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Please be very careful editing this stuff</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"f4e52fd1-4a37-406f-82cf-e51cb977dde4\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135948,\n                    \"Version\": 4,\n                    \"Guid\": \"18f8c776-392d-43e8-afb1-e4ec659907cb\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"StreamsOut\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45125,\n                    \"Version\": 4,\n                    \"Guid\": \"e65cbf0e-8415-444b-8c76-c018a056119e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Streams Out\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"Comma separated list of streams this pipeline offers to the target. Like 'Content, Presentation, ListContent, ListPresentation'\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45126,\n                    \"Version\": 3,\n                    \"Guid\": \"fbda1223-55eb-405f-99a3-4dff47cc79ea\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45152,\n                    \"Version\": 2,\n                    \"Guid\": \"b8e18079-d7ae-47cb-af24-174b5b167746\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"StreamWiring\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45127,\n                    \"Version\": 4,\n                    \"Guid\": \"8597cd16-2cb5-4bd5-94af-a3b9ef656602\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Stream Wiring\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"List of connections between the parts of this pipeline, each connection on one line, like 6730:Default>6732:Default\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45128,\n                    \"Version\": 3,\n                    \"Guid\": \"7719f9a1-905a-4501-8e91-8e692f8397ce\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45153,\n                    \"Version\": 2,\n                    \"Guid\": \"3fa3e6d8-9242-42e1-8d13-dc4184203fe1\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VisualDesignerData\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-json\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 135586,\n                    \"Version\": 7,\n                    \"Guid\": \"f09ddc98-2037-4b63-aa22-d1267b324b29\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"{\\\"ShowDataSourceDetails\\\":true}\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-json\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"VisualDesignerData\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Contains UI configuration / settings. Will not affect the backend, just the display of the query.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135587,\n                    \"Version\": 5,\n                    \"Guid\": \"0c21341b-6c33-4792-88fe-bf73b2a17875\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135588,\n                    \"Version\": 1,\n                    \"Guid\": \"7d6b9263-1351-4208-85b2-c4b035c8d298\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 135946,\n                    \"Version\": 4,\n                    \"Guid\": \"f655ac6f-db30-4964-92c0-ee0ff460bcfe\",\n                    \"Type\": {\n                      \"Id\": \"@string-json\",\n                      \"Name\": \"@string-json\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"JsonSchemaMode\": {\n                          \"en-us\": \"none\"\n                        },\n                        \"JsonSchemaRaw\": {\n                          \"en-us\": \"\"\n                        },\n                        \"JsonSchemaSource\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"JsonValidation\": {\n                          \"en-us\": \"strict\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"JsonSchemaUrl\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"Rows\": {\n                          \"en-us\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 135949,\n              \"Version\": 2,\n              \"Guid\": \"f4e52fd1-4a37-406f-82cf-e51cb977dde4\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return context.debug; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"DataPipelinePart\",\n            \"Name\": \"DataPipelinePart\",\n            \"Scope\": \"System.DataSources\",\n            \"Metadata\": [\n              {\n                \"Id\": 45146,\n                \"Version\": 2,\n                \"Guid\": \"ce3bc4fa-1f60-46b6-b6a8-9f26e981b55d\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"A part in the data pipeline, usually a data source/target element.\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>This is an internal data-type, usually invisible to the user. It contains the specs for a DataSource part inside a VisualQuery (DataPipeline). You should usually not edit this yourself, as you'll probably break something.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Query Part\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"DataPipelinePart\"\n                }\n              },\n              {\n                \"Id\": 137454,\n                \"Version\": 1,\n                \"Guid\": \"5ceca9a8-eda2-46d5-a47b-84b7a6c686d9\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"DataPipelinePart\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Name\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45131,\n                    \"Version\": 3,\n                    \"Guid\": \"848cf93b-b0fb-405a-9abf-f4dbbd15333c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Name\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"The part name for easy identification by the user\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45132,\n                    \"Version\": 3,\n                    \"Guid\": \"536504b2-8914-41ee-a17d-65cded02d08e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45155,\n                    \"Version\": 1,\n                    \"Guid\": \"a1bef096-4ab2-4fbf-8429-48e7f3c1a0f5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45133,\n                    \"Version\": 3,\n                    \"Guid\": \"0bb6d7dc-4918-4f05-9ce3-4eaaf105cd18\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Description\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Notes about this item\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45134,\n                    \"Version\": 3,\n                    \"Guid\": \"3221122f-0fe5-4714-8088-f6e83df36d79\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45156,\n                    \"Version\": 1,\n                    \"Guid\": \"b6d59b24-e328-4b7f-8f9d-fc3e6f7f54a7\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PartAssemblyAndType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45135,\n                    \"Version\": 6,\n                    \"Guid\": \"a44a5c63-b20e-4096-92ba-32bdb8f2923b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Identity\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is the identity of the DataSource - usually a GUID or Assembly and type info to help the system find this dll etc.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45136,\n                    \"Version\": 5,\n                    \"Guid\": \"ced8f8a3-4f49-44d3-a573-386d9aa526c5\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45157,\n                    \"Version\": 3,\n                    \"Guid\": \"eca41956-0eb4-4a43-bd0f-7c4ca0ed5d76\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"VisualDesignerData\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-json\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45137,\n                    \"Version\": 6,\n                    \"Guid\": \"1a3c49c4-471a-4338-b862-1e20bf4720c5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-json\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Visual Designer Data\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"Technical data for the designer so it can save it's values etc.\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45138,\n                    \"Version\": 4,\n                    \"Guid\": \"ef734c14-4efa-4288-9764-ee2d2eb7aa53\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45158,\n                    \"Version\": 1,\n                    \"Guid\": \"3f98bef5-f95d-4c1d-ae8c-0eec97198603\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 135945,\n                    \"Version\": 1,\n                    \"Guid\": \"ca02b45f-d534-4b6a-911d-1bc51550c44c\",\n                    \"Type\": {\n                      \"Id\": \"@string-json\",\n                      \"Name\": \"@string-json\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"JsonSchemaMode\": {\n                          \"en-us\": \"none\"\n                        },\n                        \"JsonSchemaRaw\": {\n                          \"en-us\": \"\"\n                        },\n                        \"JsonSchemaSource\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"JsonValidation\": {\n                          \"en-us\": \"strict\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"JsonSchemaUrl\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"Rows\": {\n                          \"en-us\": 25\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-resources.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"8cfea27d-ab69-42e7-bfcb-0aa054eacbfb\",\n            \"Name\": \"ResourcesSystem\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 132213,\n                \"Version\": 1,\n                \"Guid\": \"4fc531f6-9548-4298-832e-5d98cd8ffb56\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Here you can configure System Resources. If you're new to this please <a href=\\\"https://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">read the docs</a>.&nbsp;</p>\\n<p>As of now, there are not many pre-defined <em>SystemResources</em> - so if this form looks pretty empty that's expected \\uD83D\\uDE09.</p>\\n<p>Remember that you can always create <em>custom resources </em>for anything you want. These will not be stored here, but in a new ContentType called&nbsp;<em>Resources</em> which you would create on your own.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"System Resources\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"<p>These settings override defaults provided at the global level. Make sure you understand Settings before doing much here. <a href=\\\"https://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Read the docs please</a>.&nbsp;</p>\\n<p>Note: you should usually only have exactly 1 item in this list. The only exception is on the main <strong>Content</strong> app where you have two items (one affecting only the current App, one affecting the entire Site).&nbsp;</p>\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"8cfea27d-ab69-42e7-bfcb-0aa054eacbfb\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 132215,\n                    \"Version\": 2,\n                    \"Guid\": \"9d4b1723-383d-4f16-8589-6eae07b2511d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"System Resources\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132216,\n                    \"Version\": 1,\n                    \"Guid\": \"30490916-f80d-4bf2-b74c-09c8b83851cb\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132217,\n                    \"Version\": 1,\n                    \"Guid\": \"80ae7716-eb37-4e87-b932-7f16de538796\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TestMessage\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 132205,\n                    \"Version\": 2,\n                    \"Guid\": \"c4d6ec9f-fca2-4413-be77-fa671d2ca9dd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Test Message (TestMessage)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is just a dummy test message which will always be in the PresetSystem data to verify resources work.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132209,\n                    \"Version\": 1,\n                    \"Guid\": \"27eb0826-5452-4de3-806b-e285956bf6a3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132210,\n                    \"Version\": 1,\n                    \"Guid\": \"a5bee366-0780-4ed1-9280-172d5662f490\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SettingsEntityScope\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 132204,\n                    \"Version\": 5,\n                    \"Guid\": \"a7e23a29-1b9a-4022-8632-7277ff6845c3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Scope / Reach of these Resources\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Leave on Default in 99% of the cases. Only rare cases use Site. See docs.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132207,\n                    \"Version\": 3,\n                    \"Guid\": \"8d864fdc-d11c-479a-89fe-6206023288a6\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132208,\n                    \"Version\": 3,\n                    \"Guid\": \"046451e4-3860-47e5-82e5-e4dc78ec5a3c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default (current App)\\nsite:Site (these Settings affect all Apps of this Site)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MessageSiteScope\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 132211,\n                    \"Version\": 4,\n                    \"Guid\": \"26de0eb1-19b2-488d-a58e-cf78d08f576d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Important: Site-Scope only Works in the Content-App (OLD, remove some time)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>Important Information about Site-Level Resources</strong></p>\\n<p>Normally all resources only affect the current app. Switching the above setting to <strong>Site</strong> will affect the entire site&nbsp;<em>but only if you are in the primary Content-App</em>. On any other App it will still only affect the current app. Read more about <a href=\\\"http://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">resources</a>.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GoogleMaps\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 132239,\n                    \"Version\": 3,\n                    \"Guid\": \"ca2459d8-4a7b-435c-b768-5aa40222f014\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Google Maps\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132240,\n                    \"Version\": 2,\n                    \"Guid\": \"25232847-80da-48d6-a0e4-b07f58d3ad5b\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"\\uD83C\\uDF10GoogleMaps\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Toolbar\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 168752,\n                    \"Version\": 5,\n                    \"Guid\": \"f66487be-7c17-42fa-9fd4-2d53fc8c4c15\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Toolbar\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 168753,\n                    \"Version\": 4,\n                    \"Guid\": \"357c276d-06b0-440e-9a2e-b690645edd46\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"\\uD83C\\uDF10Toolbar\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"40e561d2-096f-4ff7-a388-55f61a19490c\",\n            \"Name\": \"\\uD83C\\uDF10GoogleMaps\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 132238,\n                \"Version\": 1,\n                \"Guid\": \"886e8b4c-6a04-44d5-b641-d632f54cfaf7\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>These resources are to be used with Google Maps implementations.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"\\uD83C\\uDF10GoogleMaps\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"40e561d2-096f-4ff7-a388-55f61a19490c\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Identifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 132244,\n                    \"Version\": 7,\n                    \"Guid\": \"cd5948e1-94b2-4742-88da-7986a568e1d8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"GoogleMaps\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Identifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132245,\n                    \"Version\": 6,\n                    \"Guid\": \"58f12a41-b38a-4acb-afa2-5519d3fa3bca\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132246,\n                    \"Version\": 6,\n                    \"Guid\": \"33501e3a-af78-4fed-8861-fca4988b92aa\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"WarningApiKeyForDemoOnly\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 132237,\n                    \"Version\": 2,\n                    \"Guid\": \"7877762a-e261-4d59-a01d-a30b1f214c17\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Warning Message: Api-Key is for Demo Purposes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\",\n                          \"de-de\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132242,\n                    \"Version\": 1,\n                    \"Guid\": \"758f3da9-c075-4ff7-814f-5472cb03eac0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132243,\n                    \"Version\": 1,\n                    \"Guid\": \"1f99b176-a683-4196-b927-b62869a27140\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"29be4120-d21f-473a-a5c9-9ce10f0248c7\",\n            \"Name\": \"\\uD83C\\uDF10Toolbar\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [],\n            \"Attributes\": [\n              {\n                \"Name\": \"Identifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 168746,\n                    \"Version\": 2,\n                    \"Guid\": \"58b2014a-bbb8-46e3-8fb6-7b706045954e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Toolbar\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Identifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 168747,\n                    \"Version\": 1,\n                    \"Guid\": \"2a7ae2dd-754c-4c6a-8d2e-57dd8f01c0bf\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 168748,\n                    \"Version\": 1,\n                    \"Guid\": \"7e786097-950e-48af-af62-e776874bd4fa\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IsDemoItem\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 168744,\n                    \"Version\": 1,\n                    \"Guid\": \"4254c9a4-c6ae-4528-94fc-8975e93b911a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"IsDemoItem\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IsDemoSubItem\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 168745,\n                    \"Version\": 1,\n                    \"Guid\": \"26f32cb0-f31f-41cf-b480-b740f204aa7a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"IsDemoSubItem\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        }\n      ],\n      \"Entities\": [\n        {\n          \"Id\": 132214,\n          \"Version\": 5,\n          \"Guid\": \"a0bedfbb-57eb-44b6-a4ce-738b199fdbc2\",\n          \"Type\": {\n            \"Id\": \"8cfea27d-ab69-42e7-bfcb-0aa054eacbfb\",\n            \"Name\": \"ResourcesSystem\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"SettingsEntityScope\": {\n                \"en-us\": \"\"\n              },\n              \"TestMessage\": {\n                \"en-us\": \"This is a test-message for testing the Resources - always remember that the answer is 42!\",\n                \"de-de\": \"Das ist eine Testmeldung für die Ressourcen (Resources). Vergiss nicht: die Antwort ist immer 42!\"\n              },\n              \"Title\": {\n                \"en-us\": \"System Resources\"\n              }\n            },\n            \"Entity\": {\n              \"GoogleMaps\": {\n                \"*\": [\n                  \"d3af78fc-8d7a-44f4-9712-ec8554714158\"\n                ]\n              },\n              \"Toolbar\": {\n                \"*\": [\n                  \"1d9dc186-d707-467b-ba49-c2e58d2869a0\"\n                ]\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166591,\n              \"Version\": 1,\n              \"Guid\": \"af6d1d4c-57de-48a5-b001-3f0b33a5349e\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"e3d5d17c-126e-4061-8f44-658406df642a\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"a0bedfbb-57eb-44b6-a4ce-738b199fdbc2\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 132241,\n          \"Version\": 8,\n          \"Guid\": \"d3af78fc-8d7a-44f4-9712-ec8554714158\",\n          \"Type\": {\n            \"Id\": \"40e561d2-096f-4ff7-a388-55f61a19490c\",\n            \"Name\": \"\\uD83C\\uDF10GoogleMaps\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Identifier\": {\n                \"en-us\": \"GoogleMaps\"\n              },\n              \"WarningApiKeyForDemoOnly\": {\n                \"en-us\": \"<p><strong>Warning:</strong> This GoogleMap uses a demo API-Key, which will cause problems on live web sites. <a href=\\\"https://azing.org/2sxc/r/ApSwlItl\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Please change the Google ApiKey</a>.</p>\",\n                \"de-de\": \"<p><strong>Achtung:</strong> Diese GoogleMap verwendet einen API-Key f&uuml;r Demo-Zwecke. Das w&uuml;rde sp&auml;ter Probleme verursachen. Bitte <a href=\\\"https://azing.org/2sxc/r/ApSwlItl\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">&auml;ndere den API-Key</a>.</p>\"\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166592,\n              \"Version\": 1,\n              \"Guid\": \"53673bf0-1986-411d-906c-933db7bce302\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"e3d5d17c-126e-4061-8f44-658406df642a\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"d3af78fc-8d7a-44f4-9712-ec8554714158\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 168749,\n          \"Version\": 1,\n          \"Guid\": \"1d9dc186-d707-467b-ba49-c2e58d2869a0\",\n          \"Type\": {\n            \"Id\": \"29be4120-d21f-473a-a5c9-9ce10f0248c7\",\n            \"Name\": \"\\uD83C\\uDF10Toolbar\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Identifier\": {\n                \"en-us\": \"Toolbar\"\n              },\n              \"IsDemoItem\": {\n                \"en-us\": \"This is a demo item. When you edit it, it will create a new item.\",\n                \"de-de\": \"Dies ist ein Demo-Element. Wenn de ihn bearbeitest, wird ein neues Element erstellt.\"\n              },\n              \"IsDemoSubItem\": {\n                \"en-us\": \"This is a sub item of a demo-item. You must first edit the main item to start adding sub items.\",\n                \"de-de\": \"Dies ist ein Unterelement eines Demo-Elements. Du musst zuerst das Hauptelement bearbeiten, um Unterelemente hinzuzufügen.\"\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 168751,\n              \"Version\": 1,\n              \"Guid\": \"65141641-8f57-474b-b0bc-8f153e2eb748\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"e3d5d17c-126e-4061-8f44-658406df642a\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"1d9dc186-d707-467b-ba49-c2e58d2869a0\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-settings-web-resources-data.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"66f19c62-371e-4ad1-a98b-de0745507be4\",\n            \"Name\": \"⚙️WebResource\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 166467,\n                \"Version\": 1,\n                \"Guid\": \"cad9fa69-b654-414a-9de2-cc59be5664be\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Web Resource\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"66f19c62-371e-4ad1-a98b-de0745507be4\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130637,\n                    \"Version\": 4,\n                    \"Guid\": \"b460d734-3b44-4f2e-9006-affa1d3a842a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Settings Identifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"915a2d6e-7092-4552-a367-a68e753777e3\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130646,\n                    \"Version\": 3,\n                    \"Guid\": \"c4fe15aa-1c62-4ba3-918f-14e043cea781\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130647,\n                    \"Version\": 3,\n                    \"Guid\": \"c7e54e84-093c-4c7c-9f90-719c536534be\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130638,\n                    \"Version\": 8,\n                    \"Guid\": \"885919d3-9278-4278-89c0-b83e5ceaa0bd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Name / Item Identifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Select a predefined identifier or create your own with the TT-button. These identifiers are case-insensitive.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130643,\n                    \"Version\": 6,\n                    \"Guid\": \"78c62298-7189-45eb-a2cb-de21d26d9ac3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130644,\n                    \"Version\": 6,\n                    \"Guid\": \"7fc87496-192e-4d70-8884-74392a3fcee0\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"Bootstrap4:Bootstrap4\\nBootstrap5:Bootstrap5\\nfancybox3:fancybox3\\nfancybox4:fancybox4\\nFontAwesome5:FontAwesome5\\nFontAwesome6:FontAwesome6\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Enabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130656,\n                    \"Version\": 7,\n                    \"Guid\": \"7f966c33-b4d7-41c8-90a8-ad28395b8d51\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Enabled\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Usually it's enabled, but if the skin already includes it, set to false to avoid it being added again.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130657,\n                    \"Version\": 6,\n                    \"Guid\": \"fc93ad3a-a947-452c-9893-47c5d1c2ed9f\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"Disable this resource\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"Don't configure / use default setting\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"Enable this resource\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Html\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130639,\n                    \"Version\": 5,\n                    \"Guid\": \"62a70977-5a94-4c11-ae2d-51b233e4b4f4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Raw Html Snippets for this Resource (Html)\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is the raw HTML to add, incl. JS/CSS tags etc.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130648,\n                    \"Version\": 4,\n                    \"Guid\": \"70304913-6bde-4f25-bddb-9310f8a677ee\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130649,\n                    \"Version\": 4,\n                    \"Guid\": \"e45576ab-6895-4e56-9594-de392ca1e1bf\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 20\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169560,\n                    \"Version\": 2,\n                    \"Guid\": \"770341e9-6a2a-4349-a2e4-c5f0387b50da\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169561,\n                    \"Version\": 1,\n                    \"Guid\": \"f964befb-f612-4a82-b83a-bc75da716427\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AutoOptimize\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169562,\n                    \"Version\": 2,\n                    \"Guid\": \"6caf29fa-4e9a-45bf-bd8d-5a48006be1ee\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"AutoOptimize\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169563,\n                    \"Version\": 1,\n                    \"Guid\": \"6d4cbce9-da2c-4ee8-bcab-f9c5dcb814e6\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Disable automatic optimizations\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Automatically optimize, bundle etc.\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130645,\n              \"Version\": 2,\n              \"Guid\": \"915a2d6e-7092-4552-a367-a68e753777e3\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return 'WebResources.' + data.ItemIdentifier; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"9ff20ccf-3ff7-4a76-b749-dd22771df730\",\n            \"Name\": \"⚙️WebResources\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 130636,\n                \"Version\": 4,\n                \"Guid\": \"d7779b22-0193-43f4-b8fe-50132c133d34\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"*\": \"Items\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Web Resources are additional script etc. which are often loaded from a CDN.&nbsp;</p>\\n<p>The default configuration will continue to point to the latest CDN versions you need - but you can always override this in your System/Site/App as needed.</p>\\n<p>Only Apps which explicitly want to load these resources from the Settings will actually obey this - older and custom apps may have their own list of things they load.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"⚙️WebResources\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"9ff20ccf-3ff7-4a76-b749-dd22771df730\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130628,\n                    \"Version\": 2,\n                    \"Guid\": \"04c3974c-a33b-425e-bdc6-5670403471b3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"WebResources\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"SettingsIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130629,\n                    \"Version\": 1,\n                    \"Guid\": \"70449387-aef3-4fa2-b6b9-fff1da999497\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130630,\n                    \"Version\": 1,\n                    \"Guid\": \"8313a56b-a109-4016-a955-8d455cb9e876\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CdnSourceNotEnabledWarning\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169950,\n                    \"Version\": 4,\n                    \"Guid\": \"3a897222-1950-4d38-a0b1-fe5af3f98888\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"CdnSourceNotEnabledWarning\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>⚠️ Warning ⚠️</strong></p>\\n<p>You have configured an alternate CDN source. It appears that the features for this are not enabled, so the settings will not have an effect. See <a href=\\\"https://r.2sxc.org/cdn\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">CDN docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"69741b0b-6734-49b8-a8b5-46b42908e302\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CdnSourcePublic\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169551,\n                    \"Version\": 9,\n                    \"Guid\": \"c26bb49e-8607-47bd-add3-12962104a963\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"CDN Source for Public Resources\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Preferred location where to load public resources from, such as bootstrap, fancybox etc.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169552,\n                    \"Version\": 8,\n                    \"Guid\": \"4d053dd3-3456-41d9-a797-90b9ab0849d7\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169553,\n                    \"Version\": 8,\n                    \"Guid\": \"880a956f-d542-4608-8e6a-055858a1e589\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Not set - use system default (usually Public CDNs)\\ncdn:Public CDNs such as Google-Fonts\\nhttps\\\\://cdn.2sxc.org/packages:2sxc CDN (cdn.2sxc.org)\\n/cdn/packages:Local - on this website (/cdn)\\ncustom:Custom path or site (switch to text-mode to type custom value)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CdnSourceEdit\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169564,\n                    \"Version\": 6,\n                    \"Guid\": \"7d01e570-7af5-4ed2-bfe1-0ba58a956a1d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"CDN Source for Edit Resources\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These are resources used in the edit dialog, such as icons and fonts.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169565,\n                    \"Version\": 5,\n                    \"Guid\": \"0e2a664d-e946-4585-a1e3-6a2a810d00bd\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169566,\n                    \"Version\": 5,\n                    \"Guid\": \"4eac359d-372e-42d1-94c5-3628c9a79fab\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Not set - use system default (usually Public CDNs)\\ncdn:Public CDNs such as Google-Fonts\\nhttps\\\\://cdn.2sxc.org/packages:2sxc CDN (cdn.2sxc.org)\\n/cdn/packages:Local - on this website (/cdn)\\ncustom:Custom path or site (switch to text-mode to type custom value)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Items\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130635,\n                    \"Version\": 9,\n                    \"Guid\": \"c3fa7759-f4fb-4266-ac54-89857e301ccb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Resource Items\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130641,\n                    \"Version\": 8,\n                    \"Guid\": \"19b7bfe7-2bb6-4022-a851-a481c81cd492\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️WebResource\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 169951,\n              \"Version\": 3,\n              \"Guid\": \"69741b0b-6734-49b8-a8b5-46b42908e302\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const hasCdn = data.CdnSourceEdit || data.CdnSourcePublic;\\n  if (!hasCdn) return false;\\n  // show the warning if any of the features are not enabled\\n  const f = context.features;\\n  if (!f.isEnabled('CdnSourceEdit') || !f.isEnabled('CdnSourcePublic'))\\n    return true;\\n  return false;\\n});\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ],\n      \"Entities\": [\n        {\n          \"Id\": 130652,\n          \"Version\": 12,\n          \"Guid\": \"06f4fa58-2e91-4896-a16e-3bbaf9a5f491\",\n          \"Type\": {\n            \"Id\": \"9ff20ccf-3ff7-4a76-b749-dd22771df730\",\n            \"Name\": \"⚙️WebResources\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"CdnSourceEdit\": {\n                \"en-us\": \"\"\n              },\n              \"CdnSourcePublic\": {\n                \"en-us\": \"\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"WebResources\"\n              }\n            },\n            \"Entity\": {\n              \"Items\": {\n                \"*\": [\n                  \"e6d3d600-ea17-4957-9c56-9bae78329c67\",\n                  \"72286f65-e38b-42ee-a0da-0c73e55f7ba4\",\n                  \"4b9ef331-480a-4a38-86f1-a580f8345677\",\n                  \"3356ad17-91ce-4814-83c1-9f527697391a\",\n                  \"38e0226d-4c31-4d2e-ab97-8e16483ddf94\",\n                  \"3e6811a8-87ab-4954-8402-6e2b3d80c6e2\"\n                ]\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166554,\n              \"Version\": 1,\n              \"Guid\": \"3c2edf90-4fe7-42dc-9031-af52dcecc36d\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1a29fa3e-69e7-48db-836f-c04ee3991284\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"06f4fa58-2e91-4896-a16e-3bbaf9a5f491\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130653,\n          \"Version\": 6,\n          \"Guid\": \"e6d3d600-ea17-4957-9c56-9bae78329c67\",\n          \"Type\": {\n            \"Id\": \"66f19c62-371e-4ad1-a98b-de0745507be4\",\n            \"Name\": \"⚙️WebResource\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Html\": {\n                \"en-us\": \"<link rel=\\\"stylesheet\\\" href=\\\"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css\\\" integrity=\\\"sha256-+IZRbz1B6ee9mUx/ejmonK+ulIP5A5bLDd6v6NHqXnI=\\\" crossorigin=\\\"anonymous\\\">\\n\\n<script src=\\\"https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js\\\" integrity=\\\"sha256-GRJrh0oydT1CwS36bBeJK/2TggpaUQC6GzTaTQdZm0k=\\\" crossorigin=\\\"anonymous\\\"></script>\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Bootstrap4\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"WebResources.Bootstrap4\"\n              }\n            },\n            \"Boolean\": {\n              \"AutoOptimize\": {\n                \"en-us\": true\n              },\n              \"Enabled\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166555,\n              \"Version\": 1,\n              \"Guid\": \"136bb934-15a8-418f-9b74-2a76abdd8022\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1a29fa3e-69e7-48db-836f-c04ee3991284\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e6d3d600-ea17-4957-9c56-9bae78329c67\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130654,\n          \"Version\": 9,\n          \"Guid\": \"38e0226d-4c31-4d2e-ab97-8e16483ddf94\",\n          \"Type\": {\n            \"Id\": \"66f19c62-371e-4ad1-a98b-de0745507be4\",\n            \"Name\": \"⚙️WebResource\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Html\": {\n                \"en-us\": \"<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js\\\" integrity=\\\"sha512-Tn2m0TIpgVyTzzvmxLNuqbSJH3JP8jm+Cy3hvHrW7ndTDcJ1w5mBiksqDBb8GpE2ksktFvDB/ykZ0mDpsZj20w==\\\" crossorigin=\\\"anonymous\\\" referrerpolicy=\\\"no-referrer\\\"></script>\\n\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"FontAwesome5\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"WebResources.FontAwesome5\"\n              }\n            },\n            \"Boolean\": {\n              \"AutoOptimize\": {\n                \"en-us\": true\n              },\n              \"Enabled\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 144504,\n              \"Version\": 1,\n              \"Guid\": \"049f481e-a3aa-4a85-afe7-8c88ccafd38d\",\n              \"Type\": {\n                \"Id\": \"5e958dc6-2922-4d68-835c-7b9711538b12\",\n                \"Name\": \"NoteDecorator\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Note\": {\n                    \"en-us\": \"<p>Get updated links from the <a href=\\\"https://cdnjs.com/libraries/font-awesome/5.15.4\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">CDNJS</a>.</p>\"\n                  },\n                  \"NoteType\": {\n                    \"en-us\": \"note\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Get updated links from the CDN...\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"38e0226d-4c31-4d2e-ab97-8e16483ddf94\"\n              }\n            },\n            {\n              \"Id\": 166556,\n              \"Version\": 1,\n              \"Guid\": \"b757c81f-6b2a-46a6-be76-30a907586813\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1a29fa3e-69e7-48db-836f-c04ee3991284\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"38e0226d-4c31-4d2e-ab97-8e16483ddf94\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130655,\n          \"Version\": 5,\n          \"Guid\": \"4b9ef331-480a-4a38-86f1-a580f8345677\",\n          \"Type\": {\n            \"Id\": \"66f19c62-371e-4ad1-a98b-de0745507be4\",\n            \"Name\": \"⚙️WebResource\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Html\": {\n                \"en-us\": \"<link rel=\\\"stylesheet\\\" href=\\\"https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css\\\" integrity=\\\"sha512-H9jrZiiopUdsLpg94A333EfumgUBpO9MdbxStdeITo+KEIMaNfHNvwyjjDJb+ERPaRS6DpyRlKbvPUasNItRyw==\\\" crossorigin=\\\"anonymous\\\" referrerpolicy=\\\"no-referrer\\\" />\\n\\n<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js\\\" integrity=\\\"sha512-uURl+ZXMBrF4AwGaWmEetzrd+J5/8NRkWAvJx5sbPSSuOb0bZLqf+tOzniObO00BjHa/dD7gub9oCGMLPQHtQA==\\\" crossorigin=\\\"anonymous\\\" referrerpolicy=\\\"no-referrer\\\"></script>\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Fancybox3\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"WebResources.Fancybox3\"\n              }\n            },\n            \"Boolean\": {\n              \"AutoOptimize\": {\n                \"en-us\": true\n              },\n              \"Enabled\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166557,\n              \"Version\": 1,\n              \"Guid\": \"7db3406c-be34-4953-aa9e-7170ba075e5b\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1a29fa3e-69e7-48db-836f-c04ee3991284\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"4b9ef331-480a-4a38-86f1-a580f8345677\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130658,\n          \"Version\": 7,\n          \"Guid\": \"72286f65-e38b-42ee-a0da-0c73e55f7ba4\",\n          \"Type\": {\n            \"Id\": \"66f19c62-371e-4ad1-a98b-de0745507be4\",\n            \"Name\": \"⚙️WebResource\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Html\": {\n                \"en-us\": \"<link rel=\\\"stylesheet\\\" href=\\\"https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css\\\" integrity=\\\"sha256-wLz3iY/cO4e6vKZ4zRmo4+9XDpMcgKOvv/zEU3OMlRo=\\\" crossorigin=\\\"anonymous\\\">\\n\\n<script src=\\\"https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js\\\" integrity=\\\"sha256-m81NDyncZVbr7v9E6qCWXwx/cwjuWDlHCMzi9pjMobA=\\\" crossorigin=\\\"anonymous\\\"></script>\\n\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Bootstrap5\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"WebResources.Bootstrap5\"\n              }\n            },\n            \"Boolean\": {\n              \"AutoOptimize\": {\n                \"en-us\": true\n              },\n              \"Enabled\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166558,\n              \"Version\": 1,\n              \"Guid\": \"c0c72782-77a4-4419-be31-7c5ac4f7bca0\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1a29fa3e-69e7-48db-836f-c04ee3991284\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"72286f65-e38b-42ee-a0da-0c73e55f7ba4\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 131820,\n          \"Version\": 11,\n          \"Guid\": \"3356ad17-91ce-4814-83c1-9f527697391a\",\n          \"Type\": {\n            \"Id\": \"66f19c62-371e-4ad1-a98b-de0745507be4\",\n            \"Name\": \"⚙️WebResource\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Html\": {\n                \"en-us\": \"<link rel=\\\"stylesheet\\\" href=\\\"https://cdn.jsdelivr.net/npm/@fancyapps/ui@4.0.31/dist/fancybox.css\\\" integrity=\\\"sha256-7gMVmh7i2Xmo99mvvfnSn9dZfunTii7j4yPdmTAMUR0=\\\" crossorigin=\\\"anonymous\\\">\\n\\n<script src=\\\"https://cdn.jsdelivr.net/npm/@fancyapps/ui@4.0.31/dist/fancybox.umd.js\\\" integrity=\\\"sha256-0af2VbC4vmPsa8OLBAKBmLoyuKq4bBlKK2KOgMWayio=\\\" crossorigin=\\\"anonymous\\\"></script>\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"fancybox4\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"WebResources.fancybox4\"\n              }\n            },\n            \"Boolean\": {\n              \"AutoOptimize\": {\n                \"en-us\": true\n              },\n              \"Enabled\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 144503,\n              \"Version\": 1,\n              \"Guid\": \"04c9dd2c-f931-48b0-a1ad-7473e2526f00\",\n              \"Type\": {\n                \"Id\": \"5e958dc6-2922-4d68-835c-7b9711538b12\",\n                \"Name\": \"NoteDecorator\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Note\": {\n                    \"en-us\": \"<p>Best update with exact version links and SRI from here:</p>\\n<p><a href=\\\"https://www.jsdelivr.com/package/npm/@fancyapps/ui?path=dist\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">https://www.jsdelivr.com/package/npm/@fancyapps/ui?path=dist</a>&nbsp;&nbsp;</p>\"\n                  },\n                  \"NoteType\": {\n                    \"en-us\": \"note\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Best update with exact version...\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3356ad17-91ce-4814-83c1-9f527697391a\"\n              }\n            },\n            {\n              \"Id\": 166559,\n              \"Version\": 1,\n              \"Guid\": \"b5aca58e-d6af-4489-9853-dcaaab66b3cb\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1a29fa3e-69e7-48db-836f-c04ee3991284\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3356ad17-91ce-4814-83c1-9f527697391a\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 144505,\n          \"Version\": 5,\n          \"Guid\": \"3e6811a8-87ab-4954-8402-6e2b3d80c6e2\",\n          \"Type\": {\n            \"Id\": \"66f19c62-371e-4ad1-a98b-de0745507be4\",\n            \"Name\": \"⚙️WebResource\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Html\": {\n                \"en-us\": \"<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/js/all.min.js\\\" integrity=\\\"sha512-2bMhOkE/ACz21dJT8zBOMgMecNxx0d37NND803ExktKiKdSzdwn+L7i9fdccw/3V06gM/DBWKbYmQvKMdAA9Nw==\\\" crossorigin=\\\"anonymous\\\" referrerpolicy=\\\"no-referrer\\\"></script>\\n\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"FontAwesome6\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"WebResources.FontAwesome6\"\n              }\n            },\n            \"Boolean\": {\n              \"AutoOptimize\": {\n                \"en-us\": true\n              },\n              \"Enabled\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 144506,\n              \"Version\": 1,\n              \"Guid\": \"be43a43e-56c9-4660-97a4-a3aadafa370e\",\n              \"Type\": {\n                \"Id\": \"5e958dc6-2922-4d68-835c-7b9711538b12\",\n                \"Name\": \"NoteDecorator\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Note\": {\n                    \"en-us\": \"<p>Get updated links from the <a href=\\\"https://cdnjs.com/libraries/font-awesome/6.1.1\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">CDNJS</a>.</p>\"\n                  },\n                  \"NoteType\": {\n                    \"en-us\": \"note\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Get updated links from the CDN...\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3e6811a8-87ab-4954-8402-6e2b3d80c6e2\"\n              }\n            },\n            {\n              \"Id\": 166560,\n              \"Version\": 1,\n              \"Guid\": \"ecf47466-931f-4e69-9c56-d8e3a0853d38\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"1a29fa3e-69e7-48db-836f-c04ee3991284\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3e6811a8-87ab-4954-8402-6e2b3d80c6e2\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-settings.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"813a3cb7-1a89-4477-bdfe-8863ab3ae59a\",\n            \"Name\": \"SettingsSystem\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 130614,\n                \"Version\": 7,\n                \"Guid\": \"c0313d2f-899f-4d31-b863-6c10ff6f8383\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Here you can configure System Settings. If you're new to this please <a href=\\\"https://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">read the docs</a>.&nbsp;</p>\\n<p>Remember that you can always create <em>custom settings</em> for anything you want. These will not be stored here, but in a new ContentType called <em>Settings</em> which you would create on your own.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"System Settings\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"<p>These settings override defaults provided at the global level. Make sure you understand Settings before doing much here. <a href=\\\"https://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Read the docs please</a>.&nbsp;</p>\\n<p>Note: you should usually only have exactly 1 item in this list. The only exception is on the main <strong>Content</strong> app where you have two items (one affecting only the current App, one affecting the entire Site).&nbsp;</p>\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"813a3cb7-1a89-4477-bdfe-8863ab3ae59a\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130556,\n                    \"Version\": 4,\n                    \"Guid\": \"2cb4d735-f4dc-44c5-8890-36e7b8f50201\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"System Settings\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130559,\n                    \"Version\": 3,\n                    \"Guid\": \"050a85b3-1508-4200-852a-93d04889492f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130560,\n                    \"Version\": 3,\n                    \"Guid\": \"81c65f11-5b9c-4994-9dd8-ab4c33259d4c\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SettingsEntityScope\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130610,\n                    \"Version\": 7,\n                    \"Guid\": \"198ac2ed-06af-4cf0-9ae4-94a665fba259\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Scope / Reach of these Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Leave on Default in 99% of the cases. Only rare cases use Site. See <a href=\\\"https://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130611,\n                    \"Version\": 6,\n                    \"Guid\": \"6bf1cfc3-8a1e-4f48-a7c9-9f86ea03894a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130612,\n                    \"Version\": 6,\n                    \"Guid\": \"d8b1df1c-1a22-4a5d-9e72-69da716c7126\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default (current App)\\nsite:Site (these Settings affect all Apps of this Site)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MessageGlobalScope\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166050,\n                    \"Version\": 4,\n                    \"Guid\": \"1a824775-95df-4d4b-9ea8-687a25404772\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MessageGlobalScope\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>You are Editing Global Settings</strong></p>\\n<p>These settings will affect the entire system. There are identical settings for each Site / Portal or for specific Apps. App settings will override Site settings, which override Global settings, which override built-in presets. See&nbsp;<a href=\\\"https://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8ada531e-f7ea-4c14-b843-91b9d86cbea7\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MessageSiteScope\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 131471,\n                    \"Version\": 11,\n                    \"Guid\": \"623eb94e-c2ea-4436-b32c-61311ea3d714\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Important: Site-Scope\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>You are Editing Site-Level Settings</strong></p>\\n<p>These settings will affect the current Site / Portal. There are identical settings for the entire System (global), or for specific Apps. App settings will override Site settings, which override System settings, which override built-in presets. See&nbsp;<a href=\\\"https://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"e78504d3-1016-43e2-9a42-692554ea9145\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MessageAppScope\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166051,\n                    \"Version\": 4,\n                    \"Guid\": \"1df44260-b2ee-4452-8cbd-8e43a4ae1fec\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MessageAppScope\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>You are Editing App Settings</strong></p>\\n<p>These settings will affect the current App. There are identical settings for each Site / Portal or for specific the entire System (global). App settings will override Site settings, which override Global settings, which override built-in presets. See <a href=\\\"https://r.2sxc.org/settings\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"414f8b4d-6b9c-4acf-a0b0-53a1ffa2a5b5\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupContent\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130602,\n                    \"Version\": 4,\n                    \"Guid\": \"33d8eef3-9a7f-4756-8c82-11f6e8b79c69\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Content / Output Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"015cd69e-c652-4cce-ad01-e4a644cbd318\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130603,\n                    \"Version\": 3,\n                    \"Guid\": \"a54af856-06e3-4915-ba80-5ea3900871c3\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Images\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130659,\n                    \"Version\": 5,\n                    \"Guid\": \"1b86a72c-9ea8-4927-8ed7-b03111c6f087\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Images\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130660,\n                    \"Version\": 4,\n                    \"Guid\": \"c8a913ba-d892-4f70-9d37-199f610f9cc3\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"⚙️Images\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": true\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Copyright\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182642,\n                    \"Version\": 3,\n                    \"Guid\": \"ffbc2df0-83a1-4883-b7bc-68fbffc1b0a5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Copyright (WIP v17)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182643,\n                    \"Version\": 2,\n                    \"Guid\": \"6bc5d0cb-be03-4138-8d46-3bb960a63d42\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️CopyrightSettings\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupInputFields\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185438,\n                    \"Version\": 2,\n                    \"Guid\": \"8a5a2402-02d5-4137-a6f6-17c3aa532aa2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Input Fields\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185440,\n                    \"Version\": 1,\n                    \"Guid\": \"8e2e45ff-232d-4aab-acfb-6bd922c2f4b3\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"InputFields\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185439,\n                    \"Version\": 8,\n                    \"Guid\": \"8fd45cd0-1c46-473b-a2ef-b4aa52669fc9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Input Fields\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185441,\n                    \"Version\": 2,\n                    \"Guid\": \"d0463c61-ed48-4111-a122-0290217137ef\",\n                    \"Type\": {\n                      \"Id\": \"6fa7f390-7612-40c6-baff-2bcf6140a85f\",\n                      \"Name\": \"@entity-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"6c5d1062-1628-4b45-8f33-1b93a39f2ac5\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185453,\n                    \"Version\": 3,\n                    \"Guid\": \"03ee551e-e6f2-42e0-a4fd-29d882acf516\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️InputFields\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupThirdParty\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134257,\n                    \"Version\": 3,\n                    \"Guid\": \"86c1cd5d-3b16-4071-b048-2942fc03f253\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Extensions / Third-Party Services\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"f526066d-7f78-4177-a81a-1a1248018a54\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134259,\n                    \"Version\": 2,\n                    \"Guid\": \"d4765e91-ccc9-4204-8d40-3a0be958a94b\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GoogleRecaptcha\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134258,\n                    \"Version\": 4,\n                    \"Guid\": \"cf06e71c-f14e-4f0a-a0a0-455b6628cd9c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Google Recaptcha Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134260,\n                    \"Version\": 3,\n                    \"Guid\": \"66f7c299-a872-4313-a3c6-ccc14e4262e2\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️GoogleRecaptcha\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GoogleMaps\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130558,\n                    \"Version\": 3,\n                    \"Guid\": \"5b9ddffb-03e2-45a2-a109-cff38919e4f0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Google Maps Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130562,\n                    \"Version\": 2,\n                    \"Guid\": \"51fc1f39-6e7a-4bed-a26b-12254214526f\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"⚙️GoogleMaps\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": true\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GoogleTranslate\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164898,\n                    \"Version\": 2,\n                    \"Guid\": \"91efd773-b042-481e-82bc-fb3bb9d065cd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Google Translate (WIP / BETA v15)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164899,\n                    \"Version\": 1,\n                    \"Guid\": \"b8424c6f-66bf-49ce-856d-b17f0d63b366\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️GoogleTranslate\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupWebResources\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130625,\n                    \"Version\": 4,\n                    \"Guid\": \"41d29954-c106-4742-b59f-91d18d74beee\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Web Resources\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"19bb9348-59b3-4c23-b769-a950de118cf2\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130683,\n                    \"Version\": 3,\n                    \"Guid\": \"f9a34b2b-fc02-4e3f-9cf9-e1b9263bd6ca\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"WebResources\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130626,\n                    \"Version\": 3,\n                    \"Guid\": \"c4f29d42-b61a-4a08-8ee6-b1113e4b9f92\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"WebResources\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130642,\n                    \"Version\": 2,\n                    \"Guid\": \"1df20cb6-629e-4550-ba4f-22ddae96d050\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️WebResources\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupSecurity\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144474,\n                    \"Version\": 5,\n                    \"Guid\": \"cb63ebab-2640-4261-86ca-735f1290b7c6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Security / Content Security Policies\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144476,\n                    \"Version\": 4,\n                    \"Guid\": \"75539fd7-1e8e-4cd7-887d-5a228632f0b6\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentSecurityPolicies\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144475,\n                    \"Version\": 3,\n                    \"Guid\": \"ef86dbc2-faf5-4078-a934-2f191fb50d99\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Security Policies\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144477,\n                    \"Version\": 2,\n                    \"Guid\": \"665b299b-40b5-404e-9cbc-7b45e3828ae0\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️ContentSecurityPolicies\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupSiteSetup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164888,\n                    \"Version\": 4,\n                    \"Guid\": \"78b2fc6b-6ca9-4c07-86a8-ae9206f9a3b9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Site Setup Settings (new in v15)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164890,\n                    \"Version\": 3,\n                    \"Guid\": \"5b7d19d2-4ea2-4487-b6d6-1f006015576e\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SiteSetup\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164889,\n                    \"Version\": 4,\n                    \"Guid\": \"c0fead0b-da4c-4ee6-b770-5960a157edfb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Site Setup Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"3984debd-09ca-4e42-93b6-4284af3dcffe\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164891,\n                    \"Version\": 2,\n                    \"Guid\": \"b1eae523-a9b9-417f-aaee-102807385525\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️SiteSetup\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupInPage\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130601,\n                    \"Version\": 4,\n                    \"Guid\": \"2c04ce26-d2bd-4696-acab-36d5265481a3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"In-Page Edit Experience Settings (not yet implemented)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130604,\n                    \"Version\": 3,\n                    \"Guid\": \"1851dc87-f322-4346-acd3-38b778fbd2d9\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"QuickEdit\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130557,\n                    \"Version\": 5,\n                    \"Guid\": \"92c49d95-789d-49b7-a98d-a9a9d05e8035\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"QuickEdit Settings\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130561,\n                    \"Version\": 4,\n                    \"Guid\": \"f3872579-aec0-45c2-80a7-7e86d2fe35e5\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"⚙️QuickEdit\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": false\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": true\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 166052,\n              \"Version\": 2,\n              \"Guid\": \"8ada531e-f7ea-4c14-b843-91b9d86cbea7\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return context.app.isGlobal; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 166053,\n              \"Version\": 2,\n              \"Guid\": \"e78504d3-1016-43e2-9a42-692554ea9145\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return context.app.isSite; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 166054,\n              \"Version\": 2,\n              \"Guid\": \"414f8b4d-6b9c-4acf-a0b0-53a1ffa2a5b5\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return !(context.app.isSite || context.app.isGlobal);\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130627,\n              \"Version\": 2,\n              \"Guid\": \"015cd69e-c652-4cce-ad01-e4a644cbd318\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { \\n  const symbols = [];\\n  if(data.GoogleMaps.length) symbols.push('\\uD83C\\uDF10');\\n  if(data.Images.length) symbols.push('\\uD83D\\uDDBC️');\\n  const addition = symbols.length ? ' (' + symbols.join(',') + ')' : '';\\n  return data.default + addition; \\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 185442,\n              \"Version\": 2,\n              \"Guid\": \"6c5d1062-1628-4b45-8f33-1b93a39f2ac5\",\n              \"Type\": {\n                \"Id\": \"f11f79a2-186b-49ec-89d6-be260698e371\",\n                \"Name\": \"UiPickerSourceEntity\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"ContentTypeNames\": {\n                    \"en-us\": \"⚙️InputFieldsWysiwygSettings\"\n                  },\n                  \"CreateTypes\": {\n                    \"en-us\": \"⚙️InputFieldsWysiwygSettings\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Title\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Picker Entity - Input Fields (ATM only field wysiwyg)\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Guid\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 134262,\n              \"Version\": 2,\n              \"Guid\": \"f526066d-7f78-4177-a81a-1a1248018a54\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { \\n  const symbols = [];\\n  if(data.GoogleRecaptcha.length) symbols.push('\\uD83D\\uDD11');\\n  const addition = symbols.length ? ' (' + symbols.join(',') + ')' : '';\\n  return data.default + addition; \\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130682,\n              \"Version\": 1,\n              \"Guid\": \"19bb9348-59b3-4c23-b769-a950de118cf2\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return data.default + (data.WebResources.length ? ' (✔️)': ''); }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 166041,\n              \"Version\": 2,\n              \"Guid\": \"3984debd-09ca-4e42-93b6-4284af3dcffe\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return context.debug; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"d7f2e4fa-5306-41bb-a3cd-d9529c838879\",\n            \"Name\": \"\\uD83E\\uDDD1‍\\uD83D\\uDCBBSystemExportConfiguration\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 165960,\n                \"Version\": 4,\n                \"Guid\": \"36e39115-81bd-458b-92d6-52338e48a24b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Configuration for a specific export\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Define export packages for quick re-export of certain parts of the App.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"\\uD83E\\uDDD1‍\\uD83D\\uDCBBExport Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"d7f2e4fa-5306-41bb-a3cd-d9529c838879\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Name\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 165951,\n                    \"Version\": 1,\n                    \"Guid\": \"84a30b63-d348-4b0d-909c-03ce0c2df7de\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Name\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"WarningRequiresFeature\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166415,\n                    \"Version\": 3,\n                    \"Guid\": \"141c8eca-c247-45d6-8e99-2fe8ae43d1b6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"WarningRequiresFeature\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>⚠️ Warning - Feature not Enabled ⚠️</strong></p>\\n<p>This configuration requires the feature <strong>DataExportImportBundles</strong>. Without it, it will not have an effect.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"9cc5420b-097f-4af8-a8f3-a8b27cccf9a7\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ExportFormat\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 165952,\n                    \"Version\": 3,\n                    \"Guid\": \"9796b144-1972-4e25-9e01-a8f1f1cad9bd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"json\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Export Format\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 165955,\n                    \"Version\": 2,\n                    \"Guid\": \"89d6b2bc-d793-430c-89ac-9010e05731d6\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 165956,\n                    \"Version\": 2,\n                    \"Guid\": \"b74b6a5a-3084-406e-a1e7-21b6a533fbcc\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"json:JSON\\njson-zip:Zipped JSON (not supported yet)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"FileName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 165953,\n                    \"Version\": 2,\n                    \"Guid\": \"98d81fa6-33c9-458f-8c86-2cd655ea1eac\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"app-data.json\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"File Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 165957,\n                    \"Version\": 1,\n                    \"Guid\": \"ef6354de-6e3f-4116-8978-36b68aa79fc3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 165958,\n                    \"Version\": 1,\n                    \"Guid\": \"523a4d76-62ac-4f6b-b41f-36a3815f9052\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PreserveMarkers\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 165954,\n                    \"Version\": 4,\n                    \"Guid\": \"7103b508-ce9c-4e33-bb40-1d0176f3cbaa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Preserve Markers\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 165959,\n                    \"Version\": 3,\n                    \"Guid\": \"2cc0e49d-91fa-4d76-9d5a-4482789fc659\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Remove Export-Metadata Markers\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Preserve Export Metadata Markers\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EntitiesWithMetadata\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166445,\n                    \"Version\": 5,\n                    \"Guid\": \"5dad1f37-2379-4ff3-bbb0-49ca6f86a162\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"With Metadata\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166446,\n                    \"Version\": 3,\n                    \"Guid\": \"ebd7978c-dca3-4301-bee9-4e2268640b33\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"When exporting Entities, flush Metadata\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"When exporting Entities, keep Metadata (recommended)\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 166416,\n              \"Version\": 2,\n              \"Guid\": \"9cc5420b-097f-4af8-a8f3-a8b27cccf9a7\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return !context.features.isEnabled('DataExportImportBundles');\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"5f431769-ff03-472e-aab5-33891af10acc\",\n            \"Name\": \"⚙️ContentSecurityPolicies\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 144468,\n                \"Version\": 4,\n                \"Guid\": \"d4b784fd-ab13-41c8-a92b-8f3e3c00eb68\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"Items\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p><img src=\\\"/Portals/system-types/adam/System-Types/_YS31BOryEGpK48-PADraA/EditInstructions/blobid3.svg\\\" alt=\\\"\\\" width=\\\"100%\\\" /></p>\\n<p>Content Security Policies are security configurations for CSP.&nbsp;&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Content Security Policies\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5f431769-ff03-472e-aab5-33891af10acc\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144469,\n                    \"Version\": 3,\n                    \"Guid\": \"240ee6bc-874a-46af-b9e3-5c3c954b4438\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"ContentSecurityPolicies\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"SettingsIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144472,\n                    \"Version\": 2,\n                    \"Guid\": \"aed104fd-4c0c-4519-8f1f-5855e67af962\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144473,\n                    \"Version\": 2,\n                    \"Guid\": \"ee7a6890-723a-48b5-8caf-5c8a60dde864\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MsgWarningFeatureDisabled\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144498,\n                    \"Version\": 4,\n                    \"Guid\": \"ae1d4551-1470-4dc2-982b-3fe7e2d30ce4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MsgWarningFeatureDisabled\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<h3><span style=\\\"color: #e03e2d;\\\">Warning</span></h3>\\n<p>The <strong>ContentSecurityPolicy</strong> feature is&nbsp;<strong>disabled</strong>. In this mode, this configuration will not have an effect.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"420612fc-6056-49a9-baa5-8267c72e86bc\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Items\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144470,\n                    \"Version\": 3,\n                    \"Guid\": \"8b004990-fba8-4baa-9717-4f9dc42ea422\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Items\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144471,\n                    \"Version\": 2,\n                    \"Guid\": \"864fe97a-82c6-4f91-a1af-6f7de0ca6f9c\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️ContentSecurityPolicy\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 144499,\n              \"Version\": 2,\n              \"Guid\": \"420612fc-6056-49a9-baa5-8267c72e86bc\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return !context.features.isEnabled('ContentSecurityPolicy'); }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"92f2eb3c-c3b7-4378-82df-b2393da6687e\",\n            \"Name\": \"⚙️ContentSecurityPolicy\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 144478,\n                \"Version\": 2,\n                \"Guid\": \"938a4147-c2ef-4ae1-9849-46dc9cef4b5a\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p><img srcset=\\\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyNi4zLjEsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iRWJlbmVfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAxOTY4LjkgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxOTY4LjkgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojMDAwMDNFO30NCgkuc3Qxe2ZpbGw6I0ZGRkZGRjt9DQo8L3N0eWxlPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTE2NC40LDI1MEgwVjg1LjZDMCwzOC40LDM4LjQsMCw4NS42LDBIMjUwdjE2NC40QzI1MCwyMTEuNiwyMTEuNiwyNTAsMTY0LjQsMjUweiIvPg0KPGc+DQoJPHBhdGggY2xhc3M9InN0MSIgZD0iTTE4Mi4yLDk2LjVjMCw1MS45LTMxLjksODAuOC01MS45LDg5LjFjLTIuOCwxLjEtNS45LDEuMS04LjYsMEM5Ni42LDE3NS4yLDY5LjcsMTQzLDY5LjcsOTYuNQ0KCQljMC00LjUsMi43LTguNiw2LjktMTAuNGw0NS0xOC44YzEuMS0wLjUsMy4xLTAuOSw0LjMtMC45YzEuMiwwLDMuMiwwLjQsNC4zLDAuOWw0NSwxOC44QzE3OS41LDg3LjgsMTgyLjIsOTEuOSwxODIuMiw5Ni41eg0KCQkgTTE3MSw5Ni41bC00NS0xOC44TDgxLDk2LjVjMCwzOS43LDIyLjIsNjkuMiw0NSw3OC44QzE0Ny45LDE2Ni4xLDE3MSwxMzcuMiwxNzEsOTYuNXogTTExOC4yLDEzNC42bDMzLjEtMzIuOQ0KCQljMS4xLTEuMSwyLjktMS4xLDQsMGw1LjMsNS4zYzEuMSwxLjEsMS4xLDIuOSwwLDRsLTQwLjUsNDAuMWMtMS4xLDEuMS0yLjksMS4xLTQsMGwtMjEuMy0yMS40Yy0xLjEtMS4xLTEuMS0yLjksMC00bDUuMy01LjMNCgkJYzEuMS0xLjEsMi45LTEuMSw0LDBMMTE4LjIsMTM0LjZ6Ii8+DQo8L2c+DQo8Zz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMzkyLDE3MGMtMjYuOC0yLTQ3LjctMjQuMy00Ny43LTUxLjRjMC0yNy40LDIxLjMtNDkuNiw0Ny43LTUxLjV2MTUuMWMtMTgsMi4zLTMwLjQsMTguNi0zMC40LDM2LjUNCgkJYzAsMTcuNSwxMi40LDM0LjUsMzAuNCwzNi40VjE3MHogTTM5OS4zLDY3LjFjMTIuNSwxLjQsMjQuNyw2LjEsMzMuMiwxNC42YzEuNiwxLjYsMS4zLDIuNi0wLjMsNC4zbC02LjUsNy4xDQoJCWMtMS42LDEuNy0yLjYsMi00LjMsMC4zYy02LTYuNC0xMy4yLTkuOS0yMi4yLTExLjFWNjcuMXogTTM5OS4zLDE1NWM4LjktMS4xLDE2LTQuNywyMi4zLTExLjJjMS43LTEuNywyLjctMS4zLDQuMywwLjNsNi41LDcuMQ0KCQljMS42LDEuOCwxLjgsMi43LDAuMSw0LjRjLTguNyw4LjUtMjEuMiwxMy41LTMzLjIsMTQuNVYxNTV6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTQ3OC45LDE2OS43Yy0xOC43LTEuOC0zMy45LTE3LjgtMzMuOS0zNy41YzAtMTkuOSwxNS4zLTM1LjksMzMuOS0zNy42djE0LjhjLTEwLjIsMS44LTE3LjksMTEuMS0xNy45LDIyLjkNCgkJYzAsMTIuMiw4LjEsMjEuMywxNy45LDIzVjE2OS43eiBNNDg2LDE1NS4zYzEwLjItMS43LDE4LTExLjEsMTgtMjNzLTgtMjEuMy0xOC0yMi45Vjk0LjZjMTkuMiwyLDM0LjEsMTgsMzQuMSwzNy42DQoJCWMwLDE5LjUtMTQuOCwzNS42LTM0LjEsMzcuNVYxNTUuM3oiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNTU0LjcsMTY1LjNjMCwyLjMtMC43LDMtMywzaC0xMC4yYy0yLjMsMC0zLTAuNy0zLTNWOTljMC0yLjMsMC43LTMsMy0zaDUuMWMyLjcsMCw0LjQsMC40LDUuNSwxLjdsMi42LDQNCgkJVjE2NS4zeiBNNTYxLjgsOTguM2MzLjQtMi42LDcuNy0zLjgsMTIuOS0zLjhjMTUuNiwwLDI3LjUsOC40LDI3LjUsMzIuOHYzOC4xYzAsMi4zLTAuNywzLTMsM2gtMTAuMmMtMi4zLDAtMy0wLjctMy0zdi0zNC41DQoJCWMwLTE1LjEtNS41LTIxLjktMTUuNS0yMS45Yy00LjEsMC02LjcsMS40LTguOCwzLjNWOTguM3oiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNjIwLjgsMTA5Yy0yLjMsMC0zLTAuNy0zLTN2LTdjMC0yLjMsMC43LTMsMy0zaDUuM1Y4Mi4xYzAtMi4zLDAuNi0zLDMtM2gxMC4xYzIuMywwLDMsMC43LDMsM1Y5NmgyMS45DQoJCWMyLjMsMCwzLDAuNywzLDMuMXY2LjhjMCwyLjMtMC43LDMtMywzSDYyMC44eiBNNjQyLjEsMTE2LjJ2MjEuM2MwLDEyLjgsNC40LDE3LjksMTMuMSwxNy45YzMuMSwwLDUuNS0wLjMsOC41LTEuNw0KCQljMi43LTEuNCwzLjMtMS4zLDMuOCwxLjdsMS4zLDcuMWMwLjQsMi4xLDAuMywyLjgtMS42LDMuOGMtNS43LDMuNS0xMS45LDMuNS0xMy44LDMuNWMtMTguNywwLTI3LjQtMTEuOC0yNy40LTMxLjR2LTIyLjNINjQyLjF6Ig0KCQkvPg0KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik02OTcuMywxMzIuOGMwLDEzLjIsOS40LDIzLjEsMjEuOSwyMy4xYzUsMCwxMi4xLTEuMSwxOS41LTUuNGMyLjEtMSwyLjgtMS42LDQuMywwLjNsNC4xLDUuMQ0KCQljMS40LDEuNywxLjcsMi42LDAuNCw0Yy02LjUsNi40LTE4LjMsOS45LTI4LjcsOS45Yy0yMS40LDAtMzguMi0xNi45LTM4LjItMzcuNmMwLTE5LjUsMTQuNi0zNS41LDMzLjQtMzcuNXYxMy4zDQoJCWMtMTAuMiwyLjEtMTYuNiwxMS4yLTE2LjYsMjMuN1YxMzIuOHogTTcwNC43LDEyNi45aDMyLjFjLTEtOC40LTYtMTYuOS0xNS44LTE4LjlWOTQuNmMyMS4yLDEuNywzMi4yLDE5LjIsMzIuMiwzOS44DQoJCWMwLDIuMy0wLjQsMy4xLTIuOCwzLjFoLTQ1LjdDNzAzLjgsMTM0LjIsNzAzLjgsMTMwLjEsNzA0LjcsMTI2Ljl6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTc4Ny4xLDE2NS4zYzAsMi4zLTAuNywzLTMsM2gtMTAuMmMtMi4zLDAtMy0wLjctMy0zVjk5YzAtMi4zLDAuNy0zLDMtM2g1LjFjMi43LDAsNC40LDAuNCw1LjUsMS43bDIuNiw0DQoJCVYxNjUuM3ogTTc5NC4yLDk4LjNjMy40LTIuNiw3LjctMy44LDEyLjktMy44YzE1LjYsMCwyNy41LDguNCwyNy41LDMyLjh2MzguMWMwLDIuMy0wLjcsMy0zLDNoLTEwLjJjLTIuMywwLTMtMC43LTMtM3YtMzQuNQ0KCQljMC0xNS4xLTUuNS0yMS45LTE1LjUtMjEuOWMtNC4xLDAtNi43LDEuNC04LjgsMy4zVjk4LjN6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTg1My4xLDEwOWMtMi4zLDAtMy0wLjctMy0zdi03YzAtMi4zLDAuNy0zLDMtM2g1LjNWODIuMWMwLTIuMywwLjYtMywzLTNoMTAuMWMyLjMsMCwzLDAuNywzLDNWOTZoMjEuOQ0KCQljMi4zLDAsMywwLjcsMywzLjF2Ni44YzAsMi4zLTAuNywzLTMsM0g4NTMuMXogTTg3NC40LDExNi4ydjIxLjNjMCwxMi44LDQuNCwxNy45LDEzLjEsMTcuOWMzLjEsMCw1LjUtMC4zLDguNS0xLjcNCgkJYzIuNy0xLjQsMy4zLTEuMywzLjgsMS43bDEuMyw3LjFjMC40LDIuMSwwLjMsMi44LTEuNiwzLjhjLTUuNywzLjUtMTEuOSwzLjUtMTMuOCwzLjVjLTE4LjcsMC0yNy40LTExLjgtMjcuNC0zMS40di0yMi4zSDg3NC40eiINCgkJLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNOTgzLjIsMTY5LjZjLTEyLjgtMS0yMi4zLTQtMzItMTAuNWMtMi4xLTEuMy0xLjgtMi4zLTAuOS00LjNsNC40LTcuMWMxLjEtMiwyLTIuNyw0LjEtMS4zDQoJCWM4LjUsNS40LDE2LjIsNy40LDI0LjMsOC4yVjE2OS42eiBNOTg0LjksODIuNmMtMTMuNSwxLjMtMTYuOSw4LjctMTYuOSwxNS4zYzAsOS41LDEwLjEsMTEuNiwyNC42LDEzLjUNCgkJYzE3LjMsMi4xLDMzLjksNy41LDMzLjksMjguNWMwLDE1LjMtMTIuMiwyOS44LTM2LjEsMzB2LTE1LjFjMTEuNS0wLjQsMTkuNS00LjQsMTkuNS0xNC4yYzAtMTAuMi05LjUtMTIuOS0yNS40LTE1LjENCgkJYy0xNS41LTItMzMuMS03LjQtMzMuMS0yNy4xYzAtMTIuNCw4LjktMjkuOCwzMy41LTMxLjFWODIuNnogTTk5Miw2Ny40YzExLjgsMC45LDIwLjksNC41LDMxLDEwLjhjMiwxLjEsMS43LDIuMywwLjcsNC4zbC00LjMsNw0KCQljLTEuMSwyLTIuMSwyLjgtNC4xLDEuNGMtOC43LTUuNy0xNS41LTgtMjMuMy04LjRWNjcuNHoiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTA1NS45LDEzMi44YzAsMTMuMiw5LjQsMjMuMSwyMS45LDIzLjFjNSwwLDEyLjEtMS4xLDE5LjUtNS40YzIuMS0xLDIuOC0xLjYsNC4zLDAuM2w0LjEsNS4xDQoJCWMxLjQsMS43LDEuNywyLjYsMC40LDRjLTYuNSw2LjQtMTguMyw5LjktMjguNyw5LjljLTIxLjQsMC0zOC4yLTE2LjktMzguMi0zNy42YzAtMTkuNSwxNC42LTM1LjUsMzMuNC0zNy41djEzLjMNCgkJYy0xMC4yLDIuMS0xNi42LDExLjItMTYuNiwyMy43VjEzMi44eiBNMTA2My4yLDEyNi45aDMyLjFjLTEtOC40LTYtMTYuOS0xNS44LTE4LjlWOTQuNmMyMS4yLDEuNywzMi4yLDE5LjIsMzIuMiwzOS44DQoJCWMwLDIuMy0wLjQsMy4xLTIuOCwzLjFoLTQ1LjdDMTA2Mi40LDEzNC4yLDEwNjIuNCwxMzAuMSwxMDYzLjIsMTI2Ljl6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTExNTcuMiwxMDkuM2MtOS44LDEuNy0xOCwxMC42LTE4LDIzYzAsMTIuMSw3LjgsMjEuMiwxOCwyMi45djE0LjZjLTE5LjctMS44LTM0LjEtMTguNS0zNC4xLTM3LjUNCgkJYzAtMTkuMiwxNC4zLTM1LjgsMzQuMS0zNy42VjEwOS4zeiBNMTE2NC4yLDk0LjZjOC40LDAuOSwxNiw0LDIyLjcsMTAuNWMxLjMsMS4zLDEsMi0wLjQsMy43bC01LjMsNS43Yy0xLjYsMS43LTIuNiwyLjEtNC4zLDAuNg0KCQljLTQuMy00LTguNy01LjMtMTIuOC02Vjk0LjZ6IE0xMTY0LjIsMTU1LjNjNS4xLTAuOSw4LjgtMi40LDEyLjgtNmMxLjgtMS42LDIuNy0xLjEsNC4zLDAuNmw1LjMsNS43YzEuNCwxLjcsMS43LDIuNCwwLjQsMy43DQoJCWMtNi44LDYuNS0xMy45LDkuNS0yMi43LDEwLjVWMTU1LjN6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTEyNDIuNiwxNjYuMWMtMy40LDIuNi03LjcsMy44LTEyLjksMy44Yy0xNS42LDAtMjcuNS04LjQtMjcuNS0zMi44Vjk5YzAtMi4zLDAuNy0zLDMtM2gxMC4yYzIuMywwLDMsMC43LDMsMw0KCQl2MzQuNmMwLDE0LjksNS41LDIxLjcsMTUuNSwyMS43YzQuMSwwLDYuNy0xLjQsOC44LTMuM1YxNjYuMXogTTEyNDkuNyw5OWMwLTIuMywwLjctMywzLTNoMTAuMmMyLjMsMCwzLDAuNywzLDN2NjYuMw0KCQljMCwyLjMtMC43LDMtMywzaC01LjFjLTIuNywwLTQuNC0wLjQtNS41LTEuN2wtMi42LTRWOTl6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTEzMDYuOCwxNjUuM2MtMC4xLDIuMy0wLjcsMy0zLDNoLTEwLjJjLTIuMywwLTMtMC43LTMtM1Y5OWMwLTIuMywwLjctMywzLTNoNS4xYzQuNCwwLDUsMC45LDguMSw0LjRWMTY1LjN6DQoJCSBNMTMxMy45LDk5LjZjMy44LTIuNyw4LjktNS4xLDE4LjYtNS4xYzIuOCwwLDMuMSwwLjksMi44LDIuOGwtMS42LDEwLjRjLTAuNCwyLjMtMS4xLDIuOC0zLjQsMi44Yy03LDAtMTIuMSwxLjgtMTYuNSw1LjVWOTkuNnoiDQoJCS8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTEzNjAuMyw2My40YzUuNCwwLDkuOSw0LjUsOS45LDEwLjFjMCw1LjUtNC41LDkuOC05LjksOS44Yy01LjUsMC05LjktNC4zLTkuOS05LjgNCgkJQzEzNTAuNCw2Ny45LDEzNTQuOCw2My40LDEzNjAuMyw2My40eiBNMTM1Mi4zLDk5YzAtMi4zLDAuNy0zLDMtM2gxMC4yYzIuMywwLDMsMC43LDMsM3Y2Ni4zYzAsMi4zLTAuNywzLTMsM2gtMTAuMg0KCQljLTIuMywwLTMtMC43LTMtM1Y5OXoiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTM5MiwxMDljLTIuMywwLTMtMC43LTMtM3YtN2MwLTIuMywwLjctMywzLTNoNS4zVjgyLjFjMC0yLjMsMC42LTMsMy0zaDEwLjFjMi4zLDAsMywwLjcsMywzVjk2aDIxLjkNCgkJYzIuMywwLDMsMC43LDMsMy4xdjYuOGMwLDIuMy0wLjcsMy0zLDNIMTM5MnogTTE0MTMuMywxMTYuMnYyMS4zYzAsMTIuOCw0LjQsMTcuOSwxMy4xLDE3LjljMy4xLDAsNS41LTAuMyw4LjUtMS43DQoJCWMyLjctMS40LDMuMy0xLjMsMy44LDEuN2wxLjMsNy4xYzAuNCwyLjEsMC4zLDIuOC0xLjYsMy44Yy01LjcsMy41LTExLjksMy41LTEzLjgsMy41Yy0xOC43LDAtMjcuNC0xMS44LTI3LjQtMzEuNHYtMjIuM0gxNDEzLjN6Ig0KCQkvPg0KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xNDc2LjcsMTk0LjNjLTEuMSwyLjQtMiwzLTMuOCwzaC0xMS42Yy0yLjEsMC0yLjctMC43LTEuNi0zbDE0LjYtMzIuNUwxNDQ1LjksOTljLTEtMi4zLTAuNi0zLDEuNi0zaDExLjYNCgkJYzIsMCwyLjcsMC43LDQsM2wyOC4zLDYyLjlMMTQ3Ni43LDE5NC4zeiBNMTQ4Ny4xLDEzNC43bDE1LjUtMzUuNmMxLjMtMi4zLDItMyw0LTNoMTEuNmMyLjEsMCwyLjYsMC43LDEuNiwzbC0yNC40LDU0LjENCgkJTDE0ODcuMSwxMzQuN3oiLz4NCgk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTU4Ni4yLDE2NS4zYy0wLjEsMi4zLTAuNywzLTMsM0gxNTcyYy0yLjQsMC0zLTAuNy0zLTNWNzEuOWMwLTIuNCwwLjctMywzLTNoMTQuMlYxNjUuM3ogTTE1OTMuNSwxMTQuNmgxMi40DQoJCWMxNC44LDAsMTkuNi03LDE5LjYtMTUuOWMwLTguNy00LjgtMTUuNS0xOS42LTE1LjVoLTEyLjRWNjguOWgxMy4xYzE2LjYsMCwzNS41LDYuOCwzNS41LDI5LjhzLTE4LjksMzAuMi0zNS41LDMwLjJoLTEzLjFWMTE0LjZ6Ig0KCQkvPg0KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xNjgzLjUsMTY5LjdjLTE4LjctMS44LTMzLjktMTcuOC0zMy45LTM3LjVjMC0xOS45LDE1LjMtMzUuOSwzMy45LTM3LjZ2MTQuOGMtMTAuMiwxLjgtMTcuOSwxMS4xLTE3LjksMjIuOQ0KCQljMCwxMi4yLDguMSwyMS4zLDE3LjksMjNWMTY5Ljd6IE0xNjkwLjYsMTU1LjNjMTAuMi0xLjcsMTgtMTEuMSwxOC0yM3MtOC0yMS4zLTE4LTIyLjlWOTQuNmMxOS4yLDIsMzQuMSwxOCwzNC4xLDM3LjYNCgkJYzAsMTkuNS0xNC44LDM1LjYtMzQuMSwzNy41VjE1NS4zeiIvPg0KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xNzQzLjQsNjYuNWMwLTIuMywwLjctMywzLTNoMTAuMmMyLjQsMCwzLDAuNywzLDN2OTguOGMwLDIuMy0wLjcsMy0zLDNoLTEwLjJjLTIuMywwLTMtMC43LTMtM1Y2Ni41eiIvPg0KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xNzk0LjgsNjMuNGM1LjQsMCw5LjksNC41LDkuOSwxMC4xYzAsNS41LTQuNSw5LjgtOS45LDkuOGMtNS41LDAtOS45LTQuMy05LjktOS44DQoJCUMxNzg0LjksNjcuOSwxNzg5LjMsNjMuNCwxNzk0LjgsNjMuNHogTTE3ODYuOSw5OWMwLTIuMywwLjctMywzLTNoMTAuMmMyLjMsMCwzLDAuNywzLDN2NjYuM2MwLDIuMy0wLjcsMy0zLDNoLTEwLjINCgkJYy0yLjMsMC0zLTAuNy0zLTNWOTl6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTE4NTcuNiwxMDkuM2MtOS44LDEuNy0xOCwxMC42LTE4LDIzYzAsMTIuMSw3LjgsMjEuMiwxOCwyMi45djE0LjZjLTE5LjctMS44LTM0LjEtMTguNS0zNC4xLTM3LjUNCgkJYzAtMTkuMiwxNC4zLTM1LjgsMzQuMS0zNy42VjEwOS4zeiBNMTg2NC41LDk0LjZjOC40LDAuOSwxNiw0LDIyLjcsMTAuNWMxLjMsMS4zLDEsMi0wLjQsMy43bC01LjMsNS43Yy0xLjYsMS43LTIuNiwyLjEtNC4zLDAuNg0KCQljLTQuMy00LTguNy01LjMtMTIuOC02Vjk0LjZ6IE0xODY0LjUsMTU1LjNjNS4xLTAuOSw4LjgtMi40LDEyLjgtNmMxLjgtMS42LDIuNy0xLjEsNC4zLDAuNmw1LjMsNS43YzEuNCwxLjcsMS43LDIuNCwwLjQsMy43DQoJCWMtNi44LDYuNS0xMy45LDkuNS0yMi43LDEwLjVWMTU1LjN6Ii8+DQoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTE5MjQuOSwxOTQuM2MtMS4xLDIuNC0yLDMtMy44LDNoLTExLjZjLTIuMSwwLTIuNy0wLjctMS42LTNsMTQuNi0zMi41TDE4OTQuMSw5OWMtMS0yLjMtMC42LTMsMS42LTNoMTEuNg0KCQljMiwwLDIuNywwLjcsNCwzbDI4LjMsNjIuOUwxOTI0LjksMTk0LjN6IE0xOTM1LjIsMTM0LjdsMTUuNS0zNS42YzEuMy0yLjMsMi0zLDQtM2gxMS42YzIuMSwwLDIuNiwwLjcsMS42LDNsLTI0LjQsNTQuMQ0KCQlMMTkzNS4yLDEzNC43eiIvPg0KPC9nPg0KPC9zdmc+DQo=\\\" alt=\\\"\\\" width=\\\"100%\\\" /></p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Content Security Policy\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"92f2eb3c-c3b7-4378-82df-b2393da6687e\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144480,\n                    \"Version\": 4,\n                    \"Guid\": \"da88eb53-6ec2-4c2c-9646-e1f79e7cad32\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"SettingsIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"728d2627-698b-4bc6-b34e-3bee512ab93f\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144482,\n                    \"Version\": 3,\n                    \"Guid\": \"64e3ee53-d510-4435-b70f-a7323d83b47e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144483,\n                    \"Version\": 3,\n                    \"Guid\": \"d6d9a4be-3f44-4b44-848e-22b1cb9cc5dd\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MsgWarningCspFeature\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144500,\n                    \"Version\": 3,\n                    \"Guid\": \"071f96c4-edea-479b-9989-fdbd9eb224f8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MsgWarningCspFeature\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<h3><span style=\\\"color: #e03e2d;\\\">Warning</span></h3>\\n<p>The <strong>ContentSecurityPolicy</strong> feature is&nbsp;<strong>disabled</strong>. In this mode, this configuration will not have an effect.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"67897d2b-1039-4008-9e8c-13af71fc34dc\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144459,\n                    \"Version\": 9,\n                    \"Guid\": \"bb50c3ed-1ac8-4fb1-ae9f-f5ef16f9eada\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Configuration For\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is the <em>ItemIdentifier</em></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144460,\n                    \"Version\": 8,\n                    \"Guid\": \"a7b5e5d4-83bd-4a83-83a1-1a77f58d9cec\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144461,\n                    \"Version\": 8,\n                    \"Guid\": \"1b1bd0fc-723f-4e56-982d-0d5c7dc8fb7f\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"Default:Default (this is used if no other policies apply first)\\nDev:Development - review and test using ?csp=dev\\nSystemAdmin:System Admin (Super-User) only\\nSiteAdmin:Site Admin only\\nAnonymous:Anonymous Users (not logged in users) only\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MsgDevMode\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144494,\n                    \"Version\": 3,\n                    \"Guid\": \"9fd9ff5c-f99c-49a9-9639-e6aefbe86f19\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MsgDevMode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The CSP configuration for&nbsp;<strong>Dev</strong> is meant to help you develop CSP configurations in the background, without affecting the live operations.&nbsp;</p>\\n<p>Any configuration made here will apply if these two things are given</p>\\n<ol>\\n<li>The CSP feature and the CSP URL feature are enabled</li>\\n<li>You add ?csp=dev to the url</li>\\n</ol>\\n<p>In this case it will apply the policies you add here (plus policies in Razor code), no matter what login you use.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"cd800dca-99fc-4970-bbc8-1aa215436c0e\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IsEnabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144462,\n                    \"Version\": 9,\n                    \"Guid\": \"2cf8b990-787d-4fb3-a981-b0a6f6e406f5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Enabled\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"6294cc9e-3793-4506-a777-a8aada403bb1\",\n                            \"d15730b0-3402-4cf6-a63a-ea3f792e4917\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144491,\n                    \"Version\": 6,\n                    \"Guid\": \"1c7d7e47-89ab-4be3-abcb-0284a8edcfe6\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"CSP Disabled\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"CSP Enabled will inherit setting from Global or Preset\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"CSP Enabled\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"IsEnforced\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144463,\n                    \"Version\": 8,\n                    \"Guid\": \"88ba9f39-f176-4b3d-b76c-060daf023c6e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Enforce\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"f6be3e78-a86c-44da-97d7-f283481b5f8e\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144464,\n                    \"Version\": 5,\n                    \"Guid\": \"59e23162-3843-42c0-89a1-2415136ad604\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Report Only (show warnings, don't enforce rules)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"Enforce / Report will inherit setting from Global or Preset\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Enforce rules\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MsgPoliciesInherited\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144496,\n                    \"Version\": 5,\n                    \"Guid\": \"773d4d5e-dfff-4936-b9e5-615355cb8015\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MsgPoliciesInherited\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<h4><span style=\\\"color: #236fa1;\\\">Important: Empty Policies auto-inherit Parent Policies</span></h4>\\n<p>The policy is currently empty. In this case, the policy will be inherited from the configuration with the same name, from Global or Preset</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"c6170f01-7fd3-49eb-8203-cdea80148094\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MsgAppPolicy\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144513,\n                    \"Version\": 5,\n                    \"Guid\": \"e963ca63-2738-4fff-93f7-e3b2636157f5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MsgAppPolicy\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<h4><span style=\\\"color: #236fa1;\\\">Important: App Policies</span></h4>\\n<p>You are editing the <strong>App Policies</strong>. This will be merged with the Site or Global Policies.</p>\\n<p>You also cannot change the Enabled / Report-Only at App-Level.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"49c22fa1-4e1f-4585-92e7-10d18a6da0fe\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Policies\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144465,\n                    \"Version\": 7,\n                    \"Guid\": \"835b01e9-ab75-453a-9892-fddc389bfd6e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Policies (one per line, use lines starting with // for comments)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"1571d7da-298c-476e-a25c-d2fe79c1052b\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144466,\n                    \"Version\": 4,\n                    \"Guid\": \"36d35e0b-ae2d-449d-b4d7-bd89b4e630ae\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144467,\n                    \"Version\": 4,\n                    \"Guid\": \"a5a8028e-e44d-4749-8c8d-d30292fed19a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 20\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 144481,\n              \"Version\": 1,\n              \"Guid\": \"728d2627-698b-4bc6-b34e-3bee512ab93f\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return 'ContentSecurityPolicies.' + data.ItemIdentifier; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144501,\n              \"Version\": 2,\n              \"Guid\": \"67897d2b-1039-4008-9e8c-13af71fc34dc\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return !context.features.isEnabled('ContentSecurityPolicy');\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144495,\n              \"Version\": 2,\n              \"Guid\": \"cd800dca-99fc-4970-bbc8-1aa215436c0e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.ItemIdentifier == 'Dev'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144493,\n              \"Version\": 2,\n              \"Guid\": \"6294cc9e-3793-4506-a777-a8aada403bb1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return data.ItemIdentifier == 'Dev'\\n? 'not relevant for dev-mode configuration'\\n: data.default;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Notes\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Notes\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144492,\n              \"Version\": 3,\n              \"Guid\": \"d15730b0-3402-4cf6-a63a-ea3f792e4917\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  // in dev mode, we\\n  if (context.debug) return false;\\n  return data.ItemIdentifier == 'Dev' || !(context.app.isSite || context.app.isGlobal);\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Disabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144521,\n              \"Version\": 2,\n              \"Guid\": \"f6be3e78-a86c-44da-97d7-f283481b5f8e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  // in dev mode, we\\n  if (context.debug) return false;\\n  return !(context.app.isSite || context.app.isGlobal);\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Disabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144497,\n              \"Version\": 3,\n              \"Guid\": \"c6170f01-7fd3-49eb-8203-cdea80148094\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return !data.Policies && (context.app.isSite || context.app.isGlobal);\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144514,\n              \"Version\": 2,\n              \"Guid\": \"49c22fa1-4e1f-4585-92e7-10d18a6da0fe\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  const app = context.app;\\n  return !(app.isSite || app.isGlobal);\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144512,\n              \"Version\": 3,\n              \"Guid\": \"1571d7da-298c-476e-a25c-d2fe79c1052b\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  if (context.cache.secondRun) return data.value;\\n  context.cache.secondRun = true;\\n  // detect if we're on app or site/global\\n  const onApp = !(context.app.isSite || context.app.isGlobal);\\n  var original = data.default;\\n  return onApp \\n    ? data.default.replace('Policies (', 'App Policies (') \\n    : data.default;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"f5764f60-2621-4a5d-9391-100fbe664640\",\n            \"Name\": \"⚙️GoogleMaps\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 166452,\n                \"Version\": 2,\n                \"Guid\": \"8286402e-d593-4615-a0e0-b3f9dd5e166a\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Google Maps\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"f5764f60-2621-4a5d-9391-100fbe664640\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130589,\n                    \"Version\": 3,\n                    \"Guid\": \"f1d1ccd8-f9f1-41e9-80b5-c8eb8d3e0a3e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"GoogleMaps\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title / Settings Identifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130598,\n                    \"Version\": 2,\n                    \"Guid\": \"2eb275b8-b5c2-4afa-b494-10c6c727ae5d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130599,\n                    \"Version\": 2,\n                    \"Guid\": \"b3d0af8c-a179-4002-9dfe-ebbecd799019\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Zoom\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 132247,\n                    \"Version\": 3,\n                    \"Guid\": \"b3518e15-5f91-4f35-b391-73751ef4af02\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Initial Zoom of the Map\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132248,\n                    \"Version\": 2,\n                    \"Guid\": \"9f90f92f-7b74-4bcb-b230-334ba27c91a8\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 132249,\n                    \"Version\": 2,\n                    \"Guid\": \"302e69b8-5422-408d-a326-6c0d2d79566d\",\n                    \"Type\": {\n                      \"Id\": \"@number-dropdown\",\n                      \"Name\": \"@number-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"1 (show as much as possible):1\\n2:2\\n3:3\\n4:4\\n5:5\\n6:6\\n7:7\\n8:8\\n9:9\\n10:10\\n11:11\\n12:12\\n13:13\\n14:14 (default)\\n15:15\\n16:16\\n17:17\\n18:18\\n19:19\\n20 (zoom as close as possible):20\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ApiKey\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130591,\n                    \"Version\": 3,\n                    \"Guid\": \"3a024141-f6ac-44fd-9786-ead31b01dcc2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Google Maps Api Key\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130596,\n                    \"Version\": 2,\n                    \"Guid\": \"17d48b76-3efa-4eee-82a6-08587661451a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130597,\n                    \"Version\": 2,\n                    \"Guid\": \"aad0d742-e928-4d6c-923f-8fb69830cbba\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 2\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MarkerIcon\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130621,\n                    \"Version\": 2,\n                    \"Guid\": \"fa2d78fc-dbb2-4e34-93fe-78bb116b3769\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Marker Icon\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This will set the <a href=\\\"https://developers.google.com/maps/documentation/javascript/markers\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">marker icon</a> (the \\uD83D\\uDCCD). Leave empty for the google-maps default.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130622,\n                    \"Version\": 1,\n                    \"Guid\": \"6b052128-2aad-4154-a89c-ee1e6679f287\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"*\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"*\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"*\": \"\"\n                        },\n                        \"Paths\": {\n                          \"*\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"*\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"*\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"*\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DefaultCoordinates\",\n                \"Type\": \"Custom\",\n                \"InputType\": \"custom-gps\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166027,\n                    \"Version\": 3,\n                    \"Guid\": \"1126f85e-2ac6-48e2-8542-e62a411adaa5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"custom-gps\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Default GPS Coordinates\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The initial coordinates used before it is configured. Requires <a href=\\\"https://2gl.org/feature?EditUiGpsCustomDefaults\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">EditUiGpsCustomDefaults</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"200d66a2-823b-415c-9a41-19ec5eb6e520\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"DisableAutoTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166031,\n                    \"Version\": 1,\n                    \"Guid\": \"aa41513e-05f2-499b-a437-3af8b8526fdb\",\n                    \"Type\": {\n                      \"Id\": \"@custom-gps\",\n                      \"Name\": \"@custom-gps\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Address Mask\": {\n                          \"en-us\": \"\"\n                        },\n                        \"AddressMask\": {\n                          \"en-us\": \"\"\n                        },\n                        \"LatField\": {\n                          \"en-us\": \"\"\n                        },\n                        \"LongField\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 166030,\n              \"Version\": 2,\n              \"Guid\": \"200d66a2-823b-415c-9a41-19ec5eb6e520\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return !context.features.isEnabled('EditUiGpsCustomDefaults');\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Disabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"838b51db-b06c-449b-adcc-cb508ca4b488\",\n            \"Name\": \"⚙️GoogleRecaptcha\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 130620,\n                \"Version\": 2,\n                \"Guid\": \"796f4a72-8c10-4456-8902-feb0060b7499\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Configure how Google Recaptcha should work.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"⚙️GoogleRecaptcha\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"838b51db-b06c-449b-adcc-cb508ca4b488\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134250,\n                    \"Version\": 3,\n                    \"Guid\": \"270801b1-91cf-4e45-8f16-0145c1b3f6f4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"GoogleRecaptcha\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title / Settings Identifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SiteKey\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134251,\n                    \"Version\": 3,\n                    \"Guid\": \"750733fa-9d17-4a45-9342-6bfb9eec7a29\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Site Key\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The \\\"public\\\" part of the keys, which will be used in the JavaScript.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134253,\n                    \"Version\": 2,\n                    \"Guid\": \"be1df46d-c5f8-4cd5-ba4c-11bf11b8ab83\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134254,\n                    \"Version\": 2,\n                    \"Guid\": \"b7c1fa53-f558-4f6a-929d-47c01d9c7387\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PrivateKey\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 134252,\n                    \"Version\": 3,\n                    \"Guid\": \"57f20cc1-6d1b-4ebe-8516-fa2fa76a5a4a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Private Key\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The protected key which should only be used in API backends to verify the user.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134255,\n                    \"Version\": 2,\n                    \"Guid\": \"f773bbd5-d87d-4a4e-af9a-c1969c719a7d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 134256,\n                    \"Version\": 2,\n                    \"Guid\": \"5aff68f9-26ad-43e2-8e12-26f9dbd19e06\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ScoreThreshold\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184322,\n                    \"Version\": 1,\n                    \"Guid\": \"7dbd96c0-f948-47a6-864e-ef357ea0cbc2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"0.5\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Score Threshold\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Recaptcha score / threshold which must be met to pass the test. See <a href=\\\"https://docs.cloud.google.com/recaptcha/docs/interpret-assessment-website\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>. Recommended default is 0.5, for highly attacked sites 0.7 may be better.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184323,\n                    \"Version\": 1,\n                    \"Guid\": \"c60c362d-79aa-4cbd-a21e-6ec8fa58515e\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 2\n                        },\n                        \"Max\": {\n                          \"en-us\": 1\n                        },\n                        \"Min\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"6a7b65c2-b07b-4ce0-8d5a-15572431698e\",\n            \"Name\": \"⚙️GoogleTranslate\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 166455,\n                \"Version\": 1,\n                \"Guid\": \"641dbbc5-e12a-4a67-ae86-243ffa048f6b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Google Translate\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"6a7b65c2-b07b-4ce0-8d5a-15572431698e\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164892,\n                    \"Version\": 2,\n                    \"Guid\": \"7ba81bf5-e339-4d56-a0f4-8d0935926505\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"GoogleTranslate\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title / Settings Identifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164894,\n                    \"Version\": 1,\n                    \"Guid\": \"d1d16821-8119-468a-903e-e88262662b4a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164895,\n                    \"Version\": 1,\n                    \"Guid\": \"801d857c-6d53-49f4-b4e6-5fc4d36ff648\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ApiKey\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164893,\n                    \"Version\": 4,\n                    \"Guid\": \"ee1352b6-f68f-4606-856a-3f847bca7530\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"ApiKey\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Your API key to use Google Translate.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164896,\n                    \"Version\": 3,\n                    \"Guid\": \"810150dc-8330-4928-9e77-4b8a0196783c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164897,\n                    \"Version\": 3,\n                    \"Guid\": \"1725b76d-8275-4da1-9668-e6bf17916a28\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 3\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"1a86b080-9e0d-4207-97d2-04edf80b4f2f\",\n            \"Name\": \"⚙️Image\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 166457,\n                \"Version\": 1,\n                \"Guid\": \"d7c5a829-129d-4ac5-a3db-34d003586424\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Image\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"1a86b080-9e0d-4207-97d2-04edf80b4f2f\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130667,\n                    \"Version\": 4,\n                    \"Guid\": \"7253aa04-09c6-4308-81b9-3937b36e6c61\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Settings Identifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"e9fa2064-ad18-475a-b549-cfa1434d4e15\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130675,\n                    \"Version\": 3,\n                    \"Guid\": \"17ba7686-01c7-4d01-82f4-8fd87d3d2dfd\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130676,\n                    \"Version\": 3,\n                    \"Guid\": \"2a9cadb4-11a9-4252-8278-fad10c5c89f0\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130668,\n                    \"Version\": 6,\n                    \"Guid\": \"f0df036b-1ce2-4c6c-8e25-08f85608e42e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Content\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Name / ItemIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Use the TT-Freetext option to create an own Identifier like News</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130672,\n                    \"Version\": 5,\n                    \"Guid\": \"9db820ca-4625-4e8a-968a-38792a4cdfdf\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130673,\n                    \"Version\": 5,\n                    \"Guid\": \"9629a7be-9978-49ab-bbea-5318c9414d30\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"Content:Content (the typical full-width Image in the Content-Area)\\nLightbox:Lightbox (images which open in a Lightbox)\\nSection:Section (usually a full-width background / parallax)\\nScreen:Full Screen images / Backgrounds\\nWysiwyg:Wysiwyg - for images in the Wysiwyg Editor\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 183842,\n                    \"Version\": 2,\n                    \"Guid\": \"2d77478d-7f3a-4ae7-9b1b-4979b453ba50\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Description\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Used to help select the right option in dropdowns.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183843,\n                    \"Version\": 1,\n                    \"Guid\": \"9d0208c3-aff5-4de2-a268-68c017990a89\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 183844,\n                    \"Version\": 1,\n                    \"Guid\": \"515cffe6-4730-4a76-884d-0d1f5c9eae9b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Width\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130669,\n                    \"Version\": 1,\n                    \"Guid\": \"b5be42ed-e558-46a3-95c3-2ead0f1e31f7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Width\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AspectRatio\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 131455,\n                    \"Version\": 7,\n                    \"Guid\": \"0615d0c7-797e-41fb-9759-4313d20e970a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"number-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Aspect Ratio\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>The ratio is width to height. 1 is square, 1.618 is the <a href=\\\"https://en.wikipedia.org/wiki/Golden_ratio\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Golden Ratio</a> wide-format. Used when resizing images which are proportional to the initial width.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131456,\n                    \"Version\": 5,\n                    \"Guid\": \"78c21972-4122-4a04-bb13-a87932e2c90a\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"*\": 10\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131465,\n                    \"Version\": 3,\n                    \"Guid\": \"5f494775-cb1a-47cf-836c-d7e45d3c0234\",\n                    \"Type\": {\n                      \"Id\": \"@number-dropdown\",\n                      \"Name\": \"@number-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \":Empty / no value\\n1:Square 1:1\\n2:Twice as wide, 2:1 - ideal for blogs / Social Media\\n1.618:Golden Ratio Wide\\n0.618:Golden Ratio Tall\\n1.333:Classic TV Wide 4:3\\n0.75:Classic TV Tall 4:3\\n1.777:Cinema / Smartphone Wide 16:9\\n0.5625:Cinema / Smartphone Tall 16:9\\n\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"*\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Height\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130671,\n                    \"Version\": 2,\n                    \"Guid\": \"e1e8149a-73fb-4a30-87ef-c365d82a91c0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Height\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"ad90da09-ab14-4b6a-b762-6b60613cf63c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Quality\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130670,\n                    \"Version\": 1,\n                    \"Guid\": \"cb7c6873-6bbb-4ace-8e0a-8ef46c8511b3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Quality\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ResizeMode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130684,\n                    \"Version\": 5,\n                    \"Guid\": \"d11bd984-630f-40a2-9b31-f948f394ebcc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Resize Mode (Mode)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>See <a href=\\\"https://imageresizing.net/docs/v4/reference\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">resize variations of ImageResizing.net</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130685,\n                    \"Version\": 4,\n                    \"Guid\": \"3b9de40d-8e26-4508-845b-c54668208a0b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130686,\n                    \"Version\": 4,\n                    \"Guid\": \"e365f343-3f5c-43b1-99c6-1d03864bded3\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default (not set)\\n(none):Reset to not set, even if other settings would have set this\\nmax:Max (preserve ratio)\\npad:Pad (add white to ensure size)\\ncrop:Crop (preserve ratio and crop to get into that shape)\\nstretch:Stretch (distort image if necessary)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ScaleMode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 131466,\n                    \"Version\": 8,\n                    \"Guid\": \"c62e2399-bf83-4ce2-8e65-96167db2ca75\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Scale Mode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131467,\n                    \"Version\": 7,\n                    \"Guid\": \"18edb3cf-c813-422f-b020-d647893f7bd5\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 131468,\n                    \"Version\": 7,\n                    \"Guid\": \"0b1f2d83-73f3-40ef-96bf-9984a568604c\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default (not set, downscale-only)\\n(none):Reset to not set, even if other settings would have set this\\nboth:Both - Downscale and Upscale\\ndown:Down - Downscale only - same as default\\nup:Upscale only - you probably never want this\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Format\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 137816,\n                    \"Version\": 3,\n                    \"Guid\": \"c5195e5c-59c3-4104-82e8-bea6a93ed60c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Format\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>force all resized images to use this format</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137817,\n                    \"Version\": 2,\n                    \"Guid\": \"015de30f-8bac-49cb-b562-88ab9f5e8188\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 137818,\n                    \"Version\": 2,\n                    \"Guid\": \"946ddba3-c530-438c-86f8-662bb580b1e2\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":not set (will use existing image format)\\n(none):Reset to use existing format, even if other settings had a format specified\\nwebp:WebP Format (recommended)\\npng:PNG Format\\njpg:JPEG Format\\npng:PNG Format\\ngif:GIF Format\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Advanced\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-json\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 144383,\n                    \"Version\": 11,\n                    \"Guid\": \"31cd4bb6-3a64-434e-babc-c97f836fce83\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-json\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Advanced settings configured in json. See <a href=\\\"https://docs.2sxc.org/basics/images/guide/index.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Image Resize Guide</a> and <a href=\\\"https://docs.2sxc.org/basics/configuration/settings/images/recipes.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">Image-Resize Recipe</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"00eed300-a780-4959-8c6e-b5b2a1ff8af5\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144384,\n                    \"Version\": 9,\n                    \"Guid\": \"f2e77914-359c-481c-9379-d887a7b2edad\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 144385,\n                    \"Version\": 9,\n                    \"Guid\": \"a1eb3b7a-377c-4fbf-a21f-a0fa93d6a412\",\n                    \"Type\": {\n                      \"Id\": \"@string-json\",\n                      \"Name\": \"@string-json\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"JsonSchemaMode\": {\n                          \"en-us\": \"light\"\n                        },\n                        \"JsonSchemaRaw\": {\n                          \"en-us\": \"\"\n                        },\n                        \"JsonSchemaSource\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"JsonValidation\": {\n                          \"en-us\": \"strict\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"JsonSchemaUrl\": {\n                          \"en-us\": \"https://schemas.2sxc.org/image-resize/v13/index.json\"\n                        }\n                      },\n                      \"Number\": {\n                        \"Rows\": {\n                          \"en-us\": 25\n                        }\n                      },\n                      \"Boolean\": {\n                        \"JsonCommentsAllowed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130674,\n              \"Version\": 2,\n              \"Guid\": \"e9fa2064-ad18-475a-b549-cfa1434d4e15\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return 'Images.' + data.ItemIdentifier; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 144381,\n              \"Version\": 2,\n              \"Guid\": \"ad90da09-ab14-4b6a-b762-6b60613cf63c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return !data.AspectRatio; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 160374,\n              \"Version\": 2,\n              \"Guid\": \"00eed300-a780-4959-8c6e-b5b2a1ff8af5\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  if (data.value === '{}') {\\n    return `{\\n  \\\"$schema\\\": \\\"https://schemas.2sxc.org/image-resize/v13/index.json\\\",\\n  \\\"recipe\\\": {\\n    \\\"name\\\": \\\"default\\\",\\n    \\\"variants\\\": \\\"2*, 1*, 3/4*, 1/2*\\\",\\n    \\\"setWidth\\\": false,\\n    \\\"attributes\\\": {\\n      \\\"loading\\\": \\\"lazy\\\"\\n    }\\n  }\\n}`;\\n  }\\n  return data.value;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"7edd0b8d-1405-44ed-ac33-d0d63a274bd6\",\n            \"Name\": \"⚙️Images\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 130661,\n                \"Version\": 4,\n                \"Guid\": \"17eab878-42c2-45c5-a766-c66a33ef1db6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"*\": \"Items\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>This contains global image settings. Modern Apps will follow the settings here, but some apps may still have their custom behavior.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"⚙️Images\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"7edd0b8d-1405-44ed-ac33-d0d63a274bd6\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130662,\n                    \"Version\": 2,\n                    \"Guid\": \"a141688b-027d-4a2d-a31f-6e75819d237f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Images\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"SettingsIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130664,\n                    \"Version\": 1,\n                    \"Guid\": \"28179b36-a916-4d74-aa66-d136b118c08b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130665,\n                    \"Version\": 1,\n                    \"Guid\": \"f067e605-67de-4e8c-a135-4213a533ad26\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Items\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130663,\n                    \"Version\": 8,\n                    \"Guid\": \"4f194dec-92a3-4459-92bb-9b1cf671758a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Preset Items\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130666,\n                    \"Version\": 7,\n                    \"Guid\": \"05c1f082-c301-4da9-a6d9-2b5f8beab350\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️Image\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"57248ccb-24f1-44c6-9c6c-085e44ebb0cb\",\n            \"Name\": \"⚙️License\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 165978,\n                \"Version\": 3,\n                \"Guid\": \"ccee5764-f2ff-469d-b610-72e372089a4d\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Special license ID for this system. Normally you would:</p>\\n<ol>\\n<li>Create such an item</li>\\n<li>Export it as json</li>\\n<li>Place it in the <code>App_Data/system-custom/entities/</code> folder</li>\\n</ol>\\n<p>This itself only provides an additional fingerprint for activating certain features. It does not enable the license. For this you must also have the matching license file, which you would get from 2sxc.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️License\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"57248ccb-24f1-44c6-9c6c-085e44ebb0cb\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 165976,\n                    \"Version\": 1,\n                    \"Guid\": \"48bd0a6a-bd62-4cbc-829a-9b130177a1f0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Fingerprint\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 165977,\n                    \"Version\": 1,\n                    \"Guid\": \"9ff395ea-6916-4bf7-9f00-bdf64ba77af1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Fingerprint\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"5ad95efe-1dc9-4681-adb8-42d9e7f0183b\",\n            \"Name\": \"⚙️QuickEdit\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 130619,\n                \"Version\": 3,\n                \"Guid\": \"c83fbbf0-ef8c-43c7-8c70-42814991b30a\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"*\": \"Items\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Important: This data is still experimental and more Proof-Of-Concept. It doesn't have an affect yet, so we recommend you don't add your own settings.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"⚙️QuickEdit\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5ad95efe-1dc9-4681-adb8-42d9e7f0183b\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130563,\n                    \"Version\": 3,\n                    \"Guid\": \"4f243a10-1795-4b51-afc9-118bab0cdd11\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"QuickEdit\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title / Settings Identifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130564,\n                    \"Version\": 2,\n                    \"Guid\": \"1bebc016-265b-488d-8b15-b9429930cf0c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130565,\n                    \"Version\": 2,\n                    \"Guid\": \"99f85172-ad98-4edc-a6fa-8ce4682bf3d5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Items\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130566,\n                    \"Version\": 3,\n                    \"Guid\": \"8f910efd-f176-43e3-b642-08d62f4b1486\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"QuickEdit Parts/Items\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130567,\n                    \"Version\": 2,\n                    \"Guid\": \"666bd355-4a79-4b88-bf6f-0e39d25e6860\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"*\": \"⚙️QuickEditPart\"\n                        },\n                        \"Prefill\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"*\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"*\": true\n                        },\n                        \"EnableCreate\": {\n                          \"*\": true\n                        },\n                        \"EnableDelete\": {\n                          \"*\": true\n                        },\n                        \"EnableEdit\": {\n                          \"*\": true\n                        },\n                        \"EnableRemove\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"46cd1afc-c840-4473-8586-6bb1f35656a8\",\n            \"Name\": \"⚙️QuickEditPart\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 166462,\n                \"Version\": 1,\n                \"Guid\": \"9b5b4edc-32dd-470d-ad2b-96d1ed1b30e2\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️QuickEdit Part\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"46cd1afc-c840-4473-8586-6bb1f35656a8\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130568,\n                    \"Version\": 4,\n                    \"Guid\": \"847bf7af-2f9e-43bd-9477-389c101b025f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"SettingsIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"bf0b980d-1e5c-487c-8732-ae780b7e84e0\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130579,\n                    \"Version\": 3,\n                    \"Guid\": \"9ee0bf8d-7dde-426b-afd5-2eee0f1701ca\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130580,\n                    \"Version\": 3,\n                    \"Guid\": \"d850de1d-1ae4-4623-b110-1c9a947ec669\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130569,\n                    \"Version\": 2,\n                    \"Guid\": \"4544b653-e57c-42d8-92e6-291b4d5de48e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Part\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130576,\n                    \"Version\": 1,\n                    \"Guid\": \"d7a1450e-417a-44f1-8560-c0c125d03528\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130577,\n                    \"Version\": 1,\n                    \"Guid\": \"fafd16ef-fcc9-42db-89ba-c6c2da5b6290\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"Default:Default\\nModule:Module\\nInner Content Area:InnerContentArea\\nInner Content WYSIWYG / Dynamic:InnerContentDynamic\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Enable\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130571,\n                    \"Version\": 1,\n                    \"Guid\": \"e7c1f9da-a305-4845-a837-a5dbc0247bd3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Enable\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AddApp\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130572,\n                    \"Version\": 1,\n                    \"Guid\": \"02856302-f4da-41ef-8f1b-f50ab0614e6a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"AddApp\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AddContent\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130573,\n                    \"Version\": 1,\n                    \"Guid\": \"fd280ad2-9dcf-48f2-86fe-bda9b927cda1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"AddContent\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Select\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130574,\n                    \"Version\": 1,\n                    \"Guid\": \"cd637330-f49f-46a0-b61c-3cba6620a870\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Select\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Paste\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130575,\n                    \"Version\": 1,\n                    \"Guid\": \"cae6aa41-bfec-4bd9-999c-fc83fd1beff4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Paste\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Move\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130581,\n                    \"Version\": 3,\n                    \"Guid\": \"30e2e6d1-edb8-491c-9d7f-73ee742777f0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Move\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130588,\n                    \"Version\": 2,\n                    \"Guid\": \"2cc1ecbb-7853-4013-b064-bd34d45e39f0\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130578,\n              \"Version\": 4,\n              \"Guid\": \"bf0b980d-1e5c-487c-8732-ae780b7e84e0\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return \\\"QuickEdit.\\\" + data.ItemIdentifier; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"0948fd10-7ce2-4495-bc6e-7ccb8265857e\",\n            \"Name\": \"⚙️SiteSetup\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 166061,\n                \"Version\": 1,\n                \"Guid\": \"6e5e7f67-6ad6-4fd5-8531-c0a57f116bc0\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Here you can configure aspects of how new sites are setup.</p>\\n<p>As of v15, you can what apps should be available in the Auto-Installer. If this feature is popular, we'll consider enhancing it to also support custom apps and more.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️SiteSetup\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"0948fd10-7ce2-4495-bc6e-7ccb8265857e\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164881,\n                    \"Version\": 2,\n                    \"Guid\": \"af9f284a-c6c6-4f77-886f-d05457556ec8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Installation\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164883,\n                    \"Version\": 1,\n                    \"Guid\": \"1338a5e0-8661-40e6-93d6-ce202058b0c6\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164884,\n                    \"Version\": 1,\n                    \"Guid\": \"0ec37593-6f43-44e7-b5f0-6c35fb6f8980\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"HintFeatureRequired\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166059,\n                    \"Version\": 3,\n                    \"Guid\": \"28b4578d-8771-4acc-9306-c89f7a06b8bf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"HintFeatureRequired\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>⚠️ Important&nbsp;</strong><strong>⚠️</strong></p>\\n<p>This feature is not enabled on this site. So you can configure this, but the settings will not take effect until you enable the feature <a href=\\\"https://patrons.2sxc.org/rf?AppAutoInstallerConfigurable\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">AppAutoInstallerConfigurable</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"ad2e2046-6eef-4cb1-98dd-0ae513af9e50\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AutoInstallApps\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164882,\n                    \"Version\": 4,\n                    \"Guid\": \"a4a9c154-90ea-4e8c-8895-2b8d5b0f2ee7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Apps Auto Install Rules\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164885,\n                    \"Version\": 3,\n                    \"Guid\": \"f479f640-e7a6-487b-b6d4-f4815662a580\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"⚙️SiteSetupAutoInstallApps\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 166060,\n              \"Version\": 2,\n              \"Guid\": \"ad2e2046-6eef-4cb1-98dd-0ae513af9e50\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  return !context.features.isEnabled('AppAutoInstallerConfigurable');\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"833baa25-899b-4242-ade7-323a319bcf71\",\n            \"Name\": \"⚙️SiteSetupAutoInstallApps\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 166465,\n                \"Version\": 1,\n                \"Guid\": \"2ab9428b-d082-4837-9839-54c66560eb6e\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️SiteSetup Auto Install Apps\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"833baa25-899b-4242-ade7-323a319bcf71\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Name\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164867,\n                    \"Version\": 3,\n                    \"Guid\": \"795e2d26-301a-4155-bffe-154edf2359de\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Name of App or Rule\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This has no real functionality, but is to help you be sure which app this is.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164868,\n                    \"Version\": 2,\n                    \"Guid\": \"c785c222-025f-4fd5-a397-aad907a884ad\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164869,\n                    \"Version\": 2,\n                    \"Guid\": \"9ae91ccd-1abf-4fab-8353-876045c69aa6\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Target\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164872,\n                    \"Version\": 3,\n                    \"Guid\": \"1acd3e13-346e-4bc5-9304-1576761346d6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"guid\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Target of this Rule\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>What does this rule apply to?</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164873,\n                    \"Version\": 2,\n                    \"Guid\": \"7a842c84-7d21-4b89-94bf-b44da6bcdfeb\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164874,\n                    \"Version\": 2,\n                    \"Guid\": \"637bd140-abba-4e0a-ae2e-0771151321c7\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"guid:Specific App (default)\\nall:All Apps (basically for deny-anything except whitelisted-rules)\\nurl:App Link (to zip of APP)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Mode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164865,\n                    \"Version\": 6,\n                    \"Guid\": \"335fcc90-f084-40c9-985c-54ade83297a8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"a\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Mode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"4bbd4c45-a56a-4aed-ab73-4fb6bffad6a1\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164870,\n                    \"Version\": 4,\n                    \"Guid\": \"8a543fa0-390c-4407-a61a-685afdd90248\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164871,\n                    \"Version\": 4,\n                    \"Guid\": \"0a9e4842-d548-4997-ad82-280eb0a31bf4\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"f:Forbidden (may NOT be auto-installed)\\nr:Required (MUST be installed when using auto-install)\\na:Allowed (is allowed and selected, but can also be unselected)\\no:Optional (is allowed but not selected)\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AppGuid\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-url-path\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164864,\n                    \"Version\": 4,\n                    \"Guid\": \"4790b967-fa82-4cdd-bf99-70369c4b1d9b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-url-path\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"App Guid\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Find the App Guids in the <a href=\\\"https://2sxc.org/en/apps\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">App Catalog</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"c4b84ce2-edd3-4ab5-a87c-d0534251947c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164875,\n                    \"Version\": 2,\n                    \"Guid\": \"15a2b72e-8664-4df4-869a-b90dbb1977e7\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164876,\n                    \"Version\": 2,\n                    \"Guid\": \"eecaa63b-f51e-476f-8680-e073c131a5b0\",\n                    \"Type\": {\n                      \"Id\": \"@string-url-path\",\n                      \"Name\": \"@string-url-path\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"AutoGenerateMask\": {\n                          \"en-us\": \"[Title]\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowSlashes\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Url\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164866,\n                    \"Version\": 3,\n                    \"Guid\": \"4ffbfe66-dbf0-4ce4-95aa-8c571d9a1dc6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Url\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8431ad5d-a030-4646-b524-5acf4ca502ee\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164880,\n                    \"Version\": 1,\n                    \"Guid\": \"93c49ac7-fbe8-448f-b956-357a782112e8\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 164877,\n              \"Version\": 3,\n              \"Guid\": \"4bbd4c45-a56a-4aed-ab73-4fb6bffad6a1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.Target !== ''; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 164878,\n              \"Version\": 3,\n              \"Guid\": \"c4b84ce2-edd3-4ab5-a87c-d0534251947c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.Target === 'guid'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 164879,\n              \"Version\": 2,\n              \"Guid\": \"8431ad5d-a030-4646-b524-5acf4ca502ee\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.Target === 'url'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"aed871cf-220b-4330-b368-f1259981c9c8\",\n            \"Name\": \"⚙️CopyrightSettings\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 182640,\n                \"Version\": 2,\n                \"Guid\": \"08208884-69bd-4448-8fd9-4f0f7cef5f50\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Copyright Settings\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"aed871cf-220b-4330-b368-f1259981c9c8\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182632,\n                    \"Version\": 6,\n                    \"Guid\": \"61220dc2-2824-4ef1-adad-a28373be49bc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Copyright\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"SettingsIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182635,\n                    \"Version\": 5,\n                    \"Guid\": \"680db639-cb65-4e13-9b6f-5024bd8d40a0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182636,\n                    \"Version\": 5,\n                    \"Guid\": \"3e4678e5-0250-457f-adef-289e0b5a885a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ImagesInputEnabled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182634,\n                    \"Version\": 5,\n                    \"Guid\": \"514cbecb-0063-43c1-a8a6-4f0703d746fb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Images - Copyright Input\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182639,\n                    \"Version\": 4,\n                    \"Guid\": \"750733f6-9673-4df9-8b0f-b2a558eac401\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"no copyright input for images\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"inherit default setting (no copyright input for images)\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"enable copyright input for images (toolbar-buttons)\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DisplayPrefix\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182646,\n                    \"Version\": 1,\n                    \"Guid\": \"78e0ae31-81fd-44b1-b702-763cc04f0d8f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"DisplayPrefix\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DisplayFormat\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182647,\n                    \"Version\": 2,\n                    \"Guid\": \"bbed63a0-301d-4c36-969e-46fd281181c0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"DisplayFormat\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182648,\n                    \"Version\": 1,\n                    \"Guid\": \"adf0a5fe-ef0c-46b7-b951-08df15c3020f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182649,\n                    \"Version\": 1,\n                    \"Guid\": \"318364e3-5aa1-487f-b27d-5e42e3a2cb15\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default - [prefix] [owner] [year] [type] [message]\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"60131b0d-d042-43c8-a4a7-fb44a45db60c\",\n            \"Name\": \"⚙️InputFields\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 185444,\n                \"Version\": 5,\n                \"Guid\": \"ae780cf6-edf1-443b-9e5b-ac06d545df1e\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"Items\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Input Fields (BETA)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"60131b0d-d042-43c8-a4a7-fb44a45db60c\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185448,\n                    \"Version\": 2,\n                    \"Guid\": \"e719a89c-c811-4ba8-b732-b6704d13b669\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"InputFields\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"SettingsIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185450,\n                    \"Version\": 1,\n                    \"Guid\": \"18325ede-6bd4-4c4d-8c25-139f6ad00563\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185451,\n                    \"Version\": 1,\n                    \"Guid\": \"d7e24b07-8885-470f-a75d-1843fab56f62\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Items\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185449,\n                    \"Version\": 2,\n                    \"Guid\": \"a73885a8-ef7b-4c5c-b787-5d3e846350ed\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Items\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185452,\n                    \"Version\": 1,\n                    \"Guid\": \"665c0af6-76c3-44fd-8f8a-0342a115340d\",\n                    \"Type\": {\n                      \"Id\": \"6fa7f390-7612-40c6-baff-2bcf6140a85f\",\n                      \"Name\": \"@entity-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"6c5d1062-1628-4b45-8f33-1b93a39f2ac5\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"f8a6ed24-11c0-42c4-9022-409989489563\",\n            \"Name\": \"⚙️InputFieldsWysiwygSettings\",\n            \"Scope\": \"System.Configuration\",\n            \"Metadata\": [\n              {\n                \"Id\": 185429,\n                \"Version\": 3,\n                \"Guid\": \"30e898a6-5c85-4316-bc8c-a70a24621ae1\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"⚙️Input Field - Wysiwyg Settings (beta)\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"<p>Configuration for the WYSIWYG - BETA.</p>\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"f8a6ed24-11c0-42c4-9022-409989489563\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"SettingsIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185430,\n                    \"Version\": 4,\n                    \"Guid\": \"e9157ff9-26f8-4dcf-a71f-186afd16030f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"InputFields.StringWysiwyg\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"SettingsIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185431,\n                    \"Version\": 3,\n                    \"Guid\": \"54f39b44-9a9a-437a-a1ff-6a0d7d865798\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185432,\n                    \"Version\": 3,\n                    \"Guid\": \"1eb61cc5-f3d9-42b8-8c88-0a0da9368ab7\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ItemIdentifier\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185445,\n                    \"Version\": 2,\n                    \"Guid\": \"6518ffc1-d503-43f6-aaaf-f0c602521ed9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"StringWysiwyg\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"ItemIdentifier\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185446,\n                    \"Version\": 1,\n                    \"Guid\": \"a6985349-3048-4164-8c2f-4e3fcd3204cc\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185447,\n                    \"Version\": 1,\n                    \"Guid\": \"2388e2dd-943f-4b69-8c8f-931e63cab23e\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EditorPlugin\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185433,\n                    \"Version\": 2,\n                    \"Guid\": \"a9f6a367-d31b-48f5-80c2-62d976a2758f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"tinymce\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Editor Plugin\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185456,\n                    \"Version\": 1,\n                    \"Guid\": \"a5af80fd-2ff4-4832-bd93-b59eea87346b\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185457,\n                    \"Version\": 1,\n                    \"Guid\": \"cbb82eaa-993c-46d3-b5b8-c4ee046c87c1\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ButtonSource\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185434,\n                    \"Version\": 2,\n                    \"Guid\": \"a95b1a9a-dd79-4197-9b83-cdf849fb34b3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Button HTML Source\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185436,\n                    \"Version\": 1,\n                    \"Guid\": \"5cbf571f-8ef5-4690-a129-8c4a38e21990\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"7a6b443a-6d23-45b2-9499-35743cf7d924\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ButtonSourceInDebugMode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185435,\n                    \"Version\": 2,\n                    \"Guid\": \"33c5221b-6b0a-4f6a-b5c1-4f2e3002ecaf\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Button HTML Source (when in Debug Mode)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Determine if super-users can access HTML source in debug mode.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185437,\n                    \"Version\": 1,\n                    \"Guid\": \"12db5759-46a7-4c9b-b160-16160407ed9b\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"7a6b443a-6d23-45b2-9499-35743cf7d924\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 183904,\n              \"Version\": 1,\n              \"Guid\": \"7a6b443a-6d23-45b2-9499-35743cf7d924\",\n              \"Type\": {\n                \"Id\": \"3a96ad21-027d-4679-8372-c39406ad1d11\",\n                \"Name\": \"UiPickerSourceCustomCsv\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Csv\": {\n                    \"en-us\": \"Value,Title,Info\\n,\\\"Default\\\",\\\"In default mode the button is disabled in the small editor, but enabled in the popup Dialog\\\"\\ntrue,\\\"Always Enable\\\",\\\"Enable the button in both the small editor as well as the popup dialog\\\"\\nfalse,\\\"Always Disable\\\",\\\"Disable the button in both the small editor as well as the popup dialog\\\"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Info]</p>\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"String-WYSIWyG Button Source\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ],\n      \"Entities\": [\n        {\n          \"Id\": 130583,\n          \"Version\": 18,\n          \"Guid\": \"8c87f24f-959c-4ff1-b537-077556e8d439\",\n          \"Type\": {\n            \"Id\": \"813a3cb7-1a89-4477-bdfe-8863ab3ae59a\",\n            \"Name\": \"SettingsSystem\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"SettingsEntityScope\": {\n                \"en-us\": \"\"\n              },\n              \"Title\": {\n                \"en-us\": \"System Settings\"\n              }\n            },\n            \"Entity\": {\n              \"ContentSecurityPolicies\": {\n                \"*\": [\n                  \"285c4a83-7fa2-4732-b1a2-da945b94c3dd\"\n                ]\n              },\n              \"Copyright\": {\n                \"*\": [\n                  \"7116c320-769d-4d7c-94ef-76c176a17ba2\"\n                ]\n              },\n              \"GoogleMaps\": {\n                \"*\": [\n                  \"c459f03d-bb65-4813-ac8a-0a780f72eab7\"\n                ]\n              },\n              \"GoogleRecaptcha\": {\n                \"*\": [\n                  \"7d929ae6-ffe2-4686-b3dc-cf0937abea00\"\n                ]\n              },\n              \"GoogleTranslate\": {\n                \"*\": [\n                  \"eb39ffc9-f7fa-4599-8ea4-549a8fd9d69a\"\n                ]\n              },\n              \"Images\": {\n                \"*\": [\n                  \"89184eb0-1d4d-4429-8c38-c453f8aa149d\"\n                ]\n              },\n              \"InputFields\": {\n                \"*\": [\n                  \"22930727-fb85-4dfb-86b1-6517b34ac386\"\n                ]\n              },\n              \"QuickEdit\": {\n                \"*\": [\n                  \"a88c329c-cc6e-4744-b3ec-88c186502d9d\"\n                ]\n              },\n              \"SiteSetup\": {\n                \"*\": [\n                  \"052a5e27-40f8-40bf-bd97-35a6641e9df0\"\n                ]\n              },\n              \"WebResources\": {\n                \"*\": [\n                  \"06f4fa58-2e91-4896-a16e-3bbaf9a5f491\"\n                ]\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166535,\n              \"Version\": 1,\n              \"Guid\": \"c8c3fac2-0aa3-407a-8463-a5e724f54623\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"8c87f24f-959c-4ff1-b537-077556e8d439\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 144479,\n          \"Version\": 3,\n          \"Guid\": \"285c4a83-7fa2-4732-b1a2-da945b94c3dd\",\n          \"Type\": {\n            \"Id\": \"5f431769-ff03-472e-aab5-33891af10acc\",\n            \"Name\": \"⚙️ContentSecurityPolicies\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"SettingsIdentifier\": {\n                \"en-us\": \"ContentSecurityPolicies\"\n              }\n            },\n            \"Entity\": {\n              \"Items\": {\n                \"*\": [\n                  \"429b41cd-c626-48f2-919e-63d7a4cdd226\",\n                  \"2ab98dd8-9937-4a5c-8f9f-651222c2bad9\"\n                ]\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166536,\n              \"Version\": 1,\n              \"Guid\": \"fcc413ba-ca41-40d1-bf92-89ecdeed8e11\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"285c4a83-7fa2-4732-b1a2-da945b94c3dd\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 144484,\n          \"Version\": 13,\n          \"Guid\": \"429b41cd-c626-48f2-919e-63d7a4cdd226\",\n          \"Type\": {\n            \"Id\": \"92f2eb3c-c3b7-4378-82df-b2393da6687e\",\n            \"Name\": \"⚙️ContentSecurityPolicy\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ItemIdentifier\": {\n                \"en-us\": \"Default\"\n              },\n              \"Policies\": {\n                \"en-us\": \"// *************************\\n// ALL-SRC\\n// this will be added to default and all other src which are set\\nall-src: 'self'\\nall-src: https:\\nall-src: *\\nall-src: 'unsafe-inline'\\n\\n// *************************\\n// SCRIPT-SRC\\n\\n// This is for the default asp.net web forms script block in Dnn 7 - 9\\n// For now it's disabled, as it would deactivate 'unsafe-inline'\\n// script-src: 'sha256-1lxkJKcAqLep9MQngjrTJpfkCA56HejJ0oNvP3hq0gI='\\n\\n// This will allow just about any script to run\\nscript-src: 'unsafe-eval'\\nscript-src: 'unsafe-hashes'\\n\\n// *************************\\n\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"ContentSecurityPolicies.Default\"\n              }\n            },\n            \"Boolean\": {\n              \"IsEnabled\": {\n                \"en-us\": false\n              },\n              \"IsEnforced\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166537,\n              \"Version\": 1,\n              \"Guid\": \"b9cdb5ac-5c94-4d9d-8c5b-88e0365011dc\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"429b41cd-c626-48f2-919e-63d7a4cdd226\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 144490,\n          \"Version\": 1,\n          \"Guid\": \"2ab98dd8-9937-4a5c-8f9f-651222c2bad9\",\n          \"Type\": {\n            \"Id\": \"92f2eb3c-c3b7-4378-82df-b2393da6687e\",\n            \"Name\": \"⚙️ContentSecurityPolicy\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ItemIdentifier\": {\n                \"en-us\": \"Dev\"\n              },\n              \"Policies\": {\n                \"en-us\": \"// *************************\\n// ALL-SRC\\n// this will be added to default and all other src which are set\\nall-src: 'self'\\nall-src: https:\\nall-src: *\\nall-src: 'unsafe-inline'\\n\\n// *************************\\n// SCRIPT-SRC\\n\\n// This is for the default asp.net web forms script block in Dnn 7 - 9\\n// For now it's disabled, as it would deactivate 'unsafe-inline'\\n// script-src: 'sha256-1lxkJKcAqLep9MQngjrTJpfkCA56HejJ0oNvP3hq0gI='\\n\\n// This will allow just about any script to run\\nscript-src: 'unsafe-eval'\\nscript-src: 'unsafe-hashes'\\n\\n// *************************\\n\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"ContentSecurityPolicies.Dev\"\n              }\n            },\n            \"Boolean\": {\n              \"IsEnabled\": {\n                \"en-us\": true\n              },\n              \"IsEnforced\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166538,\n              \"Version\": 1,\n              \"Guid\": \"13dd5bb1-7d3f-44f9-93c2-649d65814f50\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"2ab98dd8-9937-4a5c-8f9f-651222c2bad9\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130593,\n          \"Version\": 14,\n          \"Guid\": \"c459f03d-bb65-4813-ac8a-0a780f72eab7\",\n          \"Type\": {\n            \"Id\": \"f5764f60-2621-4a5d-9391-100fbe664640\",\n            \"Name\": \"⚙️GoogleMaps\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ApiKey\": {\n                \"en-us\": \"secure:7nRMfvzJ0BHyTtGDFaVB4kCYLBGRkgW1oAYG1KTLXk/jme8q9Hhb4a1ZOuJVwM94;iv:5cmjUX6SDTJMCj+IkwhWNA==\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"GoogleMaps\"\n              }\n            },\n            \"Hyperlink\": {\n              \"MarkerIcon\": {\n                \"en-us\": \"\"\n              }\n            },\n            \"Custom\": {\n              \"DefaultCoordinates\": {\n                \"en-us\": \"{\\\"latitude\\\":47.1747,\\\"longitude\\\":9.4692}\"\n              }\n            },\n            \"Number\": {\n              \"Zoom\": {\n                \"en-us\": 14\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166539,\n              \"Version\": 1,\n              \"Guid\": \"f0753bdc-e7a1-4b61-b721-4b4e21b34f7c\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"c459f03d-bb65-4813-ac8a-0a780f72eab7\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 164900,\n          \"Version\": 3,\n          \"Guid\": \"eb39ffc9-f7fa-4599-8ea4-549a8fd9d69a\",\n          \"Type\": {\n            \"Id\": \"6a7b65c2-b07b-4ce0-8d5a-15572431698e\",\n            \"Name\": \"⚙️GoogleTranslate\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ApiKey\": {\n                \"en-us\": \"secure:DyUZbdZzGCO4Mmllq0wgHnIi2IF3i1cGV3lUNjI1ZhX3o76cBZit//QGtk7WTvWe;iv:lAZPeWu3aKkaXgDVeAYkrA==\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"GoogleTranslate\"\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166540,\n              \"Version\": 1,\n              \"Guid\": \"a58efde7-756d-4f34-a0dc-be478b2c183b\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"eb39ffc9-f7fa-4599-8ea4-549a8fd9d69a\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 134261,\n          \"Version\": 2,\n          \"Guid\": \"7d929ae6-ffe2-4686-b3dc-cf0937abea00\",\n          \"Type\": {\n            \"Id\": \"838b51db-b06c-449b-adcc-cb508ca4b488\",\n            \"Name\": \"⚙️GoogleRecaptcha\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"PrivateKey\": {\n                \"en-us\": \"secure:qrPulUBStmCGTZ0EnQ9NdKrfe0oO+jei9fhV6+wxKCUUMxgdbA44+QaJJLECU1Eh;iv:/XLUVMOz/w8lQRLLyvD79w==\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"GoogleRecaptcha\"\n              },\n              \"SiteKey\": {\n                \"en-us\": \"secure:+klje+7SHT2AiCDpTM+AsLZ9IGcAXBV1DlGUsdWrASihQfxwa5J/y11hvn/ahemA;iv:1tYjA+gPNTKHvWTo8aef+Q==\"\n              }\n            },\n            \"Number\": {\n              \"ScoreThreshold\": {\n                \"en-us\": 0.5\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166541,\n              \"Version\": 1,\n              \"Guid\": \"5f53e47b-d9c4-4a21-9b6d-b873c4c61185\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"7d929ae6-ffe2-4686-b3dc-cf0937abea00\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130678,\n          \"Version\": 26,\n          \"Guid\": \"358ce0df-52bf-4877-bf32-19c3fb723c73\",\n          \"Type\": {\n            \"Id\": \"1a86b080-9e0d-4207-97d2-04edf80b4f2f\",\n            \"Name\": \"⚙️Image\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"{\\r\\n  \\\"recipe\\\": {\\r\\n    \\\"name\\\": \\\"default\\\",\\r\\n    \\\"variants\\\": \\\"2*, 1*, 3/4*, 1/2*\\\",\\r\\n    \\\"setWidth\\\": false,\\r\\n    \\\"attributes\\\": {\\r\\n      \\\"loading\\\": \\\"lazy\\\"\\r\\n    },\\r\\n    \\\"recipes\\\": [\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap3\\\",\\r\\n        \\\"forCss\\\": \\\"bs3\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-responsive\\\" },\\r\\n        \\\"setWidth\\\": false\\r\\n      },\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap4\\\",\\r\\n        \\\"forCss\\\": \\\"bs4\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-fluid\\\" },\\r\\n        \\\"setWidth\\\": true\\r\\n      },\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap5\\\",\\r\\n        \\\"forCss\\\": \\\"bs5\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-fluid\\\" },\\r\\n        \\\"setWidth\\\": true,\\r\\n        \\\"setHeight\\\" : true,\\r\\n        \\\"recipes\\\": [\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"12/12\\\", \\r\\n            \\\"width\\\": 1230,\\r\\n            \\\"attributes\\\":{\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 100vw, 1230px\\\"\\r\\n            }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"11/12\\\", \\\"width\\\": 1100 },\\r\\n          { \\\"forFactor\\\": \\\"10/12\\\", \\\"width\\\": 1000 },\\r\\n          { \\\"forFactor\\\": \\\"9/12\\\", \\\"width\\\": 900 },\\r\\n          { \\\"forFactor\\\": \\\"8/12\\\", \\\"width\\\": 800 },\\r\\n          { \\\"forFactor\\\": \\\"7/12\\\", \\\"width\\\": 700 },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"6/12\\\", \\r\\n            \\\"width\\\": 600, \\r\\n            \\\"attributes\\\": {\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 50vw, (max-width: 576px) 100vw, 600px\\\" \\r\\n              }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"5/12\\\", \\\"width\\\": 500 },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"4/12\\\", \\r\\n            \\\"width\\\": 390,\\r\\n            \\\"attributes\\\":{\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 34vw, (max-width: 991px) 50vw, (max-width: 575px) 100vw, 390px\\\"\\r\\n            }\\r\\n           },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"3/12\\\", \\r\\n            \\\"width\\\": 285,\\r\\n            \\\"attributes\\\": {\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 25vw, (max-width: 991px) 50vw, (max-width: 575px) 100vw, 285px\\\"\\r\\n              }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"2/12\\\", \\\"width\\\": 170 },\\r\\n          { \\\"forFactor\\\": \\\"1/12\\\", \\\"width\\\":  75 }\\r\\n        ]\\r\\n      }\\r\\n    ]\\r\\n  }\\r\\n}\"\n              },\n              \"Description\": {\n                \"en-us\": \"Standard image sizes / aspect-ratios, usually the default for most pictures.\"\n              },\n              \"Format\": {\n                \"en-us\": \"\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Content\"\n              },\n              \"ResizeMode\": {\n                \"en-us\": \"crop\"\n              },\n              \"ScaleMode\": {\n                \"en-us\": \"both\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Images.Content\"\n              }\n            },\n            \"Number\": {\n              \"AspectRatio\": {\n                \"en-us\": 1.618\n              },\n              \"Height\": {\n                \"en-us\": 865\n              },\n              \"Quality\": {\n                \"en-us\": 75\n              },\n              \"Width\": {\n                \"en-us\": 1400\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166542,\n              \"Version\": 1,\n              \"Guid\": \"0dc356a3-acff-4bcf-b276-a13e46fc3a9d\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"358ce0df-52bf-4877-bf32-19c3fb723c73\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130679,\n          \"Version\": 15,\n          \"Guid\": \"35d4e680-2f92-455a-90b7-4a5a936c287f\",\n          \"Type\": {\n            \"Id\": \"1a86b080-9e0d-4207-97d2-04edf80b4f2f\",\n            \"Name\": \"⚙️Image\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"{\\r\\n  \\\"recipe\\\": {\\r\\n    \\\"name\\\": \\\"default\\\",\\r\\n    \\\"variants\\\": \\\"2*, 1/1*, 3/4*, 1/2*\\\",\\r\\n    \\\"setWidth\\\": false\\r\\n  }\\r\\n}\"\n              },\n              \"Description\": {\n                \"en-us\": \"Large images in lightbox popups.\"\n              },\n              \"Format\": {\n                \"en-us\": \"\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Lightbox\"\n              },\n              \"ResizeMode\": {\n                \"en-us\": \"max\"\n              },\n              \"ScaleMode\": {\n                \"en-us\": \"down\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Images.Lightbox\"\n              }\n            },\n            \"Number\": {\n              \"AspectRatio\": {\n                \"en-us\": 1.333\n              },\n              \"Height\": {\n                \"en-us\": 1500\n              },\n              \"Quality\": {\n                \"en-us\": 75\n              },\n              \"Width\": {\n                \"en-us\": 2000\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166543,\n              \"Version\": 1,\n              \"Guid\": \"e5fefea9-ae40-4151-afcb-619aa88ee09b\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"35d4e680-2f92-455a-90b7-4a5a936c287f\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130680,\n          \"Version\": 16,\n          \"Guid\": \"bdbff289-219d-46d6-b697-5d17050eebe9\",\n          \"Type\": {\n            \"Id\": \"1a86b080-9e0d-4207-97d2-04edf80b4f2f\",\n            \"Name\": \"⚙️Image\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"{\\r\\n  \\\"recipe\\\": {\\r\\n    \\\"name\\\": \\\"default\\\",\\r\\n    \\\"variants\\\": \\\"3000, 2400, 1600, 1200, 800\\\",\\r\\n    \\\"setWidth\\\": false\\r\\n  }\\r\\n}\"\n              },\n              \"Description\": {\n                \"en-us\": \"Typically used for the background behind content, e.g. for parallax effects. \"\n              },\n              \"Format\": {\n                \"en-us\": \"\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Section\"\n              },\n              \"ResizeMode\": {\n                \"en-us\": \"crop\"\n              },\n              \"ScaleMode\": {\n                \"en-us\": \"both\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Images.Section\"\n              }\n            },\n            \"Number\": {\n              \"AspectRatio\": {\n                \"en-us\": 1.333\n              },\n              \"Height\": {\n                \"en-us\": 1200\n              },\n              \"Quality\": {\n                \"en-us\": 60\n              },\n              \"Width\": {\n                \"en-us\": 1600\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166544,\n              \"Version\": 1,\n              \"Guid\": \"6993d8e1-158d-4ca2-baa0-b3b846d49773\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"bdbff289-219d-46d6-b697-5d17050eebe9\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130681,\n          \"Version\": 19,\n          \"Guid\": \"8affa267-ec04-408f-af93-48c0ae693e5c\",\n          \"Type\": {\n            \"Id\": \"1a86b080-9e0d-4207-97d2-04edf80b4f2f\",\n            \"Name\": \"⚙️Image\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"{\\r\\n  \\\"recipe\\\": {\\r\\n    \\\"name\\\": \\\"default\\\",\\r\\n    \\\"variants\\\": \\\"3000, 2400, 1600, 1200, 800\\\",\\r\\n    \\\"setWidth\\\": false\\r\\n  }\\r\\n}\"\n              },\n              \"Description\": {\n                \"en-us\": \"Full-screen images.\"\n              },\n              \"Format\": {\n                \"en-us\": \"\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Screen\"\n              },\n              \"ResizeMode\": {\n                \"en-us\": \"crop\"\n              },\n              \"ScaleMode\": {\n                \"en-us\": \"both\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Images.Screen\"\n              }\n            },\n            \"Number\": {\n              \"AspectRatio\": {\n                \"en-us\": 1.333\n              },\n              \"Height\": {\n                \"en-us\": 1500\n              },\n              \"Quality\": {\n                \"en-us\": 60\n              },\n              \"Width\": {\n                \"en-us\": 2000\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166545,\n              \"Version\": 1,\n              \"Guid\": \"c7a4b6b0-f3e8-45af-aff9-dd498be1f318\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"8affa267-ec04-408f-af93-48c0ae693e5c\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130677,\n          \"Version\": 4,\n          \"Guid\": \"89184eb0-1d4d-4429-8c38-c453f8aa149d\",\n          \"Type\": {\n            \"Id\": \"7edd0b8d-1405-44ed-ac33-d0d63a274bd6\",\n            \"Name\": \"⚙️Images\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Images\"\n              }\n            },\n            \"Entity\": {\n              \"Items\": {\n                \"*\": [\n                  \"358ce0df-52bf-4877-bf32-19c3fb723c73\",\n                  \"35d4e680-2f92-455a-90b7-4a5a936c287f\",\n                  \"bdbff289-219d-46d6-b697-5d17050eebe9\",\n                  \"8affa267-ec04-408f-af93-48c0ae693e5c\",\n                  \"8c454005-9a76-48b2-a63d-7e92a731bb80\",\n                  \"6c155e30-43a4-4564-bf3f-0d80c925c4d7\"\n                ]\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166546,\n              \"Version\": 1,\n              \"Guid\": \"2ec32b16-b553-49d8-9495-2fd9b7d8a8c2\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"89184eb0-1d4d-4429-8c38-c453f8aa149d\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130582,\n          \"Version\": 2,\n          \"Guid\": \"a88c329c-cc6e-4744-b3ec-88c186502d9d\",\n          \"Type\": {\n            \"Id\": \"5ad95efe-1dc9-4681-adb8-42d9e7f0183b\",\n            \"Name\": \"⚙️QuickEdit\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"SettingsIdentifier\": {\n                \"*\": \"QuickEdit\"\n              }\n            },\n            \"Entity\": {\n              \"Items\": {\n                \"*\": [\n                  \"c8e3769a-96e9-4312-8cb4-da24f90b9fdd\",\n                  \"02667ae8-dbb6-4431-81ae-125a22f9e5ac\",\n                  \"89c89890-ab00-42f7-9ee1-c81d79855533\",\n                  \"7cb78140-86e6-401b-bca5-a46ee525b925\"\n                ]\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166547,\n              \"Version\": 1,\n              \"Guid\": \"43f8d589-2948-4a26-8a2f-ff58176ca847\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"a88c329c-cc6e-4744-b3ec-88c186502d9d\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130584,\n          \"Version\": 3,\n          \"Guid\": \"c8e3769a-96e9-4312-8cb4-da24f90b9fdd\",\n          \"Type\": {\n            \"Id\": \"46cd1afc-c840-4473-8586-6bb1f35656a8\",\n            \"Name\": \"⚙️QuickEditPart\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ItemIdentifier\": {\n                \"*\": \"Default\"\n              },\n              \"SettingsIdentifier\": {\n                \"*\": \"QuickEdit.Default\"\n              }\n            },\n            \"Boolean\": {\n              \"AddApp\": {\n                \"*\": true\n              },\n              \"AddContent\": {\n                \"*\": true\n              },\n              \"Enable\": {\n                \"*\": true\n              },\n              \"Move\": {\n                \"*\": true\n              },\n              \"Paste\": {\n                \"*\": true\n              },\n              \"Select\": {\n                \"*\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166548,\n              \"Version\": 1,\n              \"Guid\": \"f7e455a4-51de-4fc5-a97a-d3fb968ccc1b\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"c8e3769a-96e9-4312-8cb4-da24f90b9fdd\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130585,\n          \"Version\": 3,\n          \"Guid\": \"02667ae8-dbb6-4431-81ae-125a22f9e5ac\",\n          \"Type\": {\n            \"Id\": \"46cd1afc-c840-4473-8586-6bb1f35656a8\",\n            \"Name\": \"⚙️QuickEditPart\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ItemIdentifier\": {\n                \"*\": \"Module\"\n              },\n              \"SettingsIdentifier\": {\n                \"*\": \"QuickEdit.Module\"\n              }\n            },\n            \"Boolean\": {\n              \"AddApp\": {\n                \"*\": true\n              },\n              \"AddContent\": {\n                \"*\": true\n              },\n              \"Enable\": {\n                \"*\": true\n              },\n              \"Move\": {\n                \"*\": true\n              },\n              \"Paste\": {\n                \"*\": true\n              },\n              \"Select\": {\n                \"*\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166549,\n              \"Version\": 1,\n              \"Guid\": \"77dcf7a8-40f8-4c81-85e3-d2c4b1c64a76\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"02667ae8-dbb6-4431-81ae-125a22f9e5ac\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130586,\n          \"Version\": 3,\n          \"Guid\": \"89c89890-ab00-42f7-9ee1-c81d79855533\",\n          \"Type\": {\n            \"Id\": \"46cd1afc-c840-4473-8586-6bb1f35656a8\",\n            \"Name\": \"⚙️QuickEditPart\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ItemIdentifier\": {\n                \"*\": \"InnerContentArea\"\n              },\n              \"SettingsIdentifier\": {\n                \"*\": \"QuickEdit.InnerContentArea\"\n              }\n            },\n            \"Boolean\": {\n              \"AddApp\": {\n                \"*\": true\n              },\n              \"AddContent\": {\n                \"*\": true\n              },\n              \"Enable\": {\n                \"*\": true\n              },\n              \"Move\": {\n                \"*\": false\n              },\n              \"Paste\": {\n                \"*\": true\n              },\n              \"Select\": {\n                \"*\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166550,\n              \"Version\": 1,\n              \"Guid\": \"4b931acc-7554-4a5a-8961-643a196e7297\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"89c89890-ab00-42f7-9ee1-c81d79855533\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 130587,\n          \"Version\": 3,\n          \"Guid\": \"7cb78140-86e6-401b-bca5-a46ee525b925\",\n          \"Type\": {\n            \"Id\": \"46cd1afc-c840-4473-8586-6bb1f35656a8\",\n            \"Name\": \"⚙️QuickEditPart\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ItemIdentifier\": {\n                \"*\": \"InnerContentDynamic\"\n              },\n              \"SettingsIdentifier\": {\n                \"*\": \"QuickEdit.InnerContentDynamic\"\n              }\n            },\n            \"Boolean\": {\n              \"AddApp\": {\n                \"*\": true\n              },\n              \"AddContent\": {\n                \"*\": true\n              },\n              \"Enable\": {\n                \"*\": true\n              },\n              \"Move\": {\n                \"*\": false\n              },\n              \"Paste\": {\n                \"*\": false\n              },\n              \"Select\": {\n                \"*\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166551,\n              \"Version\": 1,\n              \"Guid\": \"825217f1-d5b9-44d9-a311-3ec53c241b5c\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"7cb78140-86e6-401b-bca5-a46ee525b925\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 165968,\n          \"Version\": 1,\n          \"Guid\": \"052a5e27-40f8-40bf-bd97-35a6641e9df0\",\n          \"Type\": {\n            \"Id\": \"0948fd10-7ce2-4495-bc6e-7ccb8265857e\",\n            \"Name\": \"⚙️SiteSetup\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Installation\"\n              }\n            },\n            \"Entity\": {\n              \"AutoInstallApps\": {\n                \"*\": []\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166552,\n              \"Version\": 1,\n              \"Guid\": \"4ff9ceef-85f8-4f79-96dc-42c6a25c97db\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"052a5e27-40f8-40bf-bd97-35a6641e9df0\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 169969,\n          \"Version\": 2,\n          \"Guid\": \"8c454005-9a76-48b2-a63d-7e92a731bb80\",\n          \"Type\": {\n            \"Id\": \"1a86b080-9e0d-4207-97d2-04edf80b4f2f\",\n            \"Name\": \"⚙️Image\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"{\\r\\n  \\\"recipe\\\": {\\r\\n    \\\"name\\\": \\\"default\\\",\\r\\n    \\\"variants\\\": \\\"2*, 1*, 3/4*, 1/2*\\\",\\r\\n    \\\"setWidth\\\": false,\\r\\n    \\\"attributes\\\": {\\r\\n      \\\"loading\\\": \\\"lazy\\\"\\r\\n    },\\r\\n    \\\"recipes\\\": [\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap3\\\",\\r\\n        \\\"forCss\\\": \\\"bs3\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-responsive\\\" },\\r\\n        \\\"setWidth\\\": false\\r\\n      },\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap4\\\",\\r\\n        \\\"forCss\\\": \\\"bs4\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-fluid\\\" },\\r\\n        \\\"setWidth\\\": true\\r\\n      },\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap5\\\",\\r\\n        \\\"forCss\\\": \\\"bs5\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-fluid\\\" },\\r\\n        \\\"setWidth\\\": true,\\r\\n        \\\"setHeight\\\" : true,\\r\\n        \\\"recipes\\\": [\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"12/12\\\", \\r\\n            \\\"width\\\": 1230,\\r\\n            \\\"attributes\\\":{\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 100vw, 1230px\\\"\\r\\n            }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"11/12\\\", \\\"width\\\": 1100 },\\r\\n          { \\\"forFactor\\\": \\\"10/12\\\", \\\"width\\\": 1000 },\\r\\n          { \\\"forFactor\\\": \\\"9/12\\\", \\\"width\\\": 900 },\\r\\n          { \\\"forFactor\\\": \\\"8/12\\\", \\\"width\\\": 800 },\\r\\n          { \\\"forFactor\\\": \\\"7/12\\\", \\\"width\\\": 700 },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"6/12\\\", \\r\\n            \\\"width\\\": 600, \\r\\n            \\\"attributes\\\": {\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 50vw, (max-width: 576px) 100vw, 600px\\\" \\r\\n              }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"5/12\\\", \\\"width\\\": 500 },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"4/12\\\", \\r\\n            \\\"width\\\": 390,\\r\\n            \\\"attributes\\\":{\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 34vw, (max-width: 991px) 50vw, (max-width: 575px) 100vw, 390px\\\"\\r\\n            }\\r\\n           },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"3/12\\\", \\r\\n            \\\"width\\\": 285,\\r\\n            \\\"attributes\\\": {\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 25vw, (max-width: 991px) 50vw, (max-width: 575px) 100vw, 285px\\\"\\r\\n              }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"2/12\\\", \\\"width\\\": 170 },\\r\\n          { \\\"forFactor\\\": \\\"1/12\\\", \\\"width\\\":  75 }\\r\\n        ]\\r\\n      }\\r\\n    ]\\r\\n  }\\r\\n}\"\n              },\n              \"Description\": {\n                \"en-us\": \"Recommended for auto-resizing images shown in wysiwyg content - eg. in blogs.\"\n              },\n              \"Format\": {\n                \"en-us\": \"\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Wysiwyg\"\n              },\n              \"ResizeMode\": {\n                \"en-us\": \"max\"\n              },\n              \"ScaleMode\": {\n                \"en-us\": \"both\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Images.Wysiwyg\"\n              }\n            },\n            \"Number\": {\n              \"Height\": {\n                \"en-us\": 1400\n              },\n              \"Quality\": {\n                \"en-us\": 75\n              },\n              \"Width\": {\n                \"en-us\": 1400\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 169970,\n              \"Version\": 1,\n              \"Guid\": \"2987dbad-0186-4bc0-9684-685ddf64a1e2\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"8c454005-9a76-48b2-a63d-7e92a731bb80\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 175300,\n          \"Version\": 2,\n          \"Guid\": \"6c155e30-43a4-4564-bf3f-0d80c925c4d7\",\n          \"Type\": {\n            \"Id\": \"1a86b080-9e0d-4207-97d2-04edf80b4f2f\",\n            \"Name\": \"⚙️Image\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"{\\r\\n  \\\"recipe\\\": {\\r\\n    \\\"name\\\": \\\"default\\\",\\r\\n    \\\"variants\\\": \\\"2*, 1*, 3/4*, 1/2*\\\",\\r\\n    \\\"setWidth\\\": false,\\r\\n    \\\"attributes\\\": {\\r\\n      \\\"loading\\\": \\\"lazy\\\"\\r\\n    },\\r\\n    \\\"recipes\\\": [\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap3\\\",\\r\\n        \\\"forCss\\\": \\\"bs3\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-responsive\\\" },\\r\\n        \\\"setWidth\\\": false\\r\\n      },\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap4\\\",\\r\\n        \\\"forCss\\\": \\\"bs4\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-fluid\\\" },\\r\\n        \\\"setWidth\\\": true\\r\\n      },\\r\\n      {\\r\\n        \\\"name\\\": \\\"Bootstrap5\\\",\\r\\n        \\\"forCss\\\": \\\"bs5\\\",\\r\\n        \\\"attributes\\\": { \\\"class\\\": \\\"img-fluid\\\" },\\r\\n        \\\"setWidth\\\": true,\\r\\n        \\\"setHeight\\\" : true,\\r\\n        \\\"recipes\\\": [\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"12/12\\\", \\r\\n            \\\"width\\\": 1230,\\r\\n            \\\"attributes\\\":{\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 100vw, 1230px\\\"\\r\\n            }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"11/12\\\", \\\"width\\\": 1100 },\\r\\n          { \\\"forFactor\\\": \\\"10/12\\\", \\\"width\\\": 1000 },\\r\\n          { \\\"forFactor\\\": \\\"9/12\\\", \\\"width\\\": 900 },\\r\\n          { \\\"forFactor\\\": \\\"8/12\\\", \\\"width\\\": 800 },\\r\\n          { \\\"forFactor\\\": \\\"7/12\\\", \\\"width\\\": 700 },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"6/12\\\", \\r\\n            \\\"width\\\": 600, \\r\\n            \\\"attributes\\\": {\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 50vw, (max-width: 576px) 100vw, 600px\\\" \\r\\n              }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"5/12\\\", \\\"width\\\": 500 },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"4/12\\\", \\r\\n            \\\"width\\\": 390,\\r\\n            \\\"attributes\\\":{\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 34vw, (max-width: 991px) 50vw, (max-width: 575px) 100vw, 390px\\\"\\r\\n            }\\r\\n           },\\r\\n          { \\r\\n            \\\"forFactor\\\": \\\"3/12\\\", \\r\\n            \\\"width\\\": 285,\\r\\n            \\\"attributes\\\": {\\r\\n              \\\"sizes\\\": \\\"(max-width: 1400px) 25vw, (max-width: 991px) 50vw, (max-width: 575px) 100vw, 285px\\\"\\r\\n              }\\r\\n          },\\r\\n          { \\\"forFactor\\\": \\\"2/12\\\", \\\"width\\\": 170 },\\r\\n          { \\\"forFactor\\\": \\\"1/12\\\", \\\"width\\\":  75 }\\r\\n        ]\\r\\n      }\\r\\n    ]\\r\\n  }\\r\\n}\"\n              },\n              \"Description\": {\n                \"en-us\": \"Square images such as profile pictures.\"\n              },\n              \"Format\": {\n                \"en-us\": \"\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"Square\"\n              },\n              \"ResizeMode\": {\n                \"en-us\": \"crop\"\n              },\n              \"ScaleMode\": {\n                \"en-us\": \"both\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Images.Square\"\n              }\n            },\n            \"Number\": {\n              \"AspectRatio\": {\n                \"en-us\": 1\n              },\n              \"Height\": {\n                \"en-us\": 865\n              },\n              \"Quality\": {\n                \"en-us\": 73\n              },\n              \"Width\": {\n                \"en-us\": 1400\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 175301,\n              \"Version\": 1,\n              \"Guid\": \"7d64cbc8-6c71-433f-b691-bb5e0dcab9fa\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"6c155e30-43a4-4564-bf3f-0d80c925c4d7\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 182644,\n          \"Version\": 2,\n          \"Guid\": \"7116c320-769d-4d7c-94ef-76c176a17ba2\",\n          \"Type\": {\n            \"Id\": \"aed871cf-220b-4330-b368-f1259981c9c8\",\n            \"Name\": \"⚙️CopyrightSettings\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"SettingsIdentifier\": {\n                \"en-us\": \"Copyright\"\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 182645,\n              \"Version\": 1,\n              \"Guid\": \"e6913d5f-d209-4dce-af00-a8dd39140f1b\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"7116c320-769d-4d7c-94ef-76c176a17ba2\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 185454,\n          \"Version\": 2,\n          \"Guid\": \"22930727-fb85-4dfb-86b1-6517b34ac386\",\n          \"Type\": {\n            \"Id\": \"60131b0d-d042-43c8-a4a7-fb44a45db60c\",\n            \"Name\": \"⚙️InputFields\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"SettingsIdentifier\": {\n                \"en-us\": \"InputFields\"\n              }\n            },\n            \"Entity\": {\n              \"Items\": {\n                \"*\": [\n                  \"e69e447f-8534-4182-8e56-8b0f987a48a9\"\n                ]\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 185461,\n              \"Version\": 1,\n              \"Guid\": \"53a7f6d5-a072-4037-b6e7-c12e770a7a9c\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"22930727-fb85-4dfb-86b1-6517b34ac386\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 185455,\n          \"Version\": 1,\n          \"Guid\": \"e69e447f-8534-4182-8e56-8b0f987a48a9\",\n          \"Type\": {\n            \"Id\": \"f8a6ed24-11c0-42c4-9022-409989489563\",\n            \"Name\": \"⚙️InputFieldsWysiwygSettings\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"ButtonSource\": {\n                \"en-us\": \"\"\n              },\n              \"ButtonSourceInDebugMode\": {\n                \"en-us\": \"\"\n              },\n              \"EditorPlugin\": {\n                \"en-us\": \"tinymce\"\n              },\n              \"ItemIdentifier\": {\n                \"en-us\": \"StringWysiwyg\"\n              },\n              \"SettingsIdentifier\": {\n                \"en-us\": \"InputFields.StringWysiwyg\"\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 185462,\n              \"Version\": 1,\n              \"Guid\": \"333b2897-4edd-43c2-a656-b0b22815fdad\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"48e9f943-45da-49b4-9ceb-2b91bb6a54be\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"e69e447f-8534-4182-8e56-8b0f987a48a9\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system-wysiwyg-configs.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"63a00a8a-39d8-410d-ae45-ab09ef07af5b\",\n            \"Name\": \"StringWysiwygConfiguration\",\n            \"Scope\": \"System.Fields\",\n            \"Metadata\": [\n              {\n                \"Id\": 164748,\n                \"Version\": 4,\n                \"Guid\": \"a376b4ec-1ae0-4295-a696-f7a8efe8cc87\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This is an advanced way to configure your wysiwyg, new / WIP v15.04.</p>\\n<p>\\uD83D\\uDC49\\uD83C\\uDFFD Do consult the <a href=\\\"http://r.2sxc.org/string-wyswiyg\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">string-wysiwyg docs</a>.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"String WYSIWYG Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"63a00a8a-39d8-410d-ae45-ab09ef07af5b\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164749,\n                    \"Version\": 4,\n                    \"Guid\": \"616e5886-0e71-4dca-83fe-6c59374faaed\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Name of this configuration so it's easier to identify when used</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164752,\n                    \"Version\": 3,\n                    \"Guid\": \"dd30ef07-c971-4c62-8de5-7c36a45d837c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164753,\n                    \"Version\": 3,\n                    \"Guid\": \"dea28b78-12cb-4d29-a3da-e1ef41a9a7ae\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Mode\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164751,\n                    \"Version\": 9,\n                    \"Guid\": \"f2b55ac9-29da-43f4-9a99-a2329412de45\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Mode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>A preset from which to base your custom configuration.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164754,\n                    \"Version\": 8,\n                    \"Guid\": \"57c69b36-98d6-406b-a378-769554d7c7e7\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164755,\n                    \"Version\": 8,\n                    \"Guid\": \"2df16e5a-df0a-48dc-8b2b-28cff2408ffd\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"default:Default WYSIWYG configuration\\ntext:Text WYSIWYG - optimized for formatted text without images etc.\\ntext-basic:Text-Basic - Simplified text, without headings\\ntext-minimal:Text-Minigal - Very reduced text without headings or bullets\\ntext-plain:Text-Plain - basically not a wysiwyg\\nrich:Rich Media / Images for long bodies such as Blogs\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"MessageModeRich\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 171650,\n                    \"Version\": 3,\n                    \"Guid\": \"bd265ac7-08bb-4162-a856-bb2981cc430d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"MessageModeRich\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>To learn about the new rich mode and how the Razor much be modified to support this, see <a href=\\\"https://r.2sxc.org/wysiwyg-rich\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">r.2sxc.org/wysiwyg-rich</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"c842ce13-f28b-4104-97d3-209bcf3a312a\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CustomConfiguration\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166479,\n                    \"Version\": 2,\n                    \"Guid\": \"879aa3a6-9978-46a9-a079-e6cb4c3bb651\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"CustomConfiguration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166480,\n                    \"Version\": 1,\n                    \"Guid\": \"131a7da0-949e-4103-90e8-930baecfef95\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Use Mode-Presets\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Override Presets with Custom Settings\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Advanced\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-json\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 164750,\n                    \"Version\": 4,\n                    \"Guid\": \"5a7aec8e-adea-4724-b122-83a370cf1024\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-json\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"75c5a65b-e2ce-455e-9f1e-1bcde7b63c74\",\n                            \"eb12c7d9-2c4c-476e-bfb5-b9d1aff55854\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164756,\n                    \"Version\": 1,\n                    \"Guid\": \"ecfc6ff2-58b6-4915-85ba-8b52e6bef540\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 164757,\n                    \"Version\": 1,\n                    \"Guid\": \"9d5ffee7-04eb-4a3e-92fe-90ca50c60e1b\",\n                    \"Type\": {\n                      \"Id\": \"@string-json\",\n                      \"Name\": \"@string-json\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"JsonSchemaMode\": {\n                          \"en-us\": \"none\"\n                        },\n                        \"JsonSchemaRaw\": {\n                          \"en-us\": \"\"\n                        },\n                        \"JsonSchemaSource\": {\n                          \"en-us\": \"link\"\n                        },\n                        \"JsonValidation\": {\n                          \"en-us\": \"strict\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"JsonSchemaUrl\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"Rows\": {\n                          \"en-us\": 25\n                        }\n                      },\n                      \"Boolean\": {\n                        \"JsonCommentsAllowed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 167715,\n              \"Version\": 2,\n              \"Guid\": \"75c5a65b-e2ce-455e-9f1e-1bcde7b63c74\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => { return !context.debug; });\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Disabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 166481,\n              \"Version\": 2,\n              \"Guid\": \"eb12c7d9-2c4c-476e-bfb5-b9d1aff55854\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.CustomConfiguration; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 171651,\n              \"Version\": 1,\n              \"Guid\": \"c842ce13-f28b-4104-97d3-209bcf3a312a\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.Mode == 'rich';\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ],\n      \"Entities\": [\n        {\n          \"Id\": 164758,\n          \"Version\": 4,\n          \"Guid\": \"d3dde02f-c1dc-43b8-a8b7-4be3c43eadd0\",\n          \"Type\": {\n            \"Id\": \"63a00a8a-39d8-410d-ae45-ab09ef07af5b\",\n            \"Name\": \"StringWysiwygConfiguration\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"\"\n              },\n              \"Mode\": {\n                \"en-us\": \"default\"\n              },\n              \"Title\": {\n                \"en-us\": \"Default\"\n              }\n            },\n            \"Boolean\": {\n              \"CustomConfiguration\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166511,\n              \"Version\": 1,\n              \"Guid\": \"436d4a9d-a5ee-45d2-a59c-cd710634938e\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"fdc0d360-3e20-4794-ac20-9bb57899cd24\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"d3dde02f-c1dc-43b8-a8b7-4be3c43eadd0\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 164759,\n          \"Version\": 4,\n          \"Guid\": \"3e9dd123-ccef-4d81-80e7-4c6ae6f5ddc6\",\n          \"Type\": {\n            \"Id\": \"63a00a8a-39d8-410d-ae45-ab09ef07af5b\",\n            \"Name\": \"StringWysiwygConfiguration\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"\"\n              },\n              \"Mode\": {\n                \"en-us\": \"text-minimal\"\n              },\n              \"Title\": {\n                \"en-us\": \"Text-Minimal - Only very basic formatting\"\n              }\n            },\n            \"Boolean\": {\n              \"CustomConfiguration\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166512,\n              \"Version\": 1,\n              \"Guid\": \"a709a155-de65-4621-9a64-4ab1ebb02fe4\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"fdc0d360-3e20-4794-ac20-9bb57899cd24\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"3e9dd123-ccef-4d81-80e7-4c6ae6f5ddc6\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 166477,\n          \"Version\": 3,\n          \"Guid\": \"d8d6e212-4878-4483-be4a-3de865a85ee6\",\n          \"Type\": {\n            \"Id\": \"63a00a8a-39d8-410d-ae45-ab09ef07af5b\",\n            \"Name\": \"StringWysiwygConfiguration\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"\"\n              },\n              \"Mode\": {\n                \"en-us\": \"text\"\n              },\n              \"Title\": {\n                \"en-us\": \"Text-Default - For Text Editing without Images/Media\"\n              }\n            },\n            \"Boolean\": {\n              \"CustomConfiguration\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166513,\n              \"Version\": 1,\n              \"Guid\": \"4ef8ac28-beeb-4243-b6dd-644dc38a5d02\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"fdc0d360-3e20-4794-ac20-9bb57899cd24\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"d8d6e212-4878-4483-be4a-3de865a85ee6\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 166478,\n          \"Version\": 8,\n          \"Guid\": \"52d79da0-b10d-4f62-9838-2e17b2254a3e\",\n          \"Type\": {\n            \"Id\": \"63a00a8a-39d8-410d-ae45-ab09ef07af5b\",\n            \"Name\": \"StringWysiwygConfiguration\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"\"\n              },\n              \"Mode\": {\n                \"en-us\": \"rich\"\n              },\n              \"Title\": {\n                \"en-us\": \"Rich Media (new 16.01) - With Images and Layout (for Blogs, News etc.)\"\n              }\n            },\n            \"Boolean\": {\n              \"CustomConfiguration\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166514,\n              \"Version\": 1,\n              \"Guid\": \"6625e473-3466-4129-b1f6-e3b39ca4130d\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"fdc0d360-3e20-4794-ac20-9bb57899cd24\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"52d79da0-b10d-4f62-9838-2e17b2254a3e\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 166515,\n          \"Version\": 2,\n          \"Guid\": \"c2d17507-e076-4a93-a9f9-e94e7ecc7e96\",\n          \"Type\": {\n            \"Id\": \"63a00a8a-39d8-410d-ae45-ab09ef07af5b\",\n            \"Name\": \"StringWysiwygConfiguration\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"\"\n              },\n              \"Mode\": {\n                \"en-us\": \"text-basic\"\n              },\n              \"Title\": {\n                \"en-us\": \"Text-Basic - Like Text, but without Headers\"\n              }\n            },\n            \"Boolean\": {\n              \"CustomConfiguration\": {\n                \"en-us\": false\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 166516,\n              \"Version\": 1,\n              \"Guid\": \"ca702550-5d92-48ec-bace-baf97310afe5\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"fdc0d360-3e20-4794-ac20-9bb57899cd24\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"c2d17507-e076-4a93-a9f9-e94e7ecc7e96\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 167713,\n          \"Version\": 5,\n          \"Guid\": \"df032556-2d8a-40d7-bc35-57ec9088f15d\",\n          \"Type\": {\n            \"Id\": \"63a00a8a-39d8-410d-ae45-ab09ef07af5b\",\n            \"Name\": \"StringWysiwygConfiguration\"\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"Advanced\": {\n                \"en-us\": \"\"\n              },\n              \"Mode\": {\n                \"en-us\": \"text-plain\"\n              },\n              \"Title\": {\n                \"en-us\": \"Text-Plain - Really just text, basically not a WYSIWYG\"\n              }\n            },\n            \"Boolean\": {\n              \"CustomConfiguration\": {\n                \"en-us\": true\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 167714,\n              \"Version\": 1,\n              \"Guid\": \"0a4d1e62-2ca1-45e9-9e78-2ac548b8b5ed\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"fdc0d360-3e20-4794-ac20-9bb57899cd24\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"df032556-2d8a-40d7-bc35-57ec9088f15d\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/bundles/system.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"Bundles\": [\n    {\n      \"Name\": \"default\",\n      \"ContentTypes\": [\n        {\n          \"ContentType\": {\n            \"Id\": \"ContentType\",\n            \"Name\": \"ContentType\",\n            \"Scope\": \"System\",\n            \"Metadata\": [\n              {\n                \"Id\": 45144,\n                \"Version\": 3,\n                \"Guid\": \"0047f7c3-26ee-44bb-9ab4-9eec48e37837\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"en-us\": \"Description of a Content-Type (Metadata)\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>This is (optional) metadata for the content-type. Imagine it as added information, which if available, will be used in dialogs to enhance the user experience.&nbsp;</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Content Type\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"<p>These are Metadata for existing Content-Types. Please edit with caution. Make sure you know what you're doing.&nbsp;</p>\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"ContentType\"\n                }\n              },\n              {\n                \"Id\": 137458,\n                \"Version\": 2,\n                \"Guid\": \"da6abab0-fa90-4bf9-bd1d-b0acc7288b35\",\n                \"Type\": {\n                  \"Id\": \"4c88d78f-5f3e-4b66-95f2-6d63b7858847\",\n                  \"Name\": \"MetadataForDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DeleteWarning\": {\n                      \"en-us\": \"<p>This usually contains descriptions for content-types, and shouldn't be deleted.</p>\"\n                    },\n                    \"TargetName\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Title\": {\n                      \"en-us\": \"Metadata for ContentTypes\"\n                    }\n                  },\n                  \"Number\": {\n                    \"Amount\": {\n                      \"en-us\": 1\n                    },\n                    \"TargetType\": {\n                      \"en-us\": 5\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"ContentType\"\n                }\n              },\n              {\n                \"Id\": 142656,\n                \"Version\": 1,\n                \"Guid\": \"b51d7b5a-3085-4087-b7cc-8f347434d171\",\n                \"Type\": {\n                  \"Id\": \"5e958dc6-2922-4d68-835c-7b9711538b12\",\n                  \"Name\": \"NoteDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Note\": {\n                      \"en-us\": \"<p>Warning: This data contains name/description of this Content-Type. You usually don't want to delete it.&nbsp;</p>\"\n                    },\n                    \"NoteType\": {\n                      \"en-us\": \"System.Warning.Delete\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"ContentType\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Label\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45101,\n                    \"Version\": 1,\n                    \"Guid\": \"12a7a6cd-4af8-43fd-9602-5194deb7e476\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Label\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is the nice name shown in the&nbsp;end user dialogs. You should keep it&nbsp;short and simple. Read the recommendations in <a href=\\\"http://2sxc.org/help?tag=content-type\\\" target=\\\"_blank\\\">help</a>.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45102,\n                    \"Version\": 1,\n                    \"Guid\": \"b83fc329-1fbf-486c-a90c-ee0180430930\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45103,\n                    \"Version\": 1,\n                    \"Guid\": \"f655d08d-08dd-424a-be8c-766c35d68785\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45104,\n                    \"Version\": 1,\n                    \"Guid\": \"deb013df-b677-45a2-b3fd-72fdae4bb2cc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Description\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>A nice description of what this content-type is for. It will be shown as tool-tip or help-text in normal user dialogs, so keep it&nbsp;simple and non-techie.&nbsp;</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45105,\n                    \"Version\": 1,\n                    \"Guid\": \"100a0948-c079-4266-a836-bedd739f4e85\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45106,\n                    \"Version\": 1,\n                    \"Guid\": \"887c5090-8dd4-4b44-bd25-61d95970dda9\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1.0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupMore\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130220,\n                    \"Version\": 3,\n                    \"Guid\": \"67c64f34-3f6e-4bdb-a5c6-9e71cdbfb8e1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"More Settings like Icon, Notes etc.\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8c586209-0552-4a8d-ba6b-5f614040b370\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130221,\n                    \"Version\": 2,\n                    \"Guid\": \"e6748899-cbc6-4e26-beba-22435542f0c3\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Notes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45107,\n                    \"Version\": 1,\n                    \"Guid\": \"26aaee3d-f546-46a6-883b-11750002b796\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Notes\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Use this for internal, technical notes. It won't be shown to the content editors.&nbsp;</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45108,\n                    \"Version\": 1,\n                    \"Guid\": \"05690831-7509-42fb-89e8-df7796ceab1e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Icon\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45109,\n                    \"Version\": 4,\n                    \"Guid\": \"18de4b80-06da-4f59-8c72-a015c44935a1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Icon\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Give this content-type an icon to use in tile-style buttons - see <a href=\\\"https://r.2sxc.org/app-icons\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>. We recommend using the [App:Path] placeholder.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"Drop file or use [App:Path]/file-in-your-app.png\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"5090e000-abab-403c-9aa8-1601824550d1\",\n                            null\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45110,\n                    \"Version\": 3,\n                    \"Guid\": \"5320a089-48d4-4204-834f-f2e631311847\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Link\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45111,\n                    \"Version\": 1,\n                    \"Guid\": \"afdcadc4-58e4-4229-afe5-049aa17c160d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Link\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This is an optional link to further information, tutorials, help, etc. It will be shown to the end user if such a link exists.&nbsp;</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45112,\n                    \"Version\": 1,\n                    \"Guid\": \"13473a70-31e4-4498-90b8-bdc2f574eff3\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultDialog\": {\n                          \"*\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"*\": \"\"\n                        },\n                        \"Paths\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"*\": false\n                        },\n                        \"ShowFileManager\": {\n                          \"*\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"*\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupInstructions\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130218,\n                    \"Version\": 4,\n                    \"Guid\": \"19f674bb-a807-4045-9c4d-f3a556bb29fd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Instructions for the User\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"de7676c0-37ff-493c-a73b-c6109375c530\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130219,\n                    \"Version\": 3,\n                    \"Guid\": \"219bffff-a0c9-4cb4-98cc-2fe6c89e39e7\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"EditInstructions\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45113,\n                    \"Version\": 1,\n                    \"Guid\": \"3773eafb-d6a6-4743-9493-011106ac3c28\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Edit Instructions\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>Instructions shown to the user in the edit-form for additional help/assistance.</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45114,\n                    \"Version\": 1,\n                    \"Guid\": \"70caeef5-cdad-48f8-8be1-7ef3bba85b8f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ListInstructions\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 53702,\n                    \"Version\": 2,\n                    \"Guid\": \"c04c5a13-2cc8-4fcf-a087-aaea57df08ba\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"*\": \"List Instructions\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>This text will be shown above the normal list of items to provide context or help. That will be implemented in 2sxc 10, ATM it doesn't happen yet.&nbsp;</p>\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 53703,\n                    \"Version\": 1,\n                    \"Guid\": \"1038d30e-f402-4768-ac98-5ddc44c91dec\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupFormulas\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 169124,\n                    \"Version\": 2,\n                    \"Guid\": \"d03a606d-0a2d-47d8-b664-3bca21c55ace\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Formula Settings Σ (experimental v15)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Configure special settings for formulas editing this content type. See <a href=\\\"https://r.2sxc.org/formulas\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a>.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 169125,\n                    \"Version\": 1,\n                    \"Guid\": \"6449d62f-381a-4863-b4d6-6a8aff0d71b8\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AdditionalSettings\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 166606,\n                    \"Version\": 8,\n                    \"Guid\": \"8e5012f4-558f-47cc-9078-187057b1b065\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"System Settings to allow Formulas to use (beta)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Specify what settings will be broadcast to use in the formula.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166607,\n                    \"Version\": 6,\n                    \"Guid\": \"c579910e-4251-4d30-9b58-4b543e531d9f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166608,\n                    \"Version\": 2,\n                    \"Guid\": \"9c851730-9965-4264-a3dc-543b349bfeda\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 166609,\n                    \"Version\": 4,\n                    \"Guid\": \"9dc2fc7a-0337-4bda-b271-ced10a49b0f7\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Settings\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Title\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupHidden\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130631,\n                    \"Version\": 2,\n                    \"Guid\": \"e8a10191-e3d0-49f1-984b-e128d1006089\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Super WIP / Beta Properties - don't touch\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8896ecb9-5e91-471b-8fac-d704160e5b85\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 130634,\n                    \"Version\": 1,\n                    \"Guid\": \"ccf51162-2758-4403-ade2-f6b896a3ba31\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DynamicChildrenField\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 130632,\n                    \"Version\": 1,\n                    \"Guid\": \"91d82501-b529-4f5c-802d-6617d02c4dc3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"DynamicChildrenField\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 130256,\n              \"Version\": 1,\n              \"Guid\": \"8c586209-0552-4a8d-ba6b-5f614040b370\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { return data.default + ( data.Notes || data.Icon || data.Link ? ' ✅' : '') ; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name: Indicate content\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 163997,\n              \"Version\": 3,\n              \"Guid\": \"5090e000-abab-403c-9aa8-1601824550d1\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  const icon = data.Icon.toLowerCase();\\n  if (icon.indexOf('[app:path]/') == 0)\\n    return data.default + ' \\uD83D\\uDC4D\\uD83C\\uDFFD [App:Path]/... is the best option';\\n  if (icon.indexOf('file:') == 0)\\n    return data.default + \\\" ⚠️ using 'file:...' is not ideal, see docs link in description below\\\";\\n  return data.default;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130255,\n              \"Version\": 2,\n              \"Guid\": \"de7676c0-37ff-493c-a73b-c6109375c530\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data) { \\n  return data.default + (data.EditInstructions || data.ListInstructions ? ' ✅' : ''); \\n}\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Name: Indicate it has content\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 130633,\n              \"Version\": 1,\n              \"Guid\": \"8896ecb9-5e91-471b-8fac-d704160e5b85\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"*\": \"v1(data, context) { return context.debug; }\"\n                  },\n                  \"Notes\": {\n                    \"*\": \"\"\n                  },\n                  \"Target\": {\n                    \"*\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"*\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"*\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"PermissionConfiguration\",\n            \"Name\": \"PermissionConfiguration\",\n            \"Scope\": \"System\",\n            \"Metadata\": [\n              {\n                \"Id\": 45147,\n                \"Version\": 5,\n                \"Guid\": \"bc962fea-544d-4cad-9da9-8bef0fb1d29c\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"For configuring permissions.\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"<p>Configure the permissions of views or content-types (see <a href=\\\"https://github.com/2sic/2sxc/wiki/concept-permissions\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">wiki</a>).&nbsp;</p>\\n<p>If you want to use new user-identity or groups in the permissions, you'll need to enable the <a href=\\\"https://2sxc.org/en/installations/feat/47c71ee9-ac7b-45bf-a08b-dfc8ce7c7775\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">user-feature</a> or <a href=\\\"https://2sxc.org/en/installations/feat/0fd479cc-300f-47fd-88fd-8f2fe092bc09\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">group-feature</a>.&nbsp;For the public-users-can-<em>only-create draft data</em>, make sure you also enable <a href=\\\"https://2sxc.org/en/installations/feat/d93baf71-74c6-4956-9fe0-8281acdfd14a\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">that feature</a>.</p>\"\n                    },\n                    \"Label\": {\n                      \"*\": \"Permission Configuration\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"PermissionConfiguration\"\n                }\n              },\n              {\n                \"Id\": 185423,\n                \"Version\": 1,\n                \"Guid\": \"cd6417ac-70be-4cb3-b33d-2525ad781b30\",\n                \"Type\": {\n                  \"Id\": \"9db5de57-7c16-4370-8d16-a8bf4cfe8e5b\",\n                  \"Name\": \"DataStorageDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DataProcessingHandler\": {\n                      \"en-us\": \"ToSic.Eav.Metadata.Sys.PermissionDataProcessor\"\n                    },\n                    \"StoreType\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"SaveIsDisabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"PermissionConfiguration\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45139,\n                    \"Version\": 3,\n                    \"Guid\": \"9058ec65-2c69-47f0-a641-37d697abe0c1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DefaultValue\": {\n                          \"*\": \"Security Rule\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Title\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>A title just to help you know what this rule is for.&nbsp;</p>\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"PermissionType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 139994,\n                    \"Version\": 3,\n                    \"Guid\": \"a8b1910d-e4cf-42a7-9aca-8b1a4f927f4c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Permission Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139995,\n                    \"Version\": 1,\n                    \"Guid\": \"db865551-f2cb-41e2-abe6-c0ea1bde32d9\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 139996,\n                    \"Version\": 1,\n                    \"Guid\": \"2dde4c5d-c027-48ee-b101-a1cbcdc1e15f\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Choose a type to get better guidance in selecting permissions\\ncontenttype:Content-Type Permissions\\nlanguage:Language Permissions\\nquery:Query Permissions\\napp:App Permissions\\nview:View Permissions\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"InstructionsLanguage\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 139998,\n                    \"Version\": 2,\n                    \"Guid\": \"2979f262-ac25-4e0e-b418-c5e4a1252feb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Language Permissions\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>To set language permissions, specify a user-group name in the identity, and \\\"Edit\\\" in the Grant.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"5449b7a7-2370-4b92-9893-14a2e6ac199e\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Identity\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 46137,\n                    \"Version\": 6,\n                    \"Guid\": \"9698ff5c-330c-477b-8d22-13dda68413dd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Identity\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"You can type in a user GUID here, or group number(s) like \\\"5, 12\\\". Make sure you enable the feature.\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46138,\n                    \"Version\": 5,\n                    \"Guid\": \"20e5f2c4-5f9a-43b7-816f-dcd7c1ef9b9f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 46139,\n                    \"Version\": 5,\n                    \"Guid\": \"f771be81-f781-45b1-92a4-cdef397301f3\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Condition\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45140,\n                    \"Version\": 5,\n                    \"Guid\": \"bceeaca4-3bed-4234-9306-3e82e06c6a98\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Condition\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Why this security rule should apply. <br />\\r\\nLearn more on&nbsp;<a href=\\\"http://2sxc.org/en/help?tag=permissionsconfiguration\\\" target=\\\"_blank\\\" style=\\\"font-size: 13px; line-height: 18px;\\\">2sxc.org/help?tag=permissions</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"561a7c04-037a-4ae0-a1d8-2c2dbbfbeb2c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45141,\n                    \"Version\": 4,\n                    \"Guid\": \"118f46a3-f732-4c6f-beae-9a28d23841de\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45148,\n                    \"Version\": 3,\n                    \"Guid\": \"00e1395e-3d43-44e2-b94b-ce90567411eb\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"Please Select:\\nAnonymous (any user):SecurityAccessLevel.Anonymous\\nView:SecurityAccessLevel.View\\nEdit:SecurityAccessLevel.Edit\\nAdmin:SecurityAccessLevel.Admin\\nHost:SecurityAccessLevel.Host\\nAuthor / Creator of a Content-Item:Owner\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Grant\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45142,\n                    \"Version\": 8,\n                    \"Guid\": \"07cacd48-4e7d-47fb-997b-2a2d4ec56096\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"-\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Grant\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>What we will grant in this rule.&nbsp;<br />\\r\\n<span>Learn more on&nbsp;</span><a href=\\\"http://2sxc.org/en/help?tag=permissionsconfiguration\\\" target=\\\"_blank\\\">2sxc.org/help?tag=permissions</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"8c45026c-8701-4b94-ac83-6386d01c8aa3\",\n                            \"eed58642-7465-4075-857b-fbe562b2df35\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45143,\n                    \"Version\": 7,\n                    \"Guid\": \"5c8e94dd-b3b2-40bd-87d6-d7540ef76278\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45149,\n                    \"Version\": 6,\n                    \"Guid\": \"35e59922-5e4c-409a-805d-026d8f0b7676\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"None (no permissions defined):-\\nRead:r\\nCreate (no read or edit):c\\nUpdate (read and modify existing):ru\\nDelete:d\\nEdit (Create, Read, Update, Delete):crud\\nAll Content (CRUD + Approve):cruda\\nAll Content + Permissions:crudap\\nDesign/Develop (modify internal structure):crudav\\nDesign and Permissions:crudavp\\nFull Control (usually host only):crudavpz\\nRead schema (applies to content-types):$\\nRead drafts (applies to content-types):ř\\nCreate draft (applies to content-types):č\\nUpdate drafts (applies to content-types):ǔ\\nEdit draft CRUD (applies to centent-types):řčǔď\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 139999,\n              \"Version\": 2,\n              \"Guid\": \"5449b7a7-2370-4b92-9893-14a2e6ac199e\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.PermissionType == 'language'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 139997,\n              \"Version\": 2,\n              \"Guid\": \"561a7c04-037a-4ae0-a1d8-2c2dbbfbeb2c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) { return data.PermissionType != 'language'; }\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 140000,\n              \"Version\": 2,\n              \"Guid\": \"8c45026c-8701-4b94-ac83-6386d01c8aa3\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  // if language, only allow crud\\n  return data.PermissionType == 'language' ? 'crud' : data.value;\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 140001,\n              \"Version\": 2,\n              \"Guid\": \"eed58642-7465-4075-857b-fbe562b2df35\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v1(data, context) {\\n  // if language, only allow crud\\n  return data.PermissionType == 'language';\\n}\"\n                  },\n                  \"Notes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Disabled\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Setting Disabled\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"2SexyContent-App\",\n            \"Name\": \"2SexyContent-App\",\n            \"Scope\": \"System.App\",\n            \"Metadata\": [\n              {\n                \"Id\": 45264,\n                \"Version\": 2,\n                \"Guid\": \"fea7925f-3fb1-42a4-b923-161f2ebc84c1\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Description\": {\n                      \"*\": \"Describes a 2sxc App\"\n                    },\n                    \"EditInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Label\": {\n                      \"*\": \"App Specifications\"\n                    },\n                    \"ListInstructions\": {\n                      \"*\": \"\"\n                    },\n                    \"Notes\": {\n                      \"*\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"*\": \"\"\n                    },\n                    \"Link\": {\n                      \"*\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=1\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"2SexyContent-App\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"DisplayName\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45242,\n                    \"Version\": 2,\n                    \"Guid\": \"49f597af-2a2e-4216-b42f-2290b97893c2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Display Name\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"The name of the app as shown in the app-picker. Can be translated to other languages as needed.\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45250,\n                    \"Version\": 1,\n                    \"Guid\": \"02bc09e6-f565-4c5e-b893-5fc2859bc85e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45251,\n                    \"Version\": 1,\n                    \"Guid\": \"5130aee7-c5ef-4fe1-94a3-3856ffeaed28\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45243,\n                    \"Version\": 2,\n                    \"Guid\": \"3e231c29-d0d0-4f40-bbb8-5c1f454c1277\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Description\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"A short description of this app - more for your own use.\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45252,\n                    \"Version\": 1,\n                    \"Guid\": \"2a2257ac-2ffc-4cbf-a58d-9fa8bf40062f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {},\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45253,\n                    \"Version\": 1,\n                    \"Guid\": \"c4eb0496-a36b-4390-82d5-5dfeae93ad4b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Version\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45244,\n                    \"Version\": 3,\n                    \"Guid\": \"1144757d-5ac3-435a-80e0-fb604b049370\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"00.00.01\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Version\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"A version - needed for various checks - in the format 01.03.08\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45254,\n                    \"Version\": 2,\n                    \"Guid\": \"4d90dbda-d436-4d60-8c63-d62e1c84b690\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45255,\n                    \"Version\": 2,\n                    \"Guid\": \"c9ccf464-e857-4140-aba9-81a1ec1a164c\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Folder\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45245,\n                    \"Version\": 3,\n                    \"Guid\": \"7444ffbf-b47c-4e43-935b-0043e6e925bc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Folder\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"The folder of this app within the 2sxc-folder - only change this if you know what you're doing.\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45256,\n                    \"Version\": 2,\n                    \"Guid\": \"72ca629c-6a37-4e22-a81f-d95fcb761806\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45257,\n                    \"Version\": 2,\n                    \"Guid\": \"0a433174-3f85-405d-9c49-364837f375f0\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Hidden\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45248,\n                    \"Version\": 5,\n                    \"Guid\": \"340210e1-81b3-4764-a742-bf3f66b68687\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Hidden\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"Show / hide this in the app selector. Advanced apps are usually set to hidden once the developer adds them to the necessary pages.\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45260,\n                    \"Version\": 4,\n                    \"Guid\": \"40b12003-1962-4004-aaae-4e08b7c7bab6\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Default (Visible)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"Default (Visible)\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Hidden - will not appear in add-app list\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ReverseToggle\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupFeatures\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129743,\n                    \"Version\": 4,\n                    \"Guid\": \"00e026d9-685c-47ac-8c6b-41db9655911b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"App Features\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"a0ed3d8d-3410-4317-b415-aee9b5d5b2c9\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129746,\n                    \"Version\": 2,\n                    \"Guid\": \"a70c7a0c-011d-4953-be26-fd1d84f7ab1c\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowTokenTemplates\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45246,\n                    \"Version\": 3,\n                    \"Guid\": \"d1bbd975-5e8b-4b00-92f1-f8318501d155\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Token Templates\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Allow token templates. As of now, this is only informative. In the future, it may be used to enforce certain rules.\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45258,\n                    \"Version\": 2,\n                    \"Guid\": \"aa966d1c-582e-4fe4-9581-db6096812ea2\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AllowRazorTemplates\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45247,\n                    \"Version\": 3,\n                    \"Guid\": \"a82ea4fb-f236-4264-9e08-c462bb18ed55\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Razor Templates\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"Allow token templates. As of now, this is only informative. In the future, it may be used to enforce certain rules.\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45259,\n                    \"Version\": 2,\n                    \"Guid\": \"cb09586b-5bb9-4ebf-9cf9-2932891fe39f\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"SupportsAjaxReload\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45238,\n                    \"Version\": 2,\n                    \"Guid\": \"af506a2b-a65d-4365-ac17-33c4e02e0630\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Supports Ajax Reload\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>If your views can handle being reloaded inside the page without requiring a page-refresh, then activate this. This setting applies to all views in this app, so only use it if your app is fully AJAX ready. Read more about this in <a href=\\\"//2sxc.org/help?tag=ajax\\\" target=\\\"_blank\\\">2sxc.org/help?tag=ajax</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45239,\n                    \"Version\": 2,\n                    \"Guid\": \"de1f9f5d-eb60-494a-a182-60057742ac60\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"*\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupRequirements\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129741,\n                    \"Version\": 4,\n                    \"Guid\": \"a8486bb9-04cc-4a34-8f7c-62b394553b11\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Installation Requirements\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"<p>These are requirements for installing on another platform. The developer sets these values as he/she believes is correct.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"6225b39f-aeef-4f14-92a1-8e66abae60f4\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129742,\n                    \"Version\": 2,\n                    \"Guid\": \"35750ea4-f0b9-4f63-a6b1-2c31505a8de6\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RequiredVersion\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45234,\n                    \"Version\": 4,\n                    \"Guid\": \"a9000056-63c8-4cde-b9b3-472c2113d959\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"16.00.00\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Required Version\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The version of 2sxc required for this app to work. Use it when you rely on 2sxc features which don't&nbsp;exist is other&nbsp;versions. read more on <a href=\\\"//2sxc.org/en/help?tag=app\\\" target=\\\"_blank\\\">2sxc.org/en/help?tag=app</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45235,\n                    \"Version\": 4,\n                    \"Guid\": \"b4e97da0-cec2-423b-bfd8-42911e5d9351\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45263,\n                    \"Version\": 3,\n                    \"Guid\": \"73d48c11-9200-4c3f-8555-ae0ff83aa1c0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RequiredDnnVersion\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45236,\n                    \"Version\": 3,\n                    \"Guid\": \"0f314a6f-2588-4f00-9a47-57b995528dc4\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"09.06.01\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Required DNN Version\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The version of DNN&nbsp;required for this app to work. Use it when you rely on DNN&nbsp;features which don't exist is other versions. read more on <a href=\\\"//2sxc.org/en/help?tag=app\\\" target=\\\"_blank\\\">2sxc.org/en/help?tag=app</a></p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45237,\n                    \"Version\": 3,\n                    \"Guid\": \"f2a4fa6d-95f2-4742-b370-b8f6403cb3d9\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 129750,\n                    \"Version\": 2,\n                    \"Guid\": \"6d7a591d-ca6b-456d-92ba-b68fe0785bb9\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RequiredOqtaneVersion\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129740,\n                    \"Version\": 5,\n                    \"Guid\": \"b5086140-80de-4b8b-a151-5cfa8114e23a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Required Oqtane Version\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Minimum version of Oqtane supported. Leave empty if it doesn't support Oqtane.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": true\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129744,\n                    \"Version\": 4,\n                    \"Guid\": \"06a055e9-5e5e-4212-ad06-27cb650c82f5\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129745,\n                    \"Version\": 4,\n                    \"Guid\": \"3a6ca1a4-232b-42ae-a367-a3b70f49770b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 129747,\n                    \"Version\": 3,\n                    \"Guid\": \"89448369-3fd7-4e10-851a-958f8e93bd61\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Advanced\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": false\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 129748,\n                    \"Version\": 2,\n                    \"Guid\": \"3d50c302-2565-470f-af17-0f9d8906ef1b\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"OriginalId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 45249,\n                    \"Version\": 3,\n                    \"Guid\": \"343a499c-2ab0-4e41-9bbd-d4ccfe4f6b89\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"*\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Original Id\"\n                        },\n                        \"Notes\": {\n                          \"*\": \"A GUID of the original app. This is used for cases where you clone an app with another id, and we want to remember the original ID - for example to point to help content.\"\n                        },\n                        \"Placeholder\": {\n                          \"*\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"*\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"*\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"*\": true\n                        },\n                        \"Required\": {\n                          \"*\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45261,\n                    \"Version\": 2,\n                    \"Guid\": \"83e2327f-26bb-4764-a823-123023091919\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"*\": \"\"\n                        },\n                        \"InputType\": {\n                          \"*\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  },\n                  {\n                    \"Id\": 45262,\n                    \"Version\": 2,\n                    \"Guid\": \"cef684fe-7aac-4c88-8e22-88200de8dc43\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"*\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=1\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"DebugLog\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 182539,\n                    \"Version\": 2,\n                    \"Guid\": \"a81dc518-309d-452d-8871-41b0c8b0c65d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"DebugLog\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Special value to track down issues with app data creation <a href=\\\"https://github.com/2sic/2sxc/issues/3203\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">https://github.com/2sic/2sxc/issues/3203</a>&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182540,\n                    \"Version\": 1,\n                    \"Guid\": \"e52c0fe7-9883-4b36-bdd5-c3b9d3ad6dfa\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 182541,\n                    \"Version\": 1,\n                    \"Guid\": \"75636a01-f1a1-4351-8bfb-981f0d09fbec\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 172321,\n              \"Version\": 4,\n              \"Guid\": \"a0ed3d8d-3410-4317-b415-aee9b5d5b2c9\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const token = 'Tokens: ' + (data.AllowTokenTemplates ? '✅' : '➖');\\n  const razor = 'Razor: ' + (data.AllowRazorTemplates ? '✅' : '➖');\\n  const ajax = 'Ajax: ' + (data.SupportsAjaxReload ? '✅' : '➖');\\n  return data.default + ' (' + [token, razor, ajax].join('; ') + ')';\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 172322,\n              \"Version\": 1,\n              \"Guid\": \"6225b39f-aeef-4f14-92a1-8e66abae60f4\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  const sxc = '2sxc: ' + (data.RequiredVersion || '?');\\n  const dnn = 'Dnn: ' + (data.RequiredDnnVersion || '?');\\n  const oqt = 'Oqt: ' + (data.RequiredOqtaneVersion || '❔');\\n  return data.default + ' (' + [sxc, dnn, oqt].join('; ') + ')';\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"5d70d9f6-3c03-4c09-8413-1a0c2e8dbf8f\",\n            \"Name\": \"\\uD83E\\uDD77\\uD83C\\uDFFDInsightsLoggingCustomized\",\n            \"Scope\": \"System\",\n            \"Metadata\": [\n              {\n                \"Id\": 184157,\n                \"Version\": 1,\n                \"Guid\": \"a322a8e3-159b-4e61-90e4-ffba2a1c15db\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure custom settings for how insights logging should behave on the server.</p>\\n<p><em>This does not affect the UI logging, only the backend.&nbsp;</em></p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Insights Logging - Customized\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5d70d9f6-3c03-4c09-8413-1a0c2e8dbf8f\"\n                }\n              },\n              {\n                \"Id\": 185420,\n                \"Version\": 1,\n                \"Guid\": \"fb72c3d4-43bf-4daf-9717-c9610bf56c8d\",\n                \"Type\": {\n                  \"Id\": \"9db5de57-7c16-4370-8d16-a8bf4cfe8e5b\",\n                  \"Name\": \"DataStorageDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"DataProcessingHandler\": {\n                      \"en-us\": \"\"\n                    },\n                    \"StoreType\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Number\": {\n                    \"ItemsMax\": {\n                      \"en-us\": 0\n                    }\n                  },\n                  \"Boolean\": {\n                    \"SaveIsDisabled\": {\n                      \"en-us\": true\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"5d70d9f6-3c03-4c09-8413-1a0c2e8dbf8f\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"GroupLoadSystemData\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184160,\n                    \"Version\": 2,\n                    \"Guid\": \"e2ca7a1f-0003-4757-b2ef-d9ee7839c088\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Logging of Load System Data\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is about the system content types etc. Usually this just works and does not need detailed logging.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184164,\n                    \"Version\": 1,\n                    \"Guid\": \"a3e3d1ac-62bb-468c-a9e0-097bdbdcf083\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"LoadSystemDataDetails\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184158,\n                    \"Version\": 4,\n                    \"Guid\": \"d71e3813-a895-4ff8-8093-3efa8e95925a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Load System Data - Log Details\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184165,\n                    \"Version\": 3,\n                    \"Guid\": \"a3baffa3-8a65-4a88-9c82-79b4a206fcab\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"When loading system data, never log details\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"When loading system data, use system defaults for details logging\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"When loading system data, always log details\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"LoadSystemDataSummary\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184159,\n                    \"Version\": 3,\n                    \"Guid\": \"3b7aac49-fa84-4f08-b95e-a6fbc4450b99\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Load System Data - Log Summary\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184166,\n                    \"Version\": 2,\n                    \"Guid\": \"48809728-ec88-4cf1-878c-943b32bf5ab1\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"When loading system data, never log summaries\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"When loading system data, use system defaults for summary logging\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"When loading system data, always log summaries\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupLoadApp\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184161,\n                    \"Version\": 2,\n                    \"Guid\": \"9006daf1-d350-42ad-91ff-91eaeb8554b5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Logging of Load App\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This is about logging details when apps are being loaded from the DB.</p>\\n<p>Usually this just works and does not need detailed logging.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184167,\n                    \"Version\": 1,\n                    \"Guid\": \"a7eec903-ad67-4c92-a790-fd332dd00a91\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"LoadAppDetails\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184162,\n                    \"Version\": 3,\n                    \"Guid\": \"9fa28f83-0698-4e8a-8f99-764c3582af61\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Load App - Log Details\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184168,\n                    \"Version\": 2,\n                    \"Guid\": \"445f45b3-91ad-4d4e-9c07-96451344f843\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"When loading app data, never log details\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"When loading app data, use system defaults for details logging\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"When loading app data, always log details\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"LoadAppSummary\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184163,\n                    \"Version\": 3,\n                    \"Guid\": \"284af0f9-8096-4f5f-ad5c-884dd5b30bcd\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Load App - Log Summary\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184169,\n                    \"Version\": 2,\n                    \"Guid\": \"20583cff-a36d-4f9b-8a3d-086e7e6a4d18\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"When loading app data, never log summary\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"When loading app data, use system defaults for summary logging\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"When loading app data, always log summary\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupImportData\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184183,\n                    \"Version\": 2,\n                    \"Guid\": \"bbe5ef42-dfe8-40c6-8303-988bb689f8ab\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Import Data Logging\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Determine how detailed data imports should be logged.&nbsp;</p>\\n<p>Less logging makes it easier to get an overview, but harder to pinpoint specific issues.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184186,\n                    \"Version\": 1,\n                    \"Guid\": \"712ec2dd-0e32-42aa-aed1-ce3f211b957a\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ImportDataDetails\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-tristate\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184184,\n                    \"Version\": 2,\n                    \"Guid\": \"b7f15112-61e5-4ed6-9251-b9d41b38123e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-tristate\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"ImportDataDetails\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184185,\n                    \"Version\": 1,\n                    \"Guid\": \"176a9e4d-2251-406d-aea8-c7efe0cb9563\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"When importing data, never log details\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"When importing data, use system defaults to logs details\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"When importing data, always log details\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"e523fd1a-f9e3-4e73-826e-1433e8afca8a\",\n            \"Name\": \"\\uD83E\\uDD77SqlPerformance\",\n            \"Scope\": \"System\",\n            \"Metadata\": [\n              {\n                \"Id\": 184192,\n                \"Version\": 1,\n                \"Guid\": \"5bfa96bd-8802-4d15-9c18-2ff8b9751b1b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"SQL Performance Settings\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"e523fd1a-f9e3-4e73-826e-1433e8afca8a\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"RelationshipLoadChunkingGroup\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184187,\n                    \"Version\": 1,\n                    \"Guid\": \"8b151d6d-df02-4a00-a8ce-b3b3a4e5af88\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Relationship Load Chunking\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Entity relationships are loaded in separate SQL requests. When there are many, they requested IDs will be chunked to avoid certain limits and timeouts, which may vary by SQL server edition.&nbsp;</p>\\n<p>Larger numbers (assuming your SQL can handle it) will result in faster performance.</p>\\n<p>The default for standard 2sxc is a very safe 1'000.</p>\\n<p>The default for patrons performance is set to 25'000 but may change as with time.</p>\\n<p>Leave the field empty or use 0 to use the default values. Numbers less than 10 will be ignored.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184189,\n                    \"Version\": 1,\n                    \"Guid\": \"0ac88d10-2d4a-4278-aabf-d32f65ae94b0\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"RelationshipLoadChunking\",\n                \"Type\": \"Number\",\n                \"InputType\": \"number-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184194,\n                    \"Version\": 1,\n                    \"Guid\": \"45eff176-b7c4-4d07-83c1-30fdb2111400\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"number-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Relationship Load Chunking\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"Recommended range is 5000 to 50000\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184195,\n                    \"Version\": 1,\n                    \"Guid\": \"a34c0f54-29b0-468f-9246-fbd8b8e0534a\",\n                    \"Type\": {\n                      \"Id\": \"@Number\",\n                      \"Name\": \"@Number\"\n                    },\n                    \"Attributes\": {\n                      \"Number\": {\n                        \"Decimals\": {\n                          \"en-us\": 0\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": []\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"a0f44af0-6750-40c9-9ad9-4a07b6eda8b3\",\n            \"Name\": \"\\uD83E\\uDD77AppExtension\",\n            \"Scope\": \"System\",\n            \"Metadata\": [\n              {\n                \"Id\": 184235,\n                \"Version\": 1,\n                \"Guid\": \"0460e878-eb6f-4b6f-9c4d-89c46314eab6\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"App Extension Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"a0f44af0-6750-40c9-9ad9-4a07b6eda8b3\"\n                }\n              },\n              {\n                \"Id\": 184344,\n                \"Version\": 1,\n                \"Guid\": \"f204d371-c1ed-41fe-a8b1-c4d59ce34121\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"a0f44af0-6750-40c9-9ad9-4a07b6eda8b3\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"groupSpecs\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184247,\n                    \"Version\": 1,\n                    \"Guid\": \"676893e3-d6cc-42e3-8429-0ebc8c219949\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Technical Specs\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"5f5a713d-4f0b-4c3f-9f02-a058e2e0da00\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184249,\n                    \"Version\": 1,\n                    \"Guid\": \"d425c9dd-e75c-4867-bf48-747d17c51f4d\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"nameId\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184196,\n                    \"Version\": 1,\n                    \"Guid\": \"ff9e719c-6f61-4e58-9317-9723383dbac5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"NameId\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"7136e4d6-5789-4c40-bdce-7ea39eb0ac12\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184204,\n                    \"Version\": 1,\n                    \"Guid\": \"1531c7b8-00c0-421b-968f-b437778a4a6d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184205,\n                    \"Version\": 1,\n                    \"Guid\": \"c31c33a1-a7b6-4a45-b7c3-0d32869da4e8\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 1\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"isInstalled\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184248,\n                    \"Version\": 1,\n                    \"Guid\": \"6b4e6c30-a2d5-423c-9483-1d0fe13eb8c2\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"isInstalled\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p><strong>Source</strong> extensions can be exported, <strong>Installed</strong> extensions can be updated.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184250,\n                    \"Version\": 1,\n                    \"Guid\": \"c16066d1-1ae5-4593-8725-ebafa07248c2\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"This is a Source Extension\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"This is an Installed Extension\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupDescription\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184258,\n                    \"Version\": 1,\n                    \"Guid\": \"b9d82417-9ceb-4b68-b7f7-5d2989010d03\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Description\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184261,\n                    \"Version\": 1,\n                    \"Guid\": \"a91d177e-e988-4c4f-8330-bee23e922fa6\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"name\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184197,\n                    \"Version\": 1,\n                    \"Guid\": \"21d15092-cf97-4ae2-a8de-63b812dcbe83\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184206,\n                    \"Version\": 1,\n                    \"Guid\": \"fe163b4e-6744-4fd6-ad39-ae80d6452cc7\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184207,\n                    \"Version\": 1,\n                    \"Guid\": \"37919ecb-71d5-421d-a5fe-f238ada05945\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"version\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184215,\n                    \"Version\": 1,\n                    \"Guid\": \"dbb158b8-dfb7-4497-84fd-ff0b6f6bc216\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"00.00.01\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Version\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184223,\n                    \"Version\": 1,\n                    \"Guid\": \"56ae652c-21e4-4bfa-a7a4-0f5ce800948a\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184224,\n                    \"Version\": 1,\n                    \"Guid\": \"190274c6-e5a9-4268-a020-1b7a0208ffb2\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"teaser\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184198,\n                    \"Version\": 1,\n                    \"Guid\": \"84e72856-3dc0-42d4-a496-112fd224beeb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Teaser\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184208,\n                    \"Version\": 1,\n                    \"Guid\": \"daf1f269-d6cd-49cd-90a2-167d788048d6\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184209,\n                    \"Version\": 1,\n                    \"Guid\": \"273d217f-455e-4fe2-b5dc-97c154d6a766\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"description\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184199,\n                    \"Version\": 1,\n                    \"Guid\": \"0cf1ebaa-c767-4584-b13d-8cd27f11935d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Description\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184210,\n                    \"Version\": 1,\n                    \"Guid\": \"49ad1108-431c-4e30-85ce-90c69c49c0a9\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184211,\n                    \"Version\": 1,\n                    \"Guid\": \"5ca8f803-7d54-4125-8167-14e82c53b878\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        },\n                        \"WysiwygConfiguration\": {\n                          \"en-us\": \"d3dde02f-c1dc-43b8-a8b7-4be3c43eadd0\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupCreated\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184238,\n                    \"Version\": 1,\n                    \"Guid\": \"63d26c12-0710-4606-8d75-423f841c6613\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Creator, Copyright and Links\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184239,\n                    \"Version\": 1,\n                    \"Guid\": \"6455f578-bbcc-4e44-9a1c-d0fe30389da4\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"createdBy\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184236,\n                    \"Version\": 1,\n                    \"Guid\": \"5b463e1c-9164-460b-ac96-e9586b2d217d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Created By\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184240,\n                    \"Version\": 1,\n                    \"Guid\": \"8d5374db-6d54-4229-90fd-aa41589ce6a3\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184241,\n                    \"Version\": 1,\n                    \"Guid\": \"7c32cab9-8263-4859-9be2-7b7d1dc0619a\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"copyright\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184237,\n                    \"Version\": 1,\n                    \"Guid\": \"bf306211-18b2-42b2-a057-fb8ba4145ea0\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Copyright\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184242,\n                    \"Version\": 1,\n                    \"Guid\": \"3a28b2c8-1223-452e-8e44-8e2f86b85611\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184243,\n                    \"Version\": 1,\n                    \"Guid\": \"16a0f6eb-236d-4dfe-9f6c-01521a141065\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"linkMain\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184251,\n                    \"Version\": 1,\n                    \"Guid\": \"e0fb94b9-0859-4d49-9bbd-150eeedb0ec3\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Link to Main Website\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184255,\n                    \"Version\": 1,\n                    \"Guid\": \"7d8632f9-418f-4981-a37a-50f29389bfc1\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"linkDemo\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184280,\n                    \"Version\": 1,\n                    \"Guid\": \"c803c6ca-a26f-4bfb-b081-b8a3eb32a1aa\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"linkDemo\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"linkDocs\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184252,\n                    \"Version\": 1,\n                    \"Guid\": \"398b447b-5726-4343-a55c-470ef7f3963a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Link to Docs\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184256,\n                    \"Version\": 1,\n                    \"Guid\": \"97f1967e-954b-4144-aa63-13522c17be5f\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"linkSource\",\n                \"Type\": \"Hyperlink\",\n                \"InputType\": \"hyperlink-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184253,\n                    \"Version\": 1,\n                    \"Guid\": \"2ff3960b-6f35-490e-80d6-30043405e9a8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"hyperlink-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Link to Source Code / Github\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184257,\n                    \"Version\": 1,\n                    \"Guid\": \"1a78565f-6b9e-4922-a9c5-b7d1909feb97\",\n                    \"Type\": {\n                      \"Id\": \"@Hyperlink\",\n                      \"Name\": \"@Hyperlink\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Buttons\": {\n                          \"en-us\": \"adam,more\"\n                        },\n                        \"DefaultDialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"FileFilter\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Paths\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ServerResourceMapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"ShowAdam\": {\n                          \"en-us\": true\n                        },\n                        \"ShowFileManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowImageManager\": {\n                          \"en-us\": false\n                        },\n                        \"ShowPagePicker\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupCreatedEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184307,\n                    \"Version\": 1,\n                    \"Guid\": \"ec716c77-1534-4328-b4bc-ec11442c3b14\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"groupCreatedEnd\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"messageParts\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-message\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184309,\n                    \"Version\": 1,\n                    \"Guid\": \"9be92242-3730-4be7-8043-f57d5ed2efad\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-message\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"messageParts\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<h3>Parts / Features / Functionality</h3>\\n<p>The following toggles define what this extension contains. This is important when exporting the extension, as only activated parts will be included.</p>\\n<p>Some features when activated will show additional settings to configure.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"inputFieldInside\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184203,\n                    \"Version\": 1,\n                    \"Guid\": \"e7d6b283-d8a0-4654-99d9-874437b327ba\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Has UI Fields\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>does the extension have input fields for the Edit UI?</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184213,\n                    \"Version\": 1,\n                    \"Guid\": \"852850ce-5658-437e-8b02-7b3d325167b2\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No Edit-UI Input Fields\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Has Edit-UI Input Fields\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupInputField\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184300,\n                    \"Version\": 1,\n                    \"Guid\": \"1df7ab45-ebeb-4b47-9ca8-035cd99020e9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Input Fields Configuration\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Provide additional information about input fields.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"e7f883d9-cfb3-4360-9562-886b4d97a71c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184302,\n                    \"Version\": 1,\n                    \"Guid\": \"8740923e-299e-4f32-8d38-b0fa20bbe155\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"inputFieldAssets\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184301,\n                    \"Version\": 1,\n                    \"Guid\": \"39336675-fff6-45c4-b698-b70f522fc51f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"index.js\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Input Field Assets\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Assets to load when this input field is used. Default is index.js, which should then load everything.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184303,\n                    \"Version\": 1,\n                    \"Guid\": \"bdf1ec49-0593-4e21-932f-d8dc61f2048f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184304,\n                    \"Version\": 1,\n                    \"Guid\": \"c0cead99-decd-4a6f-8b54-a3ec1a1ebc18\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Number\": {\n                        \"RowCount\": {\n                          \"en-us\": 2\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupInputFieldEnd\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-end\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184308,\n                    \"Version\": 1,\n                    \"Guid\": \"a3f788ae-d947-4f8b-af13-25293fdfbb6e\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"empty-end\"\n                        },\n                        \"Name\": {\n                          \"*\": \"groupInputFieldEnd\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"appCodeInside\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184201,\n                    \"Version\": 1,\n                    \"Guid\": \"27ea00b8-2609-4e0c-9cbd-14f03f1c8ead\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Has AppCode\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>does the extension has it's own AppCode in /AppCode/Extensions/[name]/?</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184214,\n                    \"Version\": 1,\n                    \"Guid\": \"fc229c87-44a6-4980-a614-fe324fa5ad63\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No own AppCode\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Has own AppCode\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"webApiInside\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184216,\n                    \"Version\": 1,\n                    \"Guid\": \"8eaa81d5-3ba8-4b17-ae85-c96748850f7a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Has Web Api\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>does the extension have web api controllers in /AppCode/Extensions/[name]/Api/?</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184225,\n                    \"Version\": 1,\n                    \"Guid\": \"ff6659a7-7472-44cd-b1a1-8372aef411eb\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No own WebApi\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Has own WebApi\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"razorInside\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184218,\n                    \"Version\": 1,\n                    \"Guid\": \"2abbcc69-371a-4139-9edd-d8edb34f45e1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Has Razor\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>does the extension have Razor files?</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184226,\n                    \"Version\": 1,\n                    \"Guid\": \"748fa11c-6cf1-4f49-8eaa-bd391be83ea1\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No Razor Included\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Has Razor Files\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"editionsSupported\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184298,\n                    \"Version\": 1,\n                    \"Guid\": \"2870777f-5bf4-4c10-8ecc-02e1d53acb59\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"false\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"supportsEditions\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If it supports polymorphism, then multiple editions can be installed side-by-side so that developers can try a new edition while users still see the existing, installed edition.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184299,\n                    \"Version\": 1,\n                    \"Guid\": \"526de5f1-c439-4e59-af7a-6665361d2098\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Does not support Polymorphism / Editions\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Supports Polymorphism / Editions\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"dataInside\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184231,\n                    \"Version\": 1,\n                    \"Guid\": \"a3c8e258-a26a-4f51-8fc8-de14d52fd1f9\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"has Data Bundles\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>does the extension have data which will should be exported/included?</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184232,\n                    \"Version\": 1,\n                    \"Guid\": \"0126123e-bbd6-4e8c-bdae-af5f4ad2c986\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No Data Included\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Includes Data Bundles\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupData\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184244,\n                    \"Version\": 1,\n                    \"Guid\": \"4de9d239-1754-40c3-994f-07debaba554a\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Included Data\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Specify what kind of data is included. This will affect the export and provide information to people installing this extension.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"c592e168-eeb0-4067-a689-8997f30b4672\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184245,\n                    \"Version\": 1,\n                    \"Guid\": \"f1e5ec8c-ebe4-4352-8c4b-1c111faa43e4\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"dataBundles\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184246,\n                    \"Version\": 1,\n                    \"Guid\": \"61ca9627-f31e-4811-8d9d-9dcf7d811ef1\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Data Bundles\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Reference data bundles to include / export with this extension.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184259,\n                    \"Version\": 1,\n                    \"Guid\": \"0e9babfb-2c6a-4184-a292-ce3a49e8dfbf\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.EntityPicker\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"TypeNames=d7f2e4fa-5306-41bb-a3cd-d9529c838879\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"Guid\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"contentTypesInside\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184221,\n                    \"Version\": 1,\n                    \"Guid\": \"2399385c-8350-43a6-a271-27ffb8e26202\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"has ContentTypes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The data contains Content-Types.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184229,\n                    \"Version\": 1,\n                    \"Guid\": \"5b4900c1-2124-4e9e-aadd-430aacbb1c76\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No Content-Types Included\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Has Own Content-Types\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"settingsContentType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184312,\n                    \"Version\": 1,\n                    \"Guid\": \"988f52ef-75c1-47d3-adaf-8d0e4e110e31\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Type for Extension Settings\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>If your extension has settings, specify the content-type here. Make sure it's included in the bundle.&nbsp;</p>\\n<p>We recommend that you only export the content-type, but not the data, as the data would be read-only when installed.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"566978cb-890f-4946-adb4-a7661f0320a5\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184317,\n                    \"Version\": 1,\n                    \"Guid\": \"6262e53c-38ee-4845-a4f3-000dd5e75d83\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"bc05f883-9165-4229-b08c-0f0048b5beed\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"resourcesContentType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184318,\n                    \"Version\": 1,\n                    \"Guid\": \"1af68821-e85a-494a-addf-679f33b61c1d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Resources Content Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"38483b10-b8b2-4767-a80f-991d6d3e0514\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184319,\n                    \"Version\": 1,\n                    \"Guid\": \"6bc2f83a-0da7-47e1-9bd7-6041973bbdd8\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"bc05f883-9165-4229-b08c-0f0048b5beed\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"queriesInside\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184220,\n                    \"Version\": 1,\n                    \"Guid\": \"a8a7f755-e50f-4392-85a9-ce128ac54004\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"has Queries\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The data include Queries.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184228,\n                    \"Version\": 1,\n                    \"Guid\": \"423f16b8-8899-4d1c-b778-3ae2e5eabcb6\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No Queries Included\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Contains Queries\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"viewsInside\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184219,\n                    \"Version\": 1,\n                    \"Guid\": \"428a751e-3175-4868-bfcf-e07fe6a35a33\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Has Views\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>The data contain View Configurations.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184227,\n                    \"Version\": 1,\n                    \"Guid\": \"47832075-c0bd-4305-a1a4-ff7a28768be7\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"No Views Configurations included\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Has View Configurations\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupReleases\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184262,\n                    \"Version\": 1,\n                    \"Guid\": \"0801c11f-728f-4be0-bff9-552a1171c625\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Release Information\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>This information helps the installer inform and warn about breaking changes etc.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184264,\n                    \"Version\": 1,\n                    \"Guid\": \"5b02b80e-76a6-4e4e-a2d7-1b30ecdbde2f\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"releases\",\n                \"Type\": \"Entity\",\n                \"InputType\": \"entity-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184263,\n                    \"Version\": 1,\n                    \"Guid\": \"0f7bf161-a255-48d5-a1f9-d6ce4b908c27\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"entity-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Releases\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Add releases to make it easier for the person installing it to make good decisions.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184268,\n                    \"Version\": 1,\n                    \"Guid\": \"e4c04a65-5dcd-4b20-8552-9dd67e5416cc\",\n                    \"Type\": {\n                      \"Id\": \"@Entity\",\n                      \"Name\": \"@Entity\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"EntityType\": {\n                          \"en-us\": \"1d91a2c0-4d5d-4197-8cb8-d4bfebf72f15\"\n                        },\n                        \"Prefill\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": true\n                        },\n                        \"EnableDelete\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": true\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupPlatforms\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184281,\n                    \"Version\": 1,\n                    \"Guid\": \"7fcffc32-7f0b-43d7-89a8-adc9dfac22ad\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Target Platforms\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Explain which platforms this will work on. By default, all are enabled, but disable those which won't work.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"522654a6-bef7-4597-9a4d-b1b1c34b200f\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184284,\n                    \"Version\": 1,\n                    \"Guid\": \"947764fa-f5cf-43e4-b426-e40b3a1755e3\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"sxcSupported\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184296,\n                    \"Version\": 1,\n                    \"Guid\": \"7a121a90-45c2-4334-837d-e23e89f3d8ca\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"2sxc\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184297,\n                    \"Version\": 1,\n                    \"Guid\": \"acf4575a-6dd8-4027-abb4-b68e7072472b\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"sxcVersionMin\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184287,\n                    \"Version\": 1,\n                    \"Guid\": \"129a7adc-70b4-46a6-a390-1ec58eeefff7\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"21.00.00\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"2sxc Version Minimum\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184290,\n                    \"Version\": 1,\n                    \"Guid\": \"0ce2e804-bccb-49cf-af00-dcea4f06d70d\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184291,\n                    \"Version\": 1,\n                    \"Guid\": \"75c6ee49-af49-403e-b3f0-12192cc2b83b\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"dnnSupported\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184282,\n                    \"Version\": 1,\n                    \"Guid\": \"89309d2d-9b5d-4f92-a468-26fadff03df5\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"DNN\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184285,\n                    \"Version\": 1,\n                    \"Guid\": \"96b66070-4297-4716-8565-e0e453630543\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"dnnVersionMin\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184288,\n                    \"Version\": 1,\n                    \"Guid\": \"5ddd86f0-a77d-495a-8f70-0564405e60fb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"DNN Version Minimum\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184292,\n                    \"Version\": 1,\n                    \"Guid\": \"e4cb4f43-bd62-4dee-88a5-a603ee3e5c7f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184293,\n                    \"Version\": 1,\n                    \"Guid\": \"62e8b792-18c0-4304-8866-7d55dc915883\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"oqtSupported\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184283,\n                    \"Version\": 1,\n                    \"Guid\": \"fa97cc53-c479-4802-a35e-a35edf86fe87\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"true\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Oqtane\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184286,\n                    \"Version\": 1,\n                    \"Guid\": \"76cabe88-4bdc-4dc2-9115-5fab44cf7ace\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"oqtVersionMin\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184289,\n                    \"Version\": 1,\n                    \"Guid\": \"48a1c4a3-e164-4695-bd3e-3c33e2d5b5f6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Oqtane Version Minimum\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184294,\n                    \"Version\": 1,\n                    \"Guid\": \"c43803d4-3164-42ea-b716-3d4e32926386\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184295,\n                    \"Version\": 1,\n                    \"Guid\": \"5207a723-8d4c-4bfd-9a1a-17c5eafc3017\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"groupDependencies\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184340,\n                    \"Version\": 1,\n                    \"Guid\": \"fba6cb2c-ec1f-48ef-8042-5988a6d143b8\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Dependencies\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Dependencies tell the system to include other things (such as extensions) in the export.&nbsp;</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184341,\n                    \"Version\": 1,\n                    \"Guid\": \"542e071d-5883-42ea-b24b-a63bc4a4b217\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"extensionsBundled\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184339,\n                    \"Version\": 1,\n                    \"Guid\": \"8ffb4716-1b0e-491a-8674-328c98e69d4c\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Extensions which must be Bundled / included\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Write the extension names here, comma separated; no spaces. These extensions are to be included in the export and installation.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184342,\n                    \"Version\": 1,\n                    \"Guid\": \"fab617f4-1a7c-466a-8ec3-a5889cae082f\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184343,\n                    \"Version\": 1,\n                    \"Guid\": \"9a35cab0-0c4d-4119-844b-dfc478d767b5\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 184311,\n              \"Version\": 1,\n              \"Guid\": \"5f5a713d-4f0b-4c3f-9f02-a058e2e0da00\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return `${data.default} (id: ${data.nameId})`;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184233,\n              \"Version\": 1,\n              \"Guid\": \"7136e4d6-5789-4c40-bdce-7ea39eb0ac12\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.value || context.target.entity.guid;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184305,\n              \"Version\": 1,\n              \"Guid\": \"e7f883d9-cfb3-4360-9562-886b4d97a71c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, _) => {\\n  return data.inputFieldInside;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184260,\n              \"Version\": 1,\n              \"Guid\": \"c592e168-eeb0-4067-a689-8997f30b4672\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.dataInside;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184314,\n              \"Version\": 1,\n              \"Guid\": \"566978cb-890f-4946-adb4-a7661f0320a5\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.contentTypesInside;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184316,\n              \"Version\": 1,\n              \"Guid\": \"bc05f883-9165-4229-b08c-0f0048b5beed\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"<p>For use in the AppExtensions to pick settings/resources.</p>\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>Scope: [Item:Scope]</p>\\n<p>Content Type: [Item:Title]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"[Item:Scope]: [Item:Title]\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"Scope\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.ContentTypes\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"scope=*&$filter=not startswith(Scope, 'System')\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"AppExtensions: Content Types of all Scopes except System\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"NameId\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184321,\n              \"Version\": 1,\n              \"Guid\": \"38483b10-b8b2-4767-a80f-991d6d3e0514\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.contentTypesInside;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184310,\n              \"Version\": 1,\n              \"Guid\": \"522654a6-bef7-4597-9a4d-b1b1c34b200f\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return `${data.default} (2sxc v${data.sxcVersionMin}; Dnn v${data.dnnVersionMin}; Oqtane v${data.oqtVersionMin})`;\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Name\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"1d91a2c0-4d5d-4197-8cb8-d4bfebf72f15\",\n            \"Name\": \"AppExtensionRelease\",\n            \"Scope\": \"System\",\n            \"Metadata\": [\n              {\n                \"Id\": 184279,\n                \"Version\": 1,\n                \"Guid\": \"7a365f38-0347-4679-b211-df7f2772af6b\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"App Extension Release Information\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"1d91a2c0-4d5d-4197-8cb8-d4bfebf72f15\"\n                }\n              },\n              {\n                \"Id\": 184345,\n                \"Version\": 1,\n                \"Guid\": \"ae4a22cb-1409-4d82-8b97-ef926d4ffb4b\",\n                \"Type\": {\n                  \"Id\": \"e2f569c9-d1dd-4458-a54e-4aaf53e9ae3c\",\n                  \"Name\": \"LanguagesDecorator\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"Title\": {\n                      \"en-us\": \"Disable Translation\"\n                    }\n                  },\n                  \"Boolean\": {\n                    \"Enabled\": {\n                      \"en-us\": false\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"1d91a2c0-4d5d-4197-8cb8-d4bfebf72f15\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"version\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184265,\n                    \"Version\": 1,\n                    \"Guid\": \"1647c6e5-d934-4f68-82ed-d2711667dd48\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"00.00.01\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Version\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Must be in the standard format \\\"00.00.00\\\".</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"5ccf1b4c-93f4-4874-96b8-193bd561b856\",\n                            \"d4f6fae3-818a-4513-ac61-2f3a1defc505\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184272,\n                    \"Version\": 1,\n                    \"Guid\": \"a8370a15-f1e5-4dd4-807b-05a51b7c2b28\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184273,\n                    \"Version\": 1,\n                    \"Guid\": \"2e8efcf9-d839-406e-a7a6-5b15548bcc29\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"monospace\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"isBreaking\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184267,\n                    \"Version\": 1,\n                    \"Guid\": \"d31dd8a6-7332-48c9-8012-64e816b3459b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Is Breaking Release\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Set this to true, if the update is going to be a breaking release and add release notes.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184277,\n                    \"Version\": 1,\n                    \"Guid\": \"a809f000-1b87-4cd8-94a8-505b8053a5b3\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"releaseNotes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-wysiwyg\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184266,\n                    \"Version\": 1,\n                    \"Guid\": \"3abee705-de79-40f3-9d4c-e3a534c0d59f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-wysiwyg\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Release Notes\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Add release notes, especially about breaking changes.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184275,\n                    \"Version\": 1,\n                    \"Guid\": \"92b77fb4-7c40-4efb-8f3b-712e5790b6f2\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184276,\n                    \"Version\": 1,\n                    \"Guid\": \"270d411a-4301-4514-b141-70208601d4d4\",\n                    \"Type\": {\n                      \"Id\": \"@string-wysiwyg\",\n                      \"Name\": \"@string-wysiwyg\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"ButtonAdvanced\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ButtonSource\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Dialog\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InlineInitialHeight\": {\n                          \"en-us\": \"\"\n                        },\n                        \"WysiwygConfiguration\": {\n                          \"en-us\": \"d3dde02f-c1dc-43b8-a8b7-4be3c43eadd0\"\n                        }\n                      },\n                      \"Hyperlink\": {\n                        \"ContentCss\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 184274,\n              \"Version\": 1,\n              \"Guid\": \"5ccf1b4c-93f4-4874-96b8-193bd561b856\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  // Use regex to keep only digits (0-9) and dots (.)\\n  return data.value.replace(/[^0-9.]/g, '');\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 184269,\n              \"Version\": 1,\n              \"Guid\": \"d4f6fae3-818a-4513-ac61-2f3a1defc505\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  function isValidVersion(version) {\\n    // Regex pattern: \\n    // ^\\\\d{2,}$ - starts with at least 2 digits\\n    // \\\\.       - literal dot\\n    // \\\\d{2,}   - at least 2 digits  \\n    // \\\\.       - literal dot\\n    // \\\\d{2,}$  - ends with at least 2 digits\\n    const versionPattern = /^\\\\d{2,}\\\\.\\\\d{2,}\\\\.\\\\d{2,}$/;\\n    return typeof version === 'string' && versionPattern.test(version);\\n  }\\n\\n  if (isValidVersion(data.version))\\n    return;\\n  return {\\n    value: {\\n      severity: \\\"error\\\",\\n      message: \\\"Please provide a version in the format 00.00.00\\\"\\n    }\\n  };\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Validation\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Validation\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        },\n        {\n          \"ContentType\": {\n            \"Id\": \"b08dcd23-2eb0-4a5e-a3d0-3178d2aae451\",\n            \"Name\": \"DataCopilotConfiguration\",\n            \"Scope\": \"System\",\n            \"Metadata\": [\n              {\n                \"Id\": 184324,\n                \"Version\": 2,\n                \"Guid\": \"3ea2c591-de9e-4784-b218-4cf29e5613ee\",\n                \"Type\": {\n                  \"Id\": \"ContentType\",\n                  \"Name\": \"ContentType\"\n                },\n                \"Attributes\": {\n                  \"String\": {\n                    \"AdditionalSettings\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Description\": {\n                      \"en-us\": \"\"\n                    },\n                    \"DynamicChildrenField\": {\n                      \"en-us\": \"\"\n                    },\n                    \"EditInstructions\": {\n                      \"en-us\": \"<p>Configure settings for generating data models - both typed and lightweight.</p>\"\n                    },\n                    \"Label\": {\n                      \"en-us\": \"Code Generator / Copilot Configuration\"\n                    },\n                    \"ListInstructions\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Notes\": {\n                      \"en-us\": \"\"\n                    }\n                  },\n                  \"Hyperlink\": {\n                    \"Icon\": {\n                      \"en-us\": \"\"\n                    },\n                    \"Link\": {\n                      \"en-us\": \"\"\n                    }\n                  }\n                },\n                \"Owner\": \"dnn:userid=41\",\n                \"For\": {\n                  \"Target\": \"ContentType\",\n                  \"TargetType\": 5,\n                  \"String\": \"b08dcd23-2eb0-4a5e-a3d0-3178d2aae451\"\n                }\n              }\n            ],\n            \"Attributes\": [\n              {\n                \"Name\": \"Title\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": true,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184332,\n                    \"Version\": 1,\n                    \"Guid\": \"e4b4169e-b593-4c5c-9cbd-9af6f92d97cc\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Title / Configuration Name\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184333,\n                    \"Version\": 1,\n                    \"Guid\": \"22d09e19-0d7f-4cb4-b9cc-c517649e14f0\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184334,\n                    \"Version\": 1,\n                    \"Guid\": \"cb29dc69-8e8f-4bbe-9588-90f97aa28b8d\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"OutputType\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185389,\n                    \"Version\": 2,\n                    \"Guid\": \"1841e61f-b558-4e54-beef-792442614bea\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"DataModel\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Output Type\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": true\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185391,\n                    \"Version\": 2,\n                    \"Guid\": \"3135f27a-2357-4eb0-b2e1-0a6eae741453\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"list\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"74bae28a-f606-4da4-a380-9f1abff682c1\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"CodeGenerator\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185360,\n                    \"Version\": 2,\n                    \"Guid\": \"2f12e841-c573-4161-8051-4a1b099ac617\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"CSharpTypedDataModelsGenerator\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Code Generator to use\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": true\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185365,\n                    \"Version\": 1,\n                    \"Guid\": \"a9c2f200-69c1-4dab-b696-6ce19344f65e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185366,\n                    \"Version\": 1,\n                    \"Guid\": \"f976c7fe-a485-43c5-9121-a4c3269299df\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"CSharpTypedDataModelsGenerator\\nCSharpCustomModelsGenerator\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185373,\n                    \"Version\": 2,\n                    \"Guid\": \"4473820a-b618-4bd1-b598-2efa6645b528\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"d5e64a2d-eb7e-4ca4-86f0-5d601becf4ac\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": false\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": false\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Edition\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-picker\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185374,\n                    \"Version\": 1,\n                    \"Guid\": \"6cbd6e55-0b32-4b9c-9248-761c87bda51d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-picker\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Edition (to generate the files into)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"daff7fcd-50f5-424a-93b9-87881d3bd9d5\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185376,\n                    \"Version\": 1,\n                    \"Guid\": \"38308a79-14b1-4c00-944f-4c230361c93e\",\n                    \"Type\": {\n                      \"Id\": \"e64dd20e-0055-4410-87a1-1238fe44707f\",\n                      \"Name\": \"@string-picker\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CreateParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"CreatePrefill\": {\n                          \"en-us\": \"\"\n                        },\n                        \"EditParameters\": {\n                          \"en-us\": \"\"\n                        },\n                        \"PickerDisplayMode\": {\n                          \"en-us\": \"auto-inline\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"DataSources\": {\n                          \"*\": [\n                            \"a1eb623f-32a6-46c4-bb12-858befea459a\"\n                          ]\n                        },\n                        \"PickerDisplayConfiguration\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableAddExisting\": {\n                          \"en-us\": true\n                        },\n                        \"EnableCreate\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableReselect\": {\n                          \"en-us\": false\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupContentTypes\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185361,\n                    \"Version\": 1,\n                    \"Guid\": \"a058683e-3acf-42c6-9a68-3d2646f7bc14\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Types to Export\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185363,\n                    \"Version\": 1,\n                    \"Guid\": \"af08ca74-bfe9-4275-84b5-0c4775c79336\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypeSet\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185379,\n                    \"Version\": 1,\n                    \"Guid\": \"d59f9450-c9a3-47f8-971a-96ba53d1df3f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Type Set\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Choose which content-types should be generated.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185380,\n                    \"Version\": 1,\n                    \"Guid\": \"2b3b52f8-0e2d-468a-b1e7-5d1426708b7e\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 185381,\n                    \"Version\": 1,\n                    \"Guid\": \"6dc01766-b6f5-40b8-bc22-45d23adea61d\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown\",\n                      \"Name\": \"@string-dropdown\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \":Default - all from the default scope + AppSettings and AppResources\\ncustom:Custom selection\"\n                        },\n                        \"DropdownValuesFormat\": {\n                          \"en-us\": \"value-label\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Scope\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184325,\n                    \"Version\": 1,\n                    \"Guid\": \"a65b1347-17a4-4971-88a9-82a984c1823f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Data Scope (to pick Content-Types from)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"a374f3be-6c7c-4c68-a4b7-f53cda081f5c\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184330,\n                    \"Version\": 1,\n                    \"Guid\": \"8861c58a-f3da-4e19-93e7-e8ffd303f905\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.Scopes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"$filter=not startswith(NameId, 'System')\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"NameId\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": false\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"ContentTypes\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-dropdown-query\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184327,\n                    \"Version\": 1,\n                    \"Guid\": \"d5985945-395d-4b28-987a-200ae576f75b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-dropdown-query\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Content Types\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>Select one or more.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": [\n                            \"65209d3c-2499-4099-afed-e9d4f15cc333\"\n                          ]\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184331,\n                    \"Version\": 1,\n                    \"Guid\": \"89d84dc5-d85b-4f63-96c6-c221f5149caf\",\n                    \"Type\": {\n                      \"Id\": \"@string-dropdown-query\",\n                      \"Name\": \"@string-dropdown-query\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"Label\": {\n                          \"en-us\": \"Title\"\n                        },\n                        \"MoreFields\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Query\": {\n                          \"en-us\": \"System.ContentTypes\"\n                        },\n                        \"Separator\": {\n                          \"en-us\": \",\"\n                        },\n                        \"StreamName\": {\n                          \"en-us\": \"Default\"\n                        },\n                        \"UrlParameters\": {\n                          \"en-us\": \"scope=[Scope]\"\n                        },\n                        \"Value\": {\n                          \"en-us\": \"NameId\"\n                        }\n                      },\n                      \"Boolean\": {\n                        \"AllowMultiValue\": {\n                          \"en-us\": true\n                        },\n                        \"EnableEdit\": {\n                          \"en-us\": false\n                        },\n                        \"EnableRemove\": {\n                          \"en-us\": true\n                        },\n                        \"EnableTextEntry\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupSpecs\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185362,\n                    \"Version\": 1,\n                    \"Guid\": \"afed059e-4115-46a1-81ef-3828cae591df\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Export Specs\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185364,\n                    \"Version\": 1,\n                    \"Guid\": \"6ec1dcd3-bed6-4e62-b36f-bcced3ee5e5a\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": false\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Namespace\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184326,\n                    \"Version\": 1,\n                    \"Guid\": \"24879fcd-13e2-4c28-a258-dac04b312a5f\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"AppCode.Data\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Namespace\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184328,\n                    \"Version\": 1,\n                    \"Guid\": \"d192d0c9-ad04-4766-ba1c-bca3b7f4e478\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184329,\n                    \"Version\": 1,\n                    \"Guid\": \"9b3ce044-9a6e-425e-bda4-4dffca76f614\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"TargetFolder\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 184336,\n                    \"Version\": 1,\n                    \"Guid\": \"f1f5d9c1-2d3c-4838-8398-76665beb916d\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"AppCode/Data\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"TargetFolder\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 184337,\n                    \"Version\": 1,\n                    \"Guid\": \"f3e1e915-3903-4b1b-b4cd-e9308fbedf4c\",\n                    \"Type\": {\n                      \"Id\": \"@String\",\n                      \"Name\": \"@String\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"DropdownValues\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  },\n                  {\n                    \"Id\": 184338,\n                    \"Version\": 1,\n                    \"Guid\": \"4a8141d8-4d87-4408-8b26-40c9b43bb4a2\",\n                    \"Type\": {\n                      \"Id\": \"@string-default\",\n                      \"Name\": \"@string-default\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputFontFamily\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TextWrapping\": {\n                          \"en-us\": \"\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Prefix\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185358,\n                    \"Version\": 1,\n                    \"Guid\": \"2ef02372-5886-497c-a47e-b7ae9b1090e6\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Prefix\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"Suffix\",\n                \"Type\": \"String\",\n                \"InputType\": \"string-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185359,\n                    \"Version\": 1,\n                    \"Guid\": \"9fe0f31f-fa31-4a7c-af2f-d24307ee471b\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"InputType\": {\n                          \"*\": \"string-default\"\n                        },\n                        \"Name\": {\n                          \"*\": \"Suffix\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"VisibleInEditUI\": {\n                          \"*\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"GroupAdvanced\",\n                \"Type\": \"Empty\",\n                \"InputType\": \"empty-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185425,\n                    \"Version\": 4,\n                    \"Guid\": \"0c980309-1e5b-4d92-aa76-c40e955430ab\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"empty-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"Advanced (BETA)\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"<p>These features are experimental and probably don't work yet.</p>\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185427,\n                    \"Version\": 3,\n                    \"Guid\": \"d0d6962e-329a-4e87-9649-d8dd4824d2f3\",\n                    \"Type\": {\n                      \"Id\": \"@empty-default\",\n                      \"Name\": \"@empty-default\"\n                    },\n                    \"Attributes\": {\n                      \"Boolean\": {\n                        \"DefaultCollapsed\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              },\n              {\n                \"Name\": \"AutoGenerate\",\n                \"Type\": \"Boolean\",\n                \"InputType\": \"boolean-default\",\n                \"IsTitle\": false,\n                \"Metadata\": [\n                  {\n                    \"Id\": 185426,\n                    \"Version\": 2,\n                    \"Guid\": \"af9affc8-309e-4c07-a9e3-7f9253facdfb\",\n                    \"Type\": {\n                      \"Id\": \"@All\",\n                      \"Name\": \"@All\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"CustomJavaScript\": {\n                          \"en-us\": \"\"\n                        },\n                        \"DefaultValue\": {\n                          \"en-us\": \"\"\n                        },\n                        \"InputType\": {\n                          \"en-us\": \"boolean-default\"\n                        },\n                        \"Name\": {\n                          \"en-us\": \"AutoGenerate\"\n                        },\n                        \"Notes\": {\n                          \"en-us\": \"\"\n                        },\n                        \"Placeholder\": {\n                          \"en-us\": \"\"\n                        },\n                        \"ValidationRegExJavaScript\": {\n                          \"en-us\": \"\"\n                        }\n                      },\n                      \"Entity\": {\n                        \"Errors\": {\n                          \"*\": []\n                        },\n                        \"Formulas\": {\n                          \"*\": []\n                        },\n                        \"Warnings\": {\n                          \"*\": []\n                        }\n                      },\n                      \"Boolean\": {\n                        \"Disabled\": {\n                          \"en-us\": false\n                        },\n                        \"DisableTranslation\": {\n                          \"en-us\": false\n                        },\n                        \"Required\": {\n                          \"en-us\": false\n                        },\n                        \"VisibleInEditUI\": {\n                          \"en-us\": true\n                        }\n                      }\n                    },\n                    \"Owner\": \"unknown\"\n                  },\n                  {\n                    \"Id\": 185428,\n                    \"Version\": 1,\n                    \"Guid\": \"25e68b9c-73a5-4318-81e4-7178359cb2a7\",\n                    \"Type\": {\n                      \"Id\": \"@Boolean\",\n                      \"Name\": \"@Boolean\"\n                    },\n                    \"Attributes\": {\n                      \"String\": {\n                        \"TitleFalse\": {\n                          \"en-us\": \"Don't auto re-generate code when data changes (default)\"\n                        },\n                        \"TitleIndeterminate\": {\n                          \"en-us\": \"\"\n                        },\n                        \"TitleTrue\": {\n                          \"en-us\": \"Auto re-generate code when Content-Types change\"\n                        }\n                      }\n                    },\n                    \"Owner\": \"dnn:userid=41\"\n                  }\n                ]\n              }\n            ]\n          },\n          \"Entities\": [\n            {\n              \"Id\": 185390,\n              \"Version\": 2,\n              \"Guid\": \"74bae28a-f606-4da4-a380-9f1abff682c1\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"Name\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.SysData\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"SysDataSource=System.CodeGenerators&SysDataStream=OutputType\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Query: Copilot Output Types\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 185372,\n              \"Version\": 3,\n              \"Guid\": \"d5e64a2d-eb7e-4ca4-86f0-5d601becf4ac\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"<p>[Item:DescriptionHtml]</p>\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"<p>[Item:Description]</p>\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"[Item:Name] v[Item:Version]\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"Version,Description,DescriptionHtml\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.SysData\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"SysDataSource=System.CodeGenerators&$filter=OutputType eq '[OutputType]'\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Query: Copilot Generators\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 185377,\n              \"Version\": 1,\n              \"Guid\": \"daff7fcd-50f5-424a-93b9-87881d3bd9d5\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  // console.log(\\\"isnew\\\", context.target.entity.isNew);\\n  // console.log('edition', data.value, `isEmpty: ${data.value.length}`);\\n\\n  // 1. Exit if editing something existing\\n  if (!context.target.entity.isNew)\\n    return;\\n\\n  // Otherwise try to set default to best possible value\\n  // 2. wait for options to exist\\n  if (data.options.length == 0)\\n    return;\\n\\n  // 3. Find default if given, and select that, then stop the formula\\n  const best = data.options.find(o => o?.data?.IsDefault ?? false);\\n  // console.log('options', data.options, best);\\n  return { \\n    value: best ? [best.value] : data.value,\\n    stop: true\\n  };\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Value\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Value\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 185375,\n              \"Version\": 2,\n              \"Guid\": \"a1eb623f-32a6-46c4-bb12-858befea459a\",\n              \"Type\": {\n                \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n                \"Name\": \"UiPickerSourceQuery\",\n                \"AttributeMap\": {\n                  \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n                  \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n                  \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n                  \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n                }\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"CreateTypes\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Description\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemInformation\": {\n                    \"en-us\": \"\"\n                  },\n                  \"ItemTooltip\": {\n                    \"en-us\": \"\"\n                  },\n                  \"Label\": {\n                    \"en-us\": \"\\\"[Item:Name]\\\" - [Item:Description]\"\n                  },\n                  \"MoreFields\": {\n                    \"en-us\": \"Description,IsDefault\"\n                  },\n                  \"Query\": {\n                    \"en-us\": \"System.SysData\"\n                  },\n                  \"QueryParameters\": {\n                    \"en-us\": \"SysDataSource=System.AppEditions\"\n                  },\n                  \"StreamName\": {\n                    \"en-us\": \"Default\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Query: App Editions\"\n                  },\n                  \"Value\": {\n                    \"en-us\": \"Name\"\n                  }\n                },\n                \"Hyperlink\": {\n                  \"ItemLink\": {\n                    \"en-us\": \"\"\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 185382,\n              \"Version\": 1,\n              \"Guid\": \"a374f3be-6c7c-4c68-a4b7-f53cda081f5c\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.ContentTypeSet == 'custom';\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            },\n            {\n              \"Id\": 185383,\n              \"Version\": 1,\n              \"Guid\": \"65209d3c-2499-4099-afed-e9d4f15cc333\",\n              \"Type\": {\n                \"Id\": \"772dfff1-b236-4aa9-8359-5f53c08ff7bf\",\n                \"Name\": \"UiFormula\"\n              },\n              \"Attributes\": {\n                \"String\": {\n                  \"Formula\": {\n                    \"en-us\": \"v2((data, context) => {\\n  return data.ContentTypeSet == 'custom';\\n});\"\n                  },\n                  \"Target\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  },\n                  \"Title\": {\n                    \"en-us\": \"Field.Settings.Visible\"\n                  }\n                },\n                \"Boolean\": {\n                  \"Enabled\": {\n                    \"en-us\": true\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\"\n            }\n          ]\n        }\n      ],\n      \"Entities\": [\n        {\n          \"Id\": 185412,\n          \"Version\": 4,\n          \"Guid\": \"a148a07e-7bd0-41ae-9911-a00583215ae5\",\n          \"Type\": {\n            \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n            \"Name\": \"UiPickerSourceQuery\",\n            \"AttributeMap\": {\n              \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n              \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n              \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n              \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n            }\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"CreateTypes\": {\n                \"en-us\": \"\"\n              },\n              \"Description\": {\n                \"en-us\": \"\"\n              },\n              \"ItemInformation\": {\n                \"en-us\": \"<p>[Item:AssemblyQualifiedName]</p>\"\n              },\n              \"ItemTooltip\": {\n                \"en-us\": \"\"\n              },\n              \"Label\": {\n                \"en-us\": \"FullName\"\n              },\n              \"MoreFields\": {\n                \"en-us\": \"\"\n              },\n              \"Query\": {\n                \"en-us\": \"System.SysData\"\n              },\n              \"QueryParameters\": {\n                \"en-us\": \"SysDataSource=System.DataProcessors\"\n              },\n              \"StreamName\": {\n                \"en-us\": \"Default\"\n              },\n              \"Title\": {\n                \"en-us\": \"Query: SysData DataProcessors\"\n              },\n              \"Value\": {\n                \"en-us\": \"FullName\"\n              }\n            },\n            \"Hyperlink\": {\n              \"ItemLink\": {\n                \"en-us\": \"\"\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 185414,\n              \"Version\": 1,\n              \"Guid\": \"655d92f5-252f-4d30-87fb-b3772735789b\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"acc500b8-ff84-40e6-aa1f-0cd2d762bace\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"a148a07e-7bd0-41ae-9911-a00583215ae5\"\n              }\n            }\n          ]\n        },\n        {\n          \"Id\": 185417,\n          \"Version\": 3,\n          \"Guid\": \"6e3f3520-77b9-4cb9-80ea-2d507bea197d\",\n          \"Type\": {\n            \"Id\": \"5f8e3968-e02b-40d5-ab77-f60c2e73d244\",\n            \"Name\": \"UiPickerSourceQuery\",\n            \"AttributeMap\": {\n              \"Query\": \"1454db62-f29f-4471-b2a5-5bd82817580a\",\n              \"StreamName\": \"cb87841b-d687-43ab-be67-cdb810a69e3a\",\n              \"Value\": \"0ee078ec-ee4d-41a0-b6b6-ffcdfa90f4eb\",\n              \"Label\": \"a3489bc4-6f3c-4e84-a825-2476b0ae4c32\"\n            }\n          },\n          \"Attributes\": {\n            \"String\": {\n              \"CreateTypes\": {\n                \"en-us\": \"\"\n              },\n              \"Description\": {\n                \"en-us\": \"\"\n              },\n              \"ItemInformation\": {\n                \"en-us\": \"<p>[Item:NameId]</p>\"\n              },\n              \"ItemTooltip\": {\n                \"en-us\": \"\"\n              },\n              \"Label\": {\n                \"en-us\": \"NameId\"\n              },\n              \"MoreFields\": {\n                \"en-us\": \"\"\n              },\n              \"Query\": {\n                \"en-us\": \"System.SysData\"\n              },\n              \"QueryParameters\": {\n                \"en-us\": \"SysDataSource=System.MetadataTargetTypes\"\n              },\n              \"StreamName\": {\n                \"en-us\": \"Default\"\n              },\n              \"Title\": {\n                \"en-us\": \"Query: SysData MetadataTargetType\"\n              },\n              \"Value\": {\n                \"en-us\": \"Id\"\n              }\n            },\n            \"Hyperlink\": {\n              \"ItemLink\": {\n                \"en-us\": \"\"\n              }\n            }\n          },\n          \"Owner\": \"dnn:userid=41\",\n          \"Metadata\": [\n            {\n              \"Id\": 185419,\n              \"Version\": 1,\n              \"Guid\": \"5007830c-c374-493a-8c1a-9e552f9b43ba\",\n              \"Type\": {\n                \"Id\": \"32698880-1c2e-41ab-bcfc-420091d3263f\",\n                \"Name\": \"SystemExportDecorator\"\n              },\n              \"Attributes\": {\n                \"Entity\": {\n                  \"Configuration\": {\n                    \"*\": [\n                      \"acc500b8-ff84-40e6-aa1f-0cd2d762bace\"\n                    ]\n                  }\n                }\n              },\n              \"Owner\": \"dnn:userid=41\",\n              \"For\": {\n                \"Target\": \"Entity\",\n                \"TargetType\": 4,\n                \"Guid\": \"6e3f3520-77b9-4cb9-80ea-2d507bea197d\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "Src/Data/App_Data/system/readme.md",
    "content": "﻿# invisible .data folder\n\nThis folder contains various json configuration files. \n\nthey are NOT included in the VS project, to keep them out of code analysis and search-replace loops, as they should never be changed that way."
  },
  {
    "path": "Src/Data/App_Data/system-beta/readme.md",
    "content": "﻿# .databeta folder\n\nThis folder contains data / content-types which we're still experimenting with. \n\nThis stuff should be loaded as we're developing, but should not slip into the distribution."
  },
  {
    "path": "Src/Data/App_Data/system-beta/xconfigurations/features.json",
    "content": "{\n\t\"_\": {\n\t\t\"V\": 1\n\t},\n\t\"Entity\": {\n\t\t\"Id\": 48237,\n\t\t\"Version\": 4,\n\t\t\"Guid\": \"0b5f33c3-b566-4c19-9492-2955462084c8\",\n\t\t\"Type\": {\n\t\t\t\"Name\": \"FeaturesConfiguration\",\n\t\t\t\"Id\": \"094941f2-688e-4df1-89c9-51a51c8bbb2e\"\n\t\t},\n\t\t\"Attributes\": {\n\t\t\t\"String\": {\n\t\t\t\t\"Signature\": {\n\t\t\t\t\t\"*\": \"testing\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"Custom\": {\n\t\t\t\t\"Features\": {\n\t\t\t\t\t\"*\": \"{\\n\\t\\\"features\\\": [{\\n\\t\\t\\\"id\\\": \\\"f6b8d6da-4744-453b-9543-0de499aa2352\\\",\\n\\t\\t\\\"enabled\\\": true,\\n\\t\\t\\\"expires\\\": \\\"2025-04-14T00:00:00+02:00\\\"\\n\\t},{\\n\\t\\t\\\"id\\\": \\\"6cac008e-0663-4cd8-92b2-1d3afbcefcd8\\\",\\n\\t\\t\\\"enabled\\\": true,\\n\\t\\t\\\"expires\\\": \\\"2025-04-14T00:00:00+02:00\\\"\\n\\t},{\\n\\t\\t\\\"id\\\": \\\"d93baf71-74c6-4956-9fe0-8281acdfd14a\\\",\\n\\t\\t\\\"enabled\\\": true,\\n\\t\\t\\\"expires\\\": \\\"2025-04-14T00:00:00+02:00\\\"\\n\\t},{\\n\\t\\t\\\"id\\\": \\\"79b9f5f8-d104-458b-8e8f-9f4a11c5935e\\\",\\n\\t\\t\\\"enabled\\\": true,\\n\\t\\t\\\"expires\\\": \\\"2025-04-14T00:00:00+02:00\\\"\\n\\t},\\n\\t{\\n\\t\\t\\\"id\\\": \\\"4f3d0021-1c8b-4286-a33b-3210ed3b2d9a\\\",\\n\\t\\t\\\"enabled\\\": true,\\n\\t\\t\\\"expires\\\": \\\"2018-04-14T00:00:00+02:00\\\"\\n\\t},\\n\\t{\\n\\t\\t\\\"id\\\": \\\"00000000-0000-0000-0000-000000000000\\\",\\n\\t\\t\\\"enabled\\\": false,\\n\\t\\t\\\"expires\\\": \\\"2018-04-13T00:00:00+02:00\\\"\\n\\t}]\\n}\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"Owner\": \"dnn:userid=1\"\n\t}\n}"
  },
  {
    "path": "Src/Data/App_Data/system-beta/xcontenttypes/Default.6d5bebc7-1caf-430c-9628-a7c30b77f393.json",
    "content": "{\n  \"_\": {\n    \"V\": 1\n  },\n  \"ContentType\": {\n    \"Id\": \"6d5bebc7-1caf-430c-9628-a7c30b77f393\",\n    \"Name\": \"TstData\",\n    \"Scope\": \"Default\",\n    \"Description\": \"\",\n    \"Attributes\": [\n      {\n        \"Name\": \"SomeText\",\n        \"Type\": \"String\",\n        \"InputType\": \"string-default\",\n        \"IsTitle\": true,\n        \"Metadata\": [\n          {\n            \"Id\": 203992,\n            \"Version\": 1,\n            \"Guid\": \"a78c4c6e-c543-454c-9ebc-b86a84491ea9\",\n            \"Type\": {\n              \"Name\": \"@All\",\n              \"Id\": \"@All\"\n            },\n            \"Attributes\": {\n              \"String\": {\n                \"InputType\": {\n                  \"*\": \"string-default\"\n                },\n                \"Name\": {\n                  \"*\": \"SomeText\"\n                }\n              },\n              \"Entity\": {\n                \"Errors\": {\n                  \"*\": []\n                },\n                \"Formulas\": {\n                  \"*\": []\n                },\n                \"Warnings\": {\n                  \"*\": []\n                }\n              },\n              \"Boolean\": {\n                \"VisibleInEditUI\": {\n                  \"*\": true\n                }\n              }\n            },\n            \"Owner\": \"dnn:userid=1\"\n          }\n        ]\n      },\n      {\n        \"Name\": \"SomeHtml\",\n        \"Type\": \"String\",\n        \"InputType\": \"string-wysiwyg\",\n        \"IsTitle\": false,\n        \"Metadata\": [\n          {\n            \"Id\": 203993,\n            \"Version\": 1,\n            \"Guid\": \"508becc7-5f90-4ae5-bbdd-07a8234d1250\",\n            \"Type\": {\n              \"Name\": \"@All\",\n              \"Id\": \"@All\"\n            },\n            \"Attributes\": {\n              \"String\": {\n                \"InputType\": {\n                  \"*\": \"string-wysiwyg\"\n                },\n                \"Name\": {\n                  \"*\": \"SomeHtml\"\n                }\n              },\n              \"Entity\": {\n                \"Errors\": {\n                  \"*\": []\n                },\n                \"Formulas\": {\n                  \"*\": []\n                },\n                \"Warnings\": {\n                  \"*\": []\n                }\n              },\n              \"Boolean\": {\n                \"VisibleInEditUI\": {\n                  \"*\": true\n                }\n              }\n            },\n            \"Owner\": \"dnn:userid=1\"\n          }\n        ]\n      }\n    ],\n    \"Metadata\": []\n  },\n  \"Entities\": []\n}\n"
  },
  {
    "path": "Src/Data/App_Data/system-beta/xcontenttypes/json.y48d849d6-b83d-4001-96e5-79da0833e84e.json",
    "content": "﻿{\"_\":{\"V\":1},\"ContentType\":{\"Id\":\"y48d849d6-b83d-4001-96e5-79da0833e84e\",\"Name\":\"JsonTest\",\"Scope\":\"json\",\"Description\":\"todo\",\"Attributes\":[{\"Name\":\"Title\",\"Type\":\"String\",\"IsTitle\":true,\"Metadata\":[{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"from code\"},\"InputType\":{\"*\":\"string-default\"}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}}}]},{\"Name\":\"Group\",\"Type\":\"Empty\",\"IsTitle\":false,\"Metadata\":[{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"empty-default\"},\"Name\":{\"*\":\"Group from Code\"}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}}}]},{\"Name\":\"Text\",\"Type\":\"String\",\"IsTitle\":false,\"Metadata\":[{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"from code\"},\"InputType\":{\"*\":\"string-default\"}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}}}]},{\"Name\":\"Number\",\"Type\":\"Number\",\"IsTitle\":false,\"Metadata\":[{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"number-default\"}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}}}]},{\"Name\":\"Entity1\",\"Type\":\"Entity\",\"IsTitle\":false,\"Metadata\":[{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"entity-default\"}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}}},{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@entity-default\",\"Id\":\"@entity-default\"},\"Attributes\":{\"String\":{\"EntityType\":{\"*\":\"BlogPost\"}},\"Boolean\":{\"AllowMultiValue\":{\"*\":false},\"EnableAddExisting\":{\"*\":true},\"EnableCreate\":{\"*\":true},\"EnableDelete\":{\"*\":false},\"EnableEdit\":{\"*\":true},\"EnableRemove\":{\"*\":true}}}}]},{\"Name\":\"EntityMulti\",\"Type\":\"Entity\",\"IsTitle\":false,\"Metadata\":[{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"entity-default\"}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}}},{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@entity-default\",\"Id\":\"@entity-default\"},\"Attributes\":{\"String\":{\"EntityType\":{\"*\":\"BlogPost\"}},\"Boolean\":{\"AllowMultiValue\":{\"*\":true},\"EnableAddExisting\":{\"*\":true},\"EnableCreate\":{\"*\":true},\"EnableDelete\":{\"*\":false},\"EnableEdit\":{\"*\":true},\"EnableRemove\":{\"*\":true}}}}]},{\"Name\":\"CodeText\",\"Type\":\"String\",\"IsTitle\":false,\"Metadata\":[{\"Id\":0,\"Version\":1,\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"string-default\"}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}}}]}],\"Metadata\":[]}}"
  },
  {
    "path": "Src/Data/json-schemas/JSON model 2sxc Image Resize Advanced.hck.json",
    "content": "{\n    \"modelName\": \"2sxc Image Resize Advanced\",\n    \"collections\": [\n        {\n            \"collectionName\": \"Recipe\",\n            \"type\": \"object\",\n            \"properties\": [\n                {\n                    \"name\": \"Name\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"string\",\n                    \"properties\": [],\n                    \"GUID\": \"3b3ce810-b40b-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    },\n                    \"code\": \"name\"\n                },\n                {\n                    \"name\": \"SetWidth\",\n                    \"hackoladeMeta\": {\n                        \"namingConvention\": \"\"\n                    },\n                    \"isActivated\": true,\n                    \"type\": \"boolean\",\n                    \"GUID\": \"41780f70-b40b-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    },\n                    \"code\": \"setWidth\"\n                },\n                {\n                    \"name\": \"Variants\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"string\",\n                    \"properties\": [],\n                    \"GUID\": \"62f4c0d0-b40b-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    },\n                    \"code\": \"variants\"\n                },\n                {\n                    \"name\": \"Attributes\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"document\",\n                    \"properties\": [],\n                    \"additionalProperties\": true,\n                    \"GUID\": \"8bded800-b40b-11ec-b2ec-ddf76f2d96ad\",\n                    \"code\": \"attributes\",\n                    \"error\": {},\n                    \"propertyNames\": {\n                        \"GUID\": \"93d73fc0-b40b-11ec-b2ec-ddf76f2d96ad\"\n                    }\n                },\n                {\n                    \"name\": \"SetHeight\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"boolean\",\n                    \"GUID\": \"a6d52830-b40b-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    },\n                    \"code\": \"setHeight\"\n                },\n                {\n                    \"name\": \"Width\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"numeric\",\n                    \"properties\": [],\n                    \"GUID\": \"bf48c520-b40b-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    },\n                    \"code\": \"width\"\n                },\n                {\n                    \"name\": \"For Css\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"string\",\n                    \"properties\": [],\n                    \"GUID\": \"d44a93e0-b40b-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    },\n                    \"code\": \"forCss\"\n                },\n                {\n                    \"name\": \"For Factor\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"any\",\n                    \"properties\": [],\n                    \"code\": \"forFactor\",\n                    \"GUID\": \"daf03ce0-b40b-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    }\n                },\n                {\n                    \"name\": \"For Tag\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"string\",\n                    \"properties\": [],\n                    \"GUID\": \"0175fe40-b40c-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    },\n                    \"code\": \"forTag\"\n                },\n                {\n                    \"name\": \"Recipes\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"array\",\n                    \"properties\": [\n                        {\n                            \"hackoladeMeta\": {},\n                            \"isActivated\": true,\n                            \"type\": \"document\",\n                            \"properties\": [],\n                            \"additionalProperties\": false,\n                            \"GUID\": \"259239b0-b40c-11ec-b2ec-ddf76f2d96ad\",\n                            \"arrayItem\": true,\n                            \"arrayParentType\": \"array\",\n                            \"error\": {}\n                        }\n                    ],\n                    \"additionalItems\": true,\n                    \"GUID\": \"258df3f0-b40c-11ec-b2ec-ddf76f2d96ad\",\n                    \"code\": \"recipes\",\n                    \"foreignCollection\": \"f98c31f0-b40a-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {}\n                }\n            ],\n            \"definitions\": {\n                \"type\": \"definitions\",\n                \"properties\": [],\n                \"GUID\": \"f98e2dc0-b40a-11ec-b2ec-ddf76f2d96ad\"\n            },\n            \"isActivated\": true,\n            \"additionalProperties\": false,\n            \"GUID\": \"f98c31f0-b40a-11ec-b2ec-ddf76f2d96ad\",\n            \"id\": \"/recipe\",\n            \"bucketId\": \"4b3a28c0-b40d-11ec-b2ec-ddf76f2d96ad\"\n        },\n        {\n            \"collectionName\": \"SettingsAdvanced\",\n            \"type\": \"object\",\n            \"properties\": [\n                {\n                    \"name\": \"Recipe\",\n                    \"hackoladeMeta\": {},\n                    \"isActivated\": true,\n                    \"type\": \"document\",\n                    \"properties\": [],\n                    \"additionalProperties\": false,\n                    \"GUID\": \"a7ed0b60-b40c-11ec-b2ec-ddf76f2d96ad\",\n                    \"error\": {\n                        \"name\": false,\n                        \"code\": false\n                    },\n                    \"code\": \"recipe\"\n                }\n            ],\n            \"definitions\": {\n                \"type\": \"definitions\",\n                \"properties\": [],\n                \"GUID\": \"18c9c8c0-b40b-11ec-b2ec-ddf76f2d96ad\"\n            },\n            \"isActivated\": true,\n            \"additionalProperties\": false,\n            \"GUID\": \"18c7ccf0-b40b-11ec-b2ec-ddf76f2d96ad\",\n            \"bucketId\": \"4b3a28c0-b40d-11ec-b2ec-ddf76f2d96ad\"\n        }\n    ],\n    \"buckets\": [\n        {\n            \"name\": \"Root\",\n            \"type\": \"bucket\",\n            \"collectionIds\": [\n                \"f98c31f0-b40a-11ec-b2ec-ddf76f2d96ad\",\n                \"18c7ccf0-b40b-11ec-b2ec-ddf76f2d96ad\"\n            ],\n            \"backgroundColor\": {\n                \"r\": 216,\n                \"g\": 0,\n                \"b\": 115,\n                \"a\": 1\n            },\n            \"show\": true,\n            \"isActivated\": true,\n            \"GUID\": \"4b3a28c0-b40d-11ec-b2ec-ddf76f2d96ad\"\n        }\n    ],\n    \"views\": [],\n    \"relationships\": [],\n    \"users\": [],\n    \"diagramViews\": [],\n    \"idToNameHashTable\": {\n        \"f98c31f0-b40a-11ec-b2ec-ddf76f2d96ad\": \"Recipe\",\n        \"18c7ccf0-b40b-11ec-b2ec-ddf76f2d96ad\": \"SettingsAdvanced\",\n        \"3b3ce810-b40b-11ec-b2ec-ddf76f2d96ad\": \"Name\",\n        \"41780f70-b40b-11ec-b2ec-ddf76f2d96ad\": \"SetWidth\",\n        \"62f4c0d0-b40b-11ec-b2ec-ddf76f2d96ad\": \"Variants\",\n        \"8bded800-b40b-11ec-b2ec-ddf76f2d96ad\": \"Attributes\",\n        \"a6d52830-b40b-11ec-b2ec-ddf76f2d96ad\": \"SetHeight\",\n        \"bf48c520-b40b-11ec-b2ec-ddf76f2d96ad\": \"Width\",\n        \"d44a93e0-b40b-11ec-b2ec-ddf76f2d96ad\": \"For Css\",\n        \"daf03ce0-b40b-11ec-b2ec-ddf76f2d96ad\": \"For Factor\",\n        \"0175fe40-b40c-11ec-b2ec-ddf76f2d96ad\": \"For Tag\",\n        \"258df3f0-b40c-11ec-b2ec-ddf76f2d96ad\": \"Recipes\",\n        \"a7ed0b60-b40c-11ec-b2ec-ddf76f2d96ad\": \"Recipe\",\n        \"4b3a28c0-b40d-11ec-b2ec-ddf76f2d96ad\": \"Root\"\n    },\n    \"definitions\": {\n        \"type\": \"definitions\",\n        \"properties\": [],\n        \"GUID\": \"e5248051-b40a-11ec-b2ec-ddf76f2d96ad\"\n    },\n    \"polyglotDefinitions\": {\n        \"type\": \"polyglotDefinitions\",\n        \"properties\": [],\n        \"GUID\": \"e5248053-b40a-11ec-b2ec-ddf76f2d96ad\"\n    },\n    \"externalDefinitions\": {\n        \"type\": \"externalDefinitions\",\n        \"properties\": [],\n        \"GUID\": \"e5248052-b40a-11ec-b2ec-ddf76f2d96ad\"\n    },\n    \"sources\": [],\n    \"decorativeSymbols\": [],\n    \"dbVendor\": \"JSON\",\n    \"dbVersion\": \"draft-07\",\n    \"appTarget\": \"JSON\",\n    \"creationTS\": \"2022-04-04T11:32:22.868Z\",\n    \"GUID\": \"e5248050-b40a-11ec-b2ec-ddf76f2d96ad\",\n    \"isLineageEnabled\": false,\n    \"hackoladeMeta\": {\n        \"validationErrors\": {\n            \"modelName\": false\n        }\n    },\n    \"author\": \"2sic\",\n    \"lastModifTS\": \"2022-04-04T12:02:25.290Z\",\n    \"persistenceSchemaVersion\": \"5\",\n    \"isCreatedByPlugin\": true,\n    \"pluginInformation\": {\n        \"pluginEngineVersion\": \"1.0.0\"\n    },\n    \"applicationInformation\": {\n        \"version\": \"5.4.11\"\n    },\n    \"settings\": {\n        \"centralPane\": {\n            \"dbLevel\": {\n                \"erd\": [\n                    {\n                        \"GUID\": \"f98c31f0-b40a-11ec-b2ec-ddf76f2d96ad\",\n                        \"x\": 443,\n                        \"y\": 85,\n                        \"width\": 184,\n                        \"height\": 231,\n                        \"color\": {}\n                    },\n                    {\n                        \"GUID\": \"18c7ccf0-b40b-11ec-b2ec-ddf76f2d96ad\",\n                        \"x\": 80,\n                        \"y\": 80,\n                        \"width\": 222,\n                        \"height\": 51,\n                        \"color\": {}\n                    }\n                ],\n                \"buckets\": [\n                    {\n                        \"x\": 40,\n                        \"y\": 40,\n                        \"GUID\": \"4b3a28c0-b40d-11ec-b2ec-ddf76f2d96ad\"\n                    }\n                ],\n                \"collapsedNodes\": [],\n                \"activeRelationship\": \"\",\n                \"activeRelationshipFields\": {\n                    \"childField\": [],\n                    \"parentField\": []\n                },\n                \"selectedCollections\": [],\n                \"displayColorPicker\": false,\n                \"graphView\": {\n                    \"erd\": [],\n                    \"buckets\": [],\n                    \"decorativeSymbols\": [],\n                    \"forceLayout\": true,\n                    \"defaultLinkLength\": 300\n                },\n                \"diagramViews\": [],\n                \"decorativeSymbols\": [],\n                \"nestedCollectionsLayout\": \"horizontal\",\n                \"options\": []\n            },\n            \"collectionLevel\": {},\n            \"changed\": false\n        },\n        \"dtDiagram\": {\n            \"collapsedNodes\": [],\n            \"shouldDistributeCollections\": false\n        }\n    }\n}"
  },
  {
    "path": "Src/Data/json-schemas/image-resize-recipe-v1.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema\",\n  \"$id\": \"http://example.com/example.json\",\n  \"type\": \"object\",\n  \"title\": \"The root schema\",\n  \"description\": \"The root schema comprises the entire JSON document.\",\n  \"default\": {},\n  \"examples\": [\n      {\n          \"recipe\": {\n              \"name\": \"default\",\n              \"variants\": \"2*, 1*, 3/4*, 1/2*\",\n              \"setWidth\": false,\n              \"attributes\": {\n                  \"loading\": \"lazy\"\n              },\n              \"recipes\": [\n                  {\n                      \"name\": \"Experimental Bootstrap3\",\n                      \"forCss\": \"bs3\",\n                      \"attributes\": {\n                          \"class\": \"img-responsive\"\n                      },\n                      \"setWidth\": false\n                  },\n                  {\n                      \"name\": \"Experimental Bootstrap5\",\n                      \"forCss\": \"bs5\",\n                      \"attributes\": {\n                          \"class\": \"img-fluid\"\n                      },\n                      \"setWidth\": true,\n                      \"recipes\": [\n                          {\n                              \"forFactor\": \"12/12\",\n                              \"width\": 1230,\n                              \"attributes\": {\n                                  \"sizes\": \"(max-width: 1400px) 100vw, 1230px\"\n                              }\n                          },\n                          {\n                              \"forFactor\": \"11/12\",\n                              \"width\": 1100\n                          },\n                          {\n                              \"forFactor\": \"1/12\",\n                              \"width\": 75\n                          }\n                      ]\n                  }\n              ]\n          }\n      }\n  ],\n  \"required\": [\n      \"recipe\"\n  ],\n  \"properties\": {\n      \"recipe\": {\n          \"$id\": \"#/properties/recipe\",\n          \"type\": \"object\",\n          \"title\": \"The recipe schema\",\n          \"description\": \"An explanation about the purpose of this instance.\",\n          \"default\": {},\n          \"examples\": [\n              {\n                  \"name\": \"default\",\n                  \"variants\": \"2*, 1*, 3/4*, 1/2*\",\n                  \"setWidth\": false,\n                  \"attributes\": {\n                      \"loading\": \"lazy\"\n                  },\n                  \"recipes\": [\n                      {\n                          \"name\": \"Experimental Bootstrap3\",\n                          \"forCss\": \"bs3\",\n                          \"attributes\": {\n                              \"class\": \"img-responsive\"\n                          },\n                          \"setWidth\": false\n                      },\n                      {\n                          \"name\": \"Experimental Bootstrap5\",\n                          \"forCss\": \"bs5\",\n                          \"attributes\": {\n                              \"class\": \"img-fluid\"\n                          },\n                          \"setWidth\": true,\n                          \"recipes\": [\n                              {\n                                  \"forFactor\": \"12/12\",\n                                  \"width\": 1230,\n                                  \"attributes\": {\n                                      \"sizes\": \"(max-width: 1400px) 100vw, 1230px\"\n                                  }\n                              },\n                              {\n                                  \"forFactor\": \"11/12\",\n                                  \"width\": 1100\n                              },\n                              {\n                                  \"forFactor\": \"1/12\",\n                                  \"width\": 75\n                              }\n                          ]\n                      }\n                  ]\n              }\n          ],\n          \"required\": [\n              \"name\",\n              \"variants\",\n              \"setWidth\",\n              \"attributes\",\n              \"recipes\"\n          ],\n          \"properties\": {\n              \"name\": {\n                  \"$id\": \"#/properties/recipe/properties/name\",\n                  \"type\": \"string\",\n                  \"title\": \"The name schema\",\n                  \"description\": \"An explanation about the purpose of this instance.\",\n                  \"default\": \"\",\n                  \"examples\": [\n                      \"default\"\n                  ]\n              },\n              \"variants\": {\n                  \"$id\": \"#/properties/recipe/properties/variants\",\n                  \"type\": \"string\",\n                  \"title\": \"The variants schema\",\n                  \"description\": \"An explanation about the purpose of this instance.\",\n                  \"default\": \"\",\n                  \"examples\": [\n                      \"2*, 1*, 3/4*, 1/2*\"\n                  ]\n              },\n              \"setWidth\": {\n                  \"$id\": \"#/properties/recipe/properties/setWidth\",\n                  \"type\": \"boolean\",\n                  \"title\": \"The setWidth schema\",\n                  \"description\": \"An explanation about the purpose of this instance.\",\n                  \"default\": false,\n                  \"examples\": [\n                      false\n                  ]\n              },\n              \"attributes\": {\n                  \"$id\": \"#/properties/recipe/properties/attributes\",\n                  \"type\": \"object\",\n                  \"title\": \"The attributes schema\",\n                  \"description\": \"An explanation about the purpose of this instance.\",\n                  \"default\": {},\n                  \"examples\": [\n                      {\n                          \"loading\": \"lazy\"\n                      }\n                  ],\n                  \"required\": [\n                      \"loading\"\n                  ],\n                  \"properties\": {\n                      \"loading\": {\n                          \"$id\": \"#/properties/recipe/properties/attributes/properties/loading\",\n                          \"type\": \"string\",\n                          \"title\": \"The loading schema\",\n                          \"description\": \"An explanation about the purpose of this instance.\",\n                          \"default\": \"\",\n                          \"examples\": [\n                              \"lazy\"\n                          ]\n                      }\n                  },\n                  \"additionalProperties\": true\n              },\n              \"recipes\": {\n                  \"$id\": \"#/properties/recipe/properties/recipes\",\n                  \"type\": \"array\",\n                  \"title\": \"The recipes schema\",\n                  \"description\": \"An explanation about the purpose of this instance.\",\n                  \"default\": [],\n                  \"examples\": [\n                      [\n                          {\n                              \"name\": \"Experimental Bootstrap3\",\n                              \"forCss\": \"bs3\",\n                              \"attributes\": {\n                                  \"class\": \"img-responsive\"\n                              },\n                              \"setWidth\": false\n                          },\n                          {\n                              \"name\": \"Experimental Bootstrap5\",\n                              \"forCss\": \"bs5\",\n                              \"attributes\": {\n                                  \"class\": \"img-fluid\"\n                              },\n                              \"setWidth\": true,\n                              \"recipes\": [\n                                  {\n                                      \"forFactor\": \"12/12\",\n                                      \"width\": 1230,\n                                      \"attributes\": {\n                                          \"sizes\": \"(max-width: 1400px) 100vw, 1230px\"\n                                      }\n                                  },\n                                  {\n                                      \"forFactor\": \"11/12\",\n                                      \"width\": 1100\n                                  },\n                                  {\n                                      \"forFactor\": \"1/12\",\n                                      \"width\": 75\n                                  }\n                              ]\n                          }\n                      ]\n                  ],\n                  \"additionalItems\": true,\n                  \"items\": {\n                      \"$id\": \"#/properties/recipe/properties/recipes/items\",\n                      \"anyOf\": [\n                          {\n                              \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/0\",\n                              \"type\": \"object\",\n                              \"title\": \"The first anyOf schema\",\n                              \"description\": \"An explanation about the purpose of this instance.\",\n                              \"default\": {},\n                              \"examples\": [\n                                  {\n                                      \"name\": \"Experimental Bootstrap3\",\n                                      \"forCss\": \"bs3\",\n                                      \"attributes\": {\n                                          \"class\": \"img-responsive\"\n                                      },\n                                      \"setWidth\": false\n                                  }\n                              ],\n                              \"required\": [\n                                  \"name\",\n                                  \"forCss\",\n                                  \"attributes\",\n                                  \"setWidth\"\n                              ],\n                              \"properties\": {\n                                  \"name\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/0/properties/name\",\n                                      \"type\": \"string\",\n                                      \"title\": \"The name schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": \"\",\n                                      \"examples\": [\n                                          \"Experimental Bootstrap3\"\n                                      ]\n                                  },\n                                  \"forCss\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/0/properties/forCss\",\n                                      \"type\": \"string\",\n                                      \"title\": \"The forCss schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": \"\",\n                                      \"examples\": [\n                                          \"bs3\"\n                                      ]\n                                  },\n                                  \"attributes\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/0/properties/attributes\",\n                                      \"type\": \"object\",\n                                      \"title\": \"The attributes schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": {},\n                                      \"examples\": [\n                                          {\n                                              \"class\": \"img-responsive\"\n                                          }\n                                      ],\n                                      \"required\": [\n                                          \"class\"\n                                      ],\n                                      \"properties\": {\n                                          \"class\": {\n                                              \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/0/properties/attributes/properties/class\",\n                                              \"type\": \"string\",\n                                              \"title\": \"The class schema\",\n                                              \"description\": \"An explanation about the purpose of this instance.\",\n                                              \"default\": \"\",\n                                              \"examples\": [\n                                                  \"img-responsive\"\n                                              ]\n                                          }\n                                      },\n                                      \"additionalProperties\": true\n                                  },\n                                  \"setWidth\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/0/properties/setWidth\",\n                                      \"type\": \"boolean\",\n                                      \"title\": \"The setWidth schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": false,\n                                      \"examples\": [\n                                          false\n                                      ]\n                                  }\n                              },\n                              \"additionalProperties\": true\n                          },\n                          {\n                              \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1\",\n                              \"type\": \"object\",\n                              \"title\": \"The second anyOf schema\",\n                              \"description\": \"An explanation about the purpose of this instance.\",\n                              \"default\": {},\n                              \"examples\": [\n                                  {\n                                      \"name\": \"Experimental Bootstrap5\",\n                                      \"forCss\": \"bs5\",\n                                      \"attributes\": {\n                                          \"class\": \"img-fluid\"\n                                      },\n                                      \"setWidth\": true,\n                                      \"recipes\": [\n                                          {\n                                              \"forFactor\": \"12/12\",\n                                              \"width\": 1230,\n                                              \"attributes\": {\n                                                  \"sizes\": \"(max-width: 1400px) 100vw, 1230px\"\n                                              }\n                                          },\n                                          {\n                                              \"forFactor\": \"11/12\",\n                                              \"width\": 1100\n                                          },\n                                          {\n                                              \"forFactor\": \"1/12\",\n                                              \"width\": 75\n                                          }\n                                      ]\n                                  }\n                              ],\n                              \"required\": [\n                                  \"name\",\n                                  \"forCss\",\n                                  \"attributes\",\n                                  \"setWidth\",\n                                  \"recipes\"\n                              ],\n                              \"properties\": {\n                                  \"name\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/name\",\n                                      \"type\": \"string\",\n                                      \"title\": \"The name schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": \"\",\n                                      \"examples\": [\n                                          \"Experimental Bootstrap5\"\n                                      ]\n                                  },\n                                  \"forCss\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/forCss\",\n                                      \"type\": \"string\",\n                                      \"title\": \"The forCss schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": \"\",\n                                      \"examples\": [\n                                          \"bs5\"\n                                      ]\n                                  },\n                                  \"attributes\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/attributes\",\n                                      \"type\": \"object\",\n                                      \"title\": \"The attributes schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": {},\n                                      \"examples\": [\n                                          {\n                                              \"class\": \"img-fluid\"\n                                          }\n                                      ],\n                                      \"required\": [\n                                          \"class\"\n                                      ],\n                                      \"properties\": {\n                                          \"class\": {\n                                              \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/attributes/properties/class\",\n                                              \"type\": \"string\",\n                                              \"title\": \"The class schema\",\n                                              \"description\": \"An explanation about the purpose of this instance.\",\n                                              \"default\": \"\",\n                                              \"examples\": [\n                                                  \"img-fluid\"\n                                              ]\n                                          }\n                                      },\n                                      \"additionalProperties\": true\n                                  },\n                                  \"setWidth\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/setWidth\",\n                                      \"type\": \"boolean\",\n                                      \"title\": \"The setWidth schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": false,\n                                      \"examples\": [\n                                          true\n                                      ]\n                                  },\n                                  \"recipes\": {\n                                      \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes\",\n                                      \"type\": \"array\",\n                                      \"title\": \"The recipes schema\",\n                                      \"description\": \"An explanation about the purpose of this instance.\",\n                                      \"default\": [],\n                                      \"examples\": [\n                                          [\n                                              {\n                                                  \"forFactor\": \"12/12\",\n                                                  \"width\": 1230,\n                                                  \"attributes\": {\n                                                      \"sizes\": \"(max-width: 1400px) 100vw, 1230px\"\n                                                  }\n                                              },\n                                              {\n                                                  \"forFactor\": \"11/12\",\n                                                  \"width\": 1100\n                                              }\n                                          ]\n                                      ],\n                                      \"additionalItems\": true,\n                                      \"items\": {\n                                          \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items\",\n                                          \"anyOf\": [\n                                              {\n                                                  \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items/anyOf/0\",\n                                                  \"type\": \"object\",\n                                                  \"title\": \"The first anyOf schema\",\n                                                  \"description\": \"An explanation about the purpose of this instance.\",\n                                                  \"default\": {},\n                                                  \"examples\": [\n                                                      {\n                                                          \"forFactor\": \"12/12\",\n                                                          \"width\": 1230,\n                                                          \"attributes\": {\n                                                              \"sizes\": \"(max-width: 1400px) 100vw, 1230px\"\n                                                          }\n                                                      }\n                                                  ],\n                                                  \"required\": [\n                                                      \"forFactor\",\n                                                      \"width\",\n                                                      \"attributes\"\n                                                  ],\n                                                  \"properties\": {\n                                                      \"forFactor\": {\n                                                          \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items/anyOf/0/properties/forFactor\",\n                                                          \"type\": \"string\",\n                                                          \"title\": \"The forFactor schema\",\n                                                          \"description\": \"An explanation about the purpose of this instance.\",\n                                                          \"default\": \"\",\n                                                          \"examples\": [\n                                                              \"12/12\"\n                                                          ]\n                                                      },\n                                                      \"width\": {\n                                                          \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items/anyOf/0/properties/width\",\n                                                          \"type\": \"integer\",\n                                                          \"title\": \"The width schema\",\n                                                          \"description\": \"An explanation about the purpose of this instance.\",\n                                                          \"default\": 0,\n                                                          \"examples\": [\n                                                              1230\n                                                          ]\n                                                      },\n                                                      \"attributes\": {\n                                                          \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items/anyOf/0/properties/attributes\",\n                                                          \"type\": \"object\",\n                                                          \"title\": \"The attributes schema\",\n                                                          \"description\": \"An explanation about the purpose of this instance.\",\n                                                          \"default\": {},\n                                                          \"examples\": [\n                                                              {\n                                                                  \"sizes\": \"(max-width: 1400px) 100vw, 1230px\"\n                                                              }\n                                                          ],\n                                                          \"required\": [\n                                                              \"sizes\"\n                                                          ],\n                                                          \"properties\": {\n                                                              \"sizes\": {\n                                                                  \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items/anyOf/0/properties/attributes/properties/sizes\",\n                                                                  \"type\": \"string\",\n                                                                  \"title\": \"The sizes schema\",\n                                                                  \"description\": \"An explanation about the purpose of this instance.\",\n                                                                  \"default\": \"\",\n                                                                  \"examples\": [\n                                                                      \"(max-width: 1400px) 100vw, 1230px\"\n                                                                  ]\n                                                              }\n                                                          },\n                                                          \"additionalProperties\": true\n                                                      }\n                                                  },\n                                                  \"additionalProperties\": true\n                                              },\n                                              {\n                                                  \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items/anyOf/1\",\n                                                  \"type\": \"object\",\n                                                  \"title\": \"The second anyOf schema\",\n                                                  \"description\": \"An explanation about the purpose of this instance.\",\n                                                  \"default\": {},\n                                                  \"examples\": [\n                                                      {\n                                                          \"forFactor\": \"11/12\",\n                                                          \"width\": 1100\n                                                      }\n                                                  ],\n                                                  \"required\": [\n                                                      \"forFactor\",\n                                                      \"width\"\n                                                  ],\n                                                  \"properties\": {\n                                                      \"forFactor\": {\n                                                          \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items/anyOf/1/properties/forFactor\",\n                                                          \"type\": \"string\",\n                                                          \"title\": \"The forFactor schema\",\n                                                          \"description\": \"An explanation about the purpose of this instance.\",\n                                                          \"default\": \"\",\n                                                          \"examples\": [\n                                                              \"11/12\"\n                                                          ]\n                                                      },\n                                                      \"width\": {\n                                                          \"$id\": \"#/properties/recipe/properties/recipes/items/anyOf/1/properties/recipes/items/anyOf/1/properties/width\",\n                                                          \"type\": \"integer\",\n                                                          \"title\": \"The width schema\",\n                                                          \"description\": \"An explanation about the purpose of this instance.\",\n                                                          \"default\": 0,\n                                                          \"examples\": [\n                                                              1100\n                                                          ]\n                                                      }\n                                                  },\n                                                  \"additionalProperties\": true\n                                              }\n                                          ]\n                                      }\n                                  }\n                              },\n                              \"additionalProperties\": true\n                          }\n                      ]\n                  }\n              }\n          },\n          \"additionalProperties\": true\n      }\n  },\n  \"additionalProperties\": true\n}"
  },
  {
    "path": "Src/Data-Dnn/App_Data/system/contenttypes/System.DataSources.Config ToSic.SexyContent.DataSources.DnnFormAndList.json",
    "content": "{\"_\":{\"V\":1},\"ContentType\":{\"Id\":\"|Config ToSic.SexyContent.DataSources.DnnFormAndList\",\"Name\":\"|Config ToSic.SexyContent.DataSources.DnnFormAndList\",\"Scope\":\"System.DataSources\",\"Description\":\"Configuration for the Form and List Data Source\",\"Attributes\":[{\"Name\":\"Title\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":true,\"Metadata\":[{\"Id\":468,\"Version\":1,\"Guid\":\"eb7cacd2-6da7-42cf-a38c-3c1e0b6f4457\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"FnL DataSource Configuration\"},\"Name\":{\"*\":\"Title\"},\"Notes\":{\"*\":\"<p>Just a title for you to give this configuration a name.</p>\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Required\":{\"*\":true},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-070000\"}]},{\"Name\":\"ModuleId\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":469,\"Version\":1,\"Guid\":\"f7093be0-ebc7-4759-aa90-d54808ba0fe2\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"Name\":{\"*\":\"FnL Module Id\"},\"Notes\":{\"*\":\"<p>The ID of the Form and List Module in DNN. The Data will be retrieved from that specific module.&nbsp;</p>\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Required\":{\"*\":true},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-070000\"}]},{\"Name\":\"TitleFieldName\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":470,\"Version\":1,\"Guid\":\"48ff65ea-ba00-4243-87c5-9132f24cd593\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"Name\":{\"*\":\"Title Field Name\"},\"Notes\":{\"*\":\"<span>The column in Form and List which should become the title of the resulting content-items. If you leave this blank, the system will just pick the first column as title.&nbsp;</span>\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-070000\"}]},{\"Name\":\"ContentTypeName\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":471,\"Version\":1,\"Guid\":\"fef1a456-4e74-4299-8a1b-792da607a5ec\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"Name\":{\"*\":\"Content Type Name\"},\"Notes\":{\"*\":\"<p>This is the internal name for the resulting Content-Type. Usually not important, if you leave it blank a default value (usually FnL) is used.&nbsp;</p>\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-070000\"}]}],\"Sharing\":{\"AlwaysShare\":true,\"ParentZoneId\":1,\"ParentAppId\":1},\"Metadata\":[]}}"
  },
  {
    "path": "Src/Data-Dnn/App_Data/system/contenttypes/System.DataSources.Config ToSic.SexyContent.DataSources.DnnSqlDataSource.json",
    "content": "{\"_\":{\"V\":1},\"ContentType\":{\"Id\":\"|Config ToSic.SexyContent.DataSources.DnnSqlDataSource\",\"Name\":\"ToSic.SexyContent.DataSources.DnnSqlDataSource\",\"Scope\":\"System.DataSources\",\"Description\":\"used to configure a DNN SqlDataSource\",\"Attributes\":[{\"Name\":\"ContentType\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":true,\"Metadata\":[{\"Id\":46932,\"Version\":7,\"Guid\":\"5bfdf93e-8fa4-40e2-bb76-3e13af2ad26c\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"en-us\":\"\"},\"DefaultValue\":{\"en-us\":\"\"},\"InputType\":{\"en-us\":\"string-default\"},\"Name\":{\"en-us\":\"Content Type Name\"},\"Notes\":{\"en-us\":\"<p>The Content-Type name used for entities which are created from SQL.</p>\"},\"Placeholder\":{\"en-us\":\"\"},\"ValidationRegExJavaScript\":{\"en-us\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Formulas\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"en-us\":false},\"DisableTranslation\":{\"en-us\":false},\"Required\":{\"en-us\":false},\"VisibleInEditUI\":{\"en-us\":true}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46933,\"Version\":6,\"Guid\":\"2ee4cd3f-5d63-46d6-8c55-ca9106521023\",\"Type\":{\"Name\":\"@String\",\"Id\":\"@String\"},\"Attributes\":{\"String\":{\"DropdownValues\":{\"en-us\":\"\"},\"InputType\":{\"en-us\":\"\"}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46950,\"Version\":5,\"Guid\":\"a79dbf61-08f9-4f3a-a7e9-baf797b8a2d0\",\"Type\":{\"Name\":\"@string-default\",\"Id\":\"@string-default\"},\"Attributes\":{\"String\":{\"InputFontFamily\":{\"en-us\":\"\"}},\"Number\":{\"RowCount\":{\"en-us\":1}}},\"Owner\":\"dnn:userid=1\"}]},{\"Name\":\"SelectCommand\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":46934,\"Version\":6,\"Guid\":\"2cc30c2a-4bf6-425d-beb6-920a1e3b155d\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"en-us\":\"\"},\"DefaultValue\":{\"en-us\":\"\"},\"InputType\":{\"en-us\":\"string-default\"},\"Name\":{\"en-us\":\"Select Command\"},\"Notes\":{\"en-us\":\"\"},\"Placeholder\":{\"en-us\":\"\"},\"ValidationRegExJavaScript\":{\"en-us\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Formulas\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"en-us\":false},\"DisableTranslation\":{\"en-us\":false},\"Required\":{\"en-us\":false},\"VisibleInEditUI\":{\"en-us\":true}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46935,\"Version\":5,\"Guid\":\"b8485426-d16a-4cc7-a4f5-5b8bc4e5cd5f\",\"Type\":{\"Name\":\"@String\",\"Id\":\"@String\"},\"Attributes\":{\"String\":{\"DropdownValues\":{\"en-us\":\"\"},\"InputType\":{\"en-us\":\"default\"}},\"Number\":{\"RowCount\":{\"en-us\":10}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46949,\"Version\":4,\"Guid\":\"db1728dd-1eca-491d-ac4c-ae618dff6a11\",\"Type\":{\"Name\":\"@string-default\",\"Id\":\"@string-default\"},\"Attributes\":{\"String\":{\"InputFontFamily\":{\"en-us\":\"\"}},\"Number\":{\"RowCount\":{\"en-us\":10}}},\"Owner\":\"dnn:userid=1\"}]}],\"Metadata\":[{\"Id\":46951,\"Version\":2,\"Guid\":\"e7e45a1c-38b2-4fa5-8801-fd1519d90ef4\",\"Type\":{\"Name\":\"ContentType\",\"Id\":\"ContentType\"},\"Attributes\":{\"String\":{\"Description\":{\"*\":\"used to configure a DNN SqlDataSource\"},\"EditInstructions\":{\"*\":\"<p>Read about this in the <a href=\\\"https://docs.2sxc.org/api/dot-net/ToSic.Sxc.Dnn.DataSources.DnnSql.html\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">docs</a></p>\"},\"Label\":{\"*\":\"DNN SQL DataSource\"},\"ListInstructions\":{\"*\":\"\"},\"Notes\":{\"*\":\"\"}},\"Hyperlink\":{\"Icon\":{\"*\":\"\"},\"Link\":{\"*\":\"\"}}},\"Owner\":\"dnn:userid=1\",\"For\":{\"Target\":\"ContentType\",\"TargetType\":5,\"String\":\"|Config ToSic.SexyContent.DataSources.DnnSqlDataSource\"}}]},\"Entities\":[]}"
  },
  {
    "path": "Src/Data-Dnn/App_Data/system/contenttypes/System.DataSources.Config ToSic.SexyContent.DataSources.DnnUserProfileDataSource.json",
    "content": "{\"_\":{\"V\":1},\"ContentType\":{\"Id\":\"|Config ToSic.SexyContent.DataSources.DnnUserProfileDataSource\",\"Name\":\"ToSic.SexyContent.DataSources.DnnUserProfileDataSource\",\"Scope\":\"System.DataSources\",\"Description\":\"Configuration for DNN UserProfile DataSource\",\"Attributes\":[{\"Name\":\"TitleFieldName\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":true,\"Metadata\":[{\"Id\":46936,\"Version\":1,\"Guid\":\"fa7be2bc-62c7-4677-9b78-f60be4e2a941\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"*\":\"\"},\"DefaultValue\":{\"*\":\"DisplayName\"},\"InputType\":{\"*\":\"string-default\"},\"Name\":{\"*\":\"Title Field Name\"},\"Notes\":{\"*\":\"<p>The&nbsp;profile field which should&nbsp;define&nbsp;title - and will be available on the object as&nbsp;EntityTitle. You can always <a href=\\\"http://2sxc.org/en/help?tag=ToSic.SexyContent.DataSources.DnnUserProfileDataSource\\\" target=\\\"_blank\\\">get more help here</a>.</p>\"},\"ValidationRegExJavaScript\":{\"*\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"*\":false},\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46937,\"Version\":1,\"Guid\":\"1fd75026-ee7b-41f5-a2ab-e299b302de47\",\"Type\":{\"Name\":\"@String\",\"Id\":\"@String\"},\"Attributes\":{\"String\":{\"DropdownValues\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"}},\"Number\":{\"RowCount\":{\"*\":1.0}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46938,\"Version\":1,\"Guid\":\"66c62507-0a7b-4860-8e56-76a439eca058\",\"Type\":{\"Name\":\"@string-default\",\"Id\":\"@string-default\"},\"Attributes\":{\"Number\":{\"RowCount\":{\"*\":1.0}}},\"Owner\":\"dnn:userid=1\"}]},{\"Name\":\"Properties\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":46939,\"Version\":1,\"Guid\":\"5c3f7727-a8b9-44a1-a3ff-299e8ec96f4d\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"*\":\"\"},\"DefaultValue\":{\"*\":\"DisplayName,Email,FirstName,LastName,Username,City,Website\"},\"InputType\":{\"*\":\"string-default\"},\"Name\":{\"*\":\"Properties\"},\"Notes\":{\"*\":\"<p>List the profile properties you want to provide.&nbsp;Typically this includes&nbsp;DisplayName,FirstName,LastName, etc. Remember to <a href=\\\"http://2sxc.org/en/help?tag=ToSic.SexyContent.DataSources.DnnUserProfileDataSource\\\" target=\\\"_blank\\\">check the help for more guidance</a>.</p>\"},\"ValidationRegExJavaScript\":{\"*\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"*\":false},\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46940,\"Version\":1,\"Guid\":\"cf30ac5b-1d15-4456-818f-1ca652f97846\",\"Type\":{\"Name\":\"@String\",\"Id\":\"@String\"},\"Attributes\":{\"String\":{\"DropdownValues\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"}},\"Number\":{\"RowCount\":{\"*\":1.0}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46941,\"Version\":1,\"Guid\":\"cabe7daf-ca2e-4abb-9c99-3e0523bcabc2\",\"Type\":{\"Name\":\"@string-default\",\"Id\":\"@string-default\"},\"Attributes\":{\"Number\":{\"RowCount\":{\"*\":1.0}}},\"Owner\":\"dnn:userid=1\"}]},{\"Name\":\"ContentTypeName\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":46942,\"Version\":1,\"Guid\":\"9e0b5607-5bca-4883-ab8f-305193f4621f\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"*\":\"\"},\"DefaultValue\":{\"*\":\"Profile\"},\"InputType\":{\"*\":\"string-default\"},\"Name\":{\"*\":\"Content Type Name\"},\"Notes\":{\"*\":\"<p>An optional term for the content-type as it will be used in your program. Example: \\\"Profile\\\"</p>\"},\"ValidationRegExJavaScript\":{\"*\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"*\":false},\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46943,\"Version\":1,\"Guid\":\"8eaac900-dd5a-4dfb-a8e9-d74bb93de039\",\"Type\":{\"Name\":\"@String\",\"Id\":\"@String\"},\"Attributes\":{\"String\":{\"DropdownValues\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"}},\"Number\":{\"RowCount\":{\"*\":1.0}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46944,\"Version\":1,\"Guid\":\"a35cec6a-a901-44d9-bbd5-c0ffd7938ee0\",\"Type\":{\"Name\":\"@string-default\",\"Id\":\"@string-default\"},\"Attributes\":{\"Number\":{\"RowCount\":{\"*\":1.0}}},\"Owner\":\"dnn:userid=1\"}]},{\"Name\":\"UserIds\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":46945,\"Version\":1,\"Guid\":\"2d6a7d60-d051-4b78-bf85-c21691051c43\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"*\":\"\"},\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"string-default\"},\"Name\":{\"*\":\"User IDs\"},\"Notes\":{\"*\":\"<p>Use this to&nbsp;limit the profiles to certain users, like \\\"740,50603,203\\\" - you can also use tokens of course, like [QueryString:UserId]. Leave blank to not filter by user-id.</p>\"},\"ValidationRegExJavaScript\":{\"*\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"*\":false},\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46946,\"Version\":1,\"Guid\":\"0752361d-2609-4530-8e27-7427363e5862\",\"Type\":{\"Name\":\"@String\",\"Id\":\"@String\"},\"Attributes\":{\"String\":{\"DropdownValues\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"}},\"Number\":{\"RowCount\":{\"*\":1.0}}},\"Owner\":\"dnn:userid=1\"},{\"Id\":46947,\"Version\":1,\"Guid\":\"aedffcdd-bf55-4876-9dc3-f73fc9156198\",\"Type\":{\"Name\":\"@string-default\",\"Id\":\"@string-default\"},\"Attributes\":{\"Number\":{\"RowCount\":{\"*\":1.0}}},\"Owner\":\"dnn:userid=1\"}]}],\"Metadata\":[{\"Id\":74256,\"Version\":1,\"Guid\":\"993e890b-62a6-4de8-b62f-30d742db3244\",\"Type\":{\"Name\":\"ContentType\",\"Id\":\"ContentType\"},\"Attributes\":{\"String\":{\"Description\":{\"*\":\"Configuration for DNN UserProfile DataSource\"},\"EditInstructions\":{\"*\":\"\"},\"Label\":{\"*\":\"DNN User Profile\"},\"ListInstructions\":{\"*\":\"\"},\"Notes\":{\"*\":\"\"}},\"Hyperlink\":{\"Icon\":{\"*\":\"\"},\"Link\":{\"*\":\"\"}}},\"Owner\":\"dnn:userid=1\",\"For\":{\"Target\":\"ContentType\",\"String\":\"|Config ToSic.SexyContent.DataSources.DnnUserProfileDataSource\"}}]}}"
  },
  {
    "path": "Src/Data-Dnn/App_Data/system/contenttypes/System.DataSources.Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnFormAndList.json",
    "content": "{\"_\":{\"V\":1},\"ContentType\":{\"Id\":\"|Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnFormAndList\",\"Name\":\"|Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnFormAndList\",\"Scope\":\"System.DataSources\",\"Description\":\"Configuration for the Form and List Data Source\",\"Attributes\":[{\"Name\":\"Title\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":true,\"Metadata\":[{\"Id\":694,\"Version\":1,\"Guid\":\"f9047247-5d8b-4c18-85e7-80dc81041c99\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"FnL DataSource Configuration\"},\"InputType\":{\"*\":\"\"},\"Name\":{\"*\":\"Title\"},\"Notes\":{\"*\":\"<p>Just a title for you to give this configuration a name.</p>\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Required\":{\"*\":true},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]},{\"Name\":\"ModuleId\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":695,\"Version\":1,\"Guid\":\"25550deb-d5be-48e9-bbdd-3e32603e1b2f\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"},\"Name\":{\"*\":\"FnL Module Id\"},\"Notes\":{\"*\":\"<p>The ID of the Form and List Module in DNN. The Data will be retrieved from that specific module.&nbsp;</p>\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Required\":{\"*\":true},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]},{\"Name\":\"TitleFieldName\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":696,\"Version\":1,\"Guid\":\"3cc9e8bb-98f8-4f28-a474-f200c0da54be\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"},\"Name\":{\"*\":\"Title Field Name\"},\"Notes\":{\"*\":\"<span>The column in Form and List which should become the title of the resulting content-items. If you leave this blank, the system will just pick the first column as title.&nbsp;</span>\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]},{\"Name\":\"ContentTypeName\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":697,\"Version\":1,\"Guid\":\"bff61cfd-4362-4c86-ac88-19f2cce62644\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"},\"Name\":{\"*\":\"Content Type Name\"},\"Notes\":{\"*\":\"<p>This is the internal name for the resulting Content-Type. Usually not important, if you leave it blank a default value (usually FnL) is used.&nbsp;</p>\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]}],\"Sharing\":{\"AlwaysShare\":true,\"ParentZoneId\":1,\"ParentAppId\":1},\"Metadata\":[]}}"
  },
  {
    "path": "Src/Data-Dnn/App_Data/system/contenttypes/System.DataSources.Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnSqlDataSource.json",
    "content": "{\"_\":{\"V\":1},\"ContentType\":{\"Id\":\"|Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnSqlDataSource\",\"Name\":\"|Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnSqlDataSource\",\"Scope\":\"System.DataSources\",\"Description\":\"used to configure a DNN SqlDataSource\",\"Attributes\":[{\"Name\":\"ContentType\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":true,\"Metadata\":[{\"Id\":698,\"Version\":1,\"Guid\":\"94eb1219-a3be-4e85-ac2d-83937776897a\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"},\"Name\":{\"*\":\"ContentType\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"},{\"Id\":699,\"Version\":1,\"Guid\":\"098fee4d-7674-4539-9e95-4fc7bd7dfdbe\",\"Type\":{\"Name\":\"@String\",\"Id\":\"@String\"},\"Attributes\":{},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]},{\"Name\":\"SelectCommand\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":700,\"Version\":1,\"Guid\":\"276ccd93-0b75-4636-a676-48f64edfe387\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"\"},\"Name\":{\"*\":\"SelectCommand\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"},{\"Id\":701,\"Version\":1,\"Guid\":\"9224d287-5874-4b47-b126-193c0c187632\",\"Type\":{\"Name\":\"@String\",\"Id\":\"@String\"},\"Attributes\":{\"Number\":{\"RowCount\":{\"*\":10.0}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]}],\"Sharing\":{\"AlwaysShare\":true,\"ParentZoneId\":1,\"ParentAppId\":1},\"Metadata\":[]}}"
  },
  {
    "path": "Src/Data-Dnn/App_Data/system/contenttypes/System.DataSources.Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnUserProfileDataSource.json",
    "content": "{\"_\":{\"V\":1},\"ContentType\":{\"Id\":\"|Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnUserProfileDataSource\",\"Name\":\"|Config ToSic.SexyContent.Environment.Dnn7.DataSources.DnnUserProfileDataSource\",\"Scope\":\"System.DataSources\",\"Description\":\"Configuration for DNN UserProfile DataSource\",\"Attributes\":[{\"Name\":\"TitleFieldName\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":true,\"Metadata\":[{\"Id\":702,\"Version\":1,\"Guid\":\"e954062a-2c38-4029-ad35-c3bcb38751d6\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"*\":\"\"},\"DefaultValue\":{\"*\":\"DisplayName\"},\"InputType\":{\"*\":\"string-default\"},\"Name\":{\"*\":\"Title Field Name\"},\"Notes\":{\"*\":\"<p>The&nbsp;profile field which should&nbsp;define&nbsp;title - and will be available on the object as&nbsp;EntityTitle. You can always <a href=\\\"http://2sxc.org/en/help?tag=ToSic.SexyContent.DataSources.DnnUserProfileDataSource\\\" target=\\\"_blank\\\">get more help here</a>.</p>\"},\"ValidationRegExJavaScript\":{\"*\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"*\":false},\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]},{\"Name\":\"Properties\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":703,\"Version\":1,\"Guid\":\"92f15927-f21a-4649-823c-5cabd3f4b01b\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"*\":\"\"},\"DefaultValue\":{\"*\":\"DisplayName,Email,FirstName,LastName,Username,City,Website\"},\"InputType\":{\"*\":\"string-default\"},\"Name\":{\"*\":\"Properties\"},\"Notes\":{\"*\":\"<p>List the profile properties you want to provide.&nbsp;Typically this includes&nbsp;DisplayName,FirstName,LastName, etc. Remember to <a href=\\\"http://2sxc.org/en/help?tag=ToSic.SexyContent.DataSources.DnnUserProfileDataSource\\\" target=\\\"_blank\\\">check the help for more guidance</a>.</p>\"},\"ValidationRegExJavaScript\":{\"*\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"*\":false},\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]},{\"Name\":\"ContentTypeName\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":704,\"Version\":1,\"Guid\":\"c9d43e11-6e20-4da7-aa0d-06c3e92092f0\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"*\":\"\"},\"DefaultValue\":{\"*\":\"Profile\"},\"InputType\":{\"*\":\"string-default\"},\"Name\":{\"*\":\"Content Type Name\"},\"Notes\":{\"*\":\"<p>An optional term for the content-type as it will be used in your program. Example: \\\"Profile\\\"</p>\"},\"ValidationRegExJavaScript\":{\"*\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"*\":false},\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]},{\"Name\":\"UserIds\",\"Type\":\"String\",\"InputType\":\"string-default\",\"IsTitle\":false,\"Metadata\":[{\"Id\":705,\"Version\":1,\"Guid\":\"14df746f-ed68-4560-b482-212f45f069e1\",\"Type\":{\"Name\":\"@All\",\"Id\":\"@All\"},\"Attributes\":{\"String\":{\"CustomJavaScript\":{\"*\":\"\"},\"DefaultValue\":{\"*\":\"\"},\"InputType\":{\"*\":\"string-default\"},\"Name\":{\"*\":\"User IDs\"},\"Notes\":{\"*\":\"<p>Use this to&nbsp;limit the profiles to certain users, like \\\"740,50603,203\\\" - you can also use tokens of course, like [QueryString:UserId]. Leave blank to not filter by user-id.</p>\"},\"ValidationRegExJavaScript\":{\"*\":\"\"}},\"Entity\":{\"Errors\":{\"*\":[]},\"Warnings\":{\"*\":[]}},\"Boolean\":{\"Disabled\":{\"*\":false},\"Required\":{\"*\":false},\"VisibleInEditUI\":{\"*\":true}}},\"Owner\":\"System-ModuleUpgrade-08.05.05\"}]}],\"Sharing\":{\"AlwaysShare\":true,\"ParentZoneId\":1,\"ParentAppId\":1},\"Metadata\":[]}}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/.gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.sln.docstates\n.vs\n\n# Build results\n\n[Dd]ebug/\n[Rr]elease/\nx64/\nbuild/\n[Bb]in/\n[Oo]bj/\n\n# Enable \"build/\" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets\n!packages/*/build/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n*_i.c\n*_p.c\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.log\n*.scc\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n*.cachefile\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n\n# Windows Azure Build Output\ncsx\n*.build.csdef\n\n# Others\nClientBin/\n\n# =========================\n# Windows detritus\n# =========================\n\n# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# =========================\n# DNN Module\n# =========================\n\n# Ignore .manifest file created by DNN while installing the module\nResources.zip.manifest\n\n# Ignore ModulePackages\n/ModulePackages/\n\n/Upgrade/Log\n/Packages/\n/_/\n\n# include bin files from koi, razor blade, and old-razorblade\n!koi/bin/\n!razorblade/bin/\n!razorblade-old/bin/\n!Extensions/ImageResizer/bin/\n!Extensions/Imageflow/bin/\n\n# Test data\n\\.data-custom/configurations/features.json\n.data-custom/contenttypes 2/\n\\.data-custom/configurations/**\n.data-custom/configurations/**"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/App_LocalResources/View.ascx.de-DE.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"ActionChangeLayoutOrContent.Text\" xml:space=\"preserve\">\n    <value>Vorlage wechseln</value>\n  </data>\n  <data name=\"ActionEdit.Text\" xml:space=\"preserve\">\n    <value>Bearbeiten</value>\n  </data>\n  <data name=\"hlkConfigurePortal.Text\" xml:space=\"preserve\">\n    <value>Portal Konfigurieren</value>\n  </data>\n  <data name=\"NoDemoItem.Text\" xml:space=\"preserve\">\n    <value>Für die ausgewählte Vorlage wurde noch kein Inhalt eingegeben.</value>\n  </data>\n  <data name=\"TemplateConfigurationMissing.Text\" xml:space=\"preserve\">\n    <value>Die gewählte Vorlage existiert nicht mehr.</value>\n  </data>\n  <data name=\"ActionEditTemplateFile.Text\" xml:space=\"preserve\">\n    <value>Vorlage bearbeiten</value>\n  </data>\n  <data name=\"ActionAdd.Text\" xml:space=\"preserve\">\n    <value>Hinzufügen</value>\n  </data>\n  <data name=\"ActionList.Text\" xml:space=\"preserve\">\n    <value>Liste bearbeiten</value>\n  </data>\n  <data name=\"DeleteContentGroupItem.Text\" xml:space=\"preserve\">\n    <value>Möchten Sie \\\"{0} ({1})\\\" wirklich löschen?</value>\n  </data>\n  <data name=\"hlkConfigureZone.Text\" xml:space=\"preserve\">\n    <value>Klick hier um dies einzurichten</value>\n  </data>\n  <data name=\"ddlContentTypeDefaultItem.Text\" xml:space=\"preserve\">\n    <value>&lt;Typ des Inhalts auswählen&gt;</value>\n  </data>\n  <data name=\"TemplateError.Text\" xml:space=\"preserve\">\n    <value>&lt;b&gt;Beim Rendern des Templates ist ein Fehler aufgetreten&lt;/b&gt;</value>\n  </data>\n  <data name=\"EnableDataPublishing.Text\" xml:space=\"preserve\">\n    <value>Dieses Modul benötigt Daten vom Server. Wenn Du diese Meldung siehst, ist das Veröffentlichen für dieses Modul nicht aktiviert. Bitte aktiviere das in den Moduleinstellungen des Moduls {0} (das Modul mit dem Titel \"{1}\").</value>\n  </data>\n  <data name=\"btnInstallGettingStarted.Text\" xml:space=\"preserve\">\n    <value>\"Getting Started\" Vorlagen installieren</value>\n  </data>\n</root>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/App_LocalResources/View.ascx.fr-FR.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"ActionChangeLayoutOrContent.Text\" xml:space=\"preserve\">\n    <value>Changer de template/modèle</value>\n  </data>\n  <data name=\"ActionEdit.Text\" xml:space=\"preserve\">\n    <value>Éditer</value>\n  </data>\n  <data name=\"hlkConfigurePortal.Text\" xml:space=\"preserve\">\n    <value>Configurer</value>\n  </data>\n  <data name=\"NoDemoItem.Text\" xml:space=\"preserve\">\n    <value>Il n'existe pas encore d'item de démo pour le modèle (template) sélectionné.</value>\n  </data>\n  <data name=\"TemplateConfigurationMissing.Text\" xml:space=\"preserve\">\n    <value>Le modèle (tempalte) sélectionné n'existe pas.</value>\n  </data>\n  <data name=\"ActionEditTemplateFile.Text\" xml:space=\"preserve\">\n    <value>Éditer le template</value>\n  </data>\n  <data name=\"ActionAdd.Text\" xml:space=\"preserve\">\n    <value>Ajouter un item</value>\n  </data>\n  <data name=\"ActionList.Text\" xml:space=\"preserve\">\n    <value>Éditer la liste</value>\n  </data>\n  <data name=\"DeleteContentGroupItem.Text\" xml:space=\"preserve\">\n    <value>Voulez-vous supprimer l'item \\\"{0} ({1})\\\"?</value>\n  </data>\n  <data name=\"hlkConfigureZone.Text\" xml:space=\"preserve\">\n    <value>Cliquer ici pour le paramétrer</value>\n  </data>\n  <data name=\"ddlContentTypeDefaultItem.Text\" xml:space=\"preserve\">\n    <value>&lt;Choisir un modèle de contenu&gt;</value>\n  </data>\n  <data name=\"TemplateError.Text\" xml:space=\"preserve\">\n    <value>&lt;b&gt;Une erreur s'est produite lors du rendu du modèle (template)&lt;/b&gt;</value>\n  </data>\n  <data name=\"x84oldEnableDataPublishing.Text\" xml:space=\"preserve\">\n    <value>Ce module tente de récupérer les données du serveur. Si vous voyez ce message, c'est parce que Data Publishing n'est pas activé sur ce module. Veuillez l'activer dans les paramètres du module {0} (le module avec le titre \"{1}\").</value>\n  </data>\n  <data name=\"btnInstallGettingStarted.Text\" xml:space=\"preserve\">\n    <value>Installer \"Getting Started\" templates</value>\n  </data>\n</root>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/App_LocalResources/View.ascx.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"ActionChangeLayoutOrContent.Text\" xml:space=\"preserve\">\n    <value>Change Template / Layout</value>\n  </data>\n  <data name=\"ActionEdit.Text\" xml:space=\"preserve\">\n    <value>Edit</value>\n  </data>\n  <data name=\"hlkConfigurePortal.Text\" xml:space=\"preserve\">\n    <value>Configure</value>\n  </data>\n  <data name=\"NoDemoItem.Text\" xml:space=\"preserve\">\n    <value>No demo item exists for the selected template.</value>\n  </data>\n  <data name=\"TemplateConfigurationMissing.Text\" xml:space=\"preserve\">\n    <value>The selected template does not exist anymore.</value>\n  </data>\n  <data name=\"ActionEditTemplateFile.Text\" xml:space=\"preserve\">\n    <value>Edit Template</value>\n  </data>\n  <data name=\"ActionAdd.Text\" xml:space=\"preserve\">\n    <value>Add Item</value>\n  </data>\n  <data name=\"ActionList.Text\" xml:space=\"preserve\">\n    <value>Edit List</value>\n  </data>\n  <data name=\"DeleteContentGroupItem.Text\" xml:space=\"preserve\">\n    <value>Do you want to delete item \\\"{0} ({1})\\\"?</value>\n  </data>\n  <data name=\"hlkConfigureZone.Text\" xml:space=\"preserve\">\n    <value>Click here to configure this</value>\n  </data>\n  <data name=\"ddlContentTypeDefaultItem.Text\" xml:space=\"preserve\">\n    <value>&lt;Choose Content Type&gt;</value>\n  </data>\n  <data name=\"TemplateError.Text\" xml:space=\"preserve\">\n    <value>&lt;b&gt;There was an error while rendering the template&lt;/b&gt;</value>\n  </data>\n  <data name=\"x84oldEnableDataPublishing.Text\" xml:space=\"preserve\">\n    <value>This module is trying to retrieve data from the server. If you see this message, it is because Data Publishing is not enabled on this module. Please enable it in the module settings of the module {0} (the module with the title \"{1}\").</value>\n  </data>\n  <data name=\"btnInstallGettingStarted.Text\" xml:space=\"preserve\">\n    <value>Install \"Getting Started\" templates</value>\n  </data>\n</root>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/BuildScripts/AfterBuild.Targets",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n\n  <Target Name=\"PostBuild\" AfterTargets=\"Build\" Condition=\"'$(DnnTargets)' != '' and '$(Configuration)' == 'Debug'\">\n    <Message Text=\"Configuration='$(Configuration)'\" Importance=\"High\"/>\n    <Message Text=\"DnnTargets='$(DnnTargets)'\" Importance=\"High\"/>\n\n    <!--Split the paths in DnnTargets into individual items-->\n    <ItemGroup>\n      <DnnRoot Include=\"$(DnnTargets)\"/>\n    </ItemGroup>\n\n    <PropertyGroup>\n      <DnnRootIdentityValue>%(DnnRoot.Identity)</DnnRootIdentityValue>\n    </PropertyGroup>\n    <Message Text=\"DnnRoot='$(DnnRootIdentityValue)'\" Importance=\"High\"/>\n  </Target>\n\n  <Target Name=\"PostBuildForEachItem\" AfterTargets=\"PostBuild\" DependsOnTargets=\"PostBuild\" Outputs=\"%(DnnRoot.Identity)\" Condition=\"'$(DnnTargets)' != '' and '$(Configuration)' == 'Debug'\">\n    <Message Text=\"Configuration='$(Configuration)'\" Importance=\"High\"/>\n    <Message Text=\"DnnRoot='%(DnnRoot.Identity)'\" Importance=\"High\"/>\n    <PropertyGroup>\n      <CurrentDnnRoot>%(DnnRoot.Identity)</CurrentDnnRoot>\n      <BuildTarget>$(CurrentDnnRoot)DesktopModules\\ToSic.Sxc</BuildTarget>\n    </PropertyGroup>\n    <!-- Echo Statements -->\n    <Message Text=\"BuildTarget='$(BuildTarget)'\" Importance=\"High\"/>\n\n    <!-- XML documentation is generated in Release only -->\n    <ItemGroup Condition=\"'$(Configuration)' == 'Release'\">\n      <!-- itmes included only in Release configuration -->\n      <!--<DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Sxc.xml\" />-->\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Sxc.Dnn.xml\" />\n    </ItemGroup>\n    \n    <ItemGroup>\n      <!-- Global / Shared 2sxc and EAV DLLs-->\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Sxc.*.dll\" Exclude=\"ToSic.Sxc.Dnn.Enterprise.dll\"/>\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Sxc.*.pdb\" Exclude=\"ToSic.Sxc.Dnn.Enterprise.pdb\"/>\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Eav.*.dll\" />\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Eav.*.pdb\" />\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Lib.*.dll\" />\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Lib.*.pdb\" />\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Sys.*.dll\" />\n      <DnnBinInclude Include=\"$(MSBuildProjectDirectory)\\bin\\ToSic.Sys.*.pdb\" />\n\n      <!-- 2sxc 13+ netstandard2.0/framework 4.7.2 assemblies -->\n      <SxcDependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Bcl.AsyncInterfaces.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Bcl.HashCode.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.EntityFrameworkCore.Abstractions.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.EntityFrameworkCore.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.EntityFrameworkCore.Relational.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.EntityFrameworkCore.SqlServer.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Caching.Abstractions.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Caching.Memory.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Configuration.Abstractions.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Configuration.Binder.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Configuration.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Logging.Abstractions.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Logging.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Options.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Microsoft.Extensions.Primitives.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\Remotion.Linq.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Buffers.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Collections.Immutable.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.ComponentModel.Annotations.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Data.SqlClient.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Diagnostics.DiagnosticSource.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Interactive.Async.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.IO.Pipelines.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Memory.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Numerics.Vectors.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Runtime.CompilerServices.Unsafe.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Text.Encodings.Web.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Text.Json.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.Threading.Tasks.Extensions.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\System.ValueTuple.dll\" />\n\n      <!-- Other DLLs -->\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\bin\\CsvHelper.dll\" />\n\n      <!-- DNN specific DLLs -->\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\Extensions\\Imageflow\\bin\\*.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\koi\\bin\\*.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\razorblade\\bin\\*.dll\" />\n      <DependeciesInclude Include=\"$(MSBuildProjectDirectory)\\razorblade-old\\bin\\*.dll\" />\n\n    </ItemGroup>\n\n    <Copy SourceFiles=\"@(DnnBinInclude)\" DestinationFolder=\"$(CurrentDnnRoot)bin\" />\n    <CopyNewerFileVersion SourceFiles=\"@(DependeciesInclude)\" DestinationFolder=\"$(CurrentDnnRoot)bin\" />\n    <CopyNewerFileVersion SourceFiles=\"@(SxcDependeciesInclude)\" DestinationFolder=\"$(CurrentDnnRoot)bin\\2sxc\" />\n\n    <!-- Copy Imageflow and dependecies -->\n    <!-- include Imageflow folder -->\n    <Exec Command=\"robocopy /S &quot;$(ProjectDir)Extensions/Imageflow/bin/&quot; &quot;$(CurrentDnnRoot)bin/&quot; /XF *.dll /XF *.dll.pending\" IgnoreExitCode=\"true\"/>\n    <ItemGroup>\n      <ImageflowAssemblyInclude Include=\"$(ProjectDir)\\Extensions\\Imageflow\\bin\\**\\ToSic.*.dll\" />\n      <ImageflowDependeciesInclude Include=\"$(ProjectDir)\\Extensions\\Imageflow\\bin\\**\\*.dll\" Exclude=\"ToSic.*.dll\"/>\n      <ImageflowAssemblyInclude Include=\"$(ProjectDir)\\Extensions\\Imageflow\\bin\\**\\imageflow.dll.pending\" />\n    </ItemGroup>\n    <CopyNewerFileVersion SourceFiles=\"@(ImageflowAssemblyInclude)\" DestinationFolder=\"$(CurrentDnnRoot)bin\" />\n    <CopyNewerFileVersion SourceFiles=\"@(ImageflowDependeciesInclude)\" DestinationFolder=\"$(CurrentDnnRoot)bin\" />\n    \n    <!-- Imageflow.dll Handling -->\n    <!-- this is optimization for development, to prevent second DNN restart that happens by 'imageflow' module when file 'imageflow.dll.pending' exists in 'bin/runtimes/win-???/native/' -->\n    <!-- when exists 'imageflow.dll.pending' it will rename it to 'imageflow.dll' ( but first need to remove old 'imageflow.dll' if one exists ) -->\n    <!-- note: DEL and RENAME cmds should have consistend backslash based path, we should not mix \\ / becuase that is not working as expected -->\n    <Exec Command=\"if exist &quot;$(CurrentDnnRoot)bin/runtimes/win-arm64/native/imageflow.dll.pending&quot; ( ( if exist &quot;$(CurrentDnnRoot)bin/runtimes/win-arm64/native/imageflow.dll&quot; del &quot;$(CurrentDnnRoot)bin\\runtimes\\win-arm64\\native\\imageflow.dll&quot; ) &amp; rename &quot;$(CurrentDnnRoot)bin\\runtimes\\win-arm64\\native\\imageflow.dll.pending&quot; imageflow.dll )\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"if exist &quot;$(CurrentDnnRoot)bin/runtimes/win-x64/native/imageflow.dll.pending&quot; ( ( if exist &quot;$(CurrentDnnRoot)bin/runtimes/win-x64/native/imageflow.dll&quot; del &quot;$(CurrentDnnRoot)bin\\runtimes\\win-x64\\native\\imageflow.dll&quot; ) &amp; rename &quot;$(CurrentDnnRoot)bin\\runtimes\\win-x64\\native\\imageflow.dll.pending&quot; imageflow.dll )\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"if exist &quot;$(CurrentDnnRoot)bin/runtimes/win-x86/native/imageflow.dll.pending&quot; ( ( if exist &quot;$(CurrentDnnRoot)bin/runtimes/win-x86/native/imageflow.dll&quot; del &quot;$(CurrentDnnRoot)bin\\runtimes\\win-x86\\native\\imageflow.dll&quot; ) &amp; rename &quot;$(CurrentDnnRoot)bin\\runtimes\\win-x86\\native\\imageflow.dll.pending&quot; imageflow.dll )\" IgnoreExitCode=\"true\"/>\n\n    <!--Copy the data folders-->\n    <Exec Command=\"robocopy /MIR &quot;$(ProjectDir)../../Data/App_Data/&quot; &quot;$(BuildTarget)/App_Data/&quot; /XO /XF &quot;$(BuildTarget)/App_Data/system-custom/configurations/features.json&quot; /XF &quot;$(BuildTarget)/App_Data/system-custom/configurations/default.license.json&quot;\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"robocopy /S &quot;$(ProjectDir)../../../../2sxc-dev-materials/App_Data/&quot; &quot;$(BuildTarget)/App_Data/&quot;\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"robocopy /MIR &quot;$(ProjectDir)../../Data/assets/ &quot; &quot;$(BuildTarget)/assets/&quot;\" IgnoreExitCode=\"true\"/>\n\n    <!--Add the DNN specific content-types-->\n    <Exec Command=\"robocopy /S &quot;$(ProjectDir)../../Data-Dnn/App_Data/system/&quot; &quot;$(BuildTarget)/App_Data/system/&quot;\" IgnoreExitCode=\"true\"/>\n\n    <!--Copy DNN JavaScripts and Bridge-->\n    <Exec Command=\"robocopy /MIR &quot;$(ProjectDir)ClientScripts/&quot; &quot;$(BuildTarget)/ClientScripts/&quot;\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"robocopy /MIR &quot;$(ProjectDir)DnnWebForms/&quot; &quot;$(BuildTarget)/DnnWebForms/&quot;\" IgnoreExitCode=\"true\"/>\n\n    <!--Copy 2sxc JS stuff (order of commands is important) -->\n    <!--\n    The commented script was initially designed to automate the deployment of JavaScript assets for the 2sxc module in a DNN development environment as part of the 2sxc backend build. \n    It has been commented out to prevent unexpected behavior for frontend (JavaScript) developers, particularly the issue of the latest JavaScript assets in the DNN development environment \n    being overwritten with older JavaScript assets from'2sxc-sources\\_latest'.\n    \n    Backend developers are advised to manually copy all JavaScript assets from '2sxc-sources\\_latest' to the DNN development environment at '2sxc-dnn\\Website\\DesktopModules\\ToSic.Sxc'. \n    This ensures the latest version of JavaScript assets are used, as this step no longer occurs automatically with each update of the 2sxc version in DNN dev env. \n    Another option is to run npm scripts in 'eav-ui', as is the practice among frontend (JavaScript) developers.\n    -->\n    <!--<Exec Command=\"robocopy /MIR &quot;$(Source)/js/&quot; &quot;$(BuildTarget)/js/&quot;\" IgnoreExitCode=\"true\" Condition=\"Exists('$(Source)')\"/>\n    <Exec Command=\"robocopy /MIR &quot;$(Source)/system/&quot; &quot;$(BuildTarget)/system/&quot;\" IgnoreExitCode=\"true\" Condition=\"Exists('$(Source)')\"/>\n    <Exec Command=\"robocopy /MIR &quot;$(Source)/dist/&quot; &quot;$(BuildTarget)/dist/&quot;\" IgnoreExitCode=\"true\" Condition=\"Exists('$(Source)')\"/>-->\n    <Exec Command=\"robocopy /S &quot;$(ProjectDir)dist/&quot; &quot;$(BuildTarget)/dist/&quot; &quot;Default.aspx&quot;\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"robocopy /MIR &quot;$(ProjectDir)ImportExport/&quot; &quot;$(BuildTarget)/ImportExport/&quot;\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"robocopy /MIR &quot;$(ProjectDir)App_LocalResources/&quot; &quot;$(BuildTarget)/App_LocalResources/&quot;\" IgnoreExitCode=\"true\"/>\n\n    <!-- 2025-11-18 2dm: since  -->\n    <!--<Exec Command=\"robocopy /MIR &quot;$(ProjectDir)Extensions/&quot; &quot;$(BuildTarget)/Extensions/&quot;\" IgnoreExitCode=\"true\"/>-->\n    <Exec Command=\"robocopy /MIR &quot;$(ProjectDir)Extensions/Imageflow/&quot; &quot;$(BuildTarget)/Extensions/Imageflow/&quot;\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"robocopy /MIR &quot;$(ProjectDir)Extensions/ToSic_vCard/&quot; &quot;$(BuildTarget)/Extensions/ToSic_vCard/&quot;\" IgnoreExitCode=\"true\"/>\n\n    <!-- Xcopy Commands -->\n    <Exec Command=\"xcopy &quot;$(ProjectDir)View.ascx&quot; &quot;$(BuildTarget)&quot; /y\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"xcopy &quot;$(ProjectDir)icon.png&quot; &quot;$(BuildTarget)&quot; /y\" IgnoreExitCode=\"true\"/>\n    <Exec Command=\"xcopy &quot;$(ProjectDir)icon-app.png&quot; &quot;$(BuildTarget)&quot; /y\" IgnoreExitCode=\"true\"/>\n    <!-- ... Add other xcopy commands similarly ... -->\n\n    <!-- Echo Statements -->\n    <Message Text=\"Copied all files to this DNN target: '$(CurrentDnnRoot)'\" Importance=\"High\"/>\n    <Message Text=\"So DesktopModules Folder is '$(BuildTarget)'\" Importance=\"High\"/>\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/BuildScripts/LoadBuildConfig.Targets",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n\n  <Target Name=\"CheckBuildTool\" BeforeTargets=\"Build\">\n    <Message Text=\"Running on .NET Core MSBuild\" Condition=\"'$(MSBuildRuntimeType)' == 'Core'\" Importance=\"high\"/>\n    <Message Text=\"Running on Full MSBuild\" Condition=\"'$(MSBuildRuntimeType)' != 'Core'\" Importance=\"high\"/>\n  </Target>\n\n  <UsingTask TaskName=\"GetBuildConfig\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net9.0\\ToSic.Sxc.BuildTasks.dll\" Condition=\"'$(MSBuildRuntimeType)' == 'Core'\"/>\n  <UsingTask TaskName=\"GetBuildConfig\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net472\\ToSic.Sxc.BuildTasks.dll\" Condition=\"'$(MSBuildRuntimeType)' != 'Core'\"/>\n  <UsingTask TaskName=\"ColorMessage\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net9.0\\ToSic.Sxc.BuildTasks.dll\" Condition=\"'$(MSBuildRuntimeType)' == 'Core'\"/>\n  <UsingTask TaskName=\"ColorMessage\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net472\\ToSic.Sxc.BuildTasks.dll\" Condition=\"'$(MSBuildRuntimeType)' != 'Core'\"/>\n\n  <Target Name=\"BuildConfigTarget\" BeforeTargets=\"Build\">\n\n    <GetBuildConfig>\n      <Output TaskParameter=\"BuildConfigPath\" PropertyName=\"BuildConfigPath\" />\n      <Output TaskParameter=\"DnnTargets\" PropertyName=\"DnnTargets\" />\n      <Output TaskParameter=\"DnnTarget\" PropertyName=\"DnnTarget\" />\n      <Output TaskParameter=\"Sources\" PropertyName=\"Sources\" />\n      <Output TaskParameter=\"Source\" PropertyName=\"Source\" />\n      <Output TaskParameter=\"DnnInstallPackage\" PropertyName=\"DnnInstallPackage\" />\n    </GetBuildConfig>\n\n    <!-- Create a property to capture the result of the Exists function -->\n    <PropertyGroup>\n      <SourceExist Condition=\"Exists('$(Source)')\">true</SourceExist>\n      <SourceExist Condition=\"!Exists('$(Source)')\">false</SourceExist>\n    </PropertyGroup>\n\n    <ColorMessage Text=\"------------------------------------------------------------------------------\" ForegroundColor=\"White\" BackgroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"$(BuildConfigPath)\" ForegroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"------------------------------------------------------------------------------\" ForegroundColor=\"White\" BackgroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"DnnTargets:\" ForegroundColor=\"White\"/>\n    <ColorMessage Text=\"$(DnnTargets)\" ForegroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"Source:\" ForegroundColor=\"White\"/>\n    <ColorMessage Text=\"$(Source)\" ForegroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"DnnInstallPackage:\" ForegroundColor=\"White\"/>\n    <ColorMessage Text=\"$(DnnInstallPackage)\" ForegroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"------------------------------------------------------------------------------\" ForegroundColor=\"White\" BackgroundColor=\"Magenta\"/>\n\n  </Target>\n\n</Project>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/BuildScripts/MSBuild.Community.Tasks.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <!-- $Id$ -->\n\n  <PropertyGroup>\n    <MSBuildCommunityTasksPath Condition=\"'$(MSBuildCommunityTasksPath)' == ''\">$(MSBuildExtensionsPath)\\MSBuildCommunityTasks</MSBuildCommunityTasksPath>\n    <!-- 2020-08-24 2dm - don't think we need this special variable for build any more -->\n    <!-- <MSBuildDnnBinPath Condition=\"'$(MSBuildDnnBinPath)' == ''\">$(MSBuildProjectDirectory)\\..\\..\\bin</MSBuildDnnBinPath> -->\n    <MSBuildCommunityTasksLib>$([MSBUILD]::Unescape($(MSBuildCommunityTasksPath)\\MSBuild.Community.Tasks.dll))</MSBuildCommunityTasksLib>\n  </PropertyGroup>\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.AspNet.InstallAspNet\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.AssemblyInfo\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Attrib\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SqlExecute\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.FileUpdate\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.FtpUpload\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.FxCop\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.GacUtil\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.GetSolutionProjects\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.ILMerge\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Mail\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Move\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Math.Add\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Math.Divide\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Math.Modulo\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Math.Multiple\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Math.Subtract\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.NDoc\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.NUnit\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Prompt\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.RegistryRead\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.RegistryWrite\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.RegexMatch\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.RegexReplace\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Script\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.ServiceController\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.ServiceQuery\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Sleep\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.IIS.AppPoolController\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.IIS.AppPoolCreate\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.IIS.AppPoolDelete\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.IIS.WebDirectoryCreate\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.IIS.WebDirectoryDelete\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.IIS.WebDirectoryScriptMap\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.IIS.WebDirectorySetting\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Install.InstallAssembly\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Install.UninstallAssembly\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Schema.TaskSchema\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SqlServer.ExecuteDDL\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssAdd\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssCheckin\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssCheckout\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssClean\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssDiff\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssGet\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssHistory\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssLabel\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.SourceSafe.VssUndoCheckout\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Subversion.SvnCheckout\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Subversion.SvnClient\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Subversion.SvnCopy\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Subversion.SvnCommit\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Subversion.SvnExport\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Subversion.SvnInfo\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Subversion.SvnUpdate\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Subversion.SvnVersion\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Tfs.TfsVersion\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.TemplateFile\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Time\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Unzip\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Version\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.WebDownload\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Xml.XmlMassUpdate\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Xml.XmlQuery\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.XmlRead\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.XmlUpdate\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Xslt\" />\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.Zip\" />\n\n  <UsingTask AssemblyFile=\"$(MSBuildCommunityTasksLib)\" TaskName=\"MSBuild.Community.Tasks.JavaScript.JSCompress\" />\n\n  <ItemGroup>\n    <FxCopRuleAssemblies Include=\"UsageRules.dll\"/>\n    <FxCopRuleAssemblies Include=\"SecurityRules.dll\"/>\n    <FxCopRuleAssemblies Include=\"PortabilityRules.dll\"/>\n    <FxCopRuleAssemblies Include=\"PerformanceRules.dll\"/>\n    <FxCopRuleAssemblies Include=\"MobilityRules.dll\"/>\n    <FxCopRuleAssemblies Include=\"InteroperabilityRules.dll\"/>\n    <FxCopRuleAssemblies Include=\"GlobalizationRules.dll\"/>\n    <FxCopRuleAssemblies Include=\"DesignRules.dll\"/>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/BuildScripts/ModulePackage.Targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- WARNING, WARNING, WARNING -->\n<!-- REMEMBER THAT IF YOU MODIFY THE TARGETS FILE YOU NEED TO CLOSE/OPEN THE PROJECT FOR THE CHANGES TO TAKE EFFECT -->\n\n<Project ToolsVersion=\"3.5\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n\n  <Import Project=\"MSBuild.Community.Tasks.Targets\" />\n  <UsingTask TaskName=\"CopyNewerFileVersion\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net472\\ToSic.Sxc.BuildTasks.dll\" />\n  <UsingTask TaskName=\"ModifyXmlDocumentation\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net472\\ToSic.Sxc.BuildTasks.dll\" />\n\n  <!-- The Dnn Build Package - Should only run after release compile -->\n  <Target Name=\"PackageModule\" AfterTargets=\"Build\" DependsOnTargets=\"BuildConfigTarget\" Condition=\" '$(Configuration)|$(Platform)|$(SourceExist)' == 'Release|AnyCPU|true' \">\n\n    <!-- Properties / Variables for the DNN Build which we need early on-->\n    <PropertyGroup>\n      <DnnManifestFile>DnnPackageBuilder/ToSic.Sxc.Dnn.dnn</DnnManifestFile>\n    </PropertyGroup>\n\n    <!-- Get the Version out of the DNN Manifest for this release -->\n    <XmlRead Prefix=\"n\" Namespace=\"http://schemas.microsoft.com/developer/msbuild/2003\" XPath=\"dotnetnuke/packages/package[1]/@version\" XmlFileName=\"$(DnnManifestFile)\">\n      <Output TaskParameter=\"Value\" PropertyName=\"Version\" />\n    </XmlRead>\n\n    <Message Text=\"DnnBuild: Starting DNN Build version $(Version)\" Importance=\"high\" />\n\n    <PropertyGroup>\n      <PackageName>ToSic.Sxc.Dnn</PackageName>\n      <TempPackageFolder>$(MSBuildProjectDirectory)\\ModulePackages\\Temp</TempPackageFolder>\n      <TempPackageResourcesFolder>$(MSBuildProjectDirectory)\\ModulePackages\\TempResources</TempPackageResourcesFolder>\n      <TempPackagePdbFolder>$(MSBuildProjectDirectory)\\ModulePackages\\TempPdb</TempPackagePdbFolder>\n      <DnnInstallPackage Condition=\" '$(DnnInstallPackage)' == '' \">../../../InstallPackages/Dnn-Installer</DnnInstallPackage>\n      <FinalZipFileName>$(PackageName).$(Version)_Install.zip</FinalZipFileName>\n      <SourceVersionFolder>$(Source)..\\$(Version)</SourceVersionFolder>\n    </PropertyGroup>\n\n    <Error Condition=\"!Exists('$(Source)')\" Text=\"DnnBuild: ERROR: Assets folder not found at $(Source)\" />\n\n    <!-- Auto-deploy the externalized map files -->\n    <!-- New in 2020-09 From now on we'll also publish the built js files to sources.2sxc.org and not include them in 2sxc-repo any more -->\n    <ItemGroup>\n      <!--include the dist, js and system folders, but as a subfolder (that's why the strange syntax) -->\n      <ExternalSourceMaps Include=\"$(Source)\\*dist\\**\\*.*\" />\n      <ExternalSourceMaps Include=\"$(Source)\\*js\\**\\*.*\" />\n      <ExternalSourceMaps Include=\"$(Source)\\*extensions\\**\\*.*\" />\n    </ItemGroup>\n\n    <!-- Only deploy files if we actually found any in '2sxc-sources/_latest' -->\n    <Message Text=\"DnnBuild: Copying all Assets to versioned folder $(SourceVersionFolder)\" Importance=\"high\" Condition=\" '@(ExternalSourceMaps)' != '' \" />\n    <RemoveDir Directories=\"$(SourceVersionFolder)\" Condition=\" '@(ExternalSourceMaps)' != '' \" />\n    <Copy SourceFiles=\"@(ExternalSourceMaps)\" DestinationFolder=\"$(SourceVersionFolder)\\%(RecursiveDir)\" Condition=\" '@(ExternalSourceMaps)' != '' \" />\n\n    <Error Condition=\"!Exists('$(SourceVersionFolder)')\" Text=\"DnnBuild: ERROR: Source version $(Version) assets folder not found at $(SourceVersionFolder)\" />\n    <Message Text=\"DnnBuild: Will get source version $(Version) assets from $(SourceVersionFolder)\" Importance=\"high\" />\n\n    <ItemGroup>\n      <DefaultExclude Include=\"**\\bin\\**\" />\n      <DefaultExclude Include=\"**\\koi\\**\" />\n      <DefaultExclude Include=\"**\\razorblade\\**\" />\n      <DefaultExclude Include=\"**\\razorblade-old\\**\" />\n      <DefaultExclude Include=\"**\\*.user\" />\n      <DefaultExclude Include=\"**\\*.suo\" />\n      <DefaultExclude Include=\"**\\*.zip\" />\n      <DefaultExclude Include=\"ModulePackages\\**\" />\n      <DefaultExclude Include=\"DnnPackageBuilder\\**\" />\n      <DefaultExclude Include=\".git\\**\" />\n      <DefaultExclude Include=\"packages\\**\" />\n      <DefaultExclude Include=\"tmp\\**\" />\n      <DefaultExclude Include=\".vs\\**\" />\n      <DefaultExclude Include=\"_\\**\" />\n      <!--<DefaultExclude Include=\".gitignore\" />-->\n    </ItemGroup>\n\n    <ItemGroup>\n      <InstallInclude Include=\"**\\*.ascx\" Exclude=\"@(DefaultExclude)\" />\n      <InstallInclude Include=\"**\\*.aspx\" Exclude=\"@(DefaultExclude)\" />\n      <InstallInclude Include=\"**\\*.asmx\" Exclude=\"@(DefaultExclude)\" />\n      <InstallInclude Include=\"**\\*.css\" Exclude=\"@(DefaultExclude)\" />\n      <InstallInclude Include=\"**\\*.html\" Exclude=\"@(DefaultExclude)\" />\n      <InstallInclude Include=\"**\\*.htm\" Exclude=\"@(DefaultExclude)\" />\n      <InstallInclude Include=\"**\\*.resx\" Exclude=\"@(DefaultExclude)\" />\n\n      <!-- all js + css + html etc. stuff from assets-->\n      <InstallInclude Include=\"$(Source)readme.md\" Exclude=\"@(DefaultExclude)\" />\n      <InstallIncludeJsJs Include=\"$(Source)\\js\\**\\*.*\" Exclude=\"$(Source)\\js\\**\\*.map\" />\n      <!-- 2025-11-25 2dm for v20.09 - moving wysiwyg & gps to /extensions -->\n      <!--<InstallIncludeSystem Include=\"$(Source)\\system\\**\\*.*\" Exclude=\"$(Source)\\system\\**\\*.map\" />-->\n      <InstallIncludeJsExtensions Include=\"$(Source)\\extensions\\**\\*.*\" Exclude=\"$(Source)\\extensions\\**\\*.map\" />\n      <InstallIncludeJsDist Include=\"$(Source)\\dist\\**\\*.*\" Exclude=\"$(Source)\\dist\\**\\*.map\" />\n      <!-- WIP - turnOn map files must be included for now-->\n      <InstallIncludeJsDist Include=\"$(Source)\\turnOn\\*.*\" />\n\n      <!-- all global types and queries -->\n      <InstallInclude Include=\"..\\..\\Data\\**\\App_Data\\new-app\\**\\*.*\" />\n      <InstallInclude Include=\"..\\..\\Data\\**\\App_Data\\system\\**\\*.json\" Exclude=\"@(DefaultExclude)\" />\n      <InstallInclude Include=\"..\\..\\Data\\**\\assets\\**\\*.*\" />\n\n      <InstallInclude Include=\"..\\..\\Data-Dnn\\**\\App_Data\\system\\**\\*.json\" Exclude=\"@(DefaultExclude)\" />\n\n      <InstallInclude Include=\"**\\*.txt\" Exclude=\"@(DefaultExclude);**\\obj\\**;**\\_ReSharper*\\**;License.txt;ReleaseNotes.txt\" />\n      <InstallInclude Include=\"**\\*.ashx\" Exclude=\"@(DefaultExclude)\" />\n      <InstallInclude Include=\"**\\*.png\" Exclude=\"@(DefaultExclude);icon.png;icon-app.png\" />\n      <InstallInclude Include=\"**\\*.config\" Exclude=\"@(DefaultExclude);**\\web-Deploy.config;**\\app.config;**\\packages.config\" />\n\n      <!-- special DNN client scripts which react when adding a module to a page (js/html) -->\n      <InstallInclude Include=\"*ClientScripts\\*.*\" />\n\n      <!--the ImportExport folder. Leading * is important so it will create a folder with this -->\n      <InstallInclude Include=\"*ImportExport\\**\\*.*\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <!-- Global / Shared 2sxc and EAV DLLs-->\n      <!--<AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Core.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Core.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Adam.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Adam.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Apps.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Apps.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Blocks.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Blocks.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Cms.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Cms.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Code.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Code.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Code.Generate.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Code.Generate.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Code.HotBuild.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Code.HotBuild.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Custom.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Custom.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Data.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Data.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Edit.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Edit.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Engines.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Engines.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Images.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Images.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.LightSpeed.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.LightSpeed.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Render.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Render.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Services.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Services.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.Web.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.Web.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.WebApi.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.WebApi.pdb\" />-->\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sxc.*.dll\" Exclude=\"ToSic.Sxc.Dnn.Enterprise.dll\"/>\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sxc.*.pdb\" Exclude=\"ToSic.Sxc.Dnn.Enterprise.pdb\"/>\n      <!-- 2025-06-04 2dm v20 doesn't have the ToSic.Eav.dll any more -->\n      <!--<AssemblyInclude Include=\"$(OutDir)\\ToSic.Eav.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Eav.pdb\" />-->\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Eav.*.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Eav.*.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Lib.*.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Lib.*.pdb\" />\n      <AssemblyInclude Include=\"$(OutDir)\\ToSic.Sys.*.dll\" />\n      <AssemblyHelper Include=\"$(OutDir)\\ToSic.Sys.*.pdb\" />\n\n      <!-- XML documentation -->\n      <!--<AssemblyDocumentation Include=\"$(OutDir)\\ToSic.Sxc.xml\" />-->\n      <AssemblyDocumentation Include=\"$(OutDir)\\ToSic.Sxc.Dnn.xml\" />\n\n      <!-- 2sxc 13+ netstandard2.0/framework 4.7.2 assemblies -->\n      <DependencyInclude Include=\"$(OutDir)\\Microsoft.Bcl.AsyncInterfaces.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Bcl.HashCode.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.EntityFrameworkCore.Abstractions.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.EntityFrameworkCore.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.EntityFrameworkCore.Relational.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.EntityFrameworkCore.SqlServer.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Caching.Abstractions.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Caching.Memory.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Configuration.Abstractions.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Configuration.Binder.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Configuration.dll\" />\n      <!--<AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.DependencyInjection.Abstractions.dll\" />-->\n      <!--<AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.DependencyInjection.dll\" />-->\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Logging.Abstractions.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Logging.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Options.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\Microsoft.Extensions.Primitives.dll\" />\n      <!--<AssemblyInclude Include=\"$(OutDir)\\Newtonsoft.Json.dll\" />-->\n      <AssemblyInclude Include=\"$(OutDir)\\Remotion.Linq.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Buffers.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Collections.Immutable.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.ComponentModel.Annotations.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Data.SqlClient.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Diagnostics.DiagnosticSource.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Interactive.Async.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.IO.Pipelines.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Memory.dll\" />\n      <!--<AssemblyInclude Include=\"$(OutDir)\\System.Net.Http.Formatting.dll\" />-->\n      <AssemblyInclude Include=\"$(OutDir)\\System.Numerics.Vectors.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Runtime.CompilerServices.Unsafe.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Text.Encodings.Web.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Text.Json.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.Threading.Tasks.Extensions.dll\" />\n      <AssemblyInclude Include=\"$(OutDir)\\System.ValueTuple.dll\" />\n      <!--<AssemblyInclude Include=\"$(OutDir)\\System.Web.Http.dll\" />-->\n      <!--<AssemblyInclude Include=\"$(OutDir)\\System.Web.Http.WebHost.dll\" />-->\n\n      <!-- Other DLLs -->\n      <AssemblyInclude Include=\"$(OutDir)\\CsvHelper.dll\" />\n\n    </ItemGroup>\n\n    <CreateItem Include=\"$(DnnManifestFile)\">\n      <Output TaskParameter=\"Include\" ItemName=\"PackageManifestFiles\" />\n    </CreateItem>\n\n    <CreateItem Include=\"DnnPackageBuilder/License.txt\">\n      <Output TaskParameter=\"Include\" ItemName=\"PackageTxtFiles\" />\n    </CreateItem>\n\n    <CreateItem Include=\"DnnPackageBuilder/ReleaseNotes.txt\">\n      <Output TaskParameter=\"Include\" ItemName=\"PackageTxtFiles\" />\n    </CreateItem>\n\n    <CreateItem Include=\"DnnPackageBuilder/icon.png;DnnPackageBuilder/icon-app.png\">\n      <Output TaskParameter=\"Include\" ItemName=\"PackageModuleIcon\" />\n    </CreateItem>\n\n    <CreateItem Include=\"DnnPackageBuilder/**\\*.sqldataprovider\">\n      <Output TaskParameter=\"Include\" ItemName=\"SqlDataProviderFiles\" />\n    </CreateItem>\n\n    <!-- Run the modification task for each documentation file -->\n    <ModifyXmlDocumentation XmlDocumentationPath=\"%(AssemblyDocumentation.Identity)\" />\n\n    <Copy SourceFiles=\"@(AssemblyInclude)\" DestinationFolder=\"$(TempPackageFolder)\\bin\" />\n    <Copy SourceFiles=\"@(AssemblyHelper)\" DestinationFolder=\"$(TempPackagePdbFolder)\\bin\" />\n    <Copy SourceFiles=\"@(AssemblyDocumentation)\" DestinationFolder=\"$(TempPackagePdbFolder)\\bin\" />\n    <Copy SourceFiles=\"@(DependencyInclude)\" DestinationFolder=\"$(TempPackageFolder)\\bin\\2sxc\" />\n    <Copy SourceFiles=\"@(SqlDataProviderFiles)\" DestinationFolder=\"$(TempPackageFolder)\\%(RecursiveDir)\" />\n    <Copy SourceFiles=\"@(PackageManifestFiles)\" DestinationFolder=\"$(TempPackageFolder)\" />\n    <Copy SourceFiles=\"@(PackageModuleIcon)\" DestinationFolder=\"$(TempPackageFolder)\" />\n    <Copy SourceFiles=\"@(PackageTxtFiles)\" DestinationFolder=\"$(TempPackageFolder)\" />\n\n    <!-- include clean-up 10.21+ -->\n    <CreateItem Include=\"DnnPackageBuilder/Cleanup\\*.txt\">\n      <Output TaskParameter=\"Include\" ItemName=\"CleanupFiles\" />\n    </CreateItem>\n    <Copy SourceFiles=\"@(CleanupFiles)\" DestinationFolder=\"$(TempPackageFolder)\\Cleanup\\%(RecursiveDir)\" />\n\n    <!-- include Imageflow folder -->\n    <ItemGroup>\n      <ImageflowFiles Include=\"$(MSBuildProjectDirectory)\\Extensions\\Imageflow\\*.*\" Exclude=\"**\\*.dll\" />\n    </ItemGroup>\n    <Copy SourceFiles=\"@(ImageflowFiles)\" DestinationFolder=\"$(TempPackageFolder)\\Extensions\\Imageflow\\%(RecursiveDir)\" />\n\n    <ItemGroup>\n      <!-- DNN specific DLLs -->\n      <ImageflowAssemblyInclude Include=\"$(MSBuildProjectDirectory)\\Extensions\\Imageflow\\bin\\*.dll\" />\n    </ItemGroup>\n    <CopyNewerFileVersion SourceFiles=\"@(ImageflowAssemblyInclude)\" DestinationFolder=\"$(TempPackageFolder)\\bin\" />\n\n    <!-- include koi folder -->\n    <ItemGroup>\n      <KoiFiles Include=\"$(MSBuildProjectDirectory)/koi/*.*\" Exclude=\"**\\*.dll\" />\n    </ItemGroup>\n    <Copy SourceFiles=\"@(KoiFiles)\" DestinationFolder=\"$(TempPackageFolder)\\koi\\%(RecursiveDir)\" />\n    <ItemGroup>\n      <KoiDllFiles Include=\"$(MSBuildProjectDirectory)/koi/bin/*.dll\" />\n    </ItemGroup>\n    <CopyNewerFileVersion SourceFiles=\"@(KoiDllFiles)\" DestinationFolder=\"$(TempPackageFolder)\\bin\" />\n\n    <!-- include new razorblade 3 module -->\n    <ItemGroup>\n      <RazorBlade3Files Include=\"$(MSBuildProjectDirectory)/razorblade/*.*\" Exclude=\"**\\*.dll\" />\n    </ItemGroup>\n    <Copy SourceFiles=\"@(RazorBlade3Files)\" DestinationFolder=\"$(TempPackageFolder)\\razorblade\\%(RecursiveDir)\" />\n    <ItemGroup>\n      <RazorBlade3DllFiles Include=\"$(MSBuildProjectDirectory)/razorblade/bin/*.dll\" />\n    </ItemGroup>\n    <CopyNewerFileVersion SourceFiles=\"@(RazorBlade3DllFiles)\" DestinationFolder=\"$(TempPackageFolder)\\bin\" />\n\n    <!-- include razorblade old module -->\n    <ItemGroup>\n      <RazorBladeFiles Include=\"$(MSBuildProjectDirectory)/razorblade-old/*.*\" Exclude=\"**\\*.dll\" />\n    </ItemGroup>\n    <Copy SourceFiles=\"@(RazorBladeFiles)\" DestinationFolder=\"$(TempPackageFolder)\\razorblade-old\\%(RecursiveDir)\" />\n    <ItemGroup>\n      <RazorBladeDllFiles Include=\"$(MSBuildProjectDirectory)/razorblade-old/bin/*.dll\" />\n    </ItemGroup>\n    <CopyNewerFileVersion SourceFiles=\"@(RazorBladeDllFiles)\" DestinationFolder=\"$(TempPackageFolder)\\bin\" />\n\n\n    <!-- create the INSTALL RESOURCES.ZIP file -->\n    <Copy SourceFiles=\"@(InstallInclude)\" DestinationFolder=\"$(TempPackageResourcesFolder)\\%(RecursiveDir)\" />\n    <Copy SourceFiles=\"@(InstallIncludeJsJs)\" DestinationFolder=\"$(TempPackageResourcesFolder)\\js\\%(RecursiveDir)\" />\n    <Copy SourceFiles=\"@(InstallIncludeJsExtensions)\" DestinationFolder=\"$(TempPackageResourcesFolder)\\extensions\\%(RecursiveDir)\" />\n    <Copy SourceFiles=\"@(InstallIncludeJsDist)\" DestinationFolder=\"$(TempPackageResourcesFolder)\\dist\\%(RecursiveDir)\" />\n\n    <CreateItem Include=\"$(TempPackageResourcesFolder)\\**\\*.*\">\n      <Output TaskParameter=\"Include\" ItemName=\"ResourcesContent\" />\n    </CreateItem>\n    <Zip Files=\"@(ResourcesContent)\" WorkingDirectory=\"$(TempPackageResourcesFolder)\" ZipFileName=\"$(TempPackageFolder)\\Resources.zip\" />\n\n    <CreateItem Include=\"$(TempPackagePdbFolder)\\**\\*.*\">\n      <Output TaskParameter=\"Include\" ItemName=\"AssemblyHelperContent\" />\n    </CreateItem>\n    <Zip Files=\"@(AssemblyHelperContent)\" WorkingDirectory=\"$(TempPackagePdbFolder)\" ZipFileName=\"$(TempPackageFolder)\\tosic.bin.debug-helpers.zip\" />\n\n    <!-- Create the Install package -->\n    <Message Text=\"DnnBuild: Creating final Zip file $(FinalZipFileName) in $(DnnInstallPackage)\" Importance=\"high\" />\n    <CreateItem Include=\"$(TempPackageFolder)\\**\\*.*\">\n      <Output TaskParameter=\"Include\" ItemName=\"OutputContent\" />\n    </CreateItem>\n    <Zip Files=\"@(OutputContent)\" WorkingDirectory=\"$(TempPackageFolder)\" ZipFileName=\"$(DnnInstallPackage)/$(FinalZipFileName)\" />\n\n    <!-- Cleanup -->\n    <Message Text=\"DnnBuild: Clean-up temporary folders\" Importance=\"high\" />\n    <RemoveDir Directories=\"$(TempPackageFolder)\" />\n    <RemoveDir Directories=\"$(TempPackageResourcesFolder)\" />\n    <RemoveDir Directories=\"$(TempPackagePdbFolder)\" />\n    <Message Text=\"DnnBuild: Clean-up temporary folders done\" Importance=\"high\" />\n\n    <Message Text=\"DnnBuild: Completed\" Importance=\"high\" />\n  </Target>\n</Project>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/BuildScripts/readme.md",
    "content": "﻿## Build Scripts\n\nThis is an MS-Build package which gets run when Visual Studio does a production build. "
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ClientScripts/ModuleEditor.js",
    "content": "(function (sxc) {\n    if (sxc || window['2sxc-loading']) return;\n    window['2sxc-loading'] = true;\n    var scripts = [\n        '/DesktopModules/ToSic.Sxc/js/2sxc.api.min.js',\n        '/DesktopModules/ToSic.Sxc/dist/inpage/inpage.min.js',\n    ];\n    console.debug('lazy loading 2sxc');\n    var head = document.getElementsByTagName('head')[0];\n    for (var i = 0; i < scripts.length; i++) head.appendChild(createScriptTag(scripts[i]));\n    function createScriptTag(url) {\n        var el = document.createElement('script');\n        el.setAttribute('defer', 'defer');\n        el.src = url;\n        return el;\n    }\n})(window['$2sxc']);"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ClientScripts/readme.md",
    "content": "﻿## ClientScripts of 2sxc\n\nThis folder contains JS which is automatically loaded by DNN 9 when a user opens the \"add module to page\" dialog. \n\nOur script ensures that the 2sxc js is loaded when the user adds the module to the page. "
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnBusinessController.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing ToSic.Sxc.Dnn.StartUp;\n\n// Note about the name\n// Some day we should change this namespace to ToSic.Sxc.Dnn.something\n// But we can't just do it, because the name is registered in Dnn DBs, so update-scripts would be needed\n// WHY IS THIS NOT PART OF THE DnnBusinessController? it seems that that is already the term in the DB?\n// Reason if that can't call StartupDnn().Configure() from ToSic.Sxc.Dnn.DnnBusinessController because of circular dependency\n// and need to configure DI before UpgradeModule to fix issue: \"Module upgrade did not complete.\"\n// \"System.ArgumentNullException: Value cannot be null. Parameter name: provider\n// at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)\n// at ToSic.Eav.Factory.GetServiceProvider()\"\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DnnBusinessController: ToSic.Sxc.Dnn.DnnBusinessController, IUpgradeable, IVersionable\n{\n    public new string UpgradeModule(string version)\n    {\n        new StartupDnn().Configure(); // can't call it from ToSic.Sxc.Dnn.DnnBusinessController because of circular dependency\n        return base.UpgradeModule(version);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/Cleanup/flush.txt",
    "content": "DesktopModules\\ToSic.Sxc\\dist\\\nDesktopModules\\ToSic.Sxc\\.data\\\nDesktopModules\\ToSic.Sxc\\App_Data\\system\\"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/Cleanup/flush20.txt",
    "content": "bin\\ToSic.Eav.dll\nbin\\ToSic.Eav.Core.dll\nbin\\ToSic.Lib.Core.dll\nbin\\ToSic.Sxc.dll\nDesktopModules\\ToSIC_SexyContent\\2Sexy Content Razor\\\nDesktopModules\\ToSIC_SexyContent\\2sxc Dnn\\\nDesktopModules\\ToSIC_SexyContent\\2sxc.WebApi.Tests\\\nDesktopModules\\ToSIC_SexyContent\\_\\\nDesktopModules\\ToSIC_SexyContent\\Administration\\\nDesktopModules\\ToSIC_SexyContent\\API\\\nDesktopModules\\ToSIC_SexyContent\\App_LocalResources\\\nDesktopModules\\ToSIC_SexyContent\\assets\\\nDesktopModules\\ToSIC_SexyContent\\bootstrap\\\nDesktopModules\\ToSIC_SexyContent\\bower_components\\\nDesktopModules\\ToSIC_SexyContent\\ClientScripts\\\nDesktopModules\\ToSIC_SexyContent\\dist\\\nDesktopModules\\ToSIC_SexyContent\\DnnWebForms\\\nDesktopModules\\ToSIC_SexyContent\\Extensions\\\nDesktopModules\\ToSIC_SexyContent\\i18n\\\nDesktopModules\\ToSIC_SexyContent\\Images\\\nDesktopModules\\ToSIC_SexyContent\\ImportExport\\\nDesktopModules\\ToSIC_SexyContent\\SexyContent\\\nDesktopModules\\ToSIC_SexyContent\\SqlDataProvider\\\nDesktopModules\\ToSIC_SexyContent\\Styles\\\nDesktopModules\\ToSIC_SexyContent\\Sxc WebApi\\\nDesktopModules\\ToSIC_SexyContent\\ToSic.Sxc.Tests\\\nDesktopModules\\ToSIC_SexyContent\\ToSic.Sxc\\\nDesktopModules\\ToSIC_SexyContent\\edit.css\nDesktopModules\\ToSIC_SexyContent\\EditContentGroup.ascx\nDesktopModules\\ToSIC_SexyContent\\EditContentGroupItem.ascx\nDesktopModules\\ToSIC_SexyContent\\EditDataSource.ascx\nDesktopModules\\ToSIC_SexyContent\\EditEntity.ascx\nDesktopModules\\ToSIC_SexyContent\\EditList.ascx\nDesktopModules\\ToSIC_SexyContent\\EditTemplateFile.ascx\nDesktopModules\\ToSIC_SexyContent\\icon-app-black.png\nDesktopModules\\ToSIC_SexyContent\\icon-app.png\nDesktopModules\\ToSIC_SexyContent\\icon-black.png\nDesktopModules\\ToSIC_SexyContent\\icon.png\nDesktopModules\\ToSIC_SexyContent\\License.txt\nDesktopModules\\ToSIC_SexyContent\\packages.config\nDesktopModules\\ToSIC_SexyContent\\readme.md\nDesktopModules\\ToSIC_SexyContent\\ReleaseNotes.txt\nDesktopModules\\ToSIC_SexyContent\\Resources.zip.manifest\nDesktopModules\\ToSIC_SexyContent\\Settings.ascx\nDesktopModules\\ToSIC_SexyContent\\SettingsWrapper.ascx\nDesktopModules\\ToSIC_SexyContent\\TemplateHelpGrid.ascx\nDesktopModules\\ToSIC_SexyContent\\turn-on.js\nDesktopModules\\ToSIC_SexyContent\\turn-on.js.map\nDesktopModules\\ToSIC_SexyContent\\View.ascx\nDesktopModules\\ToSIC_SexyContent\\ViewApp.ascx\nDesktopModules\\ToSIC_SexyContent\\web.config\nDesktopModules\\ToSIC_SexyContent\\WebConfigTemplate.config\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/ReleaseNotes.txt",
    "content": "﻿<p>\n    <b>2sxc v21.07.00</b>\n    <br><br>\n    Note: 2sxc v20 cleans up a lot of old APIs, so it's called a <a href=\"https://go.2sxc.org/mot\">MoT release</a> (Moment of Truth).\n    <br><br>\n    If you have old code, things may break and you will be guided to fix the issues.\n    <br><br>\n    Please read the release notes carefully, do backups, and test-upgrade on a copy before upgrading a live environment.\n    See the <a href=\"https://go.2sxc.org/v20\">release blog</a> for more details.\n<p>\n<br>\n<p>\n    Also read the <a href=\"https://github.com/2sic/2sxc/releases\" target=\"_blank\">release notes on Github</a><br/>\n</p>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/00.00.01.SqlDataProvider",
    "content": "/************************************************************/\n/*****              SqlDataProvider                     *****/\n/*****                                                  *****/\n/*****                                                  *****/\n/***** Note: To manually execute this script you must   *****/\n/*****       perform a search and replace operation     *****/\n/*****       for {databaseOwner} and {objectQualifier}  *****/\n/*****                                                  *****/\n/************************************************************/\n-- The following SQL script is actually 'Install.SqlDataProvider' for clean install v20.00.00 DB, but adjusted for 2sxc Package rename\n\n-- Set session language to english to ensure DateTime format is correct (all following insert statements in this script expect that)\nSET LANGUAGE English;\n\n-- Check for custom Object Qualifier - break installation if it's configured (2sxc does not support object qualifier)\nIF '{objectQualifier}' <> ''\nBEGIN\n    RAISERROR(N'Your SQL installation is non-standard using a Custom Object Qualifier. 2sic uses the standard Microsoft Entity Framework which doesn''t work well with this feature - installation aborted.', 16, 1);\n\tRETURN;\nEND\nGO\n\n-- adjusted for 2sxc Package rename\n-- find if old package '2SexyContent' is installed, and if so, skip this clean install script\nDECLARE @upgradeVersion NVARCHAR(20) = '00.00.01', @installedVersion NVARCHAR(20);\nSELECT @installedVersion = ISNULL(\n    (SELECT [Version] FROM Packages WHERE [Name] = N'2SexyContent'),\n    '00.00.00'\n);\n\n-- skip further execution if installedVersion > upgradeVersion\nIF (\n    TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) OR\n    (\n        TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) AND\n        (\n            TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) OR\n            (\n                TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) AND\n                TRY_CAST(PARSENAME(@installedVersion, 1) AS INT) > TRY_CAST(PARSENAME(@upgradeVersion, 1) AS INT)\n            )\n        )\n    )\n)\nRETURN;\n\n-- special case to handle clean install of Install.SqlDataProvider for v20.00.05 db, after 2sxc Packaga rename\nPRINT N'Clean install 00.00.01.SqlDataProvider (actually Install.SqlDataProvider for v20.00.05)';\n\n-- Start of install procedure which replaces all install scripts and code updates until and including version 20.00.05 -------------------------------------------------\n\n/****** Object:  Table [dbo].[TsDynDataApp]    Script Date: 15.5.2025. 13:42:07 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataApp](\n\t[AppId] [int] IDENTITY(1,1) NOT NULL,\n\t[ZoneId] [int] NOT NULL,\n\t[Name] [nvarchar](255) NOT NULL,\n\t[SysSettings] [nvarchar](max) NULL,\n\t[TransCreatedId] [int] NULL,\n\t[TransModifiedId] [int] NULL,\n\t[TransDeletedId] [int] NULL,\n CONSTRAINT [PK_TsDynDataApp] PRIMARY KEY CLUSTERED \n(\n\t[AppId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\n\n/****** Object:  Table [dbo].[TsDynDataAttribute]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataAttribute](\n\t[AttributeId] [int] IDENTITY(1,1) NOT NULL,\n\t[StaticName] [nvarchar](50) NOT NULL,\n\t[Type] [nvarchar](50) NOT NULL,\n\t[TransCreatedId] [int] NOT NULL,\n\t[TransDeletedId] [int] NULL,\n\t[Guid] [uniqueidentifier] NULL,\n\t[SysSettings] [nvarchar](max) NULL,\n\t[ContentTypeId] [int] NOT NULL,\n\t[SortOrder] [int] NOT NULL,\n\t[IsTitle] [bit] NOT NULL,\n\t[TransModifiedId] [int] NULL,\n CONSTRAINT [PK_TsDynDataAttribute] PRIMARY KEY CLUSTERED \n(\n\t[AttributeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataAttributeType]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataAttributeType](\n\t[Type] [nvarchar](50) NOT NULL,\n CONSTRAINT [PK_TsDynDataAttributeType] PRIMARY KEY CLUSTERED \n(\n\t[Type] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataContentType]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataContentType](\n\t[ContentTypeId] [int] IDENTITY(1,1) NOT NULL,\n\t[StaticName] [nvarchar](150) NULL,\n\t[Name] [nvarchar](150) NULL,\n\t[Scope] [nvarchar](50) NULL,\n\t[TransCreatedId] [int] NOT NULL,\n\t[TransDeletedId] [int] NULL,\n\t[AppId] [int] NOT NULL,\n\t[InheritContentTypeId] [int] NULL,\n\t[IsGlobal] [bit] NOT NULL,\n\t[Json] [nvarchar](max) NULL,\n\t[SysSettings] [nvarchar](max) NULL,\n\t[TransModifiedId] [int] NULL,\n CONSTRAINT [PK_TsDynDataContentType] PRIMARY KEY CLUSTERED \n(\n\t[ContentTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataDimension]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataDimension](\n\t[DimensionId] [int] IDENTITY(1,1) NOT NULL,\n\t[Parent] [int] NULL,\n\t[Name] [nvarchar](100) NOT NULL,\n\t[SystemKey] [nvarchar](100) NULL,\n\t[ExternalKey] [nvarchar](100) NULL,\n\t[Active] [bit] NOT NULL,\n\t[ZoneId] [int] NOT NULL,\n CONSTRAINT [PK_TsDynDataDimension] PRIMARY KEY CLUSTERED \n(\n\t[DimensionId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataEntity]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataEntity](\n\t[EntityId] [int] IDENTITY(1,1) NOT NULL,\n\t[EntityGuid] [uniqueidentifier] NOT NULL,\n\t[ContentTypeId] [int] NOT NULL,\n\t[TargetTypeId] [int] NOT NULL,\n\t[KeyNumber] [int] NULL,\n\t[KeyGuid] [uniqueidentifier] NULL,\n\t[KeyString] [nvarchar](100) NULL,\n\t[TransCreatedId] [int] NOT NULL,\n\t[TransDeletedId] [int] NULL,\n\t[IsPublished] [bit] NOT NULL,\n\t[PublishedEntityId] [int] NULL,\n\t[TransModifiedId] [int] NOT NULL,\n\t[Owner] [nvarchar](250) NULL,\n\t[Json] [nvarchar](max) NULL,\n\t[Version] [int] NOT NULL,\n\t[AppId] [int] NOT NULL,\n\t[ContentType] [nvarchar](250) NULL,\n CONSTRAINT [PK_TsDynDataEntity] PRIMARY KEY CLUSTERED \n(\n\t[EntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataHistory]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataHistory](\n\t[HistoryId] [int] IDENTITY(1,1) NOT NULL,\n\t[SourceTable] [nvarchar](250) NOT NULL,\n\t[SourceId] [int] NULL,\n\t[SourceGuid] [uniqueidentifier] NULL,\n\t[Operation] [nchar](1) NOT NULL,\n\t[Timestamp] [datetime] NOT NULL,\n\t[TransactionId] [int] NULL,\n\t[Json] [nvarchar](max) NULL,\n\t[CJson] [varbinary](max) NULL,\n CONSTRAINT [PK_TsDynDataHistory] PRIMARY KEY CLUSTERED \n(\n\t[HistoryId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataRelationship]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataRelationship](\n\t[AttributeId] [int] NOT NULL,\n\t[ParentEntityId] [int] NOT NULL,\n\t[ChildEntityId] [int] NULL,\n\t[SortOrder] [int] NOT NULL,\n CONSTRAINT [PK_TsDynDataRelationship] PRIMARY KEY CLUSTERED \n(\n\t[AttributeId] ASC,\n\t[ParentEntityId] ASC,\n\t[SortOrder] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataTargetType]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataTargetType](\n\t[TargetTypeId] [int] IDENTITY(1,1) NOT NULL,\n\t[Name] [nvarchar](50) NOT NULL,\n\t[Description] [nvarchar](max) NOT NULL,\n CONSTRAINT [PK_TsDynDataTargetType] PRIMARY KEY CLUSTERED \n(\n\t[TargetTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataTransaction]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataTransaction](\n\t[TransactionId] [int] IDENTITY(1,1) NOT NULL,\n\t[Timestamp] [datetime] NOT NULL,\n\t[User] [nvarchar](255) NULL,\n CONSTRAINT [PK_TsDynDataTransaction] PRIMARY KEY CLUSTERED \n(\n\t[TransactionId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataValue]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataValue](\n\t[ValueId] [int] IDENTITY(1,1) NOT NULL,\n\t[EntityId] [int] NOT NULL,\n\t[AttributeId] [int] NOT NULL,\n\t[Value] [nvarchar](max) NOT NULL,\n CONSTRAINT [PK_TsDynDataValue] PRIMARY KEY CLUSTERED \n(\n\t[ValueId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataValueDimension]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataValueDimension](\n\t[ValueId] [int] NOT NULL,\n\t[DimensionId] [int] NOT NULL,\n\t[ReadOnly] [bit] NOT NULL,\n CONSTRAINT [PK_TsDynDataValueDimension] PRIMARY KEY CLUSTERED \n(\n\t[ValueId] ASC,\n\t[DimensionId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY];\n\n/****** Object:  Table [dbo].[TsDynDataZone]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON;\n\nSET QUOTED_IDENTIFIER ON;\n\nCREATE TABLE [dbo].[TsDynDataZone](\n\t[ZoneId] [int] IDENTITY(1,1) NOT NULL,\n\t[Name] [nvarchar](255) NOT NULL,\n\t[TransCreatedId] [int] NULL,\n\t[TransModifiedId] [int] NULL,\n\t[TransDeletedId] [int] NULL,\n CONSTRAINT [PK_TsDynDataZone] PRIMARY KEY CLUSTERED \n(\n\t[ZoneId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY];\n\n\n\n\nSET IDENTITY_INSERT [dbo].[TsDynDataApp] ON;\nINSERT [dbo].[TsDynDataApp] ([AppId], [ZoneId], [Name], [SysSettings], [TransCreatedId], [TransModifiedId], [TransDeletedId]) VALUES (1, 1, N'Default', NULL, NULL, NULL, NULL);\nSET IDENTITY_INSERT [dbo].[TsDynDataApp] OFF;\n\n\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Boolean');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Custom');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'DateTime');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Empty');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Entity');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Hyperlink');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Number');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'String');\n\n\nSET IDENTITY_INSERT [dbo].[TsDynDataContentType] ON; \nINSERT [dbo].[TsDynDataContentType] ([ContentTypeId], [StaticName], [Name], [Scope], [TransCreatedId], [TransDeletedId], [AppId], [InheritContentTypeId], [IsGlobal], [Json], [SysSettings], [TransModifiedId]) VALUES (1, N'Default', N'Default (built in)', N'2SexyContent-System', 1, NULL, 1, NULL, 1, NULL, NULL, NULL);\nSET IDENTITY_INSERT [dbo].[TsDynDataContentType] OFF;\n\n\nSET IDENTITY_INSERT [dbo].[TsDynDataDimension] ON;\nINSERT [dbo].[TsDynDataDimension] ([DimensionId], [Parent], [Name], [SystemKey], [ExternalKey], [Active], [ZoneId]) VALUES (1, NULL, N'Culture Root', N'Culture', NULL, 1, 1);\nSET IDENTITY_INSERT [dbo].[TsDynDataDimension] OFF;\n\n\nSET IDENTITY_INSERT [dbo].[TsDynDataTargetType] ON; \nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (1, N'Default', N'Default');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (2, N'EAV Field Properties', N'EAV Field Properties');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (3, N'App', N'App');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (4, N'Entity', N'For Permissions, Data Pipelines with Pipeline Parts and Configurations');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (5, N'ContentType', N'Metadata for ContentTypes');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (6, N'Zone', N'Metadata for Zone');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (7, N'Scope', N'Metadata for Scope');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (8, N'Dimension', N'Metadata for Dimension');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (9, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (10, N'CmsObject', N'References to CMS objects like files and pages');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (11, N'System', N'Metadata for System');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (12, N'Site', N'Metadata for Site');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (13, N'SiteVariant', N'Metadata for SiteVariant');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (14, N'Page', N'Metadata for Page');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (15, N'PageVariant', N'Metadata for PageVariant');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (16, N'Module', N'Metadata for Module');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (17, N'ModuleVariant', N'Metadata for ModuleVariant');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (18, N'User', N'Metadata for User');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (19, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (20, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (21, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (22, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (23, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (24, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (25, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (26, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (27, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (28, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (29, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (30, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (31, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (32, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (33, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (34, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (35, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (36, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (37, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (38, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (39, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (40, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (41, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (42, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (43, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (44, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (45, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (46, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (47, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (48, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (49, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (50, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (51, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (52, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (53, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (54, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (55, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (56, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (57, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (58, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (59, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (60, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (61, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (62, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (63, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (64, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (65, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (66, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (67, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (68, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (69, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (70, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (71, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (72, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (73, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (74, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (75, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (76, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (77, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (78, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (79, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (80, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (81, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (82, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (83, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (84, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (85, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (86, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (87, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (88, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (89, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (90, N'Custom', N'Custom');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (91, N'Custom1', N'Custom1');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (92, N'Custom2', N'Custom2');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (93, N'Custom3', N'Custom3');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (94, N'Custom4', N'Custom4');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (95, N'Custom5', N'Custom5');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (96, N'Custom6', N'Custom6');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (97, N'Custom7', N'Custom7');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (98, N'Custom8', N'Custom8');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (99, N'Custom9', N'Custom9');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (100, N'Reserved', N'Reserved');\nSET IDENTITY_INSERT [dbo].[TsDynDataTargetType] OFF;\n\n\nSET IDENTITY_INSERT [dbo].[TsDynDataTransaction] ON;\nINSERT [dbo].[TsDynDataTransaction] ([TransactionId], [Timestamp], [User]) VALUES (1, CAST(N'2012-05-02T08:31:35.297' AS DateTime), NULL);\nINSERT [dbo].[TsDynDataTransaction] ([TransactionId], [Timestamp], [User]) VALUES (100, CAST(N'2020-10-20T00:00:00.000' AS DateTime), NULL);\nSET IDENTITY_INSERT [dbo].[TsDynDataTransaction] OFF;\n\n\nSET IDENTITY_INSERT [dbo].[TsDynDataZone] ON ;\nINSERT [dbo].[TsDynDataZone] ([ZoneId], [Name], [TransCreatedId], [TransModifiedId], [TransDeletedId]) VALUES (1, N'Default', NULL, NULL, NULL);\nSET IDENTITY_INSERT [dbo].[TsDynDataZone] OFF;\n\n\n\n\nSET ANSI_PADDING ON;\n\n/****** Object:  Index [UQ_TsDynDataApp_Name_ZoneId]    Script Date: 15.5.2025. 13:42:08 ******/\nALTER TABLE [dbo].[TsDynDataApp] ADD  CONSTRAINT [UQ_TsDynDataApp_Name_ZoneId] UNIQUE NONCLUSTERED \n(\n\t[Name] ASC,\n\t[ZoneId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataApp_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransCreatedId] ON [dbo].[TsDynDataApp]\n(\n\t[TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataApp_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransDeletedId] ON [dbo].[TsDynDataApp]\n(\n\t[TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataApp_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransModifiedId] ON [dbo].[TsDynDataApp]\n(\n\t[TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataApp_ZoneId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataApp_ZoneId] ON [dbo].[TsDynDataApp]\n(\n\t[ZoneId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataAttribute_AttributeId_StaticName]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_AttributeId_StaticName] ON [dbo].[TsDynDataAttribute]\n(\n\t[AttributeId] ASC\n)\nINCLUDE([StaticName]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataAttribute_ContentTypeId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_ContentTypeId] ON [dbo].[TsDynDataAttribute]\n(\n\t[ContentTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataAttribute_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_TransCreatedId] ON [dbo].[TsDynDataAttribute]\n(\n\t[TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataAttribute_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_TransDeletedId] ON [dbo].[TsDynDataAttribute]\n(\n\t[TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataAttribute_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_TransModifiedId] ON [dbo].[TsDynDataAttribute]\n(\n\t[TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataContentType_AppId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_AppId] ON [dbo].[TsDynDataContentType]\n(\n\t[AppId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataContentType_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_TransCreatedId] ON [dbo].[TsDynDataContentType]\n(\n\t[TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataContentType_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_TransDeletedId] ON [dbo].[TsDynDataContentType]\n(\n\t[TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataContentType_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_TransModifiedId] ON [dbo].[TsDynDataContentType]\n(\n\t[TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataDimension_ZoneId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataDimension_ZoneId] ON [dbo].[TsDynDataDimension]\n(\n\t[ZoneId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataEntity_AppId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_AppId] ON [dbo].[TsDynDataEntity]\n(\n\t[AppId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataEntity_ContentTypeId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_ContentTypeId] ON [dbo].[TsDynDataEntity]\n(\n\t[ContentTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataEntity_KeyNumber]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_KeyNumber] ON [dbo].[TsDynDataEntity]\n(\n\t[KeyNumber] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataEntity_TargetTypeId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_TargetTypeId] ON [dbo].[TsDynDataEntity]\n(\n\t[TargetTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataEntity_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_TransCreatedId] ON [dbo].[TsDynDataEntity]\n(\n\t[TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataEntity_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_TransDeletedId] ON [dbo].[TsDynDataEntity]\n(\n\t[TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataEntity_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_TransModifiedId] ON [dbo].[TsDynDataEntity]\n(\n\t[TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataHistory_SourceGuid]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_SourceGuid] ON [dbo].[TsDynDataHistory]\n(\n\t[SourceGuid] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataHistory_SourceId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_SourceId] ON [dbo].[TsDynDataHistory]\n(\n\t[SourceId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataHistory_TransactionId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_TransactionId] ON [dbo].[TsDynDataHistory]\n(\n\t[TransactionId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataRelationship_ChildEntityId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataRelationship_ChildEntityId] ON [dbo].[TsDynDataRelationship]\n(\n\t[ChildEntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataRelationship_ParentEntityId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataRelationship_ParentEntityId] ON [dbo].[TsDynDataRelationship]\n(\n\t[ParentEntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\nSET ANSI_PADDING ON;\n\n/****** Object:  Index [IX_TsDynDataTargetType_Name]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataTargetType_Name] ON [dbo].[TsDynDataTargetType]\n(\n\t[Name] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataValue_AttributeId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataValue_AttributeId] ON [dbo].[TsDynDataValue]\n(\n\t[AttributeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataValue_AttributeId_EntityId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataValue_AttributeId_EntityId] ON [dbo].[TsDynDataValue]\n(\n\t[AttributeId] ASC,\n\t[EntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataValue_EntityId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataValue_EntityId] ON [dbo].[TsDynDataValue]\n(\n\t[EntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value] ON [dbo].[TsDynDataValue]\n(\n\t[EntityId] ASC,\n\t[AttributeId] ASC,\n\t[ValueId] ASC\n)\nINCLUDE([Value]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataZone_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransCreatedId] ON [dbo].[TsDynDataZone]\n(\n\t[TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataZone_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransDeletedId] ON [dbo].[TsDynDataZone]\n(\n\t[TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\n/****** Object:  Index [IX_TsDynDataZone_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransModifiedId] ON [dbo].[TsDynDataZone]\n(\n\t[TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\n\nALTER TABLE [dbo].[TsDynDataAttribute] ADD  CONSTRAINT [DF_TsDynDataAttribute_ContentTypeId]  DEFAULT ((0)) FOR [ContentTypeId];\n\nALTER TABLE [dbo].[TsDynDataAttribute] ADD  CONSTRAINT [DF_TsDynDataAttribute_SortOrder]  DEFAULT ((0)) FOR [SortOrder];\n\nALTER TABLE [dbo].[TsDynDataAttribute] ADD  CONSTRAINT [DF_TsDynDataAttribute_IsTitle]  DEFAULT ((0)) FOR [IsTitle];\n\nALTER TABLE [dbo].[TsDynDataContentType] ADD  CONSTRAINT [DF_TsDynDataContentType_StaticName]  DEFAULT (newid()) FOR [StaticName];\n\nALTER TABLE [dbo].[TsDynDataContentType] ADD  CONSTRAINT [DF_TsDynDataContentType_IsGlobal]  DEFAULT ((0)) FOR [IsGlobal];\n\nALTER TABLE [dbo].[TsDynDataDimension] ADD  CONSTRAINT [DF_TsDynDataDimension_Active]  DEFAULT ((1)) FOR [Active];\n\nALTER TABLE [dbo].[TsDynDataEntity] ADD  CONSTRAINT [DF_TsDynDataEntity_EntityGuid]  DEFAULT (newid()) FOR [EntityGuid];\n\nALTER TABLE [dbo].[TsDynDataEntity] ADD  CONSTRAINT [DF_TsDynDataEntity_IsPublished]  DEFAULT ((1)) FOR [IsPublished];\n\nALTER TABLE [dbo].[TsDynDataHistory] ADD  CONSTRAINT [DF_TsDynDataHistory_Operation]  DEFAULT (N'I') FOR [Operation];\n\nALTER TABLE [dbo].[TsDynDataTransaction] ADD  CONSTRAINT [DF_TsDynDataTransaction_Timestamp]  DEFAULT (getutcdate()) FOR [Timestamp];\n\nALTER TABLE [dbo].[TsDynDataValueDimension] ADD  CONSTRAINT [DF_TsDynDataValueDimension_ReadOnly]  DEFAULT ((0)) FOR [ReadOnly];\n\nALTER TABLE [dbo].[TsDynDataApp]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionCreated];\n\nALTER TABLE [dbo].[TsDynDataApp]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionDeleted];\n\nALTER TABLE [dbo].[TsDynDataApp]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionModified];\n\nALTER TABLE [dbo].[TsDynDataApp]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataApp_TsDynDataZone] FOREIGN KEY([ZoneId])\nREFERENCES [dbo].[TsDynDataZone] ([ZoneId]);\n\nALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataZone];\n\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataAttributeType] FOREIGN KEY([Type])\nREFERENCES [dbo].[TsDynDataAttributeType] ([Type]);\n\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataAttributeType];\n\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataContentType] FOREIGN KEY([ContentTypeId])\nREFERENCES [dbo].[TsDynDataContentType] ([ContentTypeId]);\n\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataContentType];\n\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionCreated];\n\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionDeleted];\n\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionModified];\n\nALTER TABLE [dbo].[TsDynDataContentType]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataApp] FOREIGN KEY([AppId])\nREFERENCES [dbo].[TsDynDataApp] ([AppId]);\n\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataApp];\n\nALTER TABLE [dbo].[TsDynDataContentType]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataContentType] FOREIGN KEY([InheritContentTypeId])\nREFERENCES [dbo].[TsDynDataContentType] ([ContentTypeId]);\n\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataContentType];\n\nALTER TABLE [dbo].[TsDynDataContentType]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionCreated];\n\nALTER TABLE [dbo].[TsDynDataContentType]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionDeleted];\n\nALTER TABLE [dbo].[TsDynDataContentType]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionModified];\n\nALTER TABLE [dbo].[TsDynDataDimension]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataDimension_TsDynDataDimension] FOREIGN KEY([Parent])\nREFERENCES [dbo].[TsDynDataDimension] ([DimensionId]);\n\nALTER TABLE [dbo].[TsDynDataDimension] CHECK CONSTRAINT [FK_TsDynDataDimension_TsDynDataDimension];\n\nALTER TABLE [dbo].[TsDynDataDimension]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataDimension_TsDynDataZone] FOREIGN KEY([ZoneId])\nREFERENCES [dbo].[TsDynDataZone] ([ZoneId]);\n\nALTER TABLE [dbo].[TsDynDataDimension] CHECK CONSTRAINT [FK_TsDynDataDimension_TsDynDataZone];\n\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataApp] FOREIGN KEY([AppId])\nREFERENCES [dbo].[TsDynDataApp] ([AppId]);\n\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataApp];\n\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataContentType] FOREIGN KEY([ContentTypeId])\nREFERENCES [dbo].[TsDynDataContentType] ([ContentTypeId]);\n\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataContentType];\n\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataTargetType] FOREIGN KEY([TargetTypeId])\nREFERENCES [dbo].[TsDynDataTargetType] ([TargetTypeId]);\n\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataTargetType];\n\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionCreated];\n\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionDeleted];\n\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionModified];\n\nALTER TABLE [dbo].[TsDynDataHistory]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataHistory_TsDynDataTransaction] FOREIGN KEY([TransactionId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataHistory] CHECK CONSTRAINT [FK_TsDynDataHistory_TsDynDataTransaction];\n\nALTER TABLE [dbo].[TsDynDataRelationship]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataRelationship_TsDynDataAttribute] FOREIGN KEY([AttributeId])\nREFERENCES [dbo].[TsDynDataAttribute] ([AttributeId])\nON DELETE CASCADE;\n\nALTER TABLE [dbo].[TsDynDataRelationship] CHECK CONSTRAINT [FK_TsDynDataRelationship_TsDynDataAttribute];\n\nALTER TABLE [dbo].[TsDynDataRelationship]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataRelationship_TsDynDataEntityChild] FOREIGN KEY([ChildEntityId])\nREFERENCES [dbo].[TsDynDataEntity] ([EntityId]);\n\nALTER TABLE [dbo].[TsDynDataRelationship] CHECK CONSTRAINT [FK_TsDynDataRelationship_TsDynDataEntityChild];\n\nALTER TABLE [dbo].[TsDynDataRelationship]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataRelationship_TsDynDataEntityParent] FOREIGN KEY([ParentEntityId])\nREFERENCES [dbo].[TsDynDataEntity] ([EntityId]);\n\nALTER TABLE [dbo].[TsDynDataRelationship] CHECK CONSTRAINT [FK_TsDynDataRelationship_TsDynDataEntityParent];\n\nALTER TABLE [dbo].[TsDynDataValue]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataValue_TsDynDataAttribute] FOREIGN KEY([AttributeId])\nREFERENCES [dbo].[TsDynDataAttribute] ([AttributeId])\nON DELETE CASCADE;\n\nALTER TABLE [dbo].[TsDynDataValue] CHECK CONSTRAINT [FK_TsDynDataValue_TsDynDataAttribute];\n\nALTER TABLE [dbo].[TsDynDataValue]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataValue_TsDynDataEntity] FOREIGN KEY([EntityId])\nREFERENCES [dbo].[TsDynDataEntity] ([EntityId]);\n\nALTER TABLE [dbo].[TsDynDataValue] CHECK CONSTRAINT [FK_TsDynDataValue_TsDynDataEntity];\n\nALTER TABLE [dbo].[TsDynDataValueDimension]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataValueDimension_TsDynDataDimension] FOREIGN KEY([DimensionId])\nREFERENCES [dbo].[TsDynDataDimension] ([DimensionId]);\n\nALTER TABLE [dbo].[TsDynDataValueDimension] CHECK CONSTRAINT [FK_TsDynDataValueDimension_TsDynDataDimension];\n\nALTER TABLE [dbo].[TsDynDataValueDimension]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataValueDimension_TsDynDataValue] FOREIGN KEY([ValueId])\nREFERENCES [dbo].[TsDynDataValue] ([ValueId]);\n\nALTER TABLE [dbo].[TsDynDataValueDimension] CHECK CONSTRAINT [FK_TsDynDataValueDimension_TsDynDataValue];\n\nALTER TABLE [dbo].[TsDynDataZone]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionCreated];\n\nALTER TABLE [dbo].[TsDynDataZone]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionDeleted];\n\nALTER TABLE [dbo].[TsDynDataZone]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\n\nALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionModified];\n\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/16.07.01.SqlDataProvider",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\nDECLARE @upgradeVersion NVARCHAR(20) = '16.07.01', @installedVersion NVARCHAR(20);\nSELECT @installedVersion = ISNULL(\n    (SELECT [Version] FROM Packages WHERE [Name] = N'2SexyContent'),\n    '99.99.99'\n)\n\n-- skip further execution if installedVersion > upgradeVersion\nIF (\n    TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) OR\n    (\n        TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) AND\n        (\n            TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) OR\n            (\n                TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) AND\n                TRY_CAST(PARSENAME(@installedVersion, 1) AS INT) > TRY_CAST(PARSENAME(@upgradeVersion, 1) AS INT)\n            )\n        )\n    )\n)\nRETURN;\n\n-- if the installed version is older than the upgrade version, then we can continue with the upgrade\nPRINT N'Upgrading 2sxc from version ' + @installedVersion + ' to ' + @upgradeVersion;\n\n-- check for minimum required version of 2sxc package\nDECLARE @RequiredVersion int, @RequiredVersionIsInstalled int;\nSET @RequiredVersion = 15;\nSELECT @RequiredVersionIsInstalled = CASE WHEN EXISTS(\n    SELECT 1 FROM Packages\n    WHERE [Name] = N'2SexyContent' AND CONVERT(int, PARSENAME([Version], 3)) >= @RequiredVersion\n) THEN 1 ELSE 0 END\nIF (@RequiredVersionIsInstalled = 0)\nBEGIN\n    RAISERROR(N'2sxc 15 or newer must be installed for the app module to install.', 16, 1);\n    RETURN;\nEND\n\n-- add [Guid], [SysSettings] columns to 'ToSIC_EAV_Attributes'\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'Guid' AND Object_ID = OBJECT_ID('ToSIC_EAV_Attributes'))\nBEGIN\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] ADD [Guid] uniqueidentifier NULL,\n    [SysSettings] nvarchar(MAX) NULL;\nEND\n\n-- add [SysSettings] column to 'ToSIC_EAV_AttributeSets'\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'SysSettings' AND Object_ID = OBJECT_ID('ToSIC_EAV_AttributeSets'))\nBEGIN\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] ADD [SysSettings] nvarchar(MAX) NULL;\nEND\nGO"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/18.03.00.SqlDataProvider",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\nDECLARE @upgradeVersion NVARCHAR(20) = '18.03.00', @installedVersion NVARCHAR(20);\nSELECT @installedVersion = ISNULL(\n    (SELECT [Version] FROM Packages WHERE [Name] = N'2SexyContent'),\n    '99.99.99'\n)\n\n-- skip further execution if installedVersion > upgradeVersion\nIF (\n    TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) OR\n    (\n        TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) AND\n        (\n            TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) OR\n            (\n                TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) AND\n                TRY_CAST(PARSENAME(@installedVersion, 1) AS INT) > TRY_CAST(PARSENAME(@upgradeVersion, 1) AS INT)\n            )\n        )\n    )\n)\nRETURN;\n\n-- if the installed version is older than the upgrade version, then we can continue with the upgrade\nPRINT N'Upgrading 2sxc from version ' + @installedVersion + ' to ' + @upgradeVersion;\n\n-- check for minimum required version of 2sxc package\nDECLARE @RequiredVersion int, @RequiredVersionIsInstalled int;\nSET @RequiredVersion = 15;\nSELECT @RequiredVersionIsInstalled = CASE WHEN EXISTS(\n    SELECT 1 FROM Packages\n    WHERE [Name] = N'2SexyContent' AND CONVERT(int, PARSENAME([Version], 3)) >= @RequiredVersion\n) THEN 1 ELSE 0 END\nIF (@RequiredVersionIsInstalled = 0)\nBEGIN\n    RAISERROR(N'2sxc 15 or newer must be installed for the app module to install.', 16, 1);\n    RETURN;\nEND\n\n-- Remove AttributeGroups SQL table and related:\n-- Drop the foreign key constraint before dropping the column.\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets] \nDROP CONSTRAINT IF EXISTS [FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeGroups];\n\n-- Now it's safe to drop the column.\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets] \nDROP COLUMN IF EXISTS [AttributeGroupID];\n\n-- Drop the foreign key constraint in another table before dropping the table.\nALTER TABLE [dbo].[ToSIC_EAV_AttributeGroups] \nDROP CONSTRAINT IF EXISTS [FK_ToSIC_EAV_AttributeGroups_ToSIC_EAV_AttributeSets];\n\n-- Now it's safe to drop the table.\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AttributeGroups];\nGO"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/19.00.00.SqlDataProvider",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\nDECLARE @upgradeVersion NVARCHAR(20) = '19.00.00', @installedVersion NVARCHAR(20);\nSELECT @installedVersion = ISNULL(\n    (SELECT [Version] FROM Packages WHERE [Name] = N'2SexyContent'),\n    '99.99.99'\n)\n\n-- skip further execution if installedVersion > upgradeVersion\nIF (\n    TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) OR\n    (\n        TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) AND\n        (\n            TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) OR\n            (\n                TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) AND\n                TRY_CAST(PARSENAME(@installedVersion, 1) AS INT) > TRY_CAST(PARSENAME(@upgradeVersion, 1) AS INT)\n            )\n        )\n    )\n)\nRETURN;\n\n-- if the installed version is older than the upgrade version, then we can continue with the upgrade\nPRINT N'Upgrading 2sxc from version ' + @installedVersion + ' to ' + @upgradeVersion;\n\n-- check for minimum required version of 2sxc package\nDECLARE @RequiredVersion int, @RequiredVersionIsInstalled int;\nSET @RequiredVersion = 15;\nSELECT @RequiredVersionIsInstalled = CASE WHEN EXISTS(\n    SELECT 1 FROM Packages\n    WHERE [Name] = N'2SexyContent' AND CONVERT(int, PARSENAME([Version], 3)) >= @RequiredVersion\n) THEN 1 ELSE 0 END\nIF (@RequiredVersionIsInstalled = 0)\nBEGIN\n    RAISERROR(N'2sxc 15 or newer must be installed for the app module to install.', 16, 1);\n    RETURN;\nEND\n\n-- Drop the existing foreign key constraint\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships]\n    DROP CONSTRAINT IF EXISTS [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes];\n\n-- Add the foreign key constraint with ON DELETE CASCADE\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships]\n    ADD CONSTRAINT [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes]\n    FOREIGN KEY ([AttributeID])\n    REFERENCES [dbo].[ToSIC_EAV_Attributes] ([AttributeID])\n    ON UPDATE NO ACTION\n    ON DELETE CASCADE;\nGO"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/20.00.00.SqlDataProvider",
    "content": "SET ANSI_NULLS ON\nGO\n\nSET QUOTED_IDENTIFIER ON\nGO\n\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\nDECLARE @upgradeVersion NVARCHAR(20) = REPLACE('20-00-00','-','.'), @installedVersion NVARCHAR(20);\nSELECT @installedVersion = ISNULL(\n    (SELECT [Version] FROM Packages WHERE [Name] = N'2SexyContent'),\n    '99.99.99'\n)\n\n-- skip further execution if installedVersion > upgradeVersion\nIF (\n    TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) OR\n    (\n        TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 3) AS INT) AND\n        (\n            TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) >  TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) OR\n            (\n                TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) = TRY_CAST(PARSENAME(@upgradeVersion, 2) AS INT) AND\n                TRY_CAST(PARSENAME(@installedVersion, 1) AS INT) > TRY_CAST(PARSENAME(@upgradeVersion, 1) AS INT)\n            )\n        )\n    )\n)\nRETURN;\n\n-- continue if installedVersion <= upgradeVersion\n-- if the installed version is older than the upgrade version, then we can continue with the upgrade\nPRINT N'Upgrading 2sxc from version ' + @installedVersion + ' to ' + @upgradeVersion;\n\n-- check for minimum required version of 2sxc package\nDECLARE @RequiredVersion int, @RequiredVersionIsInstalled int;\nSET @RequiredVersion = 15;\nSELECT @RequiredVersionIsInstalled = CASE WHEN EXISTS(\n    SELECT 1 FROM Packages\n    WHERE [Name] = N'2SexyContent' AND CONVERT(int, PARSENAME([Version], 3)) >= @RequiredVersion\n) THEN 1 ELSE 0 END\nIF (@RequiredVersionIsInstalled = 0)\nBEGIN\n    RAISERROR(N'2sxc 15 or newer must be installed for the app module to install.', 16, 1);\n    RETURN;\nEND\n\nPRINT '*** Starting migration script.';\n\n-- Preflight check 1: Ensure no AttributeID appears more than once in ToSIC_EAV_AttributesInSets\nIF OBJECT_ID('[dbo].[ToSIC_EAV_AttributesInSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT 'Running Preflight check 1: Checking for duplicate AttributeIDs in ToSIC_EAV_AttributesInSets';\n\n    IF EXISTS (\n        SELECT AttributeID\n        FROM [dbo].[ToSIC_EAV_AttributesInSets]\n        GROUP BY AttributeID\n        HAVING COUNT(*) > 1\n    )\n    BEGIN\n        RAISERROR(N'Preflight check failed: Duplicate AttributeID found in ToSIC_EAV_AttributesInSets. Migration stopped.', 16, 1);\n        RETURN;\n    END\nEND\n\n\n-- Preflight check 2: Remove orphaned Attributes and related data\nIF OBJECT_ID('[dbo].[ToSIC_EAV_AttributesInSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT 'Running Preflight check 2: Removing orphaned Attributes and related data';\n\n    -- 2.1 Find orphaned AttributeIDs\n    PRINT '... Finding orphaned AttributeIDs';\n    DECLARE @OrphanedAttributes TABLE (AttributeID INT);\n    INSERT INTO @OrphanedAttributes (AttributeID)\n    SELECT a.AttributeID\n    FROM [dbo].[ToSIC_EAV_Attributes] a\n    LEFT JOIN [dbo].[ToSIC_EAV_AttributesInSets] ais ON a.AttributeID = ais.AttributeID\n    WHERE ais.AttributeID IS NULL;\n\n    -- 2.2 Find ValueIDs related to orphaned AttributeIDs\n    PRINT '... Finding related ValueIDs';\n    DECLARE @OrphanedValueIDs TABLE (ValueID INT);\n    INSERT INTO @OrphanedValueIDs (ValueID)\n    SELECT v.ValueID\n    FROM [dbo].[ToSIC_EAV_Values] v\n    INNER JOIN @OrphanedAttributes oa ON v.AttributeID = oa.AttributeID;\n\n    -- 2.3 Delete from ToSIC_EAV_ValuesDimensions (child of Values)\n    PRINT '... Deleting orphaned ValuesDimensions';\n    DELETE vd\n    FROM [dbo].[ToSIC_EAV_ValuesDimensions] vd\n    INNER JOIN @OrphanedValueIDs ov ON vd.ValueID = ov.ValueID;\n\n    -- 2.4 Delete from ToSIC_EAV_Values (child of Attributes)\n    PRINT '... Deleting orphaned Values';\n    DELETE v\n    FROM [dbo].[ToSIC_EAV_Values] v\n    INNER JOIN @OrphanedValueIDs ov ON v.ValueID = ov.ValueID;\n\n    -- 2.5 Delete from ToSIC_EAV_EntityRelationships (child of Attributes)\n    PRINT '... Deleting orphaned EntityRelationships';\n    DELETE er\n    FROM [dbo].[ToSIC_EAV_EntityRelationships] er\n    INNER JOIN @OrphanedAttributes oa ON er.AttributeID = oa.AttributeID;\n\n    -- 2.6 Delete orphaned Attributes\n    PRINT '... Deleting orphaned Attributes';\n    DELETE a\n    FROM [dbo].[ToSIC_EAV_Attributes] a\n    INNER JOIN @OrphanedAttributes oa ON a.AttributeID = oa.AttributeID;\nEND\n\n\nPRINT '1. Upgrade script started.';\n\n-- 1.1. Add new columns to ToSIC_EAV_Attributes if they do not exist yet.\n\n    PRINT '... 1.1. Adding new columns (ContentTypeId, SortOrder, IsTitle) to ToSIC_EAV_Attributes';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] ADD\n        [ContentTypeId] [int] NOT NULL CONSTRAINT DF_ToSIC_EAV_Attributes_ContentTypeId DEFAULT (0),\n        [SortOrder] [int] NOT NULL CONSTRAINT DF_ToSIC_EAV_Attributes_SortOrder DEFAULT (0),\n        [IsTitle] [bit] NOT NULL CONSTRAINT DF_ToSIC_EAV_Attributes_IsTitle DEFAULT (0);\n\n\n\n-- 1.2. Migrate data from ToSIC_EAV_AttributesInSets to new columns in ToSIC_EAV_Attributes\nIF OBJECT_ID('[dbo].[ToSIC_EAV_AttributesInSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 1.2. Migrating data from ToSIC_EAV_AttributesInSets to ToSIC_EAV_Attributes';\n    -- Keep EXEC statement, since before the EXEC statement below runs any schema changes are in effect.\n    EXEC('\n    UPDATE a\n    SET\n        a.ContentTypeId = ais.AttributeSetID,\n        a.SortOrder = ais.SortOrder,\n        a.IsTitle = ais.IsTitle\n    FROM [dbo].[ToSIC_EAV_Attributes] a\n    INNER JOIN [dbo].[ToSIC_EAV_AttributesInSets] ais\n        ON a.AttributeID = ais.AttributeID;\n    ');\nEND\n\n\n-- 1.3. Add Index on ContentTypeId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_ContentTypeId' AND Object_ID = OBJECT_ID('ToSIC_EAV_Attributes'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 1.3. Adding index IX_ToSIC_EAV_Attributes_ContentTypeId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Attributes_ContentTypeId] ON [dbo].[ToSIC_EAV_Attributes] ([ContentTypeId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 1.4. Add foreign key constraint from ContentTypeId to AttributeSets.AttributeSetID\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 1.4. Adding foreign key FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes]\n    ADD CONSTRAINT FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets\n    FOREIGN KEY ([ContentTypeId]) REFERENCES [dbo].[ToSIC_EAV_AttributeSets] ([AttributeSetID]);\nEND\n\n\n\n\n-- 2. Remove Stored Procedures and Tables\nPRINT '2. Removing obsolete Stored Procedures and Tables';\n\n\nIF OBJECT_ID('[dbo].[ToSIC_EAV_ChangeLogSet]', 'P') IS NOT NULL\nBEGIN\n    PRINT '... 2.1. Removing obsolete Stored Procedures';\n    DROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogSet];\n    DROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogGet];\n    DROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogAdd];\n    DROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_DeleteApp];\nEND\n\n\n-- Remove Tables\nIF OBJECT_ID('[dbo].[ToSIC_EAV_ContextInfo]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 2.2. Removing obsolete Tables';\n    DROP TABLE IF EXISTS [dbo].[ToSIC_EAV_ContextInfo];\n    DROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AttributesInSets];\nEND\n\n\n\n\n-- *** 3. Rename AssignmentObjectTypes to TsDynDataTargetType\nPRINT '3. Renaming table ToSIC_EAV_AssignmentObjectTypes to TsDynDataTargetType and related objects';\n\n-- 3.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_AssignmentObjectTypes' AND type = 'U')\nBEGIN\n    PRINT '... 3.1. Renaming table ToSIC_EAV_AssignmentObjectTypes to TsDynDataTargetType';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AssignmentObjectTypes]', N'TsDynDataTargetType';\nEND\n\n\n-- 3.2. Rename the primary key column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AssignmentObjectTypeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataTargetType]'))\nBEGIN\n    PRINT '... 3.2. Renaming column AssignmentObjectTypeID to TargetTypeId in TsDynDataTargetType';\n    EXEC sp_rename N'[dbo].[TsDynDataTargetType].[AssignmentObjectTypeID]', N'TargetTypeId', N'COLUMN';\nEND\n\n\n-- 3.3. Rename the primary key constraint\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_AssignmentObjectTypes' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataTargetType]'))\nBEGIN\n    PRINT '... 3.3.Renaming PK_ToSIC_EAV_AssignmentObjectTypes to PK_TsDynDataTargetType';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_AssignmentObjectTypes]', N'PK_TsDynDataTargetType', N'OBJECT';\nEND\n\n\n-- 3.4. Rename the index\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AssignmentObjectTypes')\nBEGIN\n    PRINT '... 3.4. Renaming index IX_ToSIC_EAV_AssignmentObjectTypes to IX_TsDynDataTargetType_Name';\n    EXEC sp_rename N'[dbo].[TsDynDataTargetType].[IX_ToSIC_EAV_AssignmentObjectTypes]', N'IX_TsDynDataTargetType_Name', N'INDEX';\nEND\n\n\n-- 3.5. Rename the foreign key column in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AssignmentObjectTypeID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 3.5.Renaming column AssignmentObjectTypeID to TargetTypeId in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[AssignmentObjectTypeID]', N'TargetTypeId', N'COLUMN';\nEND\n\n\n-- 3.6. Rename foreign key constraint on ToSIC_EAV_Entities\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes')\nBEGIN\n    PRINT '... 3.6. Rename FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes]', N'FK_ToSIC_EAV_Entities_TsDynDataTargetType', N'OBJECT';\nEND\n\n\n-- 3.7. Add Index on TargetTypeId if it doesn't exist\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TargetTypeId' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 3.7. Adding index IX_ToSIC_EAV_Entities_TargetTypeId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_TargetTypeId] ON [dbo].[ToSIC_EAV_Entities] ([TargetTypeId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 3.8. Recreate the foreign key constraint on ToSIC_EAV_Entities with the new names\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTargetType')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 3.8. Recreating foreign key FK_ToSIC_EAV_Entities_TsDynDataTargetType';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTargetType]\n    FOREIGN KEY([TargetTypeId])\n    REFERENCES [dbo].[TsDynDataTargetType] ([TargetTypeId]);\nEND\n\n\n-- 3.9. Check the constraint FK_ToSIC_EAV_Entities_TsDynDataTargetType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTargetType')\nBEGIN\n    PRINT '... 3.9. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataTargetType';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTargetType];\nEND\n\n\n\n\n-- *** 4. Rename ToSIC_EAV_ChangeLog to TsDynDataTransaction\nPRINT '4. Renaming table ToSIC_EAV_ChangeLog to TsDynDataTransaction and related objects';\n\n-- 4.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_ChangeLog' AND type = 'U')\nBEGIN\n    PRINT '... 4.1. Renaming table ToSIC_EAV_ChangeLog to TsDynDataTransaction';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_ChangeLog]', N'TsDynDataTransaction';\nEND\n\n\n-- 4.2. Rename the primary key column in the renamed table\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataTransaction]'))\nBEGIN\n    PRINT '... 4.2. Renaming column ChangeID to TransactionId in TsDynDataTransaction';\n    EXEC sp_rename N'[dbo].[TsDynDataTransaction].[ChangeID]', N'TransactionId', N'COLUMN';\nEND\n\n\n-- 4.3. Rename the primary key constraint\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_ChangeLog' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataTransaction]'))\nBEGIN\n    PRINT '... 4.3. Renaming PK_ToSIC_EAV_ChangeLog to PK_TsDynDataTransaction';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_ChangeLog]', N'PK_TsDynDataTransaction', N'OBJECT';\nEND\n\n\n-- 4.4. Rename the default constraint for the Timestamp column\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_ChangeLog_Timestamp' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataTransaction]'))\nBEGIN\n    PRINT '... 4.4. Renaming default constraint DF_ToSIC_EAV_ChangeLog_Timestamp';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_ChangeLog_Timestamp]', N'DF_TsDynDataTransaction_Timestamp', N'OBJECT';\nEND\n\n\n-- 4.5. Rename the foreign key column ChangeLogCreated in the referencing table (ToSIC_EAV_Attributes)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nBEGIN\n    PRINT '... 4.5. Renaming ChangeLogCreated columns in ToSIC_EAV_Attributes';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Attributes].[ChangeLogCreated]', N'TransactionIdCreated', N'COLUMN';\nEND\n\n\n-- 4.6. Rename the foreign key column ChangeLogDeleted in the referencing table (ToSIC_EAV_Attributes)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nBEGIN\n    PRINT '... 4.6. Renaming ChangeLogDeleted columns in ToSIC_EAV_Attributes';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Attributes].[ChangeLogDeleted]', N'TransactionIdDeleted', N'COLUMN';\nEND\n\n\n-- 4.7. Rename the foreign key column ChangeLogCreated in the referencing table (ToSIC_EAV_AttributeSets)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nBEGIN\n    PRINT '... 4.7. Renaming ChangeLogCreated columns in ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeSets].[ChangeLogCreated]', N'TransactionIdCreated', N'COLUMN';\nEND\n\n\n-- 4.8. Rename the foreign key column ChangeLogDeleted in the referencing table (ToSIC_EAV_AttributeSets)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nBEGIN\n    PRINT '... 4.8. Renaming ChangeLogDeleted columns in ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeSets].[ChangeLogDeleted]', N'TransactionIdDeleted', N'COLUMN';\nEND\n\n\n-- 4.9. Rename the foreign key column ChangeLogCreated in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 4.9. Renaming ChangeLogCreated columns in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[ChangeLogCreated]', N'TransactionIdCreated', N'COLUMN';\nEND\n\n\n-- 4.10. Rename the foreign key column ChangeLogModified in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogModified' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 4.10. Renaming ChangeLogModified columns in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[ChangeLogModified]', N'TransactionIdModified', N'COLUMN';\nEND\n\n\n-- 4.11. Rename the foreign key column ChangeLogDeleted in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 4.11. Renaming ChangeLogDeleted columns in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[ChangeLogDeleted]', N'TransactionIdDeleted', N'COLUMN';\nEND\n\n\n-- 4.12. Rename the foreign key column ChangeLogCreated in the referencing table (ToSIC_EAV_Values)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 4.12. Renaming ChangeLogCreated columns in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[ChangeLogCreated]', N'TransactionIdCreated', N'COLUMN';\nEND\n\n\n-- 4.12b. Rename the foreign key column ChangeLogModified in the referencing table (ToSIC_EAV_Values)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogModified' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 4.12b. Renaming ChangeLogModified columns in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[ChangeLogModified]', N'TransactionIdModified', N'COLUMN';\nEND\n\n\n-- 4.14. Rename the foreign key column ChangeLogDeleted in the referencing table (ToSIC_EAV_Values)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 4.14. Renaming ChangeLogDeleted columns in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[ChangeLogDeleted]', N'TransactionIdDeleted', N'COLUMN';\nEND\n\n\n-- 4.15. Rename the foreign key constraint FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated')\nBEGIN\n    PRINT '... 4.15. Rename the foreign key constraint FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated]', N'FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated', N'OBJECT';\nEND\n\n\n-- 4.16. Add Index on IX_ToSIC_EAV_Attributes_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.16. Adding index IX_ToSIC_EAV_Attributes_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Attributes_TransactionIdCreated] ON [dbo].[ToSIC_EAV_Attributes] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.17. Create the foreign key constraint FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.17. Creating foreign key FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.18. Check constraint FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 4.18. Checking foreign key constraints on FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] CHECK CONSTRAINT [FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated];\nEND\n\n\n-- 4.19. Rename the foreign key constraint FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted')\nBEGIN\n    PRINT '... 4.19. Rename the foreign key constraint FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted]', N'FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted', N'OBJECT';\nEND\n\n\n-- 4.20. Add Index on IX_ToSIC_EAV_Attributes_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]'))\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.20. Adding index IX_ToSIC_EAV_Attributes_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Attributes_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_Attributes] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.21. Create the foreign key constraint FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.21. Creating foreign key FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.22. Check constraint FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 4.22. Checking foreign key constraints on FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] CHECK CONSTRAINT [FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted];\nEND\n\n\n-- 4.23. Rename the foreign key constraint FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated')\nBEGIN\n    PRINT '... 4.23. Renaming FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated]', N'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated', N'OBJECT';\nEND\n\n\n-- 4.24. Add Index on IX_ToSIC_EAV_AttributeSets_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.24. Adding index IX_ToSIC_EAV_AttributeSets_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_AttributeSets_TransactionIdCreated] ON [dbo].[ToSIC_EAV_AttributeSets] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.25. Create foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.25. Creating foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.26. Check constraint FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 4.26. Checking foreign key constraints on FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated];\nEND\n\n\n-- 4.27. Rename the foreign key constraint FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted')\nBEGIN\n    PRINT '... 4.27. Renaming FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted]', N'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted', N'OBJECT';\nEND\n\n\n-- 4.28. Add Index on TransactionIdDeleted if it doesn't exist\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.28. Adding index IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_AttributeSets] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.29. Create foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.29. Creating foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.30. Check constraint FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 4.30. Checking foreign key constraints on FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted];\nEND\n\n\n-- 4.31. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated')\nBEGIN\n    PRINT '... 4.31. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated]', N'FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated', N'OBJECT';\nEND\n\n\n-- 4.32. Add Index IX_ToSIC_EAV_Entities_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.32. Adding index IX_ToSIC_EAV_Entities_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_TransactionIdCreated] ON [dbo].[ToSIC_EAV_Entities] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.33. Create foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.33. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.34. Check constraint FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 4.34. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated];\nEND\n\n\n-- 4.35. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified')\nBEGIN\n    PRINT '... 4.35. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified]', N'FK_ToSIC_EAV_Entities_TsDynDataTransactionModified', N'OBJECT';\nEND\n\n\n-- 4.36. Add Index IX_ToSIC_EAV_Entities_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.36. Adding index IX_ToSIC_EAV_Entities_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_TransactionIdModified] ON [dbo].[ToSIC_EAV_Entities] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.37. Create foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.37. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.38. Check constraint FK_ToSIC_EAV_Entities_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 4.38. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionModified];\nEND\n\n\n-- 4.39. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted')\nBEGIN\n    PRINT '... 4.39. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted]', N'FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted', N'OBJECT';\nEND\n\n\n-- 4.40. Add Index IX_ToSIC_EAV_Entities_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.40. Adding index IX_ToSIC_EAV_Entities_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_Entities] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.41. Create foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.41. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.42. Check constraint FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 4.42. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted];\nEND\n\n\n-- 4.43. Rename the foreign key constraint FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated')\nBEGIN\n    PRINT '... 4.43. Renaming FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated]', N'FK_ToSIC_EAV_Values_TsDynDataTransactionCreated', N'OBJECT';\nEND\n\n\n-- 4.44. Add Index IX_ToSIC_EAV_Values_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.44. Adding index IX_ToSIC_EAV_Values_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Values_TransactionIdCreated] ON [dbo].[ToSIC_EAV_Values] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.45. Create foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.45. Creating foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.46. Check constraint FK_ToSIC_EAV_Values_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 4.46. Checking foreign key constraints on FK_ToSIC_EAV_Values_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionCreated];\nEND\n\n\n-- 4.47. Rename the foreign key constraint FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified')\nBEGIN\n    PRINT '... 4.47. Renaming FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified]', N'FK_ToSIC_EAV_Values_TsDynDataTransactionModified', N'OBJECT';\nEND\n\n\n-- 4.48. Add Index IX_ToSIC_EAV_Values_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.48. Adding index IX_ToSIC_EAV_Values_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Values_TransactionIdModified] ON [dbo].[ToSIC_EAV_Values] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.49. Create foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.49. Creating foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.50. Check constraint FK_ToSIC_EAV_Values_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 4.50. Checking foreign key constraints on FK_ToSIC_EAV_Values_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionModified];\nEND\n\n\n-- 4.51. Rename the foreign key constraint FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted')\nBEGIN\n    PRINT '... 4.51. Renaming FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted]', N'FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted', N'OBJECT';\nEND\n\n\n-- 4.52. Add Index IX_ToSIC_EAV_Values_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.52. Adding index IX_ToSIC_EAV_Values_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Values_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_Values] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 4.53. Create foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.53. Creating foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 4.54. Check constraint FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 4.54. Checking foreign key constraints on FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted];\nEND\n\n\n\n\n-- *** 5. Rename ToSIC_EAV_DataTimeline to TsDynDataHistory and update related objects\nPRINT '5. Renaming table ToSIC_EAV_DataTimeline to TsDynDataHistory and related objects';\n\n-- 5.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_DataTimeline' AND type = 'U')\nBEGIN\n    PRINT '... 5.1. Renaming table ToSIC_EAV_DataTimeline to TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_DataTimeline]', N'TsDynDataHistory';\nEND\n\n\n-- 5.2. Rename the primary key column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'Id' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.2. Renaming column ID to HistoryId in TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[TsDynDataHistory].[ID]', N'HistoryId', N'COLUMN';\nEND\n\n\n-- 5.3. Rename the primary key constraint\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_DataTimeline' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.3. Renaming PK_ToSIC_EAV_DataTimeline to PK_TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_DataTimeline]', N'PK_TsDynDataHistory', N'OBJECT';\nEND\n\n\n-- 5.4. Drop unused/obsolete column SourceTextKey\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'SourceTextKey' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.4. Dropping obsolete column SourceTextKey';\n    ALTER TABLE [dbo].[TsDynDataHistory] DROP COLUMN [SourceTextKey];\nEND\n\n\n-- 5.5. Drop unused/obsolete column NewData\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'NewData' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.5. Dropping obsolete column NewData';\n    ALTER TABLE [dbo].[TsDynDataHistory] DROP COLUMN [NewData];\nEND\n\n\n-- 5.6. Rename SysCreatedDate column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'SysCreatedDate' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.6. Renaming column SysCreatedDate to Timestamp in TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[TsDynDataHistory].[SysCreatedDate]', N'Timestamp', N'COLUMN';\nEND\n\n\n-- 5.7. Rename SourceID column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'SourceID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.7. Renaming column SourceID to SourceId in TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[TsDynDataHistory].[SourceID]', N'SourceId', N'COLUMN';\nEND\n\n\n-- 5.8. Rename SysLogId column (the foreign key column)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'SysLogId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.8. Renaming column SysLogId to TransactionId in TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[TsDynDataHistory].[SysLogId]', N'TransactionId', N'COLUMN';\nEND\n\n\n-- 5.9. Clean up orphaned history entries before adding FK constraint\nIF EXISTS (SELECT 1 FROM [dbo].[TsDynDataHistory] hist\n    LEFT JOIN [dbo].[TsDynDataTransaction] trans ON hist.TransactionId = trans.TransactionId\n    WHERE trans.TransactionId IS NULL AND hist.TransactionId IS NOT NULL)\nBEGIN\n    PRINT '... 5.9. Cleaning up orphaned history entries in TsDynDataHistory';\n    DELETE hist\n    FROM [dbo].[TsDynDataHistory] hist\n    LEFT JOIN [dbo].[TsDynDataTransaction] trans ON hist.TransactionId = trans.TransactionId\n    WHERE trans.TransactionId IS NULL AND hist.TransactionId IS NOT NULL; -- Only delete if TransactionId was set but is now invalid\nEND\n\n\n-- 5.10. Add Index IX_TsDynDataHistory_TransactionId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataHistory_TransactionId' AND object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\n    AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 5.10.Adding index IX_TsDynDataHistory_TransactionId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_TransactionId] ON [dbo].[TsDynDataHistory] ([TransactionId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 5.11. Create the foreign key constraint referencing TsDynDataTransaction\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataHistory_TsDynDataTransaction')\n   AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 5.11. Creating foreign key FK_TsDynDataHistory_TsDynDataTransaction';\n    ALTER TABLE [dbo].[TsDynDataHistory] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataHistory_TsDynDataTransaction]\n    FOREIGN KEY([TransactionId])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 5.12. Check the constraint FK_TsDynDataHistory_TsDynDataTransaction\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataHistory_TsDynDataTransaction')\nBEGIN\n    PRINT '... 5.12. Checking foreign key constraints on FK_TsDynDataHistory_TsDynDataTransaction';\n    ALTER TABLE [dbo].[TsDynDataHistory] CHECK CONSTRAINT [FK_TsDynDataHistory_TsDynDataTransaction];\nEND\n\n\n-- 5.12b. Add Index IX_TsDynDataHistory_SourceId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataHistory_SourceId' AND object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\n    AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 5.12b. Adding index IX_TsDynDataHistory_SourceId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_SourceId] ON [dbo].[TsDynDataHistory]\n    (\n        [SourceId] ASC\n    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 5.14. Add Index IX_TsDynDataHistory_SourceGuid\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataHistory_SourceGuid' AND object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\n    AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 5.14. Adding index IX_TsDynDataHistory_SourceGuid';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_SourceGuid] ON [dbo].[TsDynDataHistory]\n    (\n        [SourceGuid] ASC\n    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 5.15. Rename constraint DF_DataTimeline_Operation\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_DataTimeline_Operation')\nBEGIN\n    PRINT '... 5.15. Renaming constraint DF_DataTimeline_Operation';\n    EXEC sp_rename N'[dbo].[DF_DataTimeline_Operation]', N'DF_TsDynDataHistory_Operation', N'OBJECT';\nEND\n\n\n\n\n-- *** 6. Rename ToSIC_EAV_Zones to TsDynDataZone and update related objects\nPRINT '6. Renaming table ToSIC_EAV_Zones to TsDynDataZone and related objects';\n\n-- 6.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Zones' AND type = 'U')\nBEGIN\n    PRINT '... 6.1. Renaming table ToSIC_EAV_Zones to TsDynDataZone';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Zones]', N'TsDynDataZone';\nEND\n\n\n-- 6.2. Rename the primary key column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ZoneID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 6.2. Renaming column ZoneID to ZoneId in TsDynDataZone';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[ZoneID]', N'ZoneId', N'COLUMN';\nEND\n\n\n-- 6.3. Rename the primary key constraint PK_ToSIC_EAV_Zones\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Zones' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 6.3. Renaming PK_ToSIC_EAV_Zones to PK_TsDynDataZone';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Zones]', N'PK_TsDynDataZone', N'OBJECT';\nEND\n\n\n-- 6.4. Add new column TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdCreated' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('TsDynDataZone', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.4. Adding TransactionIdCreated column to TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataZone] ADD [TransactionIdCreated] INT NULL;\nEND\n\n\n-- 6.5. Add new column TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdModified' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('TsDynDataZone', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.5. Adding TransactionIdModified column to TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataZone] ADD [TransactionIdModified] INT NULL;\nEND\n\n\n-- 6.6. Add new column TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdDeleted' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('TsDynDataZone', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.6. Adding TransactionIdDeleted column to TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataZone] ADD [TransactionIdDeleted] INT NULL;\nEND\n\n\n-- 6.7. Rename the foreign key column in the referencing table (ToSIC_EAV_Apps)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ZoneID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Apps]'))\nBEGIN\n    PRINT '... 6.7. Renaming column ZoneID to ZoneId in ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Apps].[ZoneID]', N'ZoneId', N'COLUMN';\nEND\n\n\n-- 6.8. Rename the foreign key column in the referencing table (ToSIC_EAV_Dimensions)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ZoneID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Dimensions]'))\nBEGIN\n    PRINT '... 6.8. Renaming column ZoneID to ZoneId in ToSIC_EAV_Dimensions';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Dimensions].[ZoneID]', N'ZoneId', N'COLUMN';\nEND\n\n\n-- 6.9. Rename the foreign key constraint FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones')\nBEGIN\n    PRINT '... 6.9. Renaming Zone foreign key from ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones]', N'FK_ToSIC_EAV_Apps_TsDynDataZone', N'OBJECT';\nEND\n\n\n-- 6.10. Rename the foreign key constraint FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones')\nBEGIN\n    PRINT '... 6.10. Renaming Zone foreign key from ToSIC_EAV_Dimensions';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones]', N'FK_ToSIC_EAV_Dimensions_TsDynDataZone', N'OBJECT';\nEND\n\n\n-- 6.11. Add Index IX_ToSIC_EAV_Dimensions_ZoneId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Dimensions_ZoneId' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Dimensions]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Dimensions]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.11. Adding index IX_ToSIC_EAV_Dimensions_ZoneId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Dimensions_ZoneId] ON [dbo].[ToSIC_EAV_Dimensions] ([ZoneId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 6.12. Create the foreign key constraint referencing TsDynDataZone\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_TsDynDataZone')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Dimensions]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.12. Creating foreign key FK_ToSIC_EAV_Dimensions_TsDynDataZone';\n    ALTER TABLE [dbo].[ToSIC_EAV_Dimensions] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Dimensions_TsDynDataZone]\n    FOREIGN KEY([ZoneId])\n    REFERENCES [dbo].[TsDynDataZone] ([ZoneId]);\nEND\n\n\n-- 6.12b. Check constraint FK_ToSIC_EAV_Dimensions_TsDynDataZone\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_TsDynDataZone')\nBEGIN\n    PRINT '... 6.12b. Checking foreign key constraints on FK_ToSIC_EAV_Dimensions_TsDynDataZone';\n    ALTER TABLE [dbo].[ToSIC_EAV_Dimensions] CHECK CONSTRAINT [FK_ToSIC_EAV_Dimensions_TsDynDataZone];\nEND\n\n\n-- 6.14. Add Index IX_TsDynDataZone_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransCreatedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.14. Adding index IX_TsDynDataZone_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransactionIdCreated] ON [dbo].[TsDynDataZone] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 6.15. Create foreign key FK_TsDynDataZone_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.15. Creating foreign key FK_TsDynDataZone_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[TsDynDataZone] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 6.16. Check constraint FK_TsDynDataZone_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 6.16. Checking foreign key constraints on FK_TsDynDataZone_TsDynDataTransactionCreated';  \n    ALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionCreated];\nEND\n\n\n-- 6.17. Add Index IX_TsDynDataZone_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransModifiedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.17. Adding index IX_TsDynDataZone_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransactionIdModified] ON [dbo].[TsDynDataZone] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 6.18. Create foreign key FK_TsDynDataZone_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.18. Creating foreign key FK_TsDynDataZone_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataZone] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 6.19. Check constraint FK_TsDynDataZone_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 6.19. Checking foreign key constraints on FK_TsDynDataZone_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionModified];\nEND\n\n\n-- 6.20. Add Index IX_TsDynDataZone_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransDeletedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.20. Adding index IX_TsDynDataZone_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransactionIdDeleted] ON [dbo].[TsDynDataZone] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 6.21. Create foreign key FK_TsDynDataZone_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.21. Creating foreign key FK_TsDynDataZone_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[TsDynDataZone] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 6.22. Check the constraints FK_TsDynDataZone_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 6.22. Checking foreign key constraints on FK_TsDynDataZone_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionDeleted];\nEND\n\n\n\n-- *** 7. Rename ToSIC_EAV_Apps to TsDynDataApp and update related objects\nPRINT '7. Renaming table ToSIC_EAV_Apps to TsDynDataApp and related objects';\n\n-- 7.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Apps' AND type = 'U')\nBEGIN\n    PRINT '... 7.1. Renaming table ToSIC_EAV_Apps to TsDynDataApp';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Apps]', N'TsDynDataApp';\nEND\n\n\n-- 7.2. Rename the primary key column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AppID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 7.2. Renaming column AppID to AppId in TsDynDataApp';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[AppID]', N'AppId', N'COLUMN';\nEND\n\n\n-- 7.3. Rename the primary key constraint\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Apps' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 7.3. Renaming PK_ToSIC_EAV_Apps to PK_TsDynDataApp';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Apps]', N'PK_TsDynDataApp', N'OBJECT';\nEND\n\n\n-- 7.4. Rename the unique constraint ToSIC_EAV_Apps_PreventDuplicates\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Apps_PreventDuplicates' AND type = 'UQ')\nBEGIN\n    PRINT '... 7.4. Renaming unique constraint ToSIC_EAV_Apps_PreventDuplicates to UQ_TsDynDataApp_Name_ZoneId';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Apps_PreventDuplicates]', N'UQ_TsDynDataApp_Name_ZoneId', N'OBJECT';\nEND\n\n\n-- 7.5. Add new column TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdCreated' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('TsDynDataApp', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.5. Adding TransactionIdCreated column to TsDynDataApp';\n    ALTER TABLE [dbo].[TsDynDataApp] ADD [TransactionIdCreated] INT NULL;\nEND\n\n\n-- 7.6. Add new column TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdModified' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('TsDynDataApp', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.6. Adding TransactionIdModified column to TsDynDataApp';\n    ALTER TABLE [dbo].[TsDynDataApp] ADD [TransactionIdModified] INT NULL;\nEND\n\n\n-- 7.7. Add new column TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdDeleted' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('TsDynDataApp', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.7. Adding TransactionIdDeleted column to TsDynDataApp';\n    ALTER TABLE [dbo].[TsDynDataApp] ADD [TransactionIdDeleted] INT NULL;\nEND\n\n\n-- 7.8. Rename the foreign key column in the referencing table (ToSIC_EAV_AttributeSets)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AppID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nBEGIN\n    PRINT '... 7.8. Renaming column AppID to AppId in ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeSets].[AppID]', N'AppId', N'COLUMN';\nEND\n\n\n-- 7.9. Rename the foreign key column in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AppID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 7.9. Renaming column AppID to AppId in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[AppID]', N'AppId', N'COLUMN';\nEND\n\n\n-- 7.10. Rename the foreign key constraint FK_ToSIC_EAV_Apps_TsDynDataZone\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Apps_TsDynDataZone')\nBEGIN\n\n    PRINT '... 7.10. Renaming Zone foreign key from ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Apps_TsDynDataZone]', N'FK_TsDynDataApp_TsDynDataZone', N'OBJECT';\nEND\n\n\n-- 7.11. Add Index IX_TsDynDataApp_ZoneId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_ZoneId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.11. Adding index IX_TsDynDataApp_ZoneId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataApp_ZoneId] ON [dbo].[TsDynDataApp] ([ZoneId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 7.12. Create the foreign key constraint FK_TsDynDataApp_TsDynDataZone\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataZone')\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.12. Creating foreign key FK_TsDynDataApp_TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataApp] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataApp_TsDynDataZone]\n    FOREIGN KEY([ZoneId])\n    REFERENCES [dbo].[TsDynDataZone] ([ZoneId]);\nEND\n\n\n-- 7.12b. Check constraint FK_TsDynDataApp_TsDynDataZone\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataZone')\nBEGIN\n    PRINT '... 7.12b. Checking foreign key constraints on FK_TsDynDataApp_TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataZone];\nEND\n\n\n-- 7.14. Rename the foreign key constraint FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps')\nBEGIN\n    PRINT '... 7.14. Renaming foreign key FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps]', N'FK_ToSIC_EAV_AttributeSets_TsDynDataApp', N'OBJECT';\nEND\n\n\n-- 7.15. Add Index IX_ToSIC_EAV_AttributeSets_AppId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_AppId' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.15. Adding index IX_ToSIC_EAV_AttributeSets_AppId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_AttributeSets_AppId] ON [dbo].[ToSIC_EAV_AttributeSets] ([AppId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 7.16. Create the foreign key constraint FK_ToSIC_EAV_AttributeSets_TsDynDataApp\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataApp')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.16. Creating foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataApp';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataApp]\n    FOREIGN KEY([AppId])\n    REFERENCES [dbo].[TsDynDataApp] ([AppId]);\nEND\n\n\n-- 7.17. Check constraint FK_ToSIC_EAV_AttributeSets_TsDynDataApp\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataApp')\nBEGIN\n    PRINT '... 7.17. Checking foreign key constraints on FK_ToSIC_EAV_AttributeSets_TsDynDataApp';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataApp];\nEND\n\n\n-- 7.18. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps')\nBEGIN\n    PRINT '... 7.18. Renaming foreign key FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps]', N'FK_ToSIC_EAV_Entities_TsDynDataApp', N'OBJECT';\nEND\n\n\n-- 7.19. Add Index IX_ToSIC_EAV_Entities_AppId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_AppId' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.19. Adding index IX_ToSIC_EAV_Entities_AppId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_AppId] ON [dbo].[ToSIC_EAV_Entities] ([AppId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 7.20. Create the foreign key constraint FK_ToSIC_EAV_Entities_TsDynDataApp\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataApp')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.20. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataApp';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataApp]\n    FOREIGN KEY([AppId])\n    REFERENCES [dbo].[TsDynDataApp] ([AppId]);\nEND\n\n\n-- 7.21. Check constraint FK_ToSIC_EAV_Entities_TsDynDataApp\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataApp')\nBEGIN\n    PRINT '... 7.21. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataApp';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataApp];\nEND\n\n\n-- 7.22. Add Index IX_TsDynDataApp_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransCreatedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.22. Adding index IX_TsDynDataApp_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransactionIdCreated] ON [dbo].[TsDynDataApp] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 7.23. Create foreign key FK_TsDynDataApp_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.23. Recreating foreign key FK_TsDynDataApp_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[TsDynDataApp] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 7.24. Check constraint FK_TsDynDataApp_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 7.24. Checking foreign key constraints on FK_TsDynDataApp_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionCreated];\nEND\n\n\n-- 7.25. Add Index IX_TsDynDataApp_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransModifiedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.25. Adding index IX_TsDynDataApp_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransactionIdModified] ON [dbo].[TsDynDataApp] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 7.26. Create foreign key FK_TsDynDataApp_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.26. Creating foreign key FK_TsDynDataApp_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataApp] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 7.27. Check constraint FK_TsDynDataApp_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 7.27. Checking foreign key constraints on FK_TsDynDataApp_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionModified];\nEND\n\n\n-- 7.28. Add Index IX_TsDynDataApp_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransDeletedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.28. Adding index IX_TsDynDataApp_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransactionIdDeleted] ON [dbo].[TsDynDataApp] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 7.29. Create foreign key FK_TsDynDataApp_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.29. Recreating foreign key FK_TsDynDataApp_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[TsDynDataApp] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 7.30. Check the constraints FK_TsDynDataApp_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 7.30. Checking foreign key constraints on FK_TsDynDataApp_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionDeleted];\nEND\n\n\n-- 7.31. Rename index IX_ToSIC_EAV_Apps_ZoneId to IX_TsDynDataApp_ZoneId if exists\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Apps_ZoneId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_ZoneId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.31. Renaming index IX_ToSIC_EAV_Apps_ZoneId to IX_TsDynDataApp_ZoneId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[IX_ToSIC_EAV_Apps_ZoneId]', N'IX_TsDynDataApp_ZoneId', N'INDEX';\nEND\n\n\n\n\n-- *** 8. Renaming table ToSIC_EAV_AttributeSets to TsDynDataContentType and update related objects\nPRINT '8. Renaming table ToSIC_EAV_AttributeSets to TsDynDataContentType and related objects';\n\n-- 8.1. Rename table ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_AttributeSets' AND type = 'U')\nBEGIN\n    PRINT '... 8.1. Renaming table ToSIC_EAV_AttributeSets to TsDynDataContentType';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeSets]', N'TsDynDataContentType';\nEND\n\n\n-- 8.2. Rename PK column AttributeSetID to ContentTypeId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AttributeSetID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.2. Renaming column AttributeSetID to ContentTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[AttributeSetID]', N'ContentTypeId', N'COLUMN';\nEND\n\n\n-- 8.3. Rename PK_ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_AttributeSets' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.3. Rename PK_ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_AttributeSets]', N'PK_TsDynDataContentType', N'OBJECT';\nEND\n\n\n-- 8.4. Rename columns UsesConfigurationOfAttributeSet to InheritContentTypeId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'UsesConfigurationOfAttributeSet' AND Object_ID = Object_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.4. Renaming column UsesConfigurationOfAttributeSet to InheritContentTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[UsesConfigurationOfAttributeSet]', N'InheritContentTypeId', N'COLUMN';\nEND\n\n\n-- 8.5. Rename columns AlwaysShareConfiguration to IsGlobal\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AlwaysShareConfiguration' AND Object_ID = Object_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.5. Renaming column AlwaysShareConfiguration to IsGlobal';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[AlwaysShareConfiguration]', N'IsGlobal', N'COLUMN';\nEND\n\n\n-- 8.6. Add column TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdModified' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND OBJECT_ID('TsDynDataContentType', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.6. Adding TransactionIdModified column to TsDynDataContentType';\n    ALTER TABLE [dbo].[TsDynDataContentType] ADD [TransactionIdModified] INT NULL;\nEND\n\n\n-- 8.7. Rename columns AttributeSetID to ContentTypeId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AttributeSetID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 8.7.Renaming column AttributeSetID to ContentTypeId';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[AttributeSetID]', N'ContentTypeId', N'COLUMN';\nEND\n\n\n-- 8.8. Rename FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets')\nBEGIN\n    PRINT '... 8.8. Rename FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets]', N'FK_TsDynDataContentType_TsDynDataContentType' , N'OBJECT';\nEND\n\n\n-- 8.9. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataApp\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataApp')\nBEGIN\n    PRINT '... 8.9. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataApp';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_TsDynDataApp]', N'FK_TsDynDataContentType_TsDynDataApp' , N'OBJECT';\nEND\n\n\n-- 8.10. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 8.10. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated]', N'FK_TsDynDataContentType_TsDynDataTransactionCreated' , N'OBJECT';\nEND\n\n\n-- 8.11. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 8.11. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted]', N'FK_TsDynDataContentType_TsDynDataTransactionDeleted' , N'OBJECT';\nEND\n\n\n-- 8.12. Rename FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets')\nBEGIN\n    PRINT '... 8.12. Rename FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets]', N'FK_ToSIC_EAV_Attributes_TsDynDataContentType' , N'OBJECT';\nEND\n\n\n-- 8.12b. Rename FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets')\nBEGIN\n    PRINT '... 8.12b. Rename FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets]', N'FK_ToSIC_EAV_Entities_TsDynDataContentType' , N'OBJECT';\nEND\n\n\n-- 8.14. Add Index on ContentTypeId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_ContentTypeId')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.14. Adding index IX_ToSIC_EAV_Entities_ContentTypeId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_ContentTypeId] ON [dbo].[ToSIC_EAV_Entities] ([ContentTypeId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 8.15. Create foreign key FK_ToSIC_EAV_Entities_TsDynDataContentType\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataContentType')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.15. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataContentType';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataContentType]\n    FOREIGN KEY([ContentTypeId])\n    REFERENCES [dbo].[TsDynDataContentType] ([ContentTypeId]);\nEND\n\n\n-- 8.16. Check the constraints FK_ToSIC_EAV_Entities_TsDynDataContentType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataContentType')\nBEGIN\n    PRINT '... 8.16. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataContentType';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataContentType];\nEND\n\n\n-- 8.17. Add Index IX_TsDynDataContentType_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransModifiedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND OBJECT_ID('[dbo].[TsDynDataContentType]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.17. Adding index IX_TsDynDataContentType_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_TransactionIdModified] ON [dbo].[TsDynDataContentType] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 8.18. Create foreign key FK_TsDynDataContentType_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataContentType_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[TsDynDataContentType]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.18. Creating foreign key FK_TsDynDataContentType_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataContentType] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 8.19. Check constraint FK_TsDynDataContentType_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataContentType_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 8.19. Checking foreign key constraints on FK_TsDynDataContentType_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionModified];\nEND\n\n\n-- 8.20. Rename index IX_ToSIC_EAV_AttributeSets_TransactionIdCreated\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.20. Renaming index IX_ToSIC_EAV_AttributeSets_TransactionIdCreated';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_ToSIC_EAV_AttributeSets_TransactionIdCreated]', N'IX_TsDynDataContentType_TransactionIdCreated', N'INDEX';\nEND\n\n\n-- 8.21. Rename index IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.21. Renaming index IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted]', N'IX_TsDynDataContentType_TransactionIdDeleted', N'INDEX';\nEND\n\n\n-- 8.22. Rename index IX_ToSIC_EAV_AttributeSets_AppId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_AppId' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.22. Renaming index IX_ToSIC_EAV_AttributeSets_AppId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_ToSIC_EAV_AttributeSets_AppId]', N'IX_TsDynDataContentType_AppId', N'INDEX';\nEND\n\n\n-- 8.23. Add Index IX_TsDynDataContentType_AppId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_AppId' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND OBJECT_ID('[dbo].[TsDynDataContentType]', 'U') IS NOT NULL \nBEGIN\n    PRINT '... 8.23. Adding index IX_TsDynDataContentType_AppId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_AppId] ON [dbo].[TsDynDataContentType] ([AppId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 8.24. Rename constraint DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration')\nBEGIN\n    PRINT '... 8.24. Renaming constraint DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration]', N'DF_TsDynDataContentType_IsGlobal', N'OBJECT';\nEND\n\n\n-- 8.25. Rename constraint DF_ToSIC_EAV_AttributeSets_StaticName\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_AttributeSets_StaticName')\nBEGIN\n    PRINT '... 8.25. Renaming constraint DF_ToSIC_EAV_AttributeSets_StaticName';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_AttributeSets_StaticName]', N'DF_TsDynDataContentType_StaticName', N'OBJECT';\nEND\n\n\n\n\n-- *** 9. Rename table ToSIC_EAV_Attributes to TsDynDataAttribute and related objects\nPRINT '9. Renaming table ToSIC_EAV_Attributes to TsDynDataAttribute and related objects';\n\n-- 9.1. Rename the table ToSIC_EAV_Attributes to TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Attributes' AND type = 'U')\nBEGIN\n    PRINT '... 9.1. Renaming table ToSIC_EAV_Attributes to TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Attributes]', N'TsDynDataAttribute';\nEND\n\n\n-- 9.2. Rename the primary key column AttributeID to AttributeId in TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.2. Renaming column AttributeID to AttributeId in TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\n\n\n-- 9.3. Rename the primary key constraint PK_ToSIC_EAV_Attributes to PK_TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Attributes' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.3. Renaming PK_ToSIC_EAV_Attributes to PK_TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Attributes]', N'PK_TsDynDataAttribute', N'OBJECT';\nEND\n\n\n-- 9.4. Add new column TransactionIdModified to TsDynDataAttribute\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = Object_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.4. Adding column TransactionIdModified to TsDynDataAttribute';\n    ALTER TABLE [dbo].[TsDynDataAttribute] ADD [TransactionIdModified] INT NULL;\nEND\n\n\n-- 9.5. Rename FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.5. Renaming FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types to FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types]', N'FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes', N'OBJECT';\nEND\n\n\n-- 9.6. Rename FK_ToSIC_EAV_Attributes_TsDynDataContentType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataContentType' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.6. Renaming FK_ToSIC_EAV_Attributes_TsDynDataContentType to FK_TsDynDataAttribute_TsDynDataContentType';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_TsDynDataContentType]', N'FK_TsDynDataAttribute_TsDynDataContentType', N'OBJECT';\nEND\n\n\n-- 9.7. Rename FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.7. Renaming FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated to FK_TsDynDataAttribute_TsDynDataTransactionCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated]', N'FK_TsDynDataAttribute_TsDynDataTransactionCreated', N'OBJECT';\nEND\n\n\n-- 9.8. Rename FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.8. Renaming FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted to FK_TsDynDataAttribute_TsDynDataTransactionDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted]', N'FK_TsDynDataAttribute_TsDynDataTransactionDeleted', N'OBJECT';\nEND\n\n\n-- 9.9. Add new Foreign Key for TransactionIdModified on TsDynDataAttribute\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataAttribute_TsDynDataTransactionModified' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.9. Adding FK_TsDynDataAttribute_TsDynDataTransactionModified to TsDynDataAttribute';\n    ALTER TABLE [dbo].[TsDynDataAttribute] WITH CHECK\n    ADD CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified]) REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\n\n\n-- 9.10. Renaming index IX_ToSIC_EAV_Attributes_ContentTypeId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_ContentTypeId' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.10. Renaming index IX_ToSIC_EAV_Attributes_ContentTypeId to IX_TsDynDataAttribute_ContentTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_ToSIC_EAV_Attributes_ContentTypeId]', N'IX_TsDynDataAttribute_ContentTypeId', N'INDEX';\nEND\n\n\n-- 9.11. Renaming index IX_ToSIC_EAV_Attributes_TransactionIdCreated\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.11. Renaming index IX_ToSIC_EAV_Attributes_TransactionIdCreated to IX_TsDynDataAttribute_TransactionIdCreated';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_ToSIC_EAV_Attributes_TransactionIdCreated]', N'IX_TsDynDataAttribute_TransactionIdCreated', N'INDEX';\nEND\n\n\n-- 9.12. Renaming index IX_ToSIC_EAV_Attributes_TransactionIdDeleted\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.12. Renaming index IX_ToSIC_EAV_Attributes_TransactionIdDeleted to IX_TsDynDataAttribute_TransactionIdDeleted';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_ToSIC_EAV_Attributes_TransactionIdDeleted]', N'IX_TsDynDataAttribute_TransactionIdDeleted', N'INDEX';\nEND\n\n\n-- 9.12b. Add new Index for TransactionIdModified on TsDynDataAttribute\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransModifiedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.12b. Adding index IX_TsDynDataAttribute_TransactionIdModified on TsDynDataAttribute';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_TransactionIdModified] ON [dbo].[TsDynDataAttribute] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 9.14. Add new Index for AttributeId inc. StaticName on TsDynDataAttribute\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_AttributeId_StaticName' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.14. Adding index IX_TsDynDataAttribute_AttributeId_StaticName';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_AttributeId_StaticName] ON [dbo].[TsDynDataAttribute] ([AttributeId] ASC) INCLUDE([StaticName])\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 9.15. Rename Default Constraints DF_ToSIC_EAV_Attributes_ContentTypeId\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Attributes_ContentTypeId' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.15. Renaming default constraint DF_ToSIC_EAV_Attributes_ContentTypeId to DF_TsDynDataAttribute_ContentTypeId';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Attributes_ContentTypeId]', N'DF_TsDynDataAttribute_ContentTypeId', N'OBJECT';\nEND\n\n\n-- 9.16. Rename Default Constraints DF_ToSIC_EAV_Attributes_SortOrder\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Attributes_SortOrder' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.16. Renaming default constraint DF_ToSIC_EAV_Attributes_SortOrder to DF_TsDynDataAttribute_SortOrder';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Attributes_SortOrder]', N'DF_TsDynDataAttribute_SortOrder', N'OBJECT';\nEND\n\n\n-- 9.17. Rename Default Constraints DF_ToSIC_EAV_Attributes_IsTitle\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Attributes_IsTitle' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.17. Renaming default constraint DF_ToSIC_EAV_Attributes_IsTitle to DF_TsDynDataAttribute_IsTitle';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Attributes_IsTitle]', N'DF_TsDynDataAttribute_IsTitle', N'OBJECT';\nEND\n\n\n-- 9.18. Renaming column AttributeID to AttributeId in ToSIC_EAV_EntityRelationships\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]'))\nBEGIN\n    PRINT '... 9.18. Renaming column AttributeID to AttributeId in ToSIC_EAV_EntityRelationships';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_EntityRelationships].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\n\n\n-- 9.19. Renaming column AttributeID to AttributeId in ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 9.19. Renaming column AttributeID to AttributeId in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\n\n\n-- 9.20. Rename FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes')\nBEGIN\n    PRINT '... 9.20. Rename FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes]', N'FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute' , N'OBJECT';\nEND\n\n\n-- 9.21. Rename FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes')\nBEGIN\n    PRINT '... 9.21. Rename FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes]', N'FK_ToSIC_EAV_Values_TsDynDataAttribute' , N'OBJECT';\nEND\n\n\n\n\n-- *** 10. Renaming table ToSIC_EAV_AttributeTypes to TsDynDataAttributeType and related objects \nPRINT '10. Renaming table ToSIC_EAV_AttributeTypes to TsDynDataAttributeType and related objects';\n\n\n-- 10.1. Rename the table ToSIC_EAV_AttributeTypes to TsDynDataAttributeType\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_AttributeTypes' AND type = 'U')\nBEGIN\n    PRINT '... 10.1. Renaming table ToSIC_EAV_AttributeTypes to TsDynDataAttributeType';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeTypes]', N'TsDynDataAttributeType';\nEND\n\n\n-- 10.2. Rename the primary key constraint PK_ToSIC_EAV_AttributeTypes to PK_TsDynDataAttributeType\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_AttributeTypes' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttributeType]'))\nBEGIN\n    PRINT '... 10.2. Renaming PK_ToSIC_EAV_AttributeTypes to PK_TsDynDataAttributeType';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_AttributeTypes]', N'PK_TsDynDataAttributeType', N'OBJECT';\nEND\n\n\n-- 10.3. Rename the foreign key constraint in TsDynDataAttribute that references this table.\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 10.3. Renaming FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes to FK_TsDynDataAttribute_TsDynDataAttributeType';\n    EXEC sp_rename N'[dbo].[FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes]', N'FK_TsDynDataAttribute_TsDynDataAttributeType', N'OBJECT';\nEND\n\n\n\n\n-- *** 11. Renaming table ToSIC_EAV_Entities to TsDynDataEntity and related objects\nPRINT '11. Renaming table ToSIC_EAV_Entities to TsDynDataEntity and related objects';\n\n-- 11.1. Rename table ToSIC_EAV_Entities to TsDynDataEntity\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Entities' AND type = 'U')\nBEGIN\n    PRINT '... 11.1. Renaming table ToSIC_EAV_Entities to TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities]', N'TsDynDataEntity';\nEND\n\n\n-- 11.2. Rename the primary key column EntityID to EntityId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'EntityID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.2. Renaming PK column EntityID to EntityId in TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[EntityID]', N'EntityId', N'COLUMN';\nEND\n\n\n-- 11.3. Rename column EntityGUID to EntityGuid\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'EntityGUID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.3. Renaming column EntityGUID to EntityGuid in TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[EntityGUID]', N'EntityGuid', N'COLUMN';\nEND\n\n\n-- 11.4. Rename the primary key constraint PK_ToSIC_EAV_Entities to PK_TsDynDataEntity\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Entities' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.4. Renaming PK_ToSIC_EAV_Entities to PK_TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Entities]', N'PK_TsDynDataEntity', N'OBJECT';\nEND\n\n\n-- 11.5. Drop the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities')\nBEGIN\n    PRINT '... 11.5. Dropping foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities';\n    ALTER TABLE [dbo].[TsDynDataEntity] DROP CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities];\nEND\n\n\n-- 11.6. Drop the ConfigurationSet column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ConfigurationSet' AND Object_ID = Object_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.6. Dropping column ConfigurationSet from TsDynDataEntity';\n    ALTER TABLE [dbo].[TsDynDataEntity] DROP COLUMN [ConfigurationSet];\nEND\n\n\n-- 11.7. Rename the column EntityID to EntityId in ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'EntityID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 11.7. Renaming column EntityID to EntityId in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[EntityID]', N'EntityId', N'COLUMN';\nEND\n\n\n-- 11.8. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataApp to FK_TsDynDataEntity_TsDynDataApp\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataApp' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.8. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataApp to FK_TsDynDataEntity_TsDynDataApp';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataApp]', N'FK_TsDynDataEntity_TsDynDataApp', N'OBJECT';\nEND\n\n\n-- 11.9. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataContentType to FK_TsDynDataEntity_TsDynDataContentType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataContentType' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.9. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataContentType to FK_TsDynDataEntity_TsDynDataContentType';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataContentType]', N'FK_TsDynDataEntity_TsDynDataContentType', N'OBJECT';\nEND\n\n\n-- 11.10. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTargetType to FK_TsDynDataEntity_TsDynDataTargetType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTargetType' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.10. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTargetType to FK_TsDynDataEntity_TsDynDataTargetType';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataTargetType]', N'FK_TsDynDataEntity_TsDynDataTargetType', N'OBJECT';\nEND\n\n\n-- 11.11. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated to FK_TsDynDataEntity_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.11. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated to FK_TsDynDataEntity_TsDynDataTransactionCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated]', N'FK_TsDynDataEntity_TsDynDataTransactionCreated', N'OBJECT';\nEND\n\n\n-- 11.12. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionModified to FK_TsDynDataEntity_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionModified' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.12. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionModified to FK_TsDynDataEntity_TsDynDataTransactionModified';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataTransactionModified]', N'FK_TsDynDataEntity_TsDynDataTransactionModified', N'OBJECT';\nEND\n\n\n-- 11.12b. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted to FK_TsDynDataEntity_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.12b. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted to FK_TsDynDataEntity_TsDynDataTransactionDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted]', N'FK_TsDynDataEntity_TsDynDataTransactionDeleted', N'OBJECT';\nEND\n\n\n-- 11.14. Renaming Default Constraint DF_ToSIC_EAV_Entities_EntityGUID to DF_TsDynDataEntity_EntityGuid\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Entities_EntityGUID' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.14. Renaming Default Constraint DF_ToSIC_EAV_Entities_EntityGUID to DF_TsDynDataEntity_EntityGuid';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Entities_EntityGUID]', N'DF_TsDynDataEntity_EntityGuid', N'OBJECT';\nEND\n\n\n-- 11.15. Renaming Default Constraint DF_ToSIC_EAV_Entities_IsPublished to DF_TsDynDataEntity_IsPublished\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Entities_IsPublished' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.15. Renaming Default Constraint DF_ToSIC_EAV_Entities_IsPublished to DF_TsDynDataEntity_IsPublished';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Entities_IsPublished]', N'DF_TsDynDataEntity_IsPublished', N'OBJECT';\nEND\n\n\n-- 11.16. Renaming Index IX_KeyNumber to IX_TsDynDataEntity_KeyNumber\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_KeyNumber' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.16. Renaming Index IX_KeyNumber to IX_TsDynDataEntity_KeyNumber';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_KeyNumber]', N'IX_TsDynDataEntity_KeyNumber', N'INDEX';\nEND\n\n\n-- 11.17. Renaming Index IX_ToSIC_EAV_Entities_AppId to IX_TsDynDataEntity_AppId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_AppId' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.17. Renaming Index IX_ToSIC_EAV_Entities_AppId to IX_TsDynDataEntity_AppId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_AppId]', N'IX_TsDynDataEntity_AppId', N'INDEX';\nEND\n\n\n-- 11.18. Renaming Index IX_ToSIC_EAV_Entities_ContentTypeId to IX_TsDynDataEntity_ContentTypeId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_ContentTypeId' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.18. Renaming Index IX_ToSIC_EAV_Entities_ContentTypeId to IX_TsDynDataEntity_ContentTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_ContentTypeId]', N'IX_TsDynDataEntity_ContentTypeId', N'INDEX';\nEND\n\n\n-- 11.19. Renaming Index IX_ToSIC_EAV_Entities_TargetTypeId to IX_TsDynDataEntity_TargetTypeId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TargetTypeId' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.19. Renaming Index IX_ToSIC_EAV_Entities_TargetTypeId to IX_TsDynDataEntity_TargetTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_TargetTypeId]', N'IX_TsDynDataEntity_TargetTypeId', N'INDEX';\nEND\n\n\n-- 11.20. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdCreated to IX_TsDynDataEntity_TransactionIdCreated\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.20. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdCreated to IX_TsDynDataEntity_TransactionIdCreated';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_TransactionIdCreated]', N'IX_TsDynDataEntity_TransactionIdCreated', N'INDEX';\nEND\n\n\n-- 11.21. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdModified to IX_TsDynDataEntity_TransactionIdModified\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.21. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdModified to IX_TsDynDataEntity_TransactionIdModified';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_TransactionIdModified]', N'IX_TsDynDataEntity_TransactionIdModified', N'INDEX';\nEND\n\n\n-- 11.22. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdDeleted to IX_TsDynDataEntity_TransactionIdDeleted\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.22. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdDeleted to IX_TsDynDataEntity_TransactionIdDeleted';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_TransactionIdDeleted]', N'IX_TsDynDataEntity_TransactionIdDeleted', N'INDEX';\nEND\n\n\n\n\n-- *** 12. Rename ToSIC_EAV_EntityRelationships to TsDynDataRelationship and related objects\nPRINT '12. Renaming table ToSIC_EAV_EntityRelationships to TsDynDataRelationship and related objects';\n\n-- 12.1. Rename table ToSIC_EAV_EntityRelationships to TsDynDataRelationship\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_EntityRelationships' AND type = 'U')\nBEGIN\n    PRINT '... 12.1. Renaming table ToSIC_EAV_EntityRelationships to TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_EntityRelationships]', N'TsDynDataRelationship';\nEND\n\n\n-- 12.2. Rename column AttributeID to AttributeId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.2. Renaming column AttributeID to AttributeId in TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[TsDynDataRelationship].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\n\n\n-- 12.3. Rename column ParentEntityID to ParentEntityId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ParentEntityID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.3. Renaming column ParentEntityID to ParentEntityId in TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[TsDynDataRelationship].[ParentEntityID]', N'ParentEntityId', N'COLUMN';\nEND\n\n\n-- 12.4. Rename column ChildEntityID to ChildEntityId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ChildEntityID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.4. Renaming column ChildEntityID to ChildEntityId in TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[TsDynDataRelationship].[ChildEntityID]', N'ChildEntityId', N'COLUMN';\nEND\n\n\n-- 12.5. Rename the primary key constraint PK_ToSIC_EAV_EntityRelationships to PK_TsDynDataRelationship\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_EntityRelationships' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.5. Renaming PK_ToSIC_EAV_EntityRelationships to PK_TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_EntityRelationships]', N'PK_TsDynDataRelationship', N'OBJECT';\nEND\n\n\n-- 12.6. Renaming FK FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute to FK_TsDynDataRelationship_TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.6. Renaming FK FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute to FK_TsDynDataRelationship_TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute]', N'FK_TsDynDataRelationship_TsDynDataAttribute', N'OBJECT';\nEND\n\n\n-- 12.7. Renaming FK FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities to FK_TsDynDataRelationship_TsDynDataEntityParent\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.7. Renaming FK FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities to FK_TsDynDataRelationship_TsDynDataEntityParent';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities]', N'FK_TsDynDataRelationship_TsDynDataEntityParent', N'OBJECT';\nEND\n\n\n-- 12.8. Renaming FK FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities to FK_TsDynDataRelationship_TsDynDataEntityChild\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.8. Renaming FK FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities to FK_TsDynDataRelationship_TsDynDataEntityChild';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities]', N'FK_TsDynDataRelationship_TsDynDataEntityChild', N'OBJECT';\nEND\n\n\n-- 12.9. Adding index IX_TsDynDataRelationship_ParentEntityId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataRelationship_ParentEntityId' AND object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\n    AND OBJECT_ID('[dbo].[TsDynDataRelationship]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'ParentEntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]')) -- Ensure column exists\nBEGIN\n    PRINT '... 12.9. Adding index IX_TsDynDataRelationship_ParentEntityId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataRelationship_ParentEntityId] ON [dbo].[TsDynDataRelationship] ([ParentEntityId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 12.10. Adding index IX_TsDynDataRelationship_ChildEntityId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataRelationship_ChildEntityId' AND object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\n    AND OBJECT_ID('[dbo].[TsDynDataRelationship]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'ChildEntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]')) -- Ensure column exists\nBEGIN\n    PRINT '... 12.10. Adding index IX_TsDynDataRelationship_ChildEntityId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataRelationship_ChildEntityId] ON [dbo].[TsDynDataRelationship] ([ChildEntityId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n\n\n-- *** 12b. Rename ToSIC_EAV_Values to TsDynDataValue and related objects\nPRINT '12b. Renaming table ToSIC_EAV_Values to TsDynDataValue and related objects';\n\n-- 12b.1. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionCreated' AND parent_object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.1. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionCreated];\nEND\n\n\n-- 12b.2. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionModified' AND parent_object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.2. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionModified];\nEND\n\n\n-- 12b.3. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted' AND parent_object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.3. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted];\nEND\n\n\n-- 12b.4. Drop old complex index IX_EAV_Values1 from ToSIC_EAV_Values (as they included TransactionId columns)\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_EAV_Values1' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.4. Dropping Index IX_EAV_Values1';\n    DROP INDEX [IX_EAV_Values1] ON [dbo].[ToSIC_EAV_Values];\nEND\n\n\n-- 12b.5. Drop old complex index IX_EAV_Values2 from ToSIC_EAV_Values (as they included TransactionId columns)\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_EAV_Values2' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.5. Dropping Index IX_EAV_Values2';\n    DROP INDEX [IX_EAV_Values2] ON [dbo].[ToSIC_EAV_Values];\nEND\n\n\n-- 12b.6. Dropping Index IX_ToSIC_EAV_Values_TransactionIdCreated\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.6. Dropping Index IX_ToSIC_EAV_Values_TransactionIdCreated';\n    DROP INDEX [IX_ToSIC_EAV_Values_TransactionIdCreated] ON [dbo].[ToSIC_EAV_Values];\nEND\n\n\n-- 12b.7. Dropping Index IX_ToSIC_EAV_Values_TransactionIdModified\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.7. Dropping Index IX_ToSIC_EAV_Values_TransactionIdModified';\n    DROP INDEX [IX_ToSIC_EAV_Values_TransactionIdModified] ON [dbo].[ToSIC_EAV_Values];\nEND\n\n\n-- 12b.8. Dropping Index IX_ToSIC_EAV_Values_TransactionIdDeleted\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.8. Dropping Index IX_ToSIC_EAV_Values_TransactionIdDeleted';\n    DROP INDEX [IX_ToSIC_EAV_Values_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_Values];\nEND\n\n\n-- 12b.9. Dropping column TransactionIdCreated from ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.9. Dropping column TransactionIdCreated from ToSIC_EAV_Values';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP COLUMN [TransactionIdCreated];\nEND\n\n\n-- 12b.10. Dropping column TransactionIdModified from ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.10. Dropping column TransactionIdModified from ToSIC_EAV_Values';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP COLUMN [TransactionIdModified];\nEND\n\n\n-- 12b.11. Dropping column TransactionIdDeleted from ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.11. Dropping column TransactionIdDeleted from ToSIC_EAV_Values';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP COLUMN [TransactionIdDeleted];\nEND\n\n\n-- 12b.12. Renaming table ToSIC_EAV_Values to TsDynDataValue\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Values' AND type = 'U')\nBEGIN\n    PRINT '... 12b.12. Renaming table ToSIC_EAV_Values to TsDynDataValue';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values]', N'TsDynDataValue';\nEND\n\n\n-- 12b.12b. Renaming column ValueID to ValueId in TsDynDataValue\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ValueID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.12b.Renaming column ValueID to ValueId in TsDynDataValue';\n    EXEC sp_rename N'[dbo].[TsDynDataValue].[ValueID]', N'ValueId', N'COLUMN';\nEND\n\n\n-- 12b.14. Renaming column EntityID to EntityId in TsDynDataValue\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'EntityID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.14. Renaming column EntityID to EntityId in TsDynDataValue';\n    EXEC sp_rename N'[dbo].[TsDynDataValue].[EntityID]', N'EntityId', N'COLUMN';\nEND\n\n\n-- 12b.15. Renaming column AttributeID to AttributeId in TsDynDataValue\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.15. Renaming column AttributeID to AttributeId in TsDynDataValue (defensive)';\n    EXEC sp_rename N'[dbo].[TsDynDataValue].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\n\n\n-- 12b.16. Renaming PK_ToSIC_EAV_Values to PK_TsDynDataValue\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Values' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.16. Renaming PK_ToSIC_EAV_Values to PK_TsDynDataValue';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Values]', N'PK_TsDynDataValue', N'OBJECT';\nEND\n\n\n-- 12b.17. Renaming FK FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values to FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values' AND parent_object_id = OBJECT_ID('[dbo].[ToSIC_EAV_ValuesDimensions]'))\nBEGIN\n    PRINT '... 12b.17. Renaming FK FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values to FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values]', N'FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue', N'OBJECT';\nEND\n\n\n-- 12b.18. Renaming FK FK_ToSIC_EAV_Values_ToSIC_EAV_Entities to FK_TsDynDataValue_TsDynDataEntity\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_Entities' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.18. Renaming FK FK_ToSIC_EAV_Values_ToSIC_EAV_Entities to FK_TsDynDataValue_TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_Entities]', N'FK_TsDynDataValue_TsDynDataEntity', N'OBJECT';\nEND\n\n\n-- 12b.19. Renaming FK FK_ToSIC_EAV_Values_TsDynDataAttribute to FK_TsDynDataValue_TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataAttribute' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.19. Renaming FK FK_ToSIC_EAV_Values_TsDynDataAttribute to FK_TsDynDataValue_TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_TsDynDataAttribute]', N'FK_TsDynDataValue_TsDynDataAttribute', N'OBJECT';\nEND\n\n\n-- 12b.20. Adding index IX_TsDynDataValue_EntityId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataValue_EntityId' AND object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\n    AND OBJECT_ID('[dbo].[TsDynDataValue]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'EntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.20. Adding index IX_TsDynDataValue_EntityId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataValue_EntityId] ON [dbo].[TsDynDataValue] ([EntityId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 12b.21. Adding index IX_TsDynDataValue_AttributeId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataValue_AttributeId' AND object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\n    AND OBJECT_ID('[dbo].[TsDynDataValue]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'AttributeId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.21. Adding index IX_TsDynDataValue_AttributeId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataValue_AttributeId] ON [dbo].[TsDynDataValue] ([AttributeId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 12b.22. Adding index IX_TsDynDataValue_AttributeId_EntityId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataValue_AttributeId_EntityId' AND object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\n    AND OBJECT_ID('[dbo].[TsDynDataValue]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'AttributeId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'EntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.22. Adding index IX_TsDynDataValue_AttributeId_EntityId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataValue_AttributeId_EntityId] ON [dbo].[TsDynDataValue] ([AttributeId] ASC, [EntityId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n-- 12b.23. Adding index IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value' AND object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\n    AND OBJECT_ID('[dbo].[TsDynDataValue]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'EntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'AttributeId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'ValueId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'Value' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.23. Adding index IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value] ON [dbo].[TsDynDataValue] ([EntityId] ASC, [AttributeId] ASC, [ValueId] ASC)\n    INCLUDE([Value])\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n\n\n\n-- *** 14. Renaming table ToSIC_EAV_Dimensions to TsDynDataDimension and related objects\nPRINT '14. Renaming table ToSIC_EAV_Dimensions to TsDynDataDimension and related objects';\n\n-- 14.1. Rename table ToSIC_EAV_Dimensions to TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Dimensions' AND type = 'U')\nBEGIN\n    PRINT '... 14.1. Renaming table ToSIC_EAV_Dimensions to TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Dimensions]', N'TsDynDataDimension';\nEND\n\n\n-- 14.2. Rename column DimensionID to DimensionId in TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'DimensionID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.2. Renaming column DimensionID to DimensionId in TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[TsDynDataDimension].[DimensionID]', N'DimensionId', N'COLUMN';\nEND\n\n\n-- 14.3. Rename Primary Key constraint for TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Dimensions' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.3. Renaming PK_ToSIC_EAV_Dimensions to PK_TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Dimensions]', N'PK_TsDynDataDimension', N'OBJECT';\nEND\n\n\n-- 14.4. Renaming FK FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1 to FK_TsDynDataDimension_TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.4. Renaming FK FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1 to FK_TsDynDataDimension_TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1]', N'FK_TsDynDataDimension_TsDynDataDimension', N'OBJECT';\nEND\n\n\n-- 14.5. Renaming FK FK_ToSIC_EAV_Dimensions_TsDynDataZone to FK_TsDynDataDimension_TsDynDataZone\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_TsDynDataZone' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.5. Renaming FK FK_ToSIC_EAV_Dimensions_TsDynDataZone to FK_TsDynDataDimension_TsDynDataZone';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Dimensions_TsDynDataZone]', N'FK_TsDynDataDimension_TsDynDataZone', N'OBJECT';\nEND\n\n\n-- 14.6. Renaming Default Constraint DF_ToSIC_EAV_Dimensions_Active to DF_TsDynDataDimension_Active\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Dimensions_Active' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.6. Renaming Default Constraint DF_ToSIC_EAV_Dimensions_Active to DF_TsDynDataDimension_Active';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Dimensions_Active]', N'DF_TsDynDataDimension_Active', N'OBJECT';\nEND\n\n\n-- 14.7. Renaming Index IX_ToSIC_EAV_Dimensions_ZoneId to IX_TsDynDataDimension_ZoneId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Dimensions_ZoneId' AND object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.7. Renaming Index IX_ToSIC_EAV_Dimensions_ZoneId to IX_TsDynDataDimension_ZoneId';\n    EXEC sp_rename N'[dbo].[TsDynDataDimension].[IX_ToSIC_EAV_Dimensions_ZoneId]', N'IX_TsDynDataDimension_ZoneId', N'INDEX';\nEND\n\n\n\n\n-- *** 15. Renaming table ToSIC_EAV_ValuesDimensions to TsDynDataValueDimension and related objects\nPRINT '15. Renaming table ToSIC_EAV_ValuesDimensions to TsDynDataValueDimension and related objects';\n\n-- 15.1. Rename table ToSIC_EAV_ValuesDimensions to TsDynDataValueDimension\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_ValuesDimensions' AND type = 'U')\nBEGIN\n    PRINT '... 15.1. Renaming table ToSIC_EAV_ValuesDimensions to TsDynDataValueDimension';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_ValuesDimensions]', N'TsDynDataValueDimension';\nEND\n\n\n-- 15.2. Rename column ValueID to ValueId in TsDynDataValueDimension\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ValueID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.2. Renaming column ValueID to ValueId in TsDynDataValueDimension';\n    EXEC sp_rename N'[dbo].[TsDynDataValueDimension].[ValueID]', N'ValueId', N'COLUMN';\nEND\n\n\n-- 15.3. Rename column DimensionID to DimensionId in TsDynDataValueDimension\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'DimensionID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.3. Renaming column DimensionID to DimensionId in TsDynDataValueDimension';\n    EXEC sp_rename N'[dbo].[TsDynDataValueDimension].[DimensionID]', N'DimensionId', N'COLUMN';\nEND\n\n\n-- 15.4. Rename Primary Key constraint for TsDynDataValueDimension\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_ValuesDimensions' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.4. Renaming PK_ToSIC_EAV_ValuesDimensions to PK_TsDynDataValueDimension';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_ValuesDimensions]', N'PK_TsDynDataValueDimension', N'OBJECT';\nEND\n\n\n-- 15.5. Renaming FK FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions to FK_TsDynDataValueDimension_TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.5. Renaming FK FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions to FK_TsDynDataValueDimension_TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions]', N'FK_TsDynDataValueDimension_TsDynDataDimension', N'OBJECT';\nEND\n\n\n-- 15.6. Renaming FK FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue to FK_TsDynDataValueDimension_TsDynDataValue\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.6. Renaming FK FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue to FK_TsDynDataValueDimension_TsDynDataValue';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue]', N'FK_TsDynDataValueDimension_TsDynDataValue', N'OBJECT';\nEND\n\n\n-- 15.7. Renaming Default Constraint DF_ToSIC_EAV_ValuesDimensions_ReadOnly to DF_TsDynDataValueDimension_ReadOnly\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_ValuesDimensions_ReadOnly' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.7. Renaming Default Constraint DF_ToSIC_EAV_ValuesDimensions_ReadOnly to DF_TsDynDataValueDimension_ReadOnly';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_ValuesDimensions_ReadOnly]', N'DF_TsDynDataValueDimension_ReadOnly', N'OBJECT';\nEND\n\n\n\n\n-- *** 16. TransactionId column => TransId migration script for all tables\nPRINT '16. TransactionId column => TransId migration script for all tables';\n\n\n-- 16.1. Processing table TsDynDataApp\n-- 16.1.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.1. Renaming column TsDynDataApp.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\n\n\n-- 16.1.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.2. Renaming column TsDynDataApp.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\n\n\n-- 16.1.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.3. Renaming column TsDynDataApp.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\n\n\n-- 16.1.4. Rename index IX_TsDynDataApp_TransactionIdCreated to IX_TsDynDataApp_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.4. Renaming index IX_TsDynDataApp_TransactionIdCreated to IX_TsDynDataApp_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[IX_TsDynDataApp_TransactionIdCreated]', N'IX_TsDynDataApp_TransCreatedId', N'INDEX';\nEND\n\n\n-- 16.1.5. Rename index IX_TsDynDataApp_TransactionIdModified to IX_TsDynDataApp_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.5. Renaming index IX_TsDynDataApp_TransactionIdModified to IX_TsDynDataApp_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[IX_TsDynDataApp_TransactionIdModified]', N'IX_TsDynDataApp_TransModifiedId', N'INDEX';\nEND\n\n\n-- 16.1.6. Rename index IX_TsDynDataApp_TransactionIdDeleted to IX_TsDynDataApp_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.6. Renaming index IX_TsDynDataApp_TransactionIdDeleted to IX_TsDynDataApp_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[IX_TsDynDataApp_TransactionIdDeleted]', N'IX_TsDynDataApp_TransDeletedId', N'INDEX';\nEND\n\n\n-- 16.2. Processing table TsDynDataAttribute\n-- 16.2.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.1. Renaming column TsDynDataAttribute.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\n\n\n-- 16.2.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.2. Renaming column TsDynDataAttribute.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\n\n\n-- 16.2.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.3. Renaming column TsDynDataAttribute.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\n\n\n-- 16.2.4. Rename index IX_TsDynDataAttribute_TransactionIdCreated to IX_TsDynDataAttribute_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.4. Renaming index IX_TsDynDataAttribute_TransactionIdCreated to IX_TsDynDataAttribute_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_TsDynDataAttribute_TransactionIdCreated]', N'IX_TsDynDataAttribute_TransCreatedId', N'INDEX';\nEND\n\n\n-- 16.2.5. Rename index IX_TsDynDataAttribute_TransactionIdModified to IX_TsDynDataAttribute_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.5. Renaming index IX_TsDynDataAttribute_TransactionIdModified to IX_TsDynDataAttribute_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_TsDynDataAttribute_TransactionIdModified]', N'IX_TsDynDataAttribute_TransModifiedId', N'INDEX';\nEND\n\n\n-- 16.2.6. Rename index IX_TsDynDataAttribute_TransactionIdDeleted to IX_TsDynDataAttribute_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.6. Renaming index IX_TsDynDataAttribute_TransactionIdDeleted to IX_TsDynDataAttribute_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_TsDynDataAttribute_TransactionIdDeleted]', N'IX_TsDynDataAttribute_TransDeletedId', N'INDEX';\nEND\n\n\n-- 16.3. Processing table TsDynDataContentType\n-- 16.3.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.1. Renaming column TsDynDataContentType.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\n\n\n-- 16.3.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.2. Renaming column TsDynDataContentType.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\n\n\n-- 16.3.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.3. Renaming column TsDynDataContentType.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\n\n\n-- 16.3.4. Rename index IX_TsDynDataContentType_TransactionIdCreated to IX_TsDynDataContentType_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.4. Renaming index IX_TsDynDataContentType_TransactionIdCreated to IX_TsDynDataContentType_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_TsDynDataContentType_TransactionIdCreated]', N'IX_TsDynDataContentType_TransCreatedId', N'INDEX';\nEND\n\n\n-- 16.3.5. Rename index IX_TsDynDataContentType_TransactionIdModified to IX_TsDynDataContentType_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.5. Renaming index IX_TsDynDataContentType_TransactionIdModified to IX_TsDynDataContentType_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_TsDynDataContentType_TransactionIdModified]', N'IX_TsDynDataContentType_TransModifiedId', N'INDEX';\nEND\n\n\n-- 16.3.6. Rename index IX_TsDynDataContentType_TransactionIdDeleted to IX_TsDynDataContentType_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.6. Renaming index IX_TsDynDataContentType_TransactionIdDeleted to IX_TsDynDataContentType_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_TsDynDataContentType_TransactionIdDeleted]', N'IX_TsDynDataContentType_TransDeletedId', N'INDEX';\nEND\n\n\n-- 16.4. Processing table TsDynDataEntity\n-- 16.4.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.1. Renaming column TsDynDataEntity.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\n\n\n-- 16.4.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.2. Renaming column TsDynDataEntity.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\n\n\n-- 16.4.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.3. Renaming column TsDynDataEntity.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\n\n\n-- 16.4.4. Rename index IX_TsDynDataEntity_TransactionIdCreated to IX_TsDynDataEntity_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.4. Renaming index IX_TsDynDataEntity_TransactionIdCreated to IX_TsDynDataEntity_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_TsDynDataEntity_TransactionIdCreated]', N'IX_TsDynDataEntity_TransCreatedId', N'INDEX';\nEND\n\n\n-- 16.4.5. Rename index IX_TsDynDataEntity_TransactionIdModified to IX_TsDynDataEntity_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.5. Renaming index IX_TsDynDataEntity_TransactionIdModified to IX_TsDynDataEntity_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_TsDynDataEntity_TransactionIdModified]', N'IX_TsDynDataEntity_TransModifiedId', N'INDEX';\nEND\n\n\n-- 16.4.6. Rename index IX_TsDynDataEntity_TransactionIdDeleted to IX_TsDynDataEntity_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.6. Renaming index IX_TsDynDataEntity_TransactionIdDeleted to IX_TsDynDataEntity_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_TsDynDataEntity_TransactionIdDeleted]', N'IX_TsDynDataEntity_TransDeletedId', N'INDEX';\nEND\n\n\n-- 16.5. Processing table TsDynDataZone\n-- 16.5.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.1. Renaming column TsDynDataZone.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\n\n\n-- 16.5.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.2. Renaming column TsDynDataZone.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\n\n\n-- 16.5.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.3. Renaming column TsDynDataZone.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\n\n\n-- 16.5.4. Rename index IX_TsDynDataZone_TransactionIdCreated to IX_TsDynDataZone_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.4. Renaming index IX_TsDynDataZone_TransactionIdCreated to IX_TsDynDataZone_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[IX_TsDynDataZone_TransactionIdCreated]', N'IX_TsDynDataZone_TransCreatedId', N'INDEX';\nEND\n\n\n-- 16.5.5. Rename index IX_TsDynDataZone_TransactionIdModified to IX_TsDynDataZone_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.5. Renaming index IX_TsDynDataZone_TransactionIdModified to IX_TsDynDataZone_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[IX_TsDynDataZone_TransactionIdModified]', N'IX_TsDynDataZone_TransModifiedId', N'INDEX';\nEND\n\n\n-- 16.5.6. Rename index IX_TsDynDataZone_TransactionIdDeleted to IX_TsDynDataZone_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.6. Renaming index IX_TsDynDataZone_TransactionIdDeleted to IX_TsDynDataZone_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[IX_TsDynDataZone_TransactionIdDeleted]', N'IX_TsDynDataZone_TransDeletedId', N'INDEX';\nEND\n\n\n\n-- 17. Adding new table type TsDynDataIntList\n-- 2025-05-12, stv, test alternative strategy to load values\n-- DROP TYPE IF EXISTS [dbo].[TsDynDataIntList];\n-- \n--IF TYPE_ID(N'[dbo].[TsDynDataIntList]') IS NULL\n--BEGIN\n--    PRINT '... 17.1. Creating new table type TsDynDataIntList for TVP';\n--    CREATE TYPE [dbo].[TsDynDataIntList] AS TABLE\n--    (\n--        Id int NOT NULL\n--    );\n--END\n-- \n\nPRINT '*** Finished migration script.';\n\nGO"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/20.00.05.SqlDataProvider",
    "content": "SET ANSI_NULLS ON\nGO\n\nSET QUOTED_IDENTIFIER ON\nGO\n\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\n-- =====================================================================\n-- Switch default value from GETDATE() to GETUTCDATE() on [dbo].[TsDynDataTransaction].[Timestamp] if the current default uses GETDATE()\n-- =====================================================================\n\nDECLARE @Definition nvarchar(max);\n\nSELECT @Definition = dc.definition\nFROM sys.default_constraints dc\n         JOIN sys.columns c ON c.default_object_id = dc.object_id\n         JOIN sys.tables t ON t.object_id = c.object_id\n         JOIN sys.schemas s ON s.schema_id = t.schema_id\nWHERE s.name = 'dbo'\n  AND t.name = 'TsDynDataTransaction'\n  AND c.name = 'Timestamp'\n  AND dc.name = 'DF_TsDynDataTransaction_Timestamp';\n\nIF @Definition IS NOT NULL AND UPPER(REPLACE(@Definition, ' ', '')) LIKE '%GETDATE()%'\n    BEGIN\n        ALTER TABLE [dbo].[TsDynDataTransaction]\n            DROP CONSTRAINT [DF_TsDynDataTransaction_Timestamp];\n\n        ALTER TABLE [dbo].[TsDynDataTransaction]\n            ADD CONSTRAINT [DF_TsDynDataTransaction_Timestamp]\n                DEFAULT (GETUTCDATE()) FOR [Timestamp];\n    END\nGO\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/21.00.00.SqlDataProvider",
    "content": "SET ANSI_NULLS ON\nGO\n\nSET QUOTED_IDENTIFIER ON\nGO\n\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\n-- =====================================================================\n-- Ensure TsDynDataHistory exists and has ParentRef (eg. \"app-42\")\n-- =====================================================================\n\n-- Add ParentRef column on existing installations\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'ParentRef' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataHistory]'))\n    AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... Adding column [ParentRef] to [dbo].[TsDynDataHistory]';\n    ALTER TABLE [dbo].[TsDynDataHistory] ADD [ParentRef] [nvarchar](250) NULL;\nEND\n\n-- Add indexes for ParentRef\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataHistory_ParentRef' AND object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\n    AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... Adding index IX_TsDynDataHistory_ParentRef';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_ParentRef] ON [dbo].[TsDynDataHistory] ([ParentRef] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\n\n-- =====================================================================\n-- TsDynDataRelationship: add ChildExternalId to support undelete\n-- =====================================================================\n\n-- Add ChildExternalId column on existing installations\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChildExternalId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataRelationship]'))\n    AND OBJECT_ID('[dbo].[TsDynDataRelationship]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... Adding column [ChildExternalId] to [dbo].[TsDynDataRelationship]';\n    ALTER TABLE [dbo].[TsDynDataRelationship] ADD [ChildExternalId] [uniqueidentifier] NULL;\nEND\n\n-- Remove TransDeletedId (was a short-lived experiment)\nIF OBJECT_ID('[dbo].[TsDynDataRelationship]', 'U') IS NOT NULL\nBEGIN\n    IF EXISTS (\n        SELECT *\n        FROM sys.foreign_keys\n        WHERE name = 'FK_TsDynDataRelationship_TsDynDataTransactionDeleted'\n          AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]')\n    )\n    BEGIN\n        PRINT '... Dropping FK FK_TsDynDataRelationship_TsDynDataTransactionDeleted';\n        ALTER TABLE [dbo].[TsDynDataRelationship] DROP CONSTRAINT [FK_TsDynDataRelationship_TsDynDataTransactionDeleted];\n    END\n\n    IF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataRelationship_TransDeletedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\n    BEGIN\n        PRINT '... Dropping index IX_TsDynDataRelationship_TransDeletedId';\n        DROP INDEX [IX_TsDynDataRelationship_TransDeletedId] ON [dbo].[TsDynDataRelationship];\n    END\n\n    IF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataRelationship]'))\n    BEGIN\n        PRINT '... Dropping column [TransDeletedId] from [dbo].[TsDynDataRelationship]';\n        ALTER TABLE [dbo].[TsDynDataRelationship] DROP COLUMN [TransDeletedId];\n    END\nEND\nGO\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/Migrate.SqlDataProvider",
    "content": "﻿-- ===================================\n-- 2sxc upgrade: rename packages, definitions & selected settings\n\n\n-- 1) Package and module definitions\nIF EXISTS (SELECT 1 FROM dbo.Packages WHERE [Name] IN ('2SexyContent','2SexyContent-App'))\nBEGIN\n\n    DECLARE @SxcModuleDefId INT, @SxcAppModuleDefId INT, @DelSxcModuleDefId INT, @DelSxcAppModuleDefId INT;\n    SET @SxcModuleDefId = (SELECT TOP 1 ModuleDefID FROM dbo.ModuleDefinitions WHERE DefinitionName IN ('2sxc'));\n    SET @SxcAppModuleDefId = (SELECT TOP 1 ModuleDefID FROM dbo.ModuleDefinitions WHERE DefinitionName IN ('2sxc-app'));\n    SET @DelSxcModuleDefId = (SELECT TOP 1 ModuleDefID FROM dbo.ModuleDefinitions WHERE DefinitionName IN ('2Sexy Content'));\n    SET @DelSxcAppModuleDefId = (SELECT TOP 1 ModuleDefID FROM dbo.ModuleDefinitions WHERE DefinitionName IN ('2Sexy Content App'));\n\n    UPDATE dbo.Modules SET ModuleDefID = @SxcModuleDefId WHERE ModuleDefID = @DelSxcModuleDefId;\n    UPDATE dbo.Modules SET ModuleDefID = @SxcAppModuleDefId WHERE ModuleDefID = @DelSxcAppModuleDefId;\n\n    DELETE FROM dbo.Packages WHERE [Name] IN ('2SexyContent','2SexyContent-App');\n    DELETE FROM dbo.ModuleDefinitions WHERE DefinitionName IN ('2Sexy Content', '2Sexy Content App');\nEND\nGO\n\n -- 2) PortalSettings: specific key rename\n UPDATE dbo.PortalSettings SET SettingName = 'TsDynDataZoneId'\n WHERE SettingName = 'ToSIC_SexyContent_ZoneID';\n\n -- 3) ModuleSettings: multiple specific key renames\n UPDATE dbo.ModuleSettings SET SettingName = 'TsDynDataApp'\n WHERE SettingName = 'ToSIC_SexyContent_AppName';\n\n UPDATE dbo.ModuleSettings SET SettingName = 'TsDynDataContentGroup'\n WHERE SettingName = 'ToSIC_SexyContent_ContentGroupGuid';\n\n UPDATE dbo.ModuleSettings SET SettingName = 'TsDynDataPreview'\n WHERE SettingName = 'ToSIC_SexyContent_PreviewTemplateId';\n\n -- 4) TabModuleSettings: same renames as ModuleSettings\n UPDATE dbo.TabModuleSettings SET SettingName = 'TsDynDataApp'\n WHERE SettingName = 'ToSIC_SexyContent_AppName';\n\n UPDATE dbo.TabModuleSettings SET SettingName = 'TsDynDataContentGroup'\n WHERE SettingName = 'ToSIC_SexyContent_ContentGroupGuid';\n\n UPDATE dbo.TabModuleSettings SET SettingName = 'TsDynDataPreview'\n WHERE SettingName = 'ToSIC_SexyContent_PreviewTemplateId';\n\n GO\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/RequireLatest.SqlDataProvider",
    "content": "﻿-- This SQL file is used for the in 2sxc package (in .dnn manifest file) for all other modules, which must not be installed or upgraded if the 2sxc module fails to install\nDECLARE @requireLatestVersion NVARCHAR(20) = '20.00.05', @installedVersion NVARCHAR(20);\nSELECT @installedVersion = ISNULL(\n    (SELECT [Version] FROM Packages WHERE [Name] = N'2sxc'),\n    '99.99.99'\n)\n\n-- skip further execution if requireLatestVersion > installedVersion\nIF (\n    TRY_CAST(PARSENAME(@requireLatestVersion, 3) AS INT) >  TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) OR\n    (\n        TRY_CAST(PARSENAME(@requireLatestVersion, 3) AS INT) = TRY_CAST(PARSENAME(@installedVersion, 3) AS INT) AND\n        (\n            TRY_CAST(PARSENAME(@requireLatestVersion, 2) AS INT) >  TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) OR\n            (\n                TRY_CAST(PARSENAME(@requireLatestVersion, 2) AS INT) = TRY_CAST(PARSENAME(@installedVersion, 2) AS INT) AND\n                TRY_CAST(PARSENAME(@requireLatestVersion, 1) AS INT) > TRY_CAST(PARSENAME(@installedVersion, 1) AS INT)\n            )\n        )\n    )\n)\nBEGIN\n\tRAISERROR(N'Installation Error: The latest 2sxc package includes multiple modules, and the 2sxc module (20.00.05) must be installed first, as other modules in the package depend on it. It appears that something went wrong during the installation. Please review the previous error messages for more details. ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************', 16, 1);\n\tRETURN;\nEND\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/RequireMinimal.SqlDataProvider",
    "content": "﻿-- This SQL file is used for the app-module package (in .dnn manifest file) which must not be installed or upgraded if the 2sxc module fails to install\nDECLARE @RequiredVersion int;\nSET @RequiredVersion = 15;\n\nDECLARE @RequiredVersionIsInstalled int;\nSELECT TOP 1 @RequiredVersionIsInstalled = CASE WHEN EXISTS(SELECT * FROM {databaseOwner}[{objectQualifier}Packages] WHERE Name IN (N'2SexyContent', N'2sxc') AND CONVERT(int, LEFT([Version], CHARINDEX('.', [Version])-1)) >= @RequiredVersion) THEN CAST (1 AS BIT) ELSE CAST (0 AS BIT) END;\n\nIf @RequiredVersionIsInstalled = 0\nBEGIN\n\tRAISERROR(N'2sxc 15 or newer must be installed for the 2sxc module to install. Probably something else went wrong while installing - see previous errors for more information. ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************', 16, 1);\n\tRETURN;\nEND\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/SqlDataProvider/Uninstall.SqlDataProvider",
    "content": "﻿-- Remove Tables\nDROP TABLE IF EXISTS [dbo].[TsDynDataRelationship]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataValueDimension]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataDimension]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataValue]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataEntity]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataHistory]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataAttribute]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataAttributeType]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataContentType]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataTargetType]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataApp]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataZone]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataTransaction]\nGO\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/license.txt",
    "content": "﻿<div>\n\t\tEverything in 2sxc is <em>free open source</em> 😉 <br>\n\t<p>\n\t\t2sxc itself is released under the MIT license. \n\t\tIt also uses many other open source components with different open-source licenses, from AGPL to X11. \n\t\tIf you want to know more, read our <a href=\"http://2sxc.org/License\" target=\"_blank\">license page</a>.\n\t</p>\n\n\t<p>\n\t\tBe sexy - give back to the community or <a href=\"https://www.kiva.org/invitedby/ijungleboy\" target=\"_blank\">to those less fortunate</a>.\n\t\tContribute your work, support others - share the 💖. \n\t</p>\n\t<p>\n\t\tAnd if you really benefit from 2sxc, please become a <a href=\"https://patrons.2sxc.org/\" target=\"_blank\">patron 🦹</a> - it's a great way to support the project and get some extra benefits.\n\t</p>\n</div>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnPackageBuilder/readme.md",
    "content": "﻿# Additional files to build the DNN Package\n\nThis folder just contains things we would remove from the root folder, to be included in the dnn package. \n\nWe are trying to clean up the main folder, so this is where add-on material should be placed\n\n## Special Cleanup folder\n\nThis contains a txt file with folders that should be flushed completely on every upgrade. \n\nWe need this, because the `dist/` folder can change often (compiled JavaScript) so we don't leave behind a bunch of unused JS. "
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnWebForms/Skins/QuickEdit.ascx",
    "content": "﻿<%@ Control Language=\"C#\" AutoEventWireup=\"true\" CodeBehind=\"QuickEdit.ascx.cs\" Inherits=\"ToSic.Sxc.Dnn.DnnWebForms.Skins.QuickEdit\" %>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnWebForms/Skins/QuickEdit.ascx.cs",
    "content": "﻿using ToSic.Sxc.Dnn.Web;\nusing ToSic.Sxc.Services;\n// ReSharper disable UnusedMember.Global\n\nnamespace ToSic.Sxc.Dnn.DnnWebForms.Skins;\n\npublic partial class QuickEdit : System.Web.UI.UserControl\n{\n    private bool _isEdit;\n    protected void Page_Load(object sender, EventArgs e)\n    {\n        _isEdit = DotNetNuke.Security.Permissions.TabPermissionController.HasTabPermission(\"EDIT\");\n        if (!_isEdit)\n            return;\n\n        this.GetScopedService<DnnClientResources>()\n            // #RemovedV20 #OldDnnAutoJQuery\n            .Init(Page, /*false,*/ null)\n            .RegisterClientDependencies(Page, true, true, true);\n    }\n\n    protected void Page_PreRender(object sender, EventArgs e)\n    {\n        // this is temp solution, because it was required for 2sxc module instance created in skin\n        if (!_isEdit)\n            return;\n        this.GetScopedService<DnnJsApiHeader>().AddHeaders();\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/DnnWebForms/Skins/QuickEdit.ascx.designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated. \n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace ToSic.Sxc.Dnn.DnnWebForms.Skins {\n    \n    \n    public partial class QuickEdit {\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/Extensions/Imageflow/License.txt",
    "content": "<p>ToSic.Imageflow.Dnn extension for <a href=\"https://dnncommunity.org/\" target=\"_blank\">DNN</a></p>\n<p>2sic <a href=\"https://www.2sic.com/\" target=\"_blank\">https://www.2sic.com/</a></p>\n<p>Imazen <a href=\"https://www.imageflow.io/\" target=\"_blank\">Imageflow</a></p>\n<p><a href=\"https://github.com/imazen/imageflow/blob/main/LICENSE\" target=\"_blank\">AGPL-3.0 License</a></p>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/Extensions/Imageflow/ReleaseNotes.txt",
    "content": "<h2>Imageflow Extension for DNN</h2>\n<p><strong>Version:</strong> 01.12.01</p>\n\n<h3>Changelog</h3>\n<ul>\n  <li>Updated Imageflow dependencies to version <code>0.14.0-rc01</code>.</li>\n  <li>Requires DNN version <strong>9.11.00</strong> or higher.</li>\n  <li>Fully compatible with DNN version <strong>10.00.00</strong>.</li>\n</ul>\n\n<h3>Notes</h3>\n<ul>\n  <li>During installation, the extension will automatically unregister the older <code>ImageResizer</code> HTTP module in <code>web.config</code>.</li>\n</ul>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/Extensions/ToSic_vCard/vCard.ashx",
    "content": "<%@ WebHandler Language=\"C#\" Class=\"VCardHandler\" %>\n\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.Text;\nusing System.Web;\n\npublic class VCardHandler : IHttpHandler\n{\n\tprivate const string PhotoPathBase = \"~\";\n\n\tpublic void ProcessRequest(HttpContext context)\n\t{\n\t\tvar card = new VCard\n\t\t{\n\t\t\tFirstName = context.Request.QueryString[\"FirstName\"],\n\t\t\tLastName = context.Request.QueryString[\"LastName\"],\n\t\t\tOrganization = context.Request.QueryString[\"Organization\"],\n\t\t\tJobTitle = context.Request.QueryString[\"JobTitle\"],\n\t\t\tStreetAddress = context.Request.QueryString[\"Address\"],\n\t\t\tZip = context.Request.QueryString[\"Zip\"],\n\t\t\tCity = context.Request.QueryString[\"City\"],\n\t\t\tCountryName = context.Request.QueryString[\"Country\"],\n\t\t\tPhone = context.Request.QueryString[\"Phone\"],\n\t\t\tPhoneCompany = context.Request.QueryString[\"PhoneCompany\"],\n\t\t\tMobile = context.Request.QueryString[\"Mobile\"],\n\t\t\tEmail = context.Request.QueryString[\"Email\"],\n\t\t\tUrl = context.Request.QueryString[\"Url\"]\n\t\t};\n\t\tif (!string.IsNullOrWhiteSpace(context.Request.QueryString[\"Photo\"]))\n\t\t\tcard.PhotoPath = context.Server.MapPath(PhotoPathBase + context.Request.QueryString[\"Photo\"]);\n\n\t\tvar response = context.Response;\n\t\tresponse.ContentType = \"text/vcard\";\n\t\tvar fileName = card.FirstName + \" \" + card.LastName;\n\t\tif (string.IsNullOrWhiteSpace(fileName))\n\t\t\tfileName = card.Organization;\n\t\tif (string.IsNullOrWhiteSpace(fileName))\n\t\t\tfileName = \"contact\";\n\t\tfileName += \".vcf\";\n\n\n\t\t// source: http://stackoverflow.com/questions/93551/how-to-encode-the-filename-parameter-of-content-disposition-header-in-http\n\t\tstring contentDisposition;\n\t\tif (context.Request.Browser.Browser == \"IE\")\t// removed version check\n\t\t\tcontentDisposition = \"attachment; filename=\" + Uri.EscapeDataString(fileName);\n\t\telse if (context.Request.Browser.Browser == \"Safari\")\n\t\t\tcontentDisposition = \"attachment; filename=\" + fileName;\n\t\telse\n\t\t\tcontentDisposition = \"attachment; filename*=UTF-8''\" + Uri.EscapeDataString(fileName);\n\t\tresponse.AddHeader(\"Content-Disposition\", contentDisposition);\n\n\t\t//response.AddHeader(\"Content-Disposition\", \"attachment; fileName=\" + fileName + \".vcf\");\n\n\t\tvar cardString = card.ToString();\n\t\tvar inputEncoding = Encoding.Default;\n\t\tvar outputEncoding = Encoding.GetEncoding(28591);\n\t\tvar cardBytes = inputEncoding.GetBytes(cardString);\n\t\tvar outputBytes = Encoding.Convert(inputEncoding, outputEncoding, cardBytes);\n\n\t\tresponse.OutputStream.Write(outputBytes, 0, outputBytes.Length);\n\t}\n\n\tpublic bool IsReusable { get { return false; } }\n\n\tinternal class VCard\n\t{\n\t\tprivate const string AddressType = \"WORK\";\n\t\tpublic string FirstName { get; set; }\n\t\tpublic string LastName { get; set; }\n\t\tpublic string Organization { get; set; }\n\t\tpublic string JobTitle { get; set; }\n\t\tpublic string StreetAddress { get; set; }\n\t\tpublic string Zip { get; set; }\n\t\tpublic string City { get; set; }\n\t\tpublic string CountryName { get; set; }\n\t\tpublic string Phone { get; set; }\n\t\tpublic string PhoneCompany { get; set; }\n\t\tpublic string Mobile { get; set; }\n\t\tpublic string Email { get; set; }\n\t\tpublic string Url { get; set; }\n\t\tpublic string PhotoPath { get; set; }\n\t\tpublic override string ToString()\n\t\t{\n\t\t\tvar builder = new StringBuilder();\n\t\t\tbuilder.AppendLine(\"BEGIN:VCARD\");\n\t\t\tbuilder.AppendLine(\"VERSION:2.1\");\n\t\t\t// Name\n\t\t\tbuilder.AppendLine(\"N;CHARSET=iso-8859-1:\" + LastName + \";\" + FirstName);\n\t\t\t// Full name\n\t\t\tif (string.IsNullOrWhiteSpace(FirstName) && string.IsNullOrWhiteSpace(FirstName))\n\t\t\t\tbuilder.AppendLine(\"FN;CHARSET=iso-8859-1:\" + Organization);\n\t\t\telse\n\t\t\t\tbuilder.AppendLine(\"FN;CHARSET=iso-8859-1:\" + FirstName + \" \" + LastName);\n\t\t\t// Address\n\t\t\tbuilder.Append(\"ADR;\" + AddressType + \";PREF;CHARSET=iso-8859-1:;;\");\n\t\t\tbuilder.Append(StreetAddress + \";\");\n\t\t\tbuilder.Append(City + \";;\");\n\t\t\tbuilder.Append(Zip + \";\");\n\t\t\tbuilder.AppendLine(CountryName);\n\t\t\t// Other data\n\t\t\tbuilder.AppendLine(\"ORG;CHARSET=iso-8859-1:\" + Organization);\n\t\t\tbuilder.AppendLine(\"TITLE;CHARSET=iso-8859-1:\" + JobTitle);\n\t\t\tbuilder.AppendLine(\"TEL;\" + AddressType + \";VOICE;CHARSET=iso-8859-1:\" + Phone);\n\t\t\tif (!string.IsNullOrWhiteSpace(PhoneCompany))\n\t\t\t\tbuilder.AppendLine(\"X-MS-TEL;VOICE;COMPANY:\" + PhoneCompany);\n\t\t\tbuilder.AppendLine(\"TEL;CELL;VOICE:\" + Mobile);\n\t\t\tbuilder.AppendLine(\"URL;\" + AddressType + \":\" + Url);\n\t\t\tbuilder.AppendLine(\"EMAIL;PREF;INTERNET:\" + Email);\n\n\t\t\t// Add image\n\t\t\tif (PhotoPath != null)\n\t\t\t{\n\t\t\t\tbuilder.AppendLine(\"PHOTO;ENCODING=BASE64;TYPE=JPEG:\");\n\t\t\t\tbuilder.AppendLine(CreateThumbnail(PhotoPath, 92, 92));\n\t\t\t\tbuilder.AppendLine(string.Empty);\n\t\t\t}\n\n\t\t\tbuilder.AppendLine(\"END:VCARD\");\n\n\t\t\treturn builder.ToString();\n\t\t}\n\t}\n\n\tinternal static string CreateThumbnail(string lcFilename, int lnWidth, int lnHeight)\n\t{\n\t\tvar loBmp = new Bitmap(lcFilename);\n\n\t\tint lnNewWidth;\n\t\tint lnNewHeight;\n\t\t// If the image is smaller than a thumbnail\n\t\tif (loBmp.Width < lnWidth && loBmp.Height < lnHeight)\n\t\t{\n\t\t\tlnNewWidth = loBmp.Width;\n\t\t\tlnNewHeight = loBmp.Height;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdecimal lnRatio;\n\t\t\tif (loBmp.Width > loBmp.Height)\n\t\t\t{\n\t\t\t\tlnRatio = (decimal)lnWidth / loBmp.Width;\n\t\t\t\tlnNewWidth = lnWidth;\n\t\t\t\tvar lnTemp = loBmp.Height * lnRatio;\n\t\t\t\tlnNewHeight = (int)lnTemp;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlnRatio = (decimal)lnHeight / loBmp.Height;\n\t\t\t\tlnNewHeight = lnHeight;\n\t\t\t\tvar lnTemp = loBmp.Width * lnRatio;\n\t\t\t\tlnNewWidth = (int)lnTemp;\n\t\t\t}\n\t\t}\n\n\t\tvar bmpOut = new Bitmap(lnNewWidth, lnNewHeight);\n\t\tvar g = Graphics.FromImage(bmpOut);\n\t\tg.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;\n\t\tg.FillRectangle(Brushes.White, 0, 0, lnNewWidth, lnNewHeight);\n\t\tg.DrawImage(loBmp, 0, 0, lnNewWidth, lnNewHeight);\n\t\tloBmp.Dispose();\n\n\t\tbyte[] byteArray;\n\t\tusing (var stream = new MemoryStream())\n\t\t{\n\t\t\t// Save the bitmap as a JPG file with zero quality level compression.\n\t\t\t// Source: http://msdn.microsoft.com/en-us/library/bb882583.aspx\n\t\t\tvar myEncoderParameters = new EncoderParameters(1);\n\t\t\tvar myEncoder = System.Drawing.Imaging.Encoder.Quality;\n\t\t\tvar myEncoderParameter = new EncoderParameter(myEncoder, 93L);\n\t\t\tmyEncoderParameters.Param[0] = myEncoderParameter;\n\n\t\t\tvar jgpEncoder = ImageCodecInfo.GetImageDecoders().First(c => c.FormatID == ImageFormat.Jpeg.Guid);\n\t\t\tbmpOut.Save(stream, jgpEncoder, myEncoderParameters);\n\t\t\tstream.Close();\n\n\t\t\tbyteArray = stream.ToArray();\n\t\t}\n\n\t\treturn Convert.ToBase64String(byteArray);\n\t}\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ImportExport/Instructions/2sxc_App_ByUnknown_NameUnknown.dnn",
    "content": "﻿<dotnetnuke type=\"Package\" version=\"5.0\">\n  <packages>\n    <package name=\"2sxc_App_BySomeone_DoesSomething\" type=\"Module\" version=\"00.00.00\">\n      <friendlyName>This is a 2sxc App for DNN</friendlyName>\n      <description>This is a 2sxc App, not a DNN Module. This is a good thing, but you're trying to install it the wrong way :) - pls visit http://2sxc.org/en/help?tag=install-app </description>\n      <!--<iconFile>DesktopModules\\ToSIC_Imazen_ImageResizer\\icon.png</iconFile>-->\n      <owner>\n        <name>The App Author</name>\n        <organization>App Author</organization>\n        <url>http://2sxc.org/</url>\n        <email>info@2sxc.org</email>\n      </owner>\n      <license src=\"License.txt\"></license>\n      <releaseNotes src=\"ReleaseNotes.txt\"></releaseNotes>\n      <azureCompatible>true</azureCompatible>\n      <dependencies>\n        <!-- this is the minimum requirement for 2sxc -->\n        <dependency type=\"CoreVersion\">07.02.00</dependency>\n      </dependencies>\n      <components>\n        <!--<component type=\"Script\">\n          <scripts>\n            <basePath>DesktopModules\\ToSIC_Imazen_ImageResizer</basePath>\n          </scripts>\n        </component>\n        <component type=\"Assembly\">\n          <assemblies>\n            <basePath>bin</basePath>\n            <assembly>\n              <name>ImageResizer.dll</name>\n            </assembly>\n            <assembly>\n              <name>ImageResizer.Plugins.DiskCache.dll</name>\n            </assembly>\n          </assemblies>\n        </component>\n\n        <component type=\"File\">\n          <files>\n            <basePath>DesktopModules/ToSIC_Imazen_ImageResizer</basePath>\n            <file>\n              <name>icon.png</name>\n            </file>\n            <file>\n              <name>License.txt</name>\n            </file>\n            <file>\n              <name>ReleaseNotes.txt</name>\n            </file>\n          </files>\n        </component>-->\n\t\t\t</components>\n    </package>\n  </packages>\n</dotnetnuke>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ImportExport/Instructions/App installation instructions.txt",
    "content": "This is a App for DNN and runs in 2sxc - an open source module which does everything for you. \n\nTo install this app, you must first install 2sxc, then upload this ZIP into 2sxc. \n\nMore: http://2sxc.org/en/help?tag=install-app"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ImportExport/Instructions/License.txt",
    "content": "﻿<p><strong>read my lips</strong>\n<span style=\"color: red\">You are trying to install this the wrong way!</span>\n\nBy installing this, you agree to not install this. \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<span style=\"color: pink\">You are trying to install this the wrong way!</span>\n\n<span style=\"color: red\">By installing this, you agree to not install this. </span>\n\nOk, you made it this far - I'm not going to stop you, but it won't work. \nAfter you realize it, try installing it using 2sxc. \n\n<span style=\"color: red\">In case you're wondering why we're making it so hard: a install-package has no \"don't-install-switch\". <em>So we have to rely on you reading this to not install it!</em> </span>\n\nLove from Liechtenstein (yes, that's a country too)\nDaniel"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ImportExport/Instructions/Online help to install this app.url",
    "content": "[InternetShortcut]\nURL=http://2sxc.org/en/help?tag=install-app\nIconFile=http://2sxc.org/Portals/_default/Skins/Microsites2014/images/favicon-2.ico\nIconIndex=1\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ImportExport/Instructions/ReleaseNotes.txt",
    "content": "﻿<p><strong>read my lips</strong>\n<span style=\"color: red\">You are trying to install this the wrong way!</span>\nThis is a 2sxc-App, something much cooler than a standard DNN-module. And it's easy to add and remove again, and you can install it per portal. So...\n\nIf you got this far, you should <a href=\"http://2sxc.org/en/help?tag=install-app\" target=\"_blank\">read the help on installing Apps</a>.\n\n\n\nDo NOT continue, this cannot be installed\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nI'm serious - don't try to install this, it won't work\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nReally, it won't.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nJust let it be ok?\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nClose this dialog now, install using 2sxc.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nLove from Switzerland,\nDaniel & the 2sic team\n</p>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ImportExport/readme.md",
    "content": "﻿## Sxc folder\n\nThis folder only contains a special folder called:\n\n/ImportExport/Instruction/\n\nReason is, that these files are always included in an exported App-ZIP. They must be here. \n\nIdeally we should move them, but then we would have duplicates on existing installations requiring clean-up, so we leave them for now. "
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Core\")]\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/StartUp/DnnDi.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav;\nusing ToSic.Eav.Run.Startup;\nusing ToSic.Razor.StartUp;\nusing ToSic.Sxc.Backend;\nusing ToSic.Sxc.Compatibility;\nusing ToSic.Sxc.DataSources;\nusing ToSic.Sxc.Dnn.Integration;\nusing ToSic.Sxc.Dnn.Startup;\nusing ToSic.Sxc.Run.Startup;\n\n\nnamespace ToSic.Sxc.Dnn.StartUp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class DnnDi\n{\n    private static bool _alreadyRegistered;\n\n    public static IServiceCollection RegisterServices(IServiceCollection services)\n    {\n        var l = BootLog.Log.Fn(\"Dnn: Registering Services\", timer: true);\n\n        if (_alreadyRegistered)\n            return OriginalServiceCollection;\n\n        // If this is called from Dnn 7 - 9.3 it won't have services, so we must create our own\n        // This is because the old Dnn wasn't DI aware\n        services ??= new ServiceCollection();\n\n        l.A(\"Will start with DNN parts\");\n        services\n            .AddDnnPlugins()\n            .AddDnnCore() // TODO: Move core stuff from AddDnn to AddDnnCore and make implementations internal\n            .AddDnnSxcDataSources()\n            .AddDnnDataSources()\n            .AddDnnWebApi()\n            .AddDnnRazor()\n            .AddDnnCompatibility();\n\n        l.A(\"Will start with ADAM and 2sxc parts\");\n        services\n            .AddAdamWebApi<int, int>()\n            .AddSxcWebApi();\n\n        l.A(\"Will start with 2sxc Code / Engines etc.\");\n        services\n            .AddSxcCustom()\n            .AddSxcCode()\n            .AddSxcCodeHotBuild()\n            .AddSxcEngines();\n\n        l.A(\"Will start with 2sxc Core\");\n        services\n            .AddSxcImages()\n            .AddSxcApps()\n            .AddSxcEdit()\n            .AddSxcData()\n            .AddSxcAdam()\n            .AddSxcAdamWork<int, int>()\n            .AddSxcBlocks()\n            .AddSxcRender()\n            .AddSxcCms()\n            .AddSxcServices()\n            .AddSxcServicesObsolete()\n            .AddSxcWeb()\n            .AddSxcLightSpeed()\n            .AddSxcCodeGen() // Code generation services\n            .AddSxcCore();\n\n        l.A(\"Will start with 2sxc Fallbacks and RazorBlade parts\");\n        services\n            .AddSxcAppsFallbacks()\n            .AddSxcCoreFallbacks()\n            .AddRazorBlade();\n\n        l.A(\"Will start with EAV and WebApi Typed parts\");\n        services\n            .AddEavAll()\n            .AddEavAllFallbacks()\n            .AddEavWebApiTypedAfterEav();\n\n        // Remember this for later, when we must start the Static Dependency Injection\n        OriginalServiceCollection = services;\n\n        _alreadyRegistered = true;\n        l.Done();\n        return services;\n    }\n\n    public static IServiceCollection OriginalServiceCollection;\n\n    public static IServiceCollection AddDnnPlugins(this IServiceCollection services)\n    {\n        // Integrate KOI Dnn-Parts\n        services.TryAddTransient<Connect.Koi.Detectors.ICssFrameworkDetector, Connect.Koi.Dnn.DetectAndCacheDnnThemeCssFramework>();\n        return services;\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/StartUp/StartupDnn.cs",
    "content": "﻿using DotNetNuke.Web.Api;\nusing System.Configuration;\nusing System.Web.Hosting;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Dnn.Integration;\nusing ToSic.Sxc.Images;\nusing ToSic.Sys.Boot;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Configuration;\nusing ToSic.Sys.Security.Encryption;\n\nnamespace ToSic.Sxc.Dnn.StartUp;\n\n/// <summary>\n/// This configures .net Core Dependency Injection\n/// The StartUp is defined as an IServiceRouteMapper.\n/// This way DNN will auto-run this code before anything else\n/// </summary>\n// ReSharper disable once UnusedMember.Global\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class StartupDnn : IServiceRouteMapper\n{\n    /// <summary>\n    /// This will be called by DNN when loading the assemblies.\n    /// We just want to trigger the DI-Configure\n    /// </summary>\n    /// <param name=\"mapRouteManager\"></param>\n    public void RegisterRoutes(IMapRoute mapRouteManager) => Configure();\n\n\n    private static bool _alreadyConfigured;\n\n    /// <summary>\n    /// Configure IoC for 2sxc. If it's already configured, do nothing.\n    /// </summary>\n    public bool Configure()\n    {\n        var l = BootLog.Log.Fn<bool>(\"Dnn: Configuring WebApi Routes\", timer: true);\n\n        // In some cases this may be called 2x - so we must avoid doing it again\n        if (_alreadyConfigured)\n            return l.ReturnFalse();\n\n        // Configure Newtonsoft Time zone handling etc. - part of WebApi\n        StartUpDnnWebApi.Configure();\n\n        // Getting the service provider in Configure is tricky business, because\n        // of .net core 2.1 bugs\n        // ATM it appears that the service provider will get destroyed after startup, so we MUST get an additional one to use here\n        // 2023-06-15 2dm - making sure that even if we use the global DI, we're always using it in a scope to never bleed global objects\n        var transientSp = DnnStaticDi.GetGlobalScopedServiceProvider();\n\n        // now we should be able to instantiate registration of DB\n        var connectionString = ConfigurationManager.ConnectionStrings[\"SiteSqlServer\"].ConnectionString;\n        \n        var globalConfig = transientSp.Build<IGlobalConfiguration>();\n\n        globalConfig.ConnectionString(connectionString);\n\n        globalConfig.GlobalFolder(HostingEnvironment.MapPath(DnnConstants.SysFolderRootVirtual)!);\n        globalConfig.AssetsVirtualUrl(DnnConstants.SysFolderRootVirtual + \"assets/\");\n        globalConfig.SharedAppsFolder(\"~/Portals/_default/\" + AppConstants.AppsRootFolder + \"/\");\n        globalConfig.TempAssemblyFolder(HostingEnvironment.MapPath($\"~/{FolderConstants.DataFolderProtected}/{FolderConstants.TempAssemblyFolder}/\")!); // \".../App_Data/2sxc.bin\"\n        globalConfig.CshtmlAssemblyFolder(HostingEnvironment.MapPath($\"~/{FolderConstants.DataFolderProtected}/{FolderConstants.CshtmlAssemblyFolder}/\")!); // \".../App_Data/2sxc.bin.cshtml\"\n        globalConfig.CryptoFolder(HostingEnvironment.MapPath($\"~/{FolderConstants.DataFolderProtected}/{FolderConstants.CryptoFolder}/\")!); // \".../App_Data/2sxc.crypto\"\n\n        var sxcSysLoader = transientSp.Build<BootCoordinator>();\n        sxcSysLoader.StartUp();\n\n        // Place a copy of the features service on the old static variable\n        // Note: not perfect, it doesn't update on changes\n        // But since we don't want to encourage this old mechanism, it's ok\n        var featuresSvc = transientSp.Build<ISysFeaturesService>();\n        SetupOldStaticFeaturesForCompatibility(featuresSvc);\n\n        // Optional registration of query string rewrite functionality implementation for dnn imageflow module\n        Imageflow.Dnn.StartUp.RegisterQueryStringRewrite(ImageflowRewrite.QueryStringRewrite);\n\n        // Clean the App_Data/2sxc.bin folder\n        transientSp.Build<Util>().CleanTempAssemblyFolder();\n\n        _alreadyConfigured = true;\n        return l.ReturnTrue();\n    }\n\n    /// <summary>\n    /// After the SysLoader got the features, we must attach it to an old API which had was public\n    /// This was used in Mobius etc. to see if features are activated\n    /// </summary>\n    public void SetupOldStaticFeaturesForCompatibility(ISysFeaturesService featuresSvc)\n    {\n#pragma warning disable CS0618\n        Eav.Configuration.Features.FeaturesFromDi = featuresSvc;\n#pragma warning restore CS0618\n\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/StartUp/StartupDnn9.cs",
    "content": "﻿using DotNetNuke.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.Dnn.StartUp;\n\n/// <summary>\n/// This is the preferred way to start Dependency Injection, but it requires Dnn 9.4+\n/// If an older version of Dnn is used, this code will not run\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class StartupDnn9 : IDnnStartup\n{\n    public void ConfigureServices(IServiceCollection services)\n    {\n        // Do standard registration of all services\n        DnnDi.RegisterServices(services);\n\n        // Give it the Dnn 9 Global Service Provider\n        // This is critical, because we need the global service provider (which will be created after this code runs)\n        // When we do start-up and use singletons.\n        // Otherwise singletons won't be properly registered. \n        // https://github.com/dnnsoftware/Dnn.Platform/blob/9f83285a15d23203cbaad72d62add864ab5b8c7f/DNN%20Platform/DotNetNuke.Web/Common/LazyServiceProvider.cs#L28\n        IServiceProvider GetPreparedServiceProvider() => typeof(DotNetNuke.Common.Globals)\n            .GetProperty(\"DependencyProvider\", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)\n            ?.GetValue(null) as IServiceProvider;\n\n        // Now activate the Service Provider, because some Dnn code still needs the static implementation\n        DnnStaticDi.StaticDiReady(GetPreparedServiceProvider);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ToSic.Sxc.Dnn.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-NetFramework.props\" />\n\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\TypeScript\\Microsoft.TypeScript.Default.props\"\n          Condition=\"Exists('$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\TypeScript\\Microsoft.TypeScript.Default.props')\" />\n  <Import Project=\"BuildScripts\\LoadBuildConfig.Targets\" />\n\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>ToSic.Sxc.Dnn</RootNamespace>\n    <AssemblyName>ToSic.Sxc.Dnn</AssemblyName>\n    <!--For reasons unknown, this is relevant, even though we import the specs with the correct moniker-->\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <TargetFrameworkProfile />\n\n    <!-- This places the EAV DLLs here, for the copy-deploy during Dev to work -->\n    <OutputPath>bin\\</OutputPath>\n  </PropertyGroup>\n\n  <!--not sure if we must specify the docs file!-->\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <DocumentationFile>bin\\ToSic.Sxc.Dnn.xml</DocumentationFile>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);MSB3277;</NoWarn>\n    <!-- ignore warning that Dnn was loaded 2x - ATM necessary for MS build? @STV -->\n    <NoWarn>$(NoWarn);MSB4011</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"DotNetNuke.Core\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.DependencyInjection\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.Web\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.Web.Client\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"2.1.1\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions\" Version=\"2.1.1\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.AspNet.WebApi.Client\" Version=\"5.2.9\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.AspNet.WebApi.WebHost\" Version=\"5.2.9\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"MSBuildTasks\">\n      <Version>1.5.0.235</Version>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"System.Diagnostics.DiagnosticSource\" Version=\"9.0.11\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Reference Include=\"Connect.Dnn.Koi, Version=2.0.0.27364, Culture=neutral, processorArchitecture=MSIL\">\n      <SpecificVersion>False</SpecificVersion>\n      <HintPath>koi\\bin\\Connect.Dnn.Koi.dll</HintPath>\n      <Private>False</Private>\n    </Reference>\n    <Reference Include=\"Connect.Koi, Version=2.0.1.0, Culture=neutral, processorArchitecture=MSIL\">\n      <SpecificVersion>False</SpecificVersion>\n      <HintPath>koi\\bin\\Connect.Koi.dll</HintPath>\n      <Private>False</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Drawing\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Web\" />\n    <Reference Include=\"System.Configuration\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"ToSic.Imageflow.Dnn\">\n      <SpecificVersion>False</SpecificVersion>\n      <HintPath>..\\..\\..\\Dependencies\\Imageflow\\Dnn\\ToSic.Imageflow.Dnn.dll</HintPath>\n      <Private>False</Private>\n      <!-- this is important, otherwise it will be copied to the bin folder -->\n    </Reference>\n    <Reference Include=\"ToSic.Razor.Dnn\">\n      <SpecificVersion>False</SpecificVersion>\n      <HintPath>..\\..\\..\\Dependencies\\RazorBlade\\Release\\net40\\ToSic.Razor.Dnn.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Cms\\ToSic.Sxc.Cms.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Code.HotBuild\\ToSic.Sxc.Code.HotBuild.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Edit\\ToSic.Sxc.Edit.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Images\\ToSic.Sxc.Images.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.LightSpeed\\ToSic.Sxc.LightSpeed.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Web\\ToSic.Sxc.Web.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Dnn.WebApi\\ToSic.Sxc.Dnn.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Dnn.Core\\ToSic.Sxc.Dnn.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Dnn.Razor\\ToSic.Sxc.Dnn.Razor.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Service Include=\"{4A0DDDB5-7A95-4FBF-97CC-616D07737A77}\" />\n    <Service Include=\"{508349B6-6B84-4DF5-91F0-309BEEBAD82D}\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"App_LocalResources\\View.ascx.resx\" />\n    <Content Include=\"App_LocalResources\\View.ascx.de-DE.resx\" />\n    <Content Include=\"BuildScripts\\ModulePackage.Targets\">\n      <SubType>Designer</SubType>\n    </Content>\n    <Content Include=\"ClientScripts\\readme.md\" />\n    <Content Include=\"DnnPackageBuilder\\SqlDataProvider\\Migrate.SqlDataProvider\" />\n    <Content Include=\"DnnPackageBuilder\\SqlDataProvider\\RequireLatest.SqlDataProvider\" />\n    <Content Include=\"DnnPackageBuilder\\ToSic.Sxc.Dnn.dnn\">\n      <SubType>Designer</SubType>\n    </Content>\n    <Content Include=\"DnnPackageBuilder\\readme.md\" />\n    <Content Include=\"BuildScripts\\readme.md\" />\n    <Content Include=\"koi\\Resources.zip\" />\n    <Content Include=\"DnnPackageBuilder\\SqlDataProvider\\16.07.01.SqlDataProvider\" />\n    <Content Include=\"DnnPackageBuilder\\SqlDataProvider\\18.03.00.SqlDataProvider\" />\n    <Content Include=\"DnnPackageBuilder\\SqlDataProvider\\19.00.00.SqlDataProvider\" />\n    <Content Include=\"DnnPackageBuilder\\SqlDataProvider\\RequireMinimal.SqlDataProvider\" />\n    <Content Include=\"DnnPackageBuilder\\SqlDataProvider\\Uninstall.SqlDataProvider\" />\n    <Content Include=\"web.config\" />\n    <None Include=\"web.Debug.config\">\n      <DependentUpon>web.config</DependentUpon>\n    </None>\n    <None Include=\"web.DebugDnn.config\">\n      <DependentUpon>web.config</DependentUpon>\n    </None>\n    <None Include=\"web.DebugOqtane.config\">\n      <DependentUpon>web.config</DependentUpon>\n    </None>\n    <None Include=\"web.Release.config\">\n      <DependentUpon>web.config</DependentUpon>\n    </None>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildBinPath)\\Microsoft.CSharp.targets\" />\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\TypeScript\\Microsoft.TypeScript.targets\"\n          Condition=\"Exists('$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\TypeScript\\Microsoft.TypeScript.targets')\" />\n  <PropertyGroup>\n    <VisualStudioVersion Condition=\"'$(VisualStudioVersion)' == ''\">10.0</VisualStudioVersion>\n    <VSToolsPath Condition=\"'$(VSToolsPath)' == ''\">$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)</VSToolsPath>\n  </PropertyGroup>\n  <Import Project=\"$(VSToolsPath)\\WebApplications\\Microsoft.WebApplication.targets\" Condition=\"Exists('$(VSToolsPath)\\WebApplications\\Microsoft.WebApplication.targets')\" />\n\n  <ProjectExtensions>\n    <VisualStudio>\n      <FlavorProperties GUID=\"{349c5851-65df-11da-9384-00065b846f21}\">\n        <WebProjectProperties>\n          <SaveServerSettingsInUserFile>True</SaveServerSettingsInUserFile>\n        </WebProjectProperties>\n      </FlavorProperties>\n    </VisualStudio>\n  </ProjectExtensions>\n\n  <!-- Run the DNN Package Builder after every build -->\n  <Import Project=\"BuildScripts\\ModulePackage.Targets\" />\n  <Import Project=\"BuildScripts\\AfterBuild.Targets\" />\n  <Target Name=\"TestMessages\" BeforeTargets=\"PrepareForBuild\">\n    <Message Text=\"Debug Messages created by 2dm\" Importance=\"High\">\n    </Message>\n    <Message Text=\"Configuration=$(Configuration)\" Importance=\"High\">\n    </Message>\n    <Message Text=\"Platform=$(Platform)\" Importance=\"High\">\n    </Message>\n    <Message Text=\"Configuration|Platform='$(Configuration)|$(Platform)'\" Importance=\"High\">\n    </Message>\n    <Message Text=\"OutputPath=$(OutputPath)\" Importance=\"High\">\n    </Message>\n  </Target>\n\n  <Target Name=\"TestMessages2\" BeforeTargets=\"Build\">\n    <Message Text=\"Debug Messages created by 2dm\" Importance=\"High\">\n    </Message>\n    <Message Text=\"Configuration=$(Configuration)\" Importance=\"High\">\n    </Message>\n    <Message Text=\"Platform=$(Platform)\" Importance=\"High\">\n    </Message>\n    <Message Text=\"Configuration|Platform='$(Configuration)|$(Platform)'\" Importance=\"High\">\n    </Message>\n    <Message Text=\"OutputPath=$(OutputPath)\" Importance=\"High\">\n    </Message>\n  </Target>\n\n  <Target Name=\"BuildConfigTarget2\" AfterTargets=\"Build\" DependsOnTargets=\"BuildConfigTarget\">\n\n    <Message Text=\"------------------------------------------------------------------------------\" Importance=\"high\" />\n    <Message Text=\"$(BuildConfigPath)\" Importance=\"high\" />\n    <Message Text=\"------------------------------------------------------------------------------\" Importance=\"high\" />\n    <Message Text=\"DnnTargets:\" Importance=\"high\" />\n    <Message Text=\"$(DnnTargets)\" Importance=\"high\" />\n    <Message Text=\"Source:\" Importance=\"high\" />\n    <Message Text=\"$(Source)\" Importance=\"high\" />\n    <Message Text=\"DnnInstallPackage:\" Importance=\"high\" />\n    <Message Text=\"$(DnnInstallPackage)\" Importance=\"high\" />\n    <Message Text=\"------------------------------------------------------------------------------\" Importance=\"high\" />\n\n  </Target>\n</Project>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/ToSic.Sxc.Dnn.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=SexyContent/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=xxx_002Dsrc/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/Upgrade/readme.md",
    "content": "﻿# Upgrade Folder\n\nPlace xml-import files here for future upgrades. \n\nThis folder used to have a bunch of xml files for upgrading V7 to V8.5.5, but these are all removed in 9.20 as it won't support upgrading these \nold versions. "
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/View.ascx",
    "content": "﻿<%@ Control Language=\"C#\" AutoEventWireup=\"true\" Inherits=\"ToSic.Sxc.Dnn.View\" Codebehind=\"View.ascx.cs\" %>\n<asp:PlaceHolder runat=\"server\" ID=\"phOutput\"></asp:PlaceHolder>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/View.ascx.Errors.cs",
    "content": "﻿using System.Web.UI;\nusing DotNetNuke.Services.Exceptions;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Render.Sys;\n\nnamespace ToSic.Sxc.Dnn;\n\npartial class View\n{\n    internal bool IsError;\n\n    /// <summary>\n    /// Run some code in a try/catch, and output it nicely if an error is thrown\n    /// </summary>\n    /// <param name=\"action\"></param>\n    private TResult TryCatchAndLogToDnn<TResult>(Func<TResult> action)\n    {\n        try\n        {\n            return action();\n        }\n        catch (Exception ex)\n        {\n            IsError = true;\n            try\n            {\n                // 1. Log to DNN\n                Exceptions.ProcessModuleLoadException(this, ex, false);\n\n                // 2. Try to show nice message on screen\n\n                // first get a rendering helper - but since BlockBuilder may be null, create a new one\n                var renderingHelper = GetService<IRenderingHelper>().Init(Block);\n                var msg = renderingHelper.DesignErrorMessage([ex], true,\n                    additionalInfo: $\" - ℹ️ CONTEXT: Page: {TabId}; Module: {ModuleId}\");\n\n                try\n                {\n                    if (Block.Context.Permissions.IsContentAdmin)\n                        msg = renderingHelper.WrapInContext(msg,\n                            instanceId: Block.ParentId,\n                            contentBlockId: Block.ContentBlockId,\n                            editContext: true,\n                            errorCode: BlockBuildingConstants.ErrorGeneral,\n                            exsOrNull: [ex]);\n                }\n                catch { /* ignore */ }\n\n                phOutput.Controls.Add(new LiteralControl(msg));\n            }\n            catch\n            {\n                phOutput.Controls.Add(new LiteralControl(\"Something went really wrong in view.ascx - check error logs\"));\n            }\n            return default;\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/View.ascx.Logging.cs",
    "content": "﻿using System.Web.Http;\nusing ToSic.Sxc.Dnn.Run;\n\nnamespace ToSic.Sxc.Dnn;\n\npartial class View\n{\n    /// <summary>\n    /// Html Comment containing the log for the current module\n    /// </summary>\n    /// <returns></returns>\n    private string HtmlLog()\n        => Log.Dump(\" - \", \"<!-- 2sxc insights for \" + ModuleId + \"\\n\", \"-->\");\n\n    /// <summary>\n    /// optional detailed logging\n    /// </summary>\n    /// <returns></returns>\n    private string GetOptionalDetailedLogToAttach()\n    {\n        try\n        {\n            // if in debug mode and is super-user (or it's been enabled for all), then add to page debug\n            if (Request.QueryString[\"debug\"] == \"true\")\n                if (UserInfo.IsSuperUser\n                    || DnnLogging.EnableLogging(GlobalConfiguration.Configuration.Properties))\n                    return HtmlLog();\n        }\n        catch { /* ignore */ }\n\n        return \"\";\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/View.ascx.Standalone.cs",
    "content": "﻿using System.Web;\n\nnamespace ToSic.Sxc.Dnn;\n\npartial class View\n{\n    public bool RenderNaked => _renderNaked ??= Request.QueryString[\"standalone\"] == \"true\";\n    private bool? _renderNaked;\n\n    private void SendStandalone(string renderedTemplate)\n    {\n        Response.Clear();\n        Response.Write(renderedTemplate);\n        Response.Flush();\n        Response.SuppressContent = true;\n        LogTimer.Done(\"Standalone\");\n        HttpContext.Current.ApplicationInstance.CompleteRequest();\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/View.ascx.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing System.Web.UI;\nusing ToSic.Eav.Web.Sys;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Dnn.Features;\nusing ToSic.Sxc.Dnn.Install;\nusing ToSic.Sxc.Dnn.Services;\nusing ToSic.Sxc.Dnn.Web;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.RenderBlock;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\n\nnamespace ToSic.Sxc.Dnn;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class View : PortalModuleBase, IActionable\n{\n    private static bool _loggedToBootLog;\n\n    public View()\n    {\n        if (_loggedToBootLog)\n            return;\n        _loggedToBootLog = true;\n        BootLog.Log.A(\"Dnn: First moment where View was used.\");\n    }\n\n    #region GetService and Service Provider\n\n    /// <summary>\n    /// Get the service provider only once - ideally in Dnn9.4 we will get it from Dnn\n    /// If we would get it multiple times, there are edge cases where it could be different each time! #2614\n    /// </summary>\n    private IServiceProvider ServiceProvider => field ??= DnnStaticDi.CreateModuleScopedServiceProvider();\n\n    private TService GetService<TService>() => ServiceProvider.Build<TService>(Log);\n\n    #endregion\n\n    /// <summary>\n    /// Block needs to self-initialize when first requested, because it's used in the Actions-Menu builder\n    /// which runs before page-load\n    /// </summary>\n    private IBlock Block => _blockGetOnce.Get(Log, () => GetService<IModuleAndBlockBuilder>().BuildBlock(ModuleConfiguration, null), timer: true);\n    private readonly GetOnce<IBlock> _blockGetOnce = new();\n\n    private IBlockBuilder BlockBuilder => field ??= GetService<IBlockBuilder>().Setup(Block);\n\n    #region Logging\n\n    /// <summary>\n    /// Get the request logging helper for this request.\n    /// </summary>\n    /// <remarks>\n    /// - Must use ServiceProvider.Build directly, as the `GetService` method would try to use the Log before it's created.\n    /// - delay creating until first use to really just track our time when needed.\n    /// </remarks>\n    private HttpRequestLoggingScoped RequestLogging => field\n        ??= ServiceProvider.Build<Generator<HttpRequestLoggingScoped, HttpRequestLoggingScoped.Opts>>()\n            .New(new() { Segment = \"module\", RootName = \"Sxc.View\" });\n\n    private ILog Log => field ??= new Log(\"Sxc.View\", RequestLogging.RootLog);\n\n    /// <summary>\n    /// Log Timer to use everywhere we want to track the cumulative time.\n    /// </summary>\n    /// <remarks>\n    /// Time must be false, as it will be started/stopped as needed within the DoInTimer methods.\n    /// </remarks>\n    protected ILogCall LogTimer => field ??= Log.Fn(timer: false);\n\n    #endregion\n\n    /// <summary>\n    /// Page Load event\n    /// </summary>\n    protected void Page_Load(object sender, EventArgs e)\n    {\n        // Add first logging message which will become the title in the logs\n        RequestLogging.RootLog.A($\"Module Title New: '{ModuleConfiguration.ModuleTitle}'\");\n\n        LogTimer.DoInTimer(() =>\n        {\n            var l = Log.Fn(message: nameof(Page_Load), timer: true);\n            // todo: this should be dynamic at some future time, because normally once it's been checked, it wouldn't need checking again\n            var checkPortalIsReady = true;\n\n            // #RemovedV20 #OldDnnAutoJQuery\n            //bool? requiresPre1025Behavior = null; // null = auto-detect, true/false\n\n            // get the block early, to see any errors separately - before accessing cache (which also uses the block)\n            var block = TryCatchAndLogToDnn(() => Block);\n\n            #region Lightspeed\n\n            try\n            {\n                if (OutputCache.Existing != null)\n                {\n                    checkPortalIsReady = false;\n                    // #RemovedV20 #OldDnnAutoJQuery\n                    //requiresPre1025Behavior = OutputCache.Existing.EnforcePre1025;\n                }\n            }\n            catch\n            {\n                /* ignore */\n            }\n\n            #endregion\n\n            // Always do this, part of the guarantee that everything will work\n            // new mechanism in 10.25\n            // this must happen in Page-Load, so we know what supporting scripts to add\n            // at this stage of the lifecycle\n            // We moved this to Page_Load because RequestAjaxAntiForgerySupport didn't work in later events\n            // ensure everything is ready and that we know if we should activate the client-dependency\n            TryCatchAndLogToDnn(() =>\n            {\n                if (checkPortalIsReady)\n                    if (!DnnReadyCheckTurbo.QuickCheckSiteAndAppFoldersAreReady(this, Log))\n                        GetService<DnnReadyCheckTurbo>().EnsureSiteAndAppFoldersAreReady(this, block);\n\n                // #RemovedV20 #OldDnnAutoJQuery\n                // var blockBuilder = requiresPre1025Behavior == false ? null : BlockBuilder;\n                _dnnClientResources = GetService<DnnClientResources>().Init(Page, /*null,*/ null /*blockBuilder*/);\n\n                // #RemovedV20 #OldDnnAutoJQuery\n                //_enforcePre1025JQueryLoading = requiresPre1025Behavior ?? _dnnClientResources.NeedsPre1025Behavior();\n                //if (_enforcePre1025JQueryLoading)\n                //    _dnnClientResources.EnforcePre1025Behavior();\n                return true;\n            });\n            l.Done();\n        });\n    }\n\n    private DnnClientResources _dnnClientResources;\n    //private bool _enforcePre1025JQueryLoading;\n\n\n    /// <summary>\n    /// Process View if a Template has been set\n    /// </summary>\n    /// <param name=\"sender\"></param>\n    /// <param name=\"e\"></param>\n    protected void Page_PreRender(object sender, EventArgs e)\n    {\n        var l = Log.Fn();\n        var finalMessage = \"\";\n        LogTimer.DoInTimer(() =>\n        {\n            // #lightspeed\n            var cachedResult = OutputCache.Existing?.Data;\n            var cacheHit = cachedResult != null;\n            if (cacheHit)\n                l.A(\"Lightspeed hit - will use cached\");\n\n            IRenderResult renderResult = null;\n            var headersAndScriptsAdded = false;\n\n            // skip this if something before this caused an error\n            if (!IsError)\n                TryCatchAndLogToDnn(() =>\n                {\n                    // Try to build the html and everything\n                    renderResult = cachedResult;\n\n                    var useLightspeed = OutputCache.IsEnabled; // ?? false;\n                    finalMessage = !useLightspeed ? \"\" : cacheHit ? \"⚡⚡\" : \"⚡⏳\";\n\n                    // Generate Render Result if not already provided by cache\n                    renderResult ??= RenderViewAndGatherJsCssSpecs(useLightspeed);\n\n                    // Apply page settings, assets, resources etc. from Render Result\n                    try\n                    {\n                        GetService<DnnPageChanges>().Apply(Page, renderResult);\n                    }\n                    catch\n                    {\n                        /* ignore */\n                    }\n\n                    // Try to add page specs about the request to the log (new v16.02)\n                    RequestLogging.StoreEntry.TryUpdateSpecs(() => new SpecsForLogHistory().BuildSpecsForLogHistory(Block));\n\n                    // call this after rendering templates, because the template may change what resources are registered\n                    _dnnClientResources.AddEverything(renderResult.Features);\n                    headersAndScriptsAdded = true; // will be true if we make it this far\n\n                    // If standalone is specified, output just the template without anything else\n                    if (RenderNaked)\n                        SendStandalone(renderResult.Html);\n                    else\n                        phOutput.Controls.Add(new LiteralControl(renderResult.Html));\n\n                    // #Lightspeed\n                    var lLightSpeed = Log.Fn(message: \"Lightspeed\", timer: true);\n\n                    // Do not save cache hits again. Cached entries may already carry compressed HTML,\n                    // so saving them again would just trigger another decompress/recompress cycle.\n                    if (!cacheHit)\n                        // #RemovedV20 #OldDnnAutoJQuery\n                        OutputCache.Save(renderResult/*, _enforcePre1025JQueryLoading*/);\n                    lLightSpeed.Done();\n\n                    return true; // dummy result for TryCatchAndLogToDnn\n                });\n\n            // if we had an error before, or have one now, re-check assets\n            if (IsError && !headersAndScriptsAdded)\n                _dnnClientResources?.AddEverything(renderResult?.Features);\n        });\n\n        // Mini workaround: We must briefly start the timer again, so that the Done() call will stop and propagate the value to the proper place\n        LogTimer.Timer.Start();\n        LogTimer.Done(IsError ? \"⚠️\" : finalMessage);\n        l.Done();\n    }\n\n    private IRenderResult RenderViewAndGatherJsCssSpecs(bool useLightspeed)\n    {\n        var l = Log.Fn<IRenderResult>(message: $\"module {ModuleId} on page {TabId}\", timer: true);\n\n        var result = new RenderResult();\n        TryCatchAndLogToDnn(() =>\n        {\n            if (RenderNaked)\n                BlockBuilder.WrapInDiv = false;\n            result = (RenderResult)BlockBuilder.Run(\n                true,\n                specs: new()\n                {\n                    UseLightspeed = useLightspeed,\n                    RenderEngineResult = GetService<DnnRequirements>().GetMessageForRequirements()\n                }\n            );\n\n            if (result.Errors?.Any() ?? false)\n            {\n                var warnings = result.Errors\n                    .Select(e => BlockBuilder.RenderingHelper.DesignError(e));\n\n                result = result with { Html = string.Join(\"\", warnings) + result.Html };\n            }\n\n            result = result with { Html = result.Html + GetOptionalDetailedLogToAttach() };\n            return true; // dummy result for TryCatchAndLogToDnn\n        });\n\n        return l.ReturnAsOk(result);\n    }\n\n    protected IOutputCache OutputCache => field ??= GetService<IOutputCache>().Init(ModuleId, TabId, Block);\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/View.ascx.designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated. \n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace ToSic.Sxc.Dnn {\n    \n    \n    public partial class View {\n        \n        /// <summary>\n        /// phOutput control.\n        /// </summary>\n        /// <remarks>\n        /// Auto-generated field.\n        /// To modify move field declaration from designer file to code-behind file.\n        /// </remarks>\n        protected global::System.Web.UI.WebControls.PlaceHolder phOutput;\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/View.ascx.menu.cs",
    "content": "﻿using DotNetNuke.Entities.Modules.Actions;\nusing DotNetNuke.Security;\nusing DotNetNuke.Services.Exceptions;\nusing ToSic.Sys.Users;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Dnn;\n\npartial class View\n{\n    #region ModuleActions on THIS DNN-Module\n\n    /// <summary>\n    /// Dnn will create the menu with all actions like edit entity, app settings, etc.\n    /// </summary>\n    public ModuleActionCollection ModuleActions => field ??= GetModuleActions();\n\n    private ModuleActionCollection GetModuleActions()\n    {\n        var l = Log.Fn<ModuleActionCollection>();\n        try\n        {\n            // Don't offer options if it's from another portal\n            if (ModuleConfiguration.PortalID != ModuleConfiguration.OwnerPortalID)\n                return l.Return([]);\n\n            var result = InitModuleActions();\n            return l.Return(result);\n        }\n        catch (Exception e)\n        {\n            Exceptions.LogException(e);\n            return l.ReturnAsError([]);\n        }\n\n    }\n\n    private ModuleActionCollection InitModuleActions()\n    {\n        var actions = new ModuleActionCollection();\n        if (Block == null)\n            return actions;\n        var block = Block;\n        var appIsKnown = block.AppId > 0;\n        var viewToUse = block.ViewIsReady ? block.View : null;\n        if (appIsKnown)\n        {\n            // Edit item\n            if (viewToUse?.UseForList == true)\n                actions.Add(GetNextActionID(), LocalizeString(\"ActionEdit.Text\"), \"\", \"\", \"edit.gif\",\n                    JsAction(\"edit\", \"{ useModuleList: true, index: 0 }\"),\n                    \"test\", true,\n                    SecurityAccessLevel.Edit, true, false);\n\n            // Change layout button\n            actions.Add(GetNextActionID(), LocalizeString(\"ActionChangeLayoutOrContent.Text\"), \"\", \"\", \"action_settings.gif\",\n                JsAction(\"layout\"),\n                false,\n                SecurityAccessLevel.Edit, true, false);\n        }\n\n        var user = GetService<IUser>();\n\n        // Edit Template Button\n        if (user.IsSiteDeveloper && appIsKnown && viewToUse != null)\n            actions.Add(GetNextActionID(), LocalizeString(\"ActionEditTemplateFile.Text\"), ModuleActionType.EditContent,\n                \"templatehelp\", \"edit.gif\",\n                JsAction(\"template-develop\"),\n                \"test\",\n                true,\n                SecurityAccessLevel.Edit, true, false);\n\n        // App management\n        if (user.IsSiteAdmin && appIsKnown)\n            actions.Add(GetNextActionID(), \"Admin\" + (block.IsContentApp ? \"\" : \" \" + block.AppOrNull?.Name), \"\",\n                \"\", \"edit.gif\",\n                JsAction(\"app\"),\n                \"\", true,\n                SecurityAccessLevel.Admin, true, false);\n\n        // Zone management (app list)\n        if (user.IsSiteAdmin)\n            actions.Add(GetNextActionID(), \"Apps Management\", \"AppManagement.Action\", \"\", \"action_settings.gif\",\n                JsAction(\"zone\"),\n                \"\", true,\n                SecurityAccessLevel.Admin, true, false);\n            \n        return actions;\n    }\n\n    private string JsAction(string action, string commandParams = null)\n    {\n        var useParams = commandParams.HasValue() ? \", params: \" + commandParams : \"\";\n        return \"javascript:$2sxc(\" + ModuleId + \").cms.run({ action: '\" + action + \"' \" + useParams + \" });\";\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/dist/CachedPageBase.cs",
    "content": "﻿using System.Web;\nusing System.Web.Caching;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Framework;\nusing ToSic.Eav.ImportExport.Integration;\nusing ToSic.Sxc.Dnn.Web;\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sxc.Web.Sys.EditUi;\nusing ToSic.Sys.Utils;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Dnn.dist;\n\npublic class CachedPageBase : CDefault // HACK: inherits dnn default.aspx to preserve correct language cookie\n{\n    private const int UnknownSiteId = -1;\n    private const int UnknownPageId = -1;\n\n    #region GetService and Service Provider\n\n    /// <summary>\n    /// Get the service provider only once - ideally in Dnn9.4 we will get it from Dnn\n    /// If we would get it multiple times, there are edge cases where it could be different each time! #2614\n    /// </summary>\n    private IServiceProvider ServiceProvider => _serviceProvider.Get(Log, DnnStaticDi.CreateModuleScopedServiceProvider);\n    private readonly GetOnce<IServiceProvider> _serviceProvider = new();\n    private TService GetService<TService>() => ServiceProvider.Build<TService>(Log);\n\n    #endregion\n\n    #region Logging\n\n    private ILog Log { get; } = new Log(\"Sxc.Dnn.CachedPageBase\");\n    private IEnvironmentLogger EnvLogger => _envLogger.Get(Log, GetService<IEnvironmentLogger>);\n    private readonly GetOnce<IEnvironmentLogger> _envLogger = new();\n    #endregion\n\n    protected string PageOutputCached(string virtualPath, EditUiResourceSettings settings)\n    {\n        // add to insights-history for analytic\n        GetService<ILogStore>().Add(\"edit-dialog\", Log);\n\n        var l = Log.Fn<string>($\"{nameof(virtualPath)}: {virtualPath}\");\n\n        var html = GetPageHtml(virtualPath);\n        l.A($\"html: {html.Length} chars\");\n\n        var siteId = GetSiteId();\n        var addOn = $\"&{DnnJsApiService.PortalIdParamName}={siteId}\";\n\n        var pageId = GetPageId();\n        var siteRoot = GetSiteRoot(pageId, siteId);\n\n        var editUiResources = GetService<EditUiResources>();\n        var assets = editUiResources.GetResources(true, siteId, settings);\n        l.A($\"customHeaders: {assets.HtmlHead}\");\n\n        var dnnJsApi = GetService<IJsApiService>();\n        var content = dnnJsApi.GetJsApiJson(pageId: pageId, siteRoot: siteRoot, rvt: null, withPublicKey: WithPublicKey());\n        l.A($\"JsApiJson: {content}\");\n\n        return l.ReturnAsOk(HtmlDialog.UpdatePlaceholders(html, content, pageId, addOn, assets.HtmlHead, \"\"));\n    }\n\n    private string GetPageHtml(string virtualPath)\n    {\n        var l = Log.Fn<string>($\"{nameof(virtualPath)}: {virtualPath}\");\n\n        var key = CacheKey(virtualPath);\n        if (Cache.Get(key) is string html) return l.Return(html,\"ok, from cache\");\n\n        l.A($\"not in cache (key:{key})\");\n\n        var path = GetPath(virtualPath);\n        l.A($\"path to file: {path}\");\n\n        html = File.ReadAllText(path);\n        l.A($\"read file: {html.Length} chars\");\n\n        html = HtmlDialog.CleanImport(html);\n        l.A($\"html adjusted: {html.Length} chars\");\n\n        Cache.Insert(key, html, new CacheDependency(path));\n        return l.Return(html, \"ok, added to cache with cache dependency on file\");\n    }\n\n    private static string CacheKey(string virtualPath) => $\"2sxc-edit-ui-page-{virtualPath}\";\n\n    private string GetPath(string virtualPath)\n    {\n        var l = Log.Fn<string>($\"{nameof(virtualPath)}: {virtualPath}\");\n        var path = Server.MapPath(virtualPath);\n        if (!File.Exists(path)) throw l.Ex(new Exception(\"File not found: \" + path));\n        return l.ReturnAsOk(path);\n    }\n\n    private int GetSiteId()\n    {\n        var l = Log.Fn<int>();\n\n        // portalId should be provided in query string (because of DNN special handling of aspx pages in DesktopModules)\n        var portalIdString = Request.QueryString[DnnJsApiService.PortalIdParamName];\n        l.A($\"{DnnJsApiService.PortalIdParamName} from query string: {portalIdString}\");\n\n        var siteId = portalIdString.HasValue() ? Convert.ToInt32(portalIdString) : UnknownSiteId;\n        l.A($\"{(siteId == UnknownSiteId ? \"unknown\" : \"\")} siteId: {siteId}\");\n\n        return l.ReturnAsOk(siteId);\n    }\n\n    private int GetPageId()\n    {\n        var l = Log.Fn<int>();\n\n        // pageId should be provided in query string\n        var pageIdString = Request.QueryString[HtmlDialog.PageIdInUrl];\n        l.A($\"{HtmlDialog.PageIdInUrl} from query string: {pageIdString}\");\n\n        var pageId = pageIdString.HasValue() ? Convert.ToInt32(pageIdString) : UnknownPageId;\n        l.A($\"{(pageId == UnknownPageId ? \"unknown\" : \"\")} pageId: {pageId}\");\n\n        return l.ReturnAsOk(pageId);\n    }\n\n    private bool WithPublicKey()\n    {\n        var l = Log.Fn<bool>();\n\n        // 'wpk' should be provided in query string\n        var withPublicKeyString = Request.QueryString[HtmlDialog.WithPublicKey];\n        l.A($\"{HtmlDialog.WithPublicKey} from query string: {withPublicKeyString}\");\n\n        var withPublicKey = withPublicKeyString.HasValue() && Convert.ToBoolean(withPublicKeyString);\n\n        return l.ReturnAsOk(withPublicKey);\n    }\n\n    /// <summary>\n    /// portalId and pageId context is lost on DesktopModules/ToSic.Sxc/dist/...aspx\n    /// and DNN Framework can not resolve site root, so we need to handle it by ourselves\n    /// </summary>\n    /// <param name=\"pageId\"></param>\n    /// <param name=\"portalId\"></param>\n    /// <returns></returns>\n    private string GetSiteRoot(int pageId, int portalId)\n    {\n        var l = Log.Fn<string>($\"{nameof(pageId)}: {pageId}, {nameof(portalId)}: {portalId}\");\n        \n        try\n        {\n            // this is fallback\n            if (pageId == UnknownPageId) \n                return l.ReturnAsError(ServicesFramework.GetServiceFrameworkRoot(), $\"fallback, because of unknown {nameof(pageId)}\");\n            \n            if (portalId == UnknownSiteId)\n            {\n                l.A($\"fallback, unknown portalId, trying to get it from {nameof(pageId)}\");\n                portalId = PortalController.GetPortalDictionary()[pageId];\n                l.A($\"{nameof(portalId)}: {portalId}\");\n            }\n\n            var primaryPortalAlias = GetPrimaryPortalAliasBasedOnRequestUrlAndCulture(portalId);\n            l.A($\"primaryPortalAlias: {primaryPortalAlias?.HTTPAlias}\");\n\n            string siteRoot;\n            if (primaryPortalAlias != null)\n            {\n                siteRoot = CleanLeadingPartSiteRoot(primaryPortalAlias.HTTPAlias);\n            }\n            else\n            {\n                siteRoot = ServicesFramework.GetServiceFrameworkRoot();\n                l.A(\"portalAlias is null, falling back to ServicesFramework.GetServiceFrameworkRoot()\");\n            }\n            l.A($\"siteRoot: {siteRoot}\");\n\n            if (string.IsNullOrEmpty(siteRoot))\n            {\n                siteRoot = \"/\";\n                l.A(\"siteRoot is empty, falling back to /\");\n            }\n            return l.ReturnAsOk(siteRoot);\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            EnvLogger.LogException(ex);\n            // if all breaks, falling back to a default value\n            return l.ReturnAsError(ServicesFramework.GetServiceFrameworkRoot(), \"error, falling back to a default value\");\n        }\n    }\n\n    private PortalAliasInfo GetPrimaryPortalAliasBasedOnRequestUrlAndCulture(int portalId)\n    {\n        var l = Log.Fn<PortalAliasInfo>($\"{nameof(portalId)}: {portalId}\");\n\n        //var cultureCode = LocaleController.Instance.GetCurrentLocale(portalId).Code;\n        var cultureCode = Thread.CurrentThread.CurrentCulture.ToString();\n        l.A($\"cultureCode: {cultureCode}\");\n\n        // Get all aliases for the portal\n        var aliases = PortalAliasController.Instance\n            .GetPortalAliasesByPortalId(portalId)\n            .ToList();\n        l.A($\"aliases: {aliases.Count}\");\n\n        // Figure out the correct alias based on the current URL and culture\n        // Should also fall back to correct primary if the current one is not found\n        var currentUrl = HttpContext.Current.Request.Url.ToString();\n        l.A($\"figure out the correct alias based on the current URL:{currentUrl} and culture:{cultureCode}.\");\n\n        // try to filter aliases on the current url\n        var aliases2 = aliases.Where(a => currentUrl.IndexOf(a.HTTPAlias, OrdinalIgnoreCase) >= 0).ToList();\n        if (!aliases2.Any())\n        {\n            l.A(\"list of aliases filtered by current url is empty, falling back to filter without current URL\");\n            aliases2 = aliases; // falling back to filter without current URL\n        }\n        aliases2.ForEach(a => l.A($\"alias: {a.HTTPAlias}, isPrimary: {a.IsPrimary}, culture: {a.CultureCode}\"));\n\n        var primaryPortalAlias = aliases2\n            .Where(a => string.Compare(a.CultureCode, cultureCode, OrdinalIgnoreCase) == 0 || string.IsNullOrEmpty(a.CultureCode))\n            .OrderByDescending(a => a.IsPrimary)\n            .ThenByDescending(a => a.CultureCode)\n            .FirstOrDefault();\n        l.A($\"primaryPortalAlias: {primaryPortalAlias?.HTTPAlias} based on culture:{cultureCode}\");\n\n        if (primaryPortalAlias == null)\n        {\n            l.A(\"primaryPortalAlias based on culture is null, falling back to the first primary alias\");\n            // fallback to the first primary first\n            primaryPortalAlias = aliases.FirstOrDefault(a => a.IsPrimary);\n            l.A($\"primaryPortalAlias: {primaryPortalAlias?.HTTPAlias}\");\n        }\n\n        if (primaryPortalAlias == null)\n        {\n            l.A(\"primaryPortalAlias is null, falling back to the first alias\");\n            // and only if this doesn't exist for random reasons, fallback to first alias\n            primaryPortalAlias = aliases.FirstOrDefault();\n            l.A($\"portalAlias: {primaryPortalAlias?.HTTPAlias}\");\n        }\n\n        return l.ReturnAsOk(primaryPortalAlias);\n    }\n\n    private string CleanLeadingPartSiteRoot(string path)\n    {\n        var l = Log.Fn<string>($\"{nameof(path)}:{path}\");\n        var index = path.IndexOf('/');\n        l.A($\"position of /: {index}\");\n        return l.ReturnAsOk(index <= 0 ? \"/\" : path.Substring(index).SuffixSlash());\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/dist/ng-edit/Default.aspx",
    "content": "﻿<%@ Page Language=\"C#\" AutoEventWireup=\"true\" CodeBehind=\"Default.aspx.cs\" Inherits=\"ToSic.Sxc.Dnn.dist.eavUi.Default\" %>\n<!-- aspx page will response html from eav-ui.html file -->\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/dist/ng-edit/Default.aspx.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.EditUi;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Dnn.dist.eavUi;\n\npublic class Default : CachedPageBase\n{\n    protected void Page_Load(object sender, EventArgs e)\n    {\n        Response.AppendHeader(\"test-dev\", \"2sxc\");\n\n        Response.Write(PageOutputCached(\"~/DesktopModules/ToSic.Sxc/dist/ng-edit/index-raw.html\",\n            EditUiResourceSettings.EditUi));\n\n        // HACK: opening editui will change user language in cookie, so disable that\n        //if (Response.Cookies[\"language\"] != null) Response.Cookies.Remove(\"language\");\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/dist/quick-dialog/Default.aspx",
    "content": "﻿<%@ Page Language=\"C#\" AutoEventWireup=\"true\" CodeBehind=\"Default.aspx.cs\" Inherits=\"ToSic.Sxc.Dnn.dist.quick_dialog.Default\" %>\n<!-- aspx page will response html from index-raw.html file -->\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/dist/quick-dialog/Default.aspx.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.EditUi;\n\nnamespace ToSic.Sxc.Dnn.dist.quick_dialog;\n\npublic class Default : CachedPageBase\n{\n    protected void Page_Load(object sender, EventArgs e)\n    {\n        Response.AppendHeader(\"test-dev\", \"2sxc\");\n\n        Response.Write(PageOutputCached(\"~/DesktopModules/ToSic.Sxc/dist/quick-dialog/index-raw.html\", EditUiResourceSettings.QuickDialog));\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/koi/License.txt",
    "content": "﻿<div class=\"License\">\n\t<h3>MIT License</h3>\n\t<p>\n\t\tCopyright (c) 2023 by <a href=\"https://2sic.com/\">2sic</a>/<a href=\"https://2sxc.org/\">2sxc</a>  <br/>\n        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated \n        documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation \n        the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and \n        to permit persons to whom the Software is furnished to do so, subject to the following conditions: <br/>\n\t    The above copyright notice and this permission notice shall be included in all copies or substantial portions \n        of the Software. <br/>\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n    </p>\n</div>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/koi/ReleaseNotes.txt",
    "content": "﻿<h3>Release Notes of Connect.Koi</h3>\n<p>\n\tThis is Connect.Koi - there are no special release notes.\n</p>\n<p class=\"Contributor\">\n\tBy DNN Connect and 2sic<br />\n\tVisit <a href=\"https://connect-koi.net/\" target=\"_blank\">https://connect-koi.net/</a> to discover more.\n</p>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/razorblade/License.txt",
    "content": "﻿<div class=\"License\">\n\t<h3>MIT License</h3>\n\t<p>\n\t\tCopyright (c) 2023 by <a href=\"https://2sic.com/\">2sic</a>/<a href=\"https://2sxc.org/\">2sxc</a>  <br/>\n        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated \n        documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation \n        the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and \n        to permit persons to whom the Software is furnished to do so, subject to the following conditions: <br/>\n\t    The above copyright notice and this permission notice shall be included in all copies or substantial portions \n        of the Software. <br/>\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n    </p>\n</div>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/razorblade/ReleaseNotes.txt",
    "content": "﻿<h3>Release Notes of RazorBlade.net v4</h3>\n<p>\n\tThis is ToSic - RazorBlade.net\n</p>\n<p class=\"Contributor\">\n\tBy <a href=\"https://www.2sic.com/\" target=\"_blank\">2sic</a>\n\t<br />\n\tRead the <a href=\"https://razor-blade.net\" target=\"_blank\">API docs</a>\n\tVisit <a href=\"https://github.com/2sic/razor-blade\" target=\"_blank\">RazorBlade.net on Github</a> to discover more, \n\tor try the <a href=\"https://2sxc.org/dnn-tutorials/\" target=\"_blank\">tutorials</a>.\n</p>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/razorblade-old/License.txt",
    "content": "﻿<div class=\"License\">\n\t<h3>MIT License</h3>\n\t<p>\n\t\tCopyright (c) 2019 by <a href=\"https://www.dnn-connect.org/\">DNN Connect</a> and <a href=\"https://2sic.com/\">2sic</a>/<a href=\"https://2sxc.org/\">2sxc</a>  <br/>\n        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated \n        documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation \n        the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and \n        to permit persons to whom the Software is furnished to do so, subject to the following conditions: <br/>\n\t    The above copyright notice and this permission notice shall be included in all copies or substantial portions \n        of the Software. <br/>\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n    </p>\n</div>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/razorblade-old/ReleaseNotes.txt",
    "content": "﻿<h3>Release Notes of Razor Blade</h3>\n<p>\n\tThis is Connect - Razor Blade\n</p>\n<p class=\"Contributor\">\n\tBy the <a href=\"https://www.dnn-connect.org/\" target=\"_blank\">DNN Connect Community</a> \n\tand <a href=\"https://www.2sic.com/\" target=\"_blank\">2sic</a>\n\t<br />\n\tVisit <a href=\"https://github.com/DNN-Connect/razor-blade\" target=\"_blank\">Razor Blade on Github</a> to discover more, \n\tor try the <a href=\"https://github.com/DNN-Connect/razor-blade-tutorial-app\" target=\"_blank\">tutorial app from github</a>.\n</p>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/web-Deploy.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <system.web>\n    <compilation debug=\"false\" targetFramework=\"4.0\">\n      <assemblies>\n        <add assembly=\"System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\" />\n      </assemblies>\n    </compilation>\n  </system.web>\n</configuration>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn/web.config",
    "content": "<?xml version=\"1.0\"?>\n<configuration>\n    <!--\n    this is dummy web.config that is not in real use,\n    it is here to suppress following VS Warning:\n    \"Found conflicts between different versions of the same dependent assembly.\n    In Visual Studio, double-click this warning (or select it and press Enter) to fix the conflicts; otherwise,\n    add the following binding redirects to the \"runtime\" node in the application configuration file...\"\n  -->\n    <runtime>\n        <assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Threading.Tasks.Extensions\" publicKeyToken=\"CC7B13FFCD2DDD51\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.2.0.1\" newVersion=\"4.2.0.1\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Runtime.CompilerServices.Unsafe\" publicKeyToken=\"B03F5F7F11D50A3A\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-6.0.0.0\" newVersion=\"6.0.0.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Memory\" publicKeyToken=\"CC7B13FFCD2DDD51\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.0.1.2\" newVersion=\"4.0.1.2\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Data.SqlClient\" publicKeyToken=\"B03F5F7F11D50A3A\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.6.1.6\" newVersion=\"4.6.1.6\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.ComponentModel.Annotations\" publicKeyToken=\"B03F5F7F11D50A3A\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.2.1.0\" newVersion=\"4.2.1.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Collections.Immutable\" publicKeyToken=\"B03F5F7F11D50A3A\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-9.0.0.0\" newVersion=\"9.0.0.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"Microsoft.Bcl.AsyncInterfaces\" publicKeyToken=\"CC7B13FFCD2DDD51\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-9.0.0.0\" newVersion=\"9.0.0.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Text.Encodings.Web\" culture=\"neutral\" publicKeyToken=\"cc7b13ffcd2ddd51\" />\n                <bindingRedirect oldVersion=\"0.0.0.0-9.0.0.0\" newVersion=\"9.0.0.0\" />\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Text.Json\" culture=\"neutral\" publicKeyToken=\"cc7b13ffcd2ddd51\" />\n                <bindingRedirect oldVersion=\"0.0.0.0-9.0.0.0\" newVersion=\"9.0.0.0\" />\n            </dependentAssembly>\n        </assemblyBinding>\n    </runtime>\n</configuration>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/Data.DynamicEntity.Toolbar/OldDynamicEntityFeatures.cs",
    "content": "﻿#if NETFRAMEWORK\n\nusing ToSic.Eav.Data;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys;\nusing ToSic.Sxc.Data.Sys.CodeDataFactory;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Edit.Toolbar.Sys;\nusing ToSic.Sxc.Services;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Compatibility;\n\n/// <summary>\n/// Helper so that the old DynamicEntity can get a toolbar\n/// </summary>\ninternal class OldDynamicEntityFeatures : IOldDynamicEntityFeatures\n{\n    public System.Web.IHtmlString GenerateOldToolbar(ICodeDataFactory cdf, IEntity entity)\n    {\n        // 2025-05-13 2dm old code, must ensure that this code doesn't need the IBlockContext\n        //var userMayEdit = Cdf.BlockOrNull?.Context.Permissions.IsContentAdmin ?? false;\n\n        // If we're not in a running context, of which we know the permissions, no toolbar\n        // Internally also verifies that we have a context (otherwise it's false), so no toolbar\n        var userMayEdit = ((CodeDataFactory)cdf).BlockOrNull?.Context.Permissions.IsContentAdmin ?? false;\n\n        if (!userMayEdit)\n            return new System.Web.HtmlString(\"\");\n\n        if (cdf.CompatibilityLevel > CompatibilityLevels.MaxLevelForEntityDotToolbar)\n            throw new(\"content.Toolbar is deprecated in the new RazorComponent. Use @Edit.TagToolbar(content) or @Edit.Toolbar(content) instead. See https://go.2sxc.org/EditToolbar\");\n\n        var toolbar = new ItemToolbar(entity).ToolbarAsTag;\n        return new System.Web.HtmlString(toolbar);\n\n    }\n\n    public IRawHtmlString Render(ICodeDataFactory cdf, ICanBeItem target)\n    {\n        if (cdf.CompatibilityLevel > CompatibilityLevels.MaxLevelForEntityDotRender)\n            throw new(\"content.Render() is deprecated in the new RazorComponent. Use GetService&lt;ToSic.Sxc.Services.IRenderService&gt;().One(content) instead.\");\n\n        return cdf.GetService<IRenderService>().One(target);\n    }\n}\n#endif\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/Eav/ToSic.Eav.Data.MetadataFor.cs",
    "content": "﻿// 2019-11-13 2dm - introduced this, because we moved metadatafor to Metadata (backwards compatibility)\n// it's used by others, like on https://stackoverflow.com/questions/55814403/2sxc-web-api-create-content-item-metadata-for-adam-asset\n\n// ReSharper disable once CheckNamespace\n\nusing ToSic.Eav.Metadata.Targets;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Eav.Data;\n\npublic class MetadataFor: Target;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/Eav.Configuration/FeatureIds.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Eav.Configuration;\n\n/// <summary>\n/// Note: these values are possibly used in published Apps - not often, but it's possible.\n/// The apps would use this to check if one of the older features existed.\n/// Just make sure we don't use them in our code. \n/// </summary>\n[PrivateApi(\"this should probably never be public, as we want to rename things at will\")]\n[Obsolete]\npublic class FeatureIds\n{\n    // Important: these names are public - don't ever change them\n    public static Guid PublicForms => BuiltInFeatures.PublicEditForm.Guid;\n    public static Guid PublicUpload => BuiltInFeatures.PublicUploadFiles.Guid;\n    public static Guid UseAdamInWebApi => BuiltInFeatures.SaveInAdamApi.Guid;\n    public static Guid PermissionCheckUserId => BuiltInFeatures.PermissionCheckUsers.Guid;\n    public static Guid PermissionCheckGroups => BuiltInFeatures.PermissionCheckGroups.Guid;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/Eav.Configuration/IFeaturesService.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Eav.Configuration;\n\n/// <summary>\n/// Features lets your code find out what system features are currently enabled/disabled in the environment.\n/// It's important to detect if the admin must activate certain features to let your code do it's work.\n/// </summary>\n/// <remarks>\n/// This replaces the older static Features accessor - please only use this from now on\n/// </remarks>\n[PrivateApi(\"was published in previous versions of 2sxc, so we must keep this available, but don't plan on providing it any more\")]\npublic interface IFeaturesService\n{\n    /// <summary>\n    /// Checks if a feature is enabled\n    /// </summary>\n    /// <param name=\"guid\">The feature Guid</param>\n    /// <returns>true if the feature is enabled</returns>\n    bool Enabled(Guid guid);\n\n    /// <summary>\n    /// Checks if a list of features are enabled, in case you need many features to be activated.\n    /// </summary>\n    /// <param name=\"guids\">list/array of Guids</param>\n    /// <returns>true if all features are enabled, false if any one of them is not</returns>\n    bool Enabled(IEnumerable<Guid> guids);\n\n\n    /// <summary>\n    /// Informs you if the enabled features are valid or not - meaning if they have been countersigned by the 2sxc features system.\n    /// As of now, it's not enforced, but in future it will be. \n    /// </summary>\n    /// <returns>true if the features were signed correctly</returns>\n    bool Valid { get; }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/Eav.Configuration/ToSic.Eav.Configuration.Features.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Eav.Configuration;\n\n/// <summary>\n/// This in an old API for determining if a system feature is enabled. Some will continue to work, but you should not use them.\n///\n/// Prefer to use the IFeatureService instead\n/// </summary>\n[Obsolete(\"Obsolete in 2sxc 12 - please use the IFeaturesService instead\")]\n[PrivateApi(\"this is just fyi, hidden since 2022-01-04\")]\npublic static class Features\n{\n\n    /// <summary>\n    /// Informs you if the enabled features are valid or not - meaning if they have been countersigned by the 2sxc features system.\n    /// As of now, it's not enforced, but in future it will be. \n    /// </summary>\n    /// <returns>true if the features were signed correctly</returns>\n    [PrivateApi]\n    [Obsolete(\"Deprecated in 2sxc 12 - use IFeatures.Valid\")]\n    public static bool Valid => LibSysFeaturesService.ValidInternal;\n\n    public static ISysFeaturesService FeaturesFromDi { get; internal set; }= null;\n\n    /// <summary>\n    /// Checks if a feature is enabled\n    /// </summary>\n    /// <param name=\"guid\">The feature Guid</param>\n    /// <returns>true if the feature is enabled</returns>\n    [Obsolete(\"Do not use anymore, get the IFeaturesService for this. Will not remove for a long time, because in use in public Apps like Mobius\")]\n    public static bool Enabled(Guid guid) => FeaturesFromDi.IsEnabled(guid);\n\n    /// <summary>\n    /// Checks if a list of features are enabled, in case you need many features to be activated.\n    /// </summary>\n    /// <param name=\"guids\">list/array of Guids</param>\n    /// <returns>true if all features are enabled, false if any one of them is not</returns>\n    [Obsolete(\"Do not use anymore, get the IFeaturesService for this. Will not remove for a long time, because in use in public Apps like Mobius\")]\n    public static bool Enabled(IEnumerable<Guid> guids) => FeaturesFromDi.IsEnabled(guids);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/Eav.Configuration/ToSic.Eav.Configuration.FeaturesService.Compatibility.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Eav.Configuration;\n\n/// <summary>\n/// Implementation for an old API which was used in some Dnn Apps\n/// Once it works, we will move it do Dnn only, so it won't work in Oqtane.\n/// </summary>\ninternal class FeaturesServiceCompatibility(ISysFeaturesService featsInternal) : IFeaturesService\n{\n    public bool Enabled(Guid guid) => featsInternal.IsEnabled(guid);\n\n    public bool Enabled(IEnumerable<Guid> guids) => featsInternal.IsEnabled(guids);\n\n    public bool Valid => featsInternal.Valid;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/StartUpCompatibility.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Configuration;\nusing ToSic.Sxc.Data.Sys;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Compatibility;\n\ninternal static class StartUpCompatibility\n{\n    /// <summary>\n    /// Add obsolete interfaces which had previously been supported\n    /// </summary>\n    /// <param name=\"services\"></param>\n    /// <returns></returns>\n    public static IServiceCollection AddDnnCompatibility(this IServiceCollection services)\n    {\n        services.TryAddTransient<ILogService, LogServiceUsingOldInterface>();\n        services.TryAddTransient<Eav.Configuration.IFeaturesService, FeaturesServiceCompatibility>();\n\n        // Helper so that the old DynamicEntity can get a toolbar\n        services.TryAddTransient<IOldDynamicEntityFeatures, OldDynamicEntityFeatures>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/Sxc/OldDataToDictionaryWrapper.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.DataSource;\nusing ToSic.Sxc.Data.Sys.Convert;\n\nnamespace ToSic.Sxc.Compatibility.Sxc;\n\n/// <summary>\n/// This is for compatibility - old code had a Sxc.Serializer.Prepare code which should still work\n/// </summary>\n// Important: Changed Dictionary... to IDictionary in 12.04 2021-08-29 - may cause issues, but probably shouldn't\n[Obsolete]\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OldDataToDictionaryWrapper\n{\n    public OldDataToDictionaryWrapper(bool userMayEdit, IConvertToEavLight innerConverter)\n    {\n        _converter = innerConverter;\n        if (_converter is ConvertToEavLightWithCmsInfo serializerWithEdit) serializerWithEdit.WithEdit = userMayEdit;\n    }\n\n    private readonly IConvertToEavLight _converter;\n\n    public IEnumerable<IDictionary<string, object>> Prepare(IEnumerable<dynamic> dynamicList)\n        => _converter.Convert(dynamicList);\n\n    public IDictionary<string, object> Prepare(ICanBeEntity dynamicEntity)\n        => _converter.Convert(dynamicEntity);\n\n    public IDictionary<string, IEnumerable<EavLightEntity>> Prepare(IDataSource source,\n        IEnumerable<string> streams = null)\n        => _converter.Convert(source, streams);\n\n    public IDictionary<string, IEnumerable<EavLightEntity>> Prepare(IDataSource source, string streams)\n        => _converter.Convert(source, streams);\n\n    public IEnumerable<IDictionary<string, object>> Prepare(IDataStream stream)\n        => _converter.Convert(stream);\n\n    public IEnumerable<IDictionary<string, object>> Prepare(IEnumerable<IEntity> entities)\n        => _converter.Convert(entities);\n\n    // Removed in v20\n    //public IEnumerable<IDictionary<string, object>> Prepare(IEnumerable<ToSic.Eav.Interfaces.IEntity> entities)\n    //    => _converter.Convert(entities as IEnumerable<IEntity>);\n\n    public IDictionary<string, object> Prepare(IEntity entity)\n        => _converter.Convert(entity);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Compatibility/Sxc/SxcHelper.cs",
    "content": "﻿using ToSic.Eav.DataFormats.EavLight;\n\nnamespace ToSic.Sxc.Compatibility.Sxc;\n\n/// <summary>\n/// This is for compatibility - old code had a Sxc.Serializer.Prepare code which should still work\n/// </summary>\n[Obsolete]\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcHelper(bool editAllowed, IConvertToEavLight innerConverter)\n{\n    public OldDataToDictionaryWrapper Serializer => field ??= new(editAllowed, innerConverter);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.Eav.Conversion.EntitiesToDictionary.cs",
    "content": "﻿// ReSharper disable once CheckNamespace\nnamespace ToSic.Eav.Conversion;\n\n/// <summary>\n/// Deprecated since v12, announced for removal in v15, removed in v20.\n/// </summary>\n[PrivateApi(\"Made private in v12.04, as it shouldn't be used in razor - but previously it was in some apps so we must assume it's in use\")]\n[Obsolete]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EntitiesToDictionary\n{\n    public EntitiesToDictionary()\n        => throw new NotSupportedException(ToSic.Eav.Factory.GenerateMessage(\"ToSic.Eav.Conversion.EntitiesToDictionary\", \"https://go.2sxc.org/brc-13-conversion\"));\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.Eav.Factory.cs",
    "content": "﻿// ReSharper disable once CheckNamespace\nnamespace ToSic.Eav;\n\n/// <summary>\n/// Deprecated since v13, announced for removal in v15, removed in v20.\n/// </summary>\n[PrivateApi(\"Up to v19 used to PublicApi(Careful - obsolete!)\")]\n[Obsolete]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class Factory\n{\n    internal static string GenerateMessage(string fullNameSpace, string link)\n        => $\"The old '{fullNameSpace}' API has been deprecated since v13 and announced for removal in v15. They were removed in v20. \" +\n           $\"For guidance, see {link}.\";\n\n    [Obsolete]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static T Resolve<T>()\n        => throw new NotSupportedException(GenerateMessage(\"ToSic.Eav.Factory.Resolve()\", \"https://go.2sxc.org/brc-13-eav-factory\"));\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.SexyContent.ContentBlocks.Render.cs",
    "content": "﻿#if NETFRAMEWORK\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.SexyContent.ContentBlocks;\n\n/// <summary>\n/// Deprecated since v13, announced for removal in v15, removed in v20.\n/// Remove this entire class (which currently just shows warnings) EOY 2025.\n/// </summary>\n[Obsolete]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class Render\n{\n    [Obsolete]\n    public static string One(object context, object noParamOrder = default, object item = null, string field = null, Guid? newGuid = null)\n        => throw new(ToSic.Sxc.Blocks.Render.GenerateMessage(\"ToSic.SexyContent.ContentBlocks.One()\"));\n\n    [Obsolete]\n    public static string All(object context, object noParamOrder = default, string field = null, string merge = null)\n        => throw new(ToSic.Sxc.Blocks.Render.GenerateMessage(\"ToSic.SexyContent.ContentBlocks.All()\"));\n}\n\n#endif"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.SexyContent.DataSources.DnnSqlDataSource.cs",
    "content": "﻿// #RemoveV20 - the new class auto-supports the old name; only code use will break\n\n//using ToSic.Eav.DataSources;\n\n//// ReSharper disable once CheckNamespace\n//namespace ToSic.SexyContent.DataSources;\n\n//// Todo: leave this helper class/message in till 2sxc 09.00, then either extract into an own DLL\n//// - we might also write some SQL to update existing pipelines, but it's not likely to have been used much...\n//// - and otherwise im might be in razor-code, which we couldn't auto-update\n\n//[Obsolete(\"This class was moved / to the ToSic.Sxc.Dnn.DataSources namespace, use that instead.\")]\n//public class DnnSqlDataSource(Sql.MyServices services)\n//    : Sxc.Dnn.DataSources.DnnSql(services);"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.SexyContent.Engines.InstancePurposes.cs",
    "content": "﻿//#if NETFRAMEWORK\n\n//// This is included for compatibility\n//// It was changed in 2sxc 10.20. 01, but some code in the wild probably uses this for comparison.\n//// old docs like https://github.com/2sic/2sxc/wiki/razor-sexycontentwebpage.instancepurpose used this namespaces\n\n//// ReSharper disable once CheckNamespace\n//namespace ToSic.SexyContent.Engines\n//{\n//    [Obsolete]\n//    [ShowApiWhenReleased(ShowApiMode.Never)]\n//    public enum InstancePurposes\n//    {\n//        WebView = 0,\n//        IndexingForSearch = 1,\n//    }\n//}\n//#endif"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.SexyContent.Environment.Dnn7.DataSources.DnnSqlDataSource.cs",
    "content": "﻿// #RemoveV20 - the new class auto-supports the old name; only code use will break\n\n//using ToSic.Eav.DataSources;\n\n//// ReSharper disable once CheckNamespace\n//namespace ToSic.SexyContent.Environment.Dnn7.DataSources;\n\n//// Todo: leave this helper class/message in till 2sxc 09.00, then either extract into an own DLL\n//// - we might also write some SQL to update existing pipelines, but it's not likely to have been used much...\n//// - and otherwise im might be in razor-code, which we couldn't auto-update\n\n//[PrivateApi]\n//[ShowApiWhenReleased(ShowApiMode.Never)]\n//[Obsolete(\"This class was moved / to ToSic.Sxc.Dnn.DataSources.DnnSql, use that instead.\")]\n//public class DnnSqlDataSource(Sql.MyServices services)\n//    : Sxc.Dnn.DataSources.DnnSql(services);"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.SexyContent.Environment.Dnn7.DataSources.DnnUserProfileDataSource.cs",
    "content": "﻿// #RemoveV20 - the new class auto-supports the old name; only code use will break\n\n//using ToSic.Eav.Data.Build;\n//using ToSic.Sxc.Dnn.DataSources;\n\n//// ReSharper disable once CheckNamespace\n//namespace ToSic.SexyContent.Environment.Dnn7.DataSources;\n\n//// Todo: leave this helper class/message in till 2sxc 09.00, then either extract into an own DLL\n//// - we might also write some SQL to update existing pipelines, but it's not likely to have been used much...\n//// - and otherwise im might be in razor-code, which we couldn't auto-update\n\n//[PrivateApi]\n//[ShowApiWhenReleased(ShowApiMode.Never)]\n//[Obsolete(\"This class was moved / to ToSic.Sxc.Dnn.DataSources.DnnUserProfile, use that instead.\")]\n//public class DnnUserProfileDataSource(DnnUserProfile.MyServices services, IDataFactory dataFactory)\n//    : DnnUserProfile(services);"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.SexyContent.Environment.Dnn7.Factory.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Portals;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Render.Sys.RenderBlock;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.SexyContent.Environment.Dnn7;\n\n/// <summary>\n/// Deprecated since v13, announced for removal in v15, removed in v20.\n/// </summary>\n[Obsolete]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class Factory\n{\n    [Obsolete]\n    public static IBlockBuilder SxcInstanceForModule(int modId, int pageId)\n        => throw new NotSupportedException(Sxc.Dnn.Factory.GenerateMessage());\n\n    [Obsolete]\n    public static IBlockBuilder SxcInstanceForModule(ModuleInfo moduleInfo)\n        => throw new NotSupportedException(Sxc.Dnn.Factory.GenerateMessage());\n\n    [Obsolete]\n    public static IBlockBuilder SxcInstanceForModule(IModule moduleInfo)\n        => throw new NotSupportedException(Sxc.Dnn.Factory.GenerateMessage());\n\n\n    [Obsolete]\n    public static IDynamicCode CodeHelpers(IBlockBuilder blockBuilder)\n        => throw new NotSupportedException(Sxc.Dnn.Factory.GenerateMessage());\n\n    /// <summary>\n    /// get a full app-object for accessing data of the app from outside\n    /// </summary>\n    /// <returns></returns>\n    [Obsolete]\n    public static IApp App(int appId, bool unusedButKeepForApiStability = false, bool showDrafts = false)\n        => throw new NotSupportedException(Sxc.Dnn.Factory.GenerateMessage());\n\n    /// <summary>\n    /// get a full app-object for accessing data of the app from outside\n    /// </summary>\n    /// <returns></returns>\n    [Obsolete]\n    public static IApp App(int zoneId, int appId, bool unusedButKeepForApiStability = false, bool showDrafts = false)\n        => throw new NotSupportedException(Sxc.Dnn.Factory.GenerateMessage());\n\n    [Obsolete]\n    public static IApp App(int appId, PortalSettings ownerPortalSettings, bool unusedButKeepForApiStability = false, bool showDrafts = false)\n        => throw new NotSupportedException(Sxc.Dnn.Factory.GenerateMessage());\n\n\n    [Obsolete]\n    public static IApp App(int zoneId, int appId, PortalSettings ownerPortalSettings, bool unusedButKeepForApiStability = false, bool showDrafts = false)\n        => throw new NotSupportedException(Sxc.Dnn.Factory.GenerateMessage());\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.Sxc.Blocks.Render.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Blocks;\n\n/// <summary>\n/// Deprecated since v12, announced for removal in v15, removed in v20.\n/// </summary>\n[PrivateApi]\n[Obsolete]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class Render\n{\n    internal static string GenerateMessage(string fullNameSpace)\n        => $\"The old {fullNameSpace} API has been deprecated since v12 and announced for removal in v15. They were removed in v20. \" +\n           $\"Please use the @Kit.Render.One(...)/All(...) instead. \" +\n           $\"For guidance, see https://go.2sxc.org/brc-20-static-render\";\n\n    [Obsolete]\n    public static string One(object parent, object noParamOrder = default, object item = null, string field = null, object newGuid = null)\n        => throw new(GenerateMessage(\"ToSic.Sxc.Blocks.One()\"));\n\n    [Obsolete]\n    public static string All(object parent, object noParamOrder = default, string field = null, string apps = null, int max = 100, string merge = null)\n        => throw new(GenerateMessage(\"ToSic.Sxc.Blocks.All()\"));\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.Sxc.Conversion.DataToDictionary.cs",
    "content": "﻿// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Conversion;\n\n/// <summary>\n/// Deprecated since v13, announced for removal in v15, removed in v20.\n/// </summary>\n[Obsolete]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DataToDictionary\n{\n    [Obsolete]\n    public DataToDictionary()\n        => throw new NotSupportedException(ToSic.Eav.Factory.GenerateMessage(\"ToSic.Sxc.Conversion.DataToDictionary\", \"https://go.2sxc.org/brc-13-conversion\"));\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.Sxc.Dnn.Factory.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// Deprecated since v13, announced for removal in v15, removed in v20.\n/// </summary>\n[Obsolete]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class Factory\n{\n    internal static string GenerateMessage([CallerMemberName] string cName = default)\n        => $\"The old {nameof(Factory)}.{cName}() API has been deprecated since v13 and announced for removal in v15. They were removed in v20. \" +\n           $\"Please use Dependency Injection and the IRenderService or IDynamicCodeService instead. \" +\n           $\"For guidance, see https://go.2sxc.org/brc-20-dnn-factory\";\n\n    [Obsolete]\n    public static object CmsBlock(int pageId, int modId)\n        => throw new NotSupportedException(GenerateMessage());\n\n    [Obsolete]\n    public static object CmsBlock(int pageId, int modId, object parentLog)\n        => throw new NotSupportedException(GenerateMessage());\n\n    [Obsolete]\n    public static object CmsBlock(object moduleInfo)\n        => throw new NotSupportedException(GenerateMessage());\n\n    [Obsolete]\n    public static object CmsBlock(object module, object parentLog = null)\n        => throw new NotSupportedException(GenerateMessage());\n\n    [Obsolete]\n    public static object DynamicCode(object blockBuilder)\n        => throw new NotSupportedException(GenerateMessage());\n\n    [Obsolete]\n    public static object App(int appId, bool unusedButKeepForApiStability = false, bool showDrafts = false, object parentLog = null)\n        => throw new NotSupportedException(GenerateMessage());\n\n    [Obsolete]\n    public static object App(int zoneId, int appId, bool unusedButKeepForApiStability = false, bool showDrafts = false, object parentLog = null)\n        => throw new NotSupportedException(GenerateMessage());\n\n    [Obsolete]\n    public static object App(int appId, object ownerPortalSettings, bool unusedButKeepForApiStability = false, bool showDrafts = false, object parentLog = null)\n        => throw new NotSupportedException(GenerateMessage());\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.Sxc.Services.ILogService.cs",
    "content": "﻿// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Obsolete, use <see cref=\"ISystemLogService\"/> instead.\n/// Note: 2024-04-22 2dm - believe this could be internal, but not 100% sure\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ILogService: ISystemLogService;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/CompatibilityStopped/ToSic.Sxc.Services.LogService.cs",
    "content": "﻿using ToSic.Sxc.Dnn.Services;\nusing ToSic.Sys.Code.InfoSystem;\n\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Obsolete, use <see cref=\"ISystemLogService\"/> instead\n/// </summary>\ninternal class LogServiceUsingOldInterface: DnnSystemLogService\n{\n    public LogServiceUsingOldInterface(CodeInfoService codeInfos)\n    {\n        throw new(\"The ToSic.Sxc.Services.ILogServices is deprecated / removed. Please use ToSic.Sxc.Services.ISystemLogService instead.\");\n        //codeInfos.Warn(V16To18(\"ToSic.Sxc.Services.ILogService\", message: \"Use ToSic.Sxc.Services.ISystemLogService instead\"));\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Custom.Dnn/Code12.cs",
    "content": "﻿using ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.Run;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Dnn;\n\n/// <summary>\n/// This is the base class for custom code (.cs) files in your Apps.\n/// By inheriting from this base class, you will automatically have the context like the App object etc. available. \n/// </summary>\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]   // #DocsButNotForIntellisense\npublic abstract class Code12 : DynamicCode12, IHasDnn\n{\n    /// <inheritdoc />\n    public IDnnContext Dnn => (ExCtxOrNull as IHasDnn)?.Dnn;\n\n    [PrivateApi] public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Adam/DnnAdam.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys;\n\nnamespace ToSic.Sxc.Dnn.Adam;\n\n/// <summary>\n/// Casting helpers so DNN code can work with the file / folder in the DNN signature\n/// </summary>\ninternal static class DnnAdam\n{\n    internal static File<int, int> AsDnn(this IFile file)\n    {\n        if (file == null)\n            return null;\n        if (file is not File<int, int> recast)\n            throw new(\"Tried to cast IFile to internal type, failed\");\n        return recast;\n    }\n\n    internal static Folder<int, int> AsDnn(this IFolder folder)\n    {\n        if (folder == null)\n            return null;\n        if (folder is not Folder<int, int> recast)\n            throw new(\"Tried to cast IFolder to internal type, failed\");\n        return recast;\n\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Adam/DnnAdamFileSystem.cs",
    "content": "﻿using DotNetNuke.Services.FileSystem;\nusing System.Configuration;\nusing System.Data.SqlClient;\nusing System.Web.Configuration;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.FileSystem;\nusing ToSic.Sxc.Adam.Sys.Manager;\n\nnamespace ToSic.Sxc.Dnn.Adam;\n\ninternal class DnnAdamFileSystem() : ServiceBase(\"Dnn.FilSys\"), IAdamFileSystem\n{\n    #region Constructor / DI / Init\n\n    public void Init(AdamManager adamManager)\n    {\n        var l = Log.Fn();\n        AdamManager = adamManager;\n        l.Done();\n    }\n\n    protected AdamManager AdamManager;\n\n    #endregion\n\n    #region FileSystem Settings\n\n    public int MaxUploadKb()\n        => (ConfigurationManager.GetSection(\"system.web/httpRuntime\") as HttpRuntimeSection)\n            ?.MaxRequestLength ?? 1;\n\n    #endregion\n\n    #region Files\n    private readonly IFileManager _dnnFiles = FileManager.Instance;\n\n    //public File<int, int> GetFile(int fileId)\n    //{\n    //    var file = _dnnFiles.GetFile(fileId);\n    //    return DnnToAdam(file);\n    //}\n\n    public IFile GetFile(AdamAssetIdentifier fileId)\n    {\n        var id = ((AdamAssetId<int>)fileId).SysId;\n        var file = _dnnFiles.GetFile(id);\n        return DnnToAdam(file);\n    }\n\n    public void Rename(IFile file, string newName)\n    {\n        var l = Log.Fn($\"{nameof(file)}:{file.Id}, {nameof(newName)}: {newName}\");\n        var dnnFile = _dnnFiles.GetFile(file.AsDnn().SysId);\n        _dnnFiles.RenameFile(dnnFile, newName);\n        l.Done();\n    }\n\n    public void Delete(IFile file)\n    {\n        var l = Log.Fn($\"file: {file.Id}\", timer: true);\n        var dnnFile = _dnnFiles.GetFile(file.AsDnn().SysId);\n        // 2025-06 For unknown reasons this suddenly breaks; same DNN, some 2sxc code\n        // Says file is in use, but if we debug-step-through, it works; seems to be timing\n        Retry.RetryOnException(() => _dnnFiles.DeleteFile(dnnFile), l, repeat: 10, delay: 200, silent: false);\n\n        l.Done();\n    }\n\n    public IFile Add(IFolder parent, Stream body, string fileName, bool ensureUniqueName)\n    {\n        var l = Log.Fn<IFile>($\"..., {fileName}, {ensureUniqueName}\");\n        if (ensureUniqueName) fileName = FindUniqueFileName(parent, fileName);\n        var dnnFolder = _dnnFolders.GetFolder(parent.AsDnn().SysId);\n        var dnnFile = _dnnFiles.AddFile(dnnFolder, Path.GetFileName(fileName), body);\n        var file = GetFile(AdamAssetIdentifier.Create(dnnFile.FileId));\n        return l.ReturnAsOk(file);\n    }\n\n    /// <summary>\n    /// When uploading a new file, we must verify that the name isn't used. \n    /// If it is used, walk through numbers to make a new name which isn't used. \n    /// </summary>\n    /// <param name=\"parentFolder\"></param>\n    /// <param name=\"fileName\"></param>\n    /// <returns></returns>\n    private string FindUniqueFileName(IFolder parentFolder, string fileName)\n    {\n        var l = Log.Fn<string>($\"..., {fileName}\");\n        var dnnFolder = _dnnFolders.GetFolder(parentFolder.AsDnn().SysId);\n        var name = Path.GetFileNameWithoutExtension(fileName);\n        var ext = Path.GetExtension(fileName);\n        for (var i = 1;\n             i < AdamConstants.MaxSameFileRetries &&\n             _dnnFiles.FileExists(dnnFolder, Path.GetFileName(fileName));\n             i++)\n            fileName = $\"{name}-{i}{ext}\";\n\n        return l.ReturnAsOk(fileName);\n    }\n\n    #endregion\n\n\n\n    #region Folders\n        \n    private readonly IFolderManager _dnnFolders = FolderManager.Instance;\n\n    public bool FolderExists(string path)\n    {\n        var l = Log.Fn<bool>($\"path:{path}\");\n        return l.ReturnAsOk(_dnnFolders.FolderExists(AdamManager.Site.Id, path));\n    } \n        \n\n    public void AddFolder(string path)\n    {\n        var l = Log.Fn($\"path:{path}\");\n        try\n        {\n            _dnnFolders.AddFolder(AdamManager.Site.Id, path);\n            l.Done(\"ok\");\n        }\n        catch (SqlException)\n        {\n            // don't do anything - this happens when multiple processes try to add the folder at the same time\n            // like when two fields in a dialog cause the web-api to create the folders in parallel calls\n            // see also https://github.com/2sic/2sxc/issues/811\n            l.Done(\"error in DNN SQL, probably folder already exists\");\n        }\n        catch (FolderAlreadyExistsException)\n        {\n            // Dnn reports it already exists - it shouldn't have got here because that was checked before\n            // but I guess depending on the DNN version this isn't 100% reliable\n            l.Done(\"Dnn says folder already exists\");\n        }\n        catch (NullReferenceException)\n        {\n            // also catch this, as it's an additional exception which also happens in the AddFolder when a folder already existed\n            l.Done(\"error, probably folder already exists\");\n        }\n    }\n\n    public void Rename(IFolder folder, string newName)\n    {\n        var l = Log.Fn($\"folder:{folder.Id}, newName:{newName}\");\n        var fld = _dnnFolders.GetFolder(folder.AsDnn().SysId);\n        _dnnFolders.RenameFolder(fld, newName);\n        l.Done();\n    }\n\n    public void Delete(IFolder folder)\n    {\n        var l = Log.Fn($\"folder:{folder.Id}\");\n        _dnnFolders.DeleteFolder(folder.AsDnn().SysId);\n        l.Done();\n    }\n\n\n    public IFolder Get(string path)\n    {\n        var l = Log.Fn<IFolder>($\"path:{path}\");\n        return l.ReturnAsOk(DnnToAdam(_dnnFolders.GetFolder(AdamManager.Site.Id, path)));\n    }\n\n\n    public List<IFolder> GetFolders(IFolder folder)\n    {\n        var l = Log.Fn<List<IFolder>>($\"folder:{folder.Id}\");\n        var fldObj = GetDnnFolder(folder.AsDnn().SysId);\n        if (fldObj == null) return l.Return([], \"\");\n\n        var firstList = _dnnFolders.GetFolders(fldObj);\n        var folders = firstList?.Select(DnnToAdam).ToList()\n                      ?? [];\n        return l.Return(folders, $\"{folders.Count}\");\n    }\n\n    //public Folder<int, int> GetFolder(int folderId)\n    //    => DnnToAdam(GetDnnFolder(folderId));\n\n    public IFolder GetFolder(AdamAssetIdentifier folderId)\n        => DnnToAdam(GetDnnFolder(((AdamAssetId<int>)folderId).SysId));\n\n\n    #endregion\n\n\n\n\n    #region Dnn typed calls\n\n    private IFolderInfo GetDnnFolder(int folderId) => _dnnFolders.GetFolder(folderId);\n\n\n    public List<IFile> GetFiles(IFolder folder)\n    {\n        var l = Log.Fn<List<IFile>>($\"folder:{folder.Id}\");\n        var fldObj = _dnnFolders.GetFolder(folder.AsDnn().SysId);\n        // sometimes the folder doesn't exist for whatever reason\n        if (fldObj == null)\n            return l.Return([], \"\");\n\n        // try to find the files\n        var firstList = _dnnFolders.GetFiles(fldObj);\n        var files = firstList?.Select(DnnToAdam).ToList()\n                    ?? [];\n        return l.Return(files, $\"{files.Count}\");\n    }\n\n    #endregion\n\n    #region DnnToAdam\n\n    private const string ErrorDnnObjectNull = \"Tried to create Adam object but the original is invalid. \" +\n                                              \"Probably the DNN file system is out of sync. \" +\n                                              \"Re-Sync in the DNN files recursively (in Admin - Files) and the error should go away. \";\n\n    public string GetUrl(string folderPath) => AdamManager.Site.ContentPath + folderPath;\n\n    private IFolder DnnToAdam(IFolderInfo dnnFolderInfo)\n    {\n        var l = Log.Fn<Folder<int, int>>($\"folderName: {dnnFolderInfo.FolderName}\");\n\n        if (dnnFolderInfo == null)\n            throw l.Done(new ArgumentNullException(nameof(dnnFolderInfo), ErrorDnnObjectNull));\n\n        var typed = new Folder<int, int>(AdamManager)\n            {\n                Path = dnnFolderInfo.FolderPath,\n                SysId = dnnFolderInfo.FolderID,\n\n                ParentSysId = dnnFolderInfo.ParentID,\n\n                Name = dnnFolderInfo.DisplayName,\n                Created = dnnFolderInfo.CreatedOnDate,\n                Modified = dnnFolderInfo.LastModifiedOnDate,\n                Url = GetUrl(dnnFolderInfo.FolderPath), // AdamManager.Site.ContentPath + dnnFolderInfo.FolderPath,\n                PhysicalPath = dnnFolderInfo.PhysicalPath,\n            };\n        if (AdamManager.UseTypedAssets)\n            return l.Return(typed, \"typed\");\n\n        var dyn = FolderDynamic<int, int>.Create(AdamManager, typed);\n        return l.Return(dyn, \"dynamic\");\n    }\n\n\n    private IFile DnnToAdam(IFileInfo dnnFileInfo)\n    {\n        var l = Log.Fn<File<int, int>>($\"fileName: {dnnFileInfo.FileName}\");\n            \n        if (dnnFileInfo == null)\n            throw l.Done(new ArgumentNullException(nameof(dnnFileInfo), ErrorDnnObjectNull));\n\n        var typed = new File<int, int>(AdamManager)\n        {\n            FullName = dnnFileInfo.FileName!,\n            Extension = dnnFileInfo.Extension,\n            Size = dnnFileInfo.Size,\n            SysId = dnnFileInfo.FileId,\n            Folder = dnnFileInfo.Folder,\n            ParentSysId = dnnFileInfo.FolderId,\n\n            Path = dnnFileInfo.RelativePath,\n\n            Created = dnnFileInfo.CreatedOnDate,\n            Modified = dnnFileInfo.LastModifiedOnDate,\n            Name = Path.GetFileNameWithoutExtension(dnnFileInfo.FileName),\n            Url = dnnFileInfo.StorageLocation == 0\n                ? $\"{AdamManager.Site.ContentPath}{dnnFileInfo.Folder}{dnnFileInfo.FileName}\"\n                : FileLinkClickController.Instance.GetFileLinkClick(dnnFileInfo),\n            PhysicalPath = dnnFileInfo.PhysicalPath,\n        };\n        if (AdamManager.UseTypedAssets)\n            return l.Return(typed, \"typed\");\n\n        var dyn = FileDynamic<int, int>.Create(AdamManager, typed);\n        return l.Return(dyn, \"dynamic\");\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Cms/DnnModuleSettings.cs",
    "content": "﻿using DotNetNuke.Common.Utilities;\nusing DotNetNuke.Entities.Modules;\n\nnamespace ToSic.Sxc.Dnn.Cms;\n\ninternal class ModuleSettingsHelper \n{\n    public ModuleInfo ModuleInfo { get; set; }\n\n    public ModuleSettingsHelper(int instanceId)\n    {\n        ModuleInfo = ModuleController.Instance.GetModule(instanceId, Null.NullInteger, true);\n    }\n\n    public string GetModuleSetting(string settingName, string defaultValue)\n    {\n        if (ModuleInfo.ModuleSettings.ContainsKey(settingName))\n            return (string) ModuleInfo.ModuleSettings[settingName];\n        return defaultValue;\n    }\n\n    public void SetModuleSetting(string settingName, string settingValue)\n    {\n        if (ModuleInfo.ModuleSettings.ContainsKey(settingName))\n            ModuleInfo.ModuleSettings[settingName] = settingValue;\n        else\n            ModuleInfo.ModuleSettings.Add(settingName, settingValue);\n        ModuleController.Instance.UpdateModule(ModuleInfo);\n    }\n\n    public void DeleteModuleSetting(string settingName)\n    {\n        if (ModuleInfo.ModuleSettings.ContainsKey(settingName))\n        {\n            ModuleInfo.ModuleSettings.Remove(settingName);\n            ModuleController.Instance.UpdateModule(ModuleInfo);\n        }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Cms/DnnModuleUpdater.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Services.Localization;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.Metadata.Sys;\nusing ToSic.Sxc.Apps.Sys.Work;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Integration.Modules;\n\nnamespace ToSic.Sxc.Dnn.Cms;\n\n// TODO: @STV - this looks very similar to the Oqtane implementation\n// Probably best to make a base class and de-duplicate.\ninternal class DnnModuleUpdater(\n    GenWorkPlus<WorkViews> workViews,\n    IZoneMapper zoneMapper,\n    IAppsCatalog appsCatalog,\n    ISite site)\n    : ServiceBase(\"Dnn.MapA2I\", connect: [workViews, appsCatalog, site, zoneMapper]), IPlatformModuleUpdater\n{\n    public void SetAppId(IModule instance, int? appId)\n    {\n        var l = Log.Fn($\"SetAppIdForInstance({instance.Id}, -, appid: {appId})\");\n        // Reset temporary template\n        ClearPreview(instance.Id);\n\n        // ToDo: Should throw exception if a real BlockConfiguration exists\n        // note: this is the correct zone, even if the module is shared from another portal, because the Site is prepared correctly\n        var zoneId = site.ZoneId;\n\n        if (appId is KnownAppsConstants.AppIdEmpty or null)\n            UpdateInstanceSettingForAllLanguages(instance.Id, ModuleSettingNames.AppName, null, Log);\n        else\n        {\n            var appName = appsCatalog.AppNameId(new AppIdentity(zoneId, appId.Value));\n            UpdateInstanceSettingForAllLanguages(instance.Id, ModuleSettingNames.AppName, appName, Log);\n        }\n\n        // Change to 1. available preferable default template if app has been set\n        if (appId.HasValue)\n        {\n            var appIdentity = new AppIdentity(zoneId, appId.Value);\n\n            var templateGuid = workViews.New(appIdentity).GetAll()\n                .OrderByDescending(v => v.Metadata.HasType(KnownDecorators.IsDefaultDecorator)) // first sort by IsDefaultDecorator DESC\n                .ThenBy(v => v.Name) // than by Name ASC\n                .FirstOrDefault(t => !t.IsHidden)?.Guid;\n\n            if (templateGuid.HasValue) SetPreview(instance.Id, templateGuid.Value);\n        }\n\n        l.Done();\n    }\n\n    protected void ClearPreview(int instanceId)\n    {\n        Log.A($\"ClearPreviewTemplate(iid: {instanceId})\");\n        UpdateInstanceSettingForAllLanguages(instanceId, ModuleSettingNames.PreviewView, null, Log);\n    }\n\n    public void SetContentGroup(int instanceId, bool blockExists, Guid guid)\n    {\n        Log.A($\"SetContentGroup(iid: {instanceId}, {nameof(blockExists)}: {blockExists}, guid: {guid})\");\n        // Remove Preview because it's not needed as soon Content is inserted\n        ClearPreview(instanceId);\n        // Update blockConfiguration Guid for this module\n        if (blockExists)\n            UpdateInstanceSettingForAllLanguages(instanceId, ModuleSettingNames.ContentGroup,\n                guid.ToString(), Log);\n    }\n\n    /// <summary>\n    /// Saves a temporary templateId to the module's settings\n    /// This templateId will be used until a ContentGroup exists\n    /// </summary>\n    public void SetPreview(int instanceId, Guid previewView)\n    {\n        var moduleController = new ModuleController();\n        var settings = moduleController.GetModule(instanceId).ModuleSettings;\n\n        // Do not allow saving the temporary template id if a ContentGroup exists for this module\n        if (settings[ModuleSettingNames.ContentGroup] != null)\n            throw new(\"Preview template id cannot be set for a module that already has content.\");\n\n        UpdateInstanceSettingForAllLanguages(instanceId, ModuleSettingNames.PreviewView, previewView.ToString(), Log);\n    }\n\n    public void UpdateTitle(IBlock block, IEntity titleItem)\n    {\n        Log.A(\"update title\");\n\n        var languages = zoneMapper.CulturesWithState(block.Context.Site);\n\n        // Find Module for default language\n        var moduleController = new ModuleController();\n        var originalModule = moduleController.GetModule(block.Context.Module.Id);\n\n        foreach (var dimension in languages)\n        {\n            if (!originalModule.IsDefaultLanguage)\n                originalModule = originalModule.DefaultLanguageModule;\n\n            try // this can sometimes fail, like if the first item is null - https://github.com/2sic/2sxc/issues/817\n            {\n                // Break if default language module is null\n                if (originalModule == null)\n                    return;\n\n                // Get Title value of Entity in current language\n                var titleValue = titleItem.Title[dimension.Code].ToString();\n\n                // Find module for given Culture\n                var moduleByCulture = moduleController.GetModuleByCulture(originalModule.ModuleID,\n                    originalModule.TabID, block.Context.Site.Id,\n                    DotNetNuke.Services.Localization.LocaleController.Instance.GetLocale(dimension.Code));\n\n                // Break if no title module found\n                if (moduleByCulture == null || titleValue == null)\n                    return;\n\n                moduleByCulture.ModuleTitle = System.Net.WebUtility.HtmlEncode(titleValue);\n                moduleController.UpdateModule(moduleByCulture);\n            }\n            catch { /* ignored */ }\n        }\n    }\n\n\n    #region Settings\n\n\n\n\n    /// <summary>\n    /// Update a setting for all language-versions of a module\n    /// </summary>\n    public static void UpdateInstanceSettingForAllLanguages(int instanceId, string key, string value, ILog log)\n    {\n        log.A($\"UpdateInstanceSettingForAllLanguages(iid: {instanceId}, key: {key}, val: {value})\");\n        var moduleController = new ModuleController();\n\n        // Find this module in other languages and update contentGroupGuid\n        var originalModule = moduleController.GetModule(instanceId);\n        var languages = LocaleController.Instance.GetLocales(originalModule.PortalID);\n\n        if (!originalModule.IsDefaultLanguage && originalModule.DefaultLanguageModule != null)\n            originalModule = originalModule.DefaultLanguageModule;\n\n        foreach (var language in languages)\n        {\n            // Find module for given Culture\n            var moduleByCulture = moduleController.GetModuleByCulture(originalModule.ModuleID, originalModule.TabID, originalModule.PortalID, language.Value);\n\n            // Break if no module found\n            if (moduleByCulture == null)\n                continue;\n\n            if (value == null)\n                moduleController.DeleteModuleSetting(moduleByCulture.ModuleID, key);\n            else\n                moduleController.UpdateModuleSetting(moduleByCulture.ModuleID, key, value);\n        }\n    }\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Cms/DnnPagePublishing.cs",
    "content": "﻿using DotNetNuke.Common.Utilities;\nusing DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Tabs;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Dnn.Context;\nusing ToSic.Sxc.Dnn.Run;\n\nusing ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Dnn.Cms;\n\ninternal partial class DnnPagePublishing(\n    LazySvc<IModuleAndBlockBuilder> moduleAndBlockBuilder,\n    GenWorkDb<WorkEntityPublish> entPublish)\n    : ServiceBase(\"Dnn.Publsh\", connect: [moduleAndBlockBuilder, entPublish]), IPagePublishing\n{\n\n    public void DoInsidePublishing(IContextOfSite context, Action<VersioningActionInfo> action)\n    {\n        var possibleContextOfBlock = context as IContextOfBlock;\n        var enabled = possibleContextOfBlock?.Publishing.ForceDraft ?? false;\n        var instanceId = possibleContextOfBlock?.Module.Id ?? EavConstants.IdNotInitialized;\n        var userId = (context.User as DnnUser)?.GetContents().UserID ?? EavConstants.IdNotInitialized;\n        Log.A($\"DoInsidePublishing(module:{instanceId}, user:{userId}, enabled:{enabled})\");\n\n        if (enabled)\n        {\n            var moduleVersionSettings = new ModuleVersions(instanceId, Log);\n                \n            // Get an new version number and submit it to DNN\n            // The submission must be made every time something changes, because a \"discard\" could have happened\n            // in the meantime.\n            TabChangeTracker.Instance.TrackModuleModification(\n                moduleVersionSettings.ModuleInfo, \n                moduleVersionSettings.IncreaseLatestVersion(), \n                userId\n            );\n        }\n\n        var versioningActionInfo = new VersioningActionInfo();\n        action.Invoke(versioningActionInfo);\n        Log.A(\"/DoInsidePublishing\");\n    }\n\n\n\n    public int GetLatestVersion(int instanceId)\n    {\n        var moduleVersionSettings = new ModuleVersions(instanceId, Log);\n        var ver = moduleVersionSettings.GetLatestVersion();\n        Log.A($\"GetLatestVersion(m:{instanceId}) = ver:{ver}\");\n        return ver;\n    }\n\n    public int GetPublishedVersion(int instanceId)\n    {\n        var moduleVersionSettings = new ModuleVersions(instanceId, Log);\n        var pubVersion = moduleVersionSettings.GetPublishedVersion();\n        Log.A($\"GetPublishedVersion(m:{instanceId}) = pub:{pubVersion}\");\n        return pubVersion;\n    }\n\n\n    public void Publish(int instanceId, int version)\n    {\n        var l = Log.Fn($\"Publish(m:{instanceId}, v:{version})\");\n        try\n        {\n            // publish all entities of this content block\n            var dnnModule = ModuleController.Instance.GetModule(instanceId, Null.NullInteger, true);\n            // must find tenant through module, as the Portal-Settings.Current is null in search mode\n            var cb = moduleAndBlockBuilder.Value.BuildBlock(dnnModule, null);\n\n            l.A($\"found dnn mod {cb.Context.Module.Id}, tenant {cb.Context.Site.Id}, cb exists: {cb.ContentGroupExists}\");\n            if (cb.ContentGroupExists)\n            {\n                l.A(\"cb exists\");\n\n                // Add content entities\n                IEnumerable<IEntity> list = new List<IEntity>();\n                list = TryToAddStream(list, cb.Data, DataSourceConstants.StreamDefaultName);\n                list = TryToAddStream(list, cb.Data, \"ListContent\");\n                list = TryToAddStream(list, cb.Data, \"PartOfPage\");\n\n                // ReSharper disable PossibleMultipleEnumeration\n                // Find related presentation entities\n                var attachedPresItems = list\n                    .Select(e => e.GetDecorator<EntityInBlockDecorator>()?.Presentation)\n                    .Where(p => p != null);\n                l.A($\"adding presentation item⋮{attachedPresItems.Count()}\");\n                list = list.Concat(attachedPresItems);\n                // ReSharper restore PossibleMultipleEnumeration\n\n                var ids = list.Where(e => !e.IsPublished).Select(e => e.EntityId).ToList();\n\n                // publish BlockConfiguration as well - if there already is one\n                if (cb.ConfigurationIsReady)\n                {\n                    l.A($\"add group id:{cb.Configuration.Id}\");\n                    ids.Add(cb.Configuration.Id);\n                }\n\n                l.A(Log.Try(() => $\"will publish id⋮{ids.Count} ids:[{ string.Join(\",\", ids.Select(i => i.ToString()).ToArray()) }]\"));\n\n                if (ids.Any())\n                    entPublish.New(cb.Context.AppReaderRequired).Publish(ids.ToArray());\n                else\n                    l.A(\"no ids found, won\\'t publish items\");\n            }\n\n            // Set published version\n            new ModuleVersions(instanceId, Log).PublishLatestVersion();\n            l.Done(\"publish completed\");\n        }\n        catch (Exception ex)\n        {\n            DnnLogging.LogToDnn(\"exception\", \"publishing\", Log, force: true);\n            DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);\n            l.Done(ex);\n            throw;\n        }\n\n    }\n\n    private IEnumerable<IEntity> TryToAddStream(IEnumerable<IEntity> list, IDataSource data, string key)\n    {\n        var cont = data.GetStream(key, nullIfNotFound: true)?.List.ToImmutableOpt();\n        Log.A($\"TryToAddStream(..., ..., key:{key}), found:{cont != null} add⋮{cont?.Count ?? 0}\" );\n        if (cont != null) list = list.Concat(cont);\n        return list;\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Cms/DnnPagePublishingSettings.cs",
    "content": "﻿using DotNetNuke.Common.Utilities;\nusing DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Tabs;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Dnn.Features;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Dnn.Cms;\n\ninternal class DnnPagePublishingGetSettings(IFeaturesService featuresService)\n    : PagePublishingGetSettingsBase(DnnConstants.LogName)\n{\n    protected override PublishingMode LookupRequirements(int moduleId)\n    {\n        Log.A($\"Requirements(mod:{moduleId}) - checking first time (others will be cached)\");\n        try\n        {\n            // TODO V14 - probably we can set ignoreCache to false then, as it's probably just a workaround for an old bug\n            var mod = ModuleController.Instance.GetModule(moduleId, Null.NullInteger, true);\n            var versioningEnabled = TabChangeSettings.Instance.IsChangeControlEnabled(mod.PortalID, mod.TabID);\n            if (!versioningEnabled)\n                return PublishingMode.DraftOptional;\n            if (!new PortalSettings(mod.PortalID).UserInfo.IsSuperUser)\n                return PublishingMode.DraftRequired;\n            return PublishingMode.DraftRequired;\n        }\n        catch\n        {\n            Log.A(\"Requirements had exception!\");\n            throw;\n        }\n    }\n\n    #region SwitchableService\n\n    public override string NameId => DnnConstants.LogName + \"PublishingSettings\";\n\n    public override int Priority => (int)PagePublishingPriorities.Platform;\n\n    /// <summary>\n    /// It's viable if it has not been turned off, which is the default\n    /// </summary>\n    /// <returns></returns>\n    public override bool IsViable() => featuresService.IsEnabled(DnnBuiltInFeatures.DnnPageWorkflow.NameId);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Cms/DnnPagePublishing_ModuleSettings.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\n\nnamespace ToSic.Sxc.Dnn.Cms;\n\npartial class DnnPagePublishing\n{\n    internal class ModuleVersions: HelperBase\n    {\n        private const string LatestVersionSettingsKey = \"LatestVersion\";\n\n        private const string PublishedVersionSettingsKey = \"PublishedVersion\";\n\n        private readonly ModuleSettingsHelper _settingsHelper;\n\n\n        public ModuleInfo ModuleInfo => _settingsHelper.ModuleInfo;\n\n\n        public ModuleVersions(int instanceId, ILog parentLog): base(parentLog, \"Dnn.ModVer\")\n        {\n            _settingsHelper = new(instanceId);\n        }\n\n\n        public int GetPublishedVersion()\n            => int.Parse(_settingsHelper.GetModuleSetting(PublishedVersionSettingsKey, \"0\"));\n\n        public int GetLatestVersion()\n            => int.Parse(_settingsHelper.GetModuleSetting(LatestVersionSettingsKey, \"0\"));\n\n        public int IncreaseLatestVersion()\n        {\n            var version = GetLatestVersion() + 1;\n            _settingsHelper.SetModuleSetting(LatestVersionSettingsKey, version.ToString());\n            return version;\n        }\n\n\n        public void PublishLatestVersion()\n        {\n            // 2017-09-13 must check maybe don't do anything, because \n            // this setting is already published by DNN when releasing the module\n            _settingsHelper.SetModuleSetting(PublishedVersionSettingsKey, GetLatestVersion().ToString());\n        }\n\n        public void DeleteLatestVersion()\n            => _settingsHelper.SetModuleSetting(LatestVersionSettingsKey, GetPublishedVersion().ToString());\n\n        public bool IsLatestVersionPublished() => GetLatestVersion() == GetPublishedVersion();\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Code/DnnDynamicCodeRootTT.cs",
    "content": "﻿using ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;\n\nnamespace ToSic.Sxc.Dnn.Code;\n\n[PrivateApi]\ninternal class DnnExecutionContext<TModel, TServiceKit>(ExecutionContext.Dependencies services)\n    : ExecutionContext<TModel, TServiceKit>(services, DnnConstants.LogName), IHasDnn\n    where TModel : class\n    where TServiceKit : ServiceKit\n{\n    /// <summary>\n    /// Dnn context with module, page, portal etc.\n    /// </summary>\n    public IDnnContext Dnn => field ??= GetService<IDnnContext>(reuse: true);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Code/DnnDynamicCodeService.cs",
    "content": "﻿using System.Web;\nusing System.Web.UI;\nusing ToSic.Sxc.Dnn.Services;\nusing ToSic.Sxc.Dnn.Web;\nusing ToSic.Sxc.Services.Sys.DynamicCodeService;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Web.Sys.PageService;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Dnn.Code;\n\n/// <summary>\n/// Dnn implementation\n/// goal is that we can hook into certain page lifecycle events to ensure changes\n/// happen to the page when necessary\n/// </summary>\ninternal class DnnDynamicCodeService: DynamicCodeService\n{\n    public record MyScopedServices(\n        LazySvc<IPageServiceShared> PageServiceShared,\n        LazySvc<PageChangeSummary> PageChangeSummary,\n        LazySvc<DnnPageChanges> DnnPageChanges,\n        LazySvc<DnnClientResources> DnnClientResources)\n        : DependenciesRecord(connect: [PageServiceShared, PageChangeSummary, DnnPageChanges, DnnClientResources]);\n\n    public DnnDynamicCodeService(Dependencies services) : base(services, $\"{DnnConstants.LogName}.DynCdS\")\n    {\n        _scopedServices = ScopedServiceProvider.Build<MyScopedServices>().ConnectServices(Log);\n        _user = services.User;\n        Page = HttpContext.Current?.Handler as Page;\n\n        if (Page != null)\n            Page.PreRender += Page_PreRender;\n    }\n\n    private readonly MyScopedServices _scopedServices;\n    private readonly LazySvc<IUser> _user;\n\n\n    private void Page_PreRender(object sender, EventArgs e)\n    {\n        var l = Log.Fn();\n        var user = _user.Value;\n        var changes = _scopedServices.PageChangeSummary.Value.FinalizeAndGetAllChanges(\n            moduleId: 0, // ignore module Id, we don't expect any caching info here\n            _scopedServices.PageServiceShared.Value,\n            new(),\n            user.IsContentAdmin\n        );\n        _scopedServices.DnnPageChanges.Value.Apply(Page, changes);\n\n        // #RemovedV20 #OldDnnAutoJQuery\n        var dnnClientResources = _scopedServices.DnnClientResources.Value.Init(Page, /*false,*/ null);\n        dnnClientResources.AddEverything(changes?.Features);\n        l.Done();\n    }\n\n    public Page Page;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Code/DnnExecutionContext.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\nusing ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;\n\nnamespace ToSic.Sxc.Dnn.Code;\n\n/// <summary>\n/// The basic DnnDynamicCode without explicitly typed model / kit\n/// </summary>\n[PrivateApi]\ninternal class DnnExecutionContext(ExecutionContext.Dependencies services)\n    : DnnExecutionContext<object, ServiceKit>(services);"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Code/IHasDnn.cs",
    "content": "﻿using ToSic.Sxc.Dnn.Run;\n\nnamespace ToSic.Sxc.Dnn.Code;\n\n/// <summary>\n/// This interface extends the IAppAndDataHelpers with the DNN Context.\n/// It's important, because if 2sxc also runs on other CMS platforms, then the Dnn Context won't be available, so it's in a separate interface.\n/// </summary>\n[PublicApi]\npublic interface IHasDnn\n{\n    /// <summary>\n    /// The DNN context. Has various objects to access the Dnn Page, etc.\n    /// </summary>\n    IDnnContext Dnn { get; }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/AppCodeCompilerNetFull.cs",
    "content": "using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;\nusing System.CodeDom.Compiler;\nusing System.Reflection;\nusing System.Text;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sys.Configuration;\nusing ToSic.Sys.Locking;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Code;\n\n[PrivateApi]\ninternal class AppCodeCompilerNetFull(\n    IHostingEnvironmentWrapper hostingEnvironment,\n    IReferencedAssembliesProvider referencedAssembliesProvider,\n    IGlobalConfiguration globalConfiguration,\n    SourceCodeHasher sourceCodeHasher,\n    AssemblyDiskCache diskCache)\n    : AppCodeCompiler(globalConfiguration, sourceCodeHasher, connect: [hostingEnvironment, referencedAssembliesProvider, sourceCodeHasher, diskCache])\n{\n    private const int LoadRetryDelayMs = 100;\n    private const int LoadRetryTimeoutMs = 3000;\n\n    /// <summary>\n    /// Get the App Code. The code is segmented into many smaller try/catch blocks to better identify where errors happen.\n    /// </summary>\n    /// <param name=\"relativePath\"></param>\n    /// <param name=\"spec\"></param>\n    /// <returns></returns>\n    public override AssemblyResult GetAppCode(string relativePath, HotBuildSpecWithSharedSuffix spec)\n    {\n        var l = Log.Fn<AssemblyResult>($\"{nameof(relativePath)}: '{relativePath}'; {spec}\", timer: true);\n\n        // Step 1: Get source files\n        string sourceRootPath;\n        string[] sourceFiles;\n        try\n        {\n            // Resolve source files\n            sourceRootPath = NormalizeFullPath(hostingEnvironment.MapPath(relativePath));\n            sourceFiles = GetSourceFiles(sourceRootPath);\n            if (sourceFiles.Length == 0)\n                return l.Return(new(), \"no source files\");\n\n        }\n        catch (Exception ex)\n        {\n            return ReturnAsError(ex, phaseName: \"get names and files\");\n        }\n\n        // Step 2: Get target paths\n        string symbolsPath, assemblyPath, dllName;\n        try\n        {\n            // Target locations\n            (symbolsPath, assemblyPath) = GetAssemblyLocations(spec, sourceRootPath);\n            dllName = Path.GetFileName(assemblyPath);\n        }\n        catch (Exception ex)\n        {\n            return ReturnAsError(ex, phaseName: \"get paths\");\n        }\n\n        // Step 3: Compile\n        CompilerResults compilerResults;\n        try\n        {\n            // Build or reuse compiled assembly. Always lock around the filesystem access to avoid\n            // overlapping readers while the compiler is still writing or an anti-virus temporarily\n            // blocks the file.\n            var assemblyLock = CompileAssemblyLocks.Get(assemblyPath);\n            var lockManager = new TryLockTryDo(assemblyLock);\n            var result = lockManager.Call(\n                conditionToGenerate: () => ShouldGenerate(assemblyPath),\n                generator: () => CompileAssemblyFromAppCodeFolder(sourceFiles, assemblyPath, relativePath, spec),\n                cacheOrFallback: () => LoadCachedAssemblyWithRetry(assemblyPath, l));\n\n            compilerResults = result.Result;\n        }\n        catch (Exception ex)\n        {\n            return ReturnAsError(ex, phaseName: \"compile\");\n        }\n\n        // Step 4: Return results, log and handle errors\n        try\n        {\n\n            var dicInfos = new Dictionary<string, string>\n            {\n                [\"DllName\"] = dllName,\n                [\"Files\"] = sourceFiles.Length.ToString(),\n                [\"Errors\"] = compilerResults.Errors.HasErrors.ToString(),\n                [\"Assembly\"] = compilerResults.Errors.HasErrors\n                    ? \"null\"\n                    : compilerResults.CompiledAssembly?.FullName ?? \"null\",\n                [\"AssemblyPath\"] = assemblyPath,\n                [\"SymbolsPath\"] = symbolsPath,\n            };\n\n            // Success\n            if (!compilerResults.Errors.HasErrors)\n            {\n                LogAllTypes(compilerResults.CompiledAssembly);\n                return l.ReturnAsOk(new(assembly: compilerResults.CompiledAssembly)\n                {\n                    AssemblyLocations = [symbolsPath, assemblyPath],\n                    Infos = dicInfos,\n                });\n            }\n\n            // Errors and warnings\n            var errorMessages = GetErrorMessages(compilerResults, l);\n            return l.ReturnAsError(new()\n            {\n                ErrorMessages = errorMessages,\n                Infos = dicInfos,\n            }, errorMessages);\n        }\n        catch (Exception ex)\n        {\n            return ReturnAsError(ex, phaseName: \"final\");\n        }\n\n        AssemblyResult ReturnAsError(Exception ex, string phaseName)\n        {\n            l.Ex(ex);\n            var errorMessage = $\"Error in phase '{phaseName}': Can't compile '{AppCodeDll}' in {Path.GetFileName(relativePath)}. Details are logged into insights. {ex.Message}\";\n            return l.ReturnAsError(new() { ErrorMessages = errorMessage, }, $\"in phase: {phaseName}\");\n        }\n    }\n\n    private static string GetErrorMessages(CompilerResults compilerResults, ILogCall<AssemblyResult> l)\n    {\n        // first return all errors and then all warnings\n        var errorsSb = new StringBuilder();\n        var warningsSb = new StringBuilder();\n        foreach (CompilerError ce in compilerResults.Errors)\n        {\n            var msg = $\"{(ce.IsWarning ? \"Warning\" : \"Error\")} ({ce.ErrorNumber}): {ce.ErrorText} in '{ce.FileName}' (Line: {ce.Line}, Column: {ce.Column}).\";\n            if (ce.IsWarning)\n            {\n                l.W(msg);\n                warningsSb.AppendLine(msg);\n            } else\n            { \n                l.E(msg);\n                errorsSb.AppendLine(msg);\n            }\n        }\n        var errors = errorsSb.Append(warningsSb).ToString();\n        return errors;\n    }\n\n    private CompilerResults CompileAssemblyFromAppCodeFolder(string[] sourceFiles, string assemblyFilePath, string relativePath, HotBuildSpec spec)\n    {\n        var l = Log.Fn<CompilerResults>($\"{nameof(sourceFiles)}: {sourceFiles.Length}; {nameof(assemblyFilePath)}: '{assemblyFilePath}'\", timer: true);\n\n        // Save to disk so it can be loaded by runtime\n        var parameters = new CompilerParameters(null, assemblyFilePath)\n        {\n            GenerateInMemory = false,\n            GenerateExecutable = false,\n            IncludeDebugInformation = true,\n            CompilerOptions = DnnRoslynConstants.CompilerOptions,\n        };\n\n        // Referenced assemblies\n        parameters.ReferencedAssemblies.AddRange(referencedAssembliesProvider.Locations(relativePath, spec).ToArray());\n\n        using var codeProvider = new CSharpCodeProvider();\n        var compilerResults = codeProvider.CompileAssemblyFromFile(parameters, sourceFiles);\n\n        return compilerResults.Errors.HasErrors\n            ? l.ReturnAsError(compilerResults)\n            : l.ReturnAsOk(compilerResults);\n    }\n\n    private CompilerResults LoadCachedAssemblyWithRetry(string assemblyPath, ILogCall<AssemblyResult> parentLog)\n    {\n        var l = parentLog.Fn<CompilerResults>($\"load from path: '{assemblyPath}'\");\n\n        // Use shared AssemblyDiskCache.LoadWithRetry instead of manual retry logic\n        var assembly = diskCache.LoadWithRetry(\n            assemblyPath,\n            loadAssembly: Assembly.LoadFrom,\n            retryDelayMs: LoadRetryDelayMs,\n            timeoutMs: LoadRetryTimeoutMs);\n\n        var result = new CompilerResults(new())\n        {\n            PathToAssembly = assemblyPath,\n            CompiledAssembly = assembly,\n        };\n\n        return l.Return(result, $\"loaded cached assembly\");\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/AssemblyExtensions.cs",
    "content": "﻿using System.Reflection;\nusing System.Web.Configuration;\n\nnamespace ToSic.Sxc.Dnn.Compile\n{\n    public static class AssemblyExtensions\n    {\n        // for assembly references\n        public static Assembly WithPolicy(this Assembly assembly) \n            =>\n            // apply binding redirections from web.config\n            Assembly.ReflectionOnlyLoad(System.AppDomain.CurrentDomain.ApplyPolicy(assembly.FullName));\n\n        public static Assembly WithPolicy(this AssemblyInfo ai)\n            =>\n                // apply binding redirections from web.config\n                Assembly.ReflectionOnlyLoad(System.AppDomain.CurrentDomain.ApplyPolicy(ai.Assembly));\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/DnnRoslynConstants.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.HotBuild;\n\nnamespace ToSic.Sxc.Dnn.Compile;\n\n/// <summary>\n/// Contains constants used for Roslyn compilation in the DNN context.\n/// These constants define default compiler options, language versions, and other settings.\n/// </summary>\ninternal class DnnRoslynConstants\n{\n    /// <summary>\n    /// Compiler options used during Roslyn compilation.\n    /// - /optimize-: Disables compiler optimizations to make debugging easier.\n    /// - /warnaserror-: Treats warnings as warnings (not errors), allowing the build to succeed even with warnings.\n    /// - {CompilerOptionLanguageVersion}: Specifies the C# language version to use (e.g., \"preview\").\n    /// - {DefaultDisableWarnings}: Suppresses specific warnings defined in the DNN web.config.\n    /// - {CompilerOptionDefine}: Defines preprocessor symbols (e.g., DEBUG, NETFRAMEWORK).\n    /// </summary>\n    public const string CompilerOptions = $\"/optimize- /warnaserror- {DefaultDisableWarnings} {CompilerOptionLanguageVersion} {CompilerOptionDefine}\";\n\n    /// <summary>\n    /// Compiler warnings to suppress, as specified in the default DNN web.config file.\n    /// These warnings are typically related to obsolete or deprecated APIs.\n    /// </summary>\n    private const string DefaultDisableWarnings = \"/nowarn:1659;1699;1701;612;618\";\n\n    /// <summary>\n    /// Compiler option to specify the language version.\n    /// This is constructed using the <see cref=\"RoslynConstants.LanguageVersion\"/>.\n    /// </summary>\n    private const string CompilerOptionLanguageVersion = $\"/langversion:{RoslynConstants.LanguageVersion}\"; // \"8\" till 2025-08-20;\n\n    /// <summary>\n    /// Defines the preprocessor symbols to be used during compilation.\n    /// These symbols allow conditional compilation for different build configurations and platforms.\n    /// Examples:\n    /// - NETFRAMEWORK: Indicates targeting the .NET Framework (used for DNN).\n    /// </summary>\n    private const string DefineConstants = \"NETFRAMEWORK\";\n\n    /// <summary>\n    /// Compiler option to define preprocessor symbols.\n    /// This is constructed using the <see cref=\"DefineConstants\"/>.\n    /// </summary>\n    private const string CompilerOptionDefine = $\"/define:{DefineConstants}\";\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/HostingEnvironmentWrapper.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn.Compile;\n\n/// <summary>\n/// wrapper around HostingEnvironment\n/// </summary>\n/// <remarks>to mock the wrapper in unit tests</remarks>\n[PrivateApi]\npublic class HostingEnvironmentWrapper : IHostingEnvironmentWrapper\n{\n    /// <summary>Maps a virtual path to a physical path on the server.</summary>\n    /// <param name=\"virtualPath\">The virtual path (absolute or relative).</param>\n    /// <returns>The physical path on the server specified by <paramref name=\"virtualPath\" />.</returns>\n    public string MapPath(string virtualPath) => System.Web.Hosting.HostingEnvironment.MapPath(virtualPath);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/IHostingEnvironmentWrapper.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn.Compile;\n\n[PrivateApi]\npublic interface IHostingEnvironmentWrapper\n{\n    string MapPath(string virtualPath);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/IReferencedAssembliesProvider.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.HotBuild;\n\nnamespace ToSic.Sxc.Dnn.Compile;\n\n[PrivateApi]\npublic interface IReferencedAssembliesProvider\n{\n    List<string> Locations(string virtualPath, HotBuildSpec spec);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/IRoslynBuildManager.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\n\nnamespace ToSic.Sxc.Dnn.Compile;\n\npublic interface IRoslynBuildManager\n{\n    AssemblyResult GetCompiledAssembly(CodeFileInfo codeFileInfo, string className, HotBuildSpec spec);\n\n    /// <summary>\n    /// Manage template compilations, cache the assembly and returns the generated type.\n    /// </summary>\n    /// <param name=\"codeFileInfo\"></param>\n    /// <param name=\"spec\"></param>\n    /// <returns>The generated type for razor cshtml.</returns>\n    Type GetCompiledType(CodeFileInfo codeFileInfo, HotBuildSpec spec);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/ReferencedAssembliesProvider.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Reflection;\nusing System.Web.Compilation;\nusing System.Web.Configuration;\nusing System.Web.Hosting;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing static System.StringComparer;\n\nnamespace ToSic.Sxc.Dnn.Compile;\n\n[PrivateApi]\npublic class ReferencedAssembliesProvider(\n    DependenciesLoader dependenciesLoader,\n    AssemblyResolver assemblyResolver,\n    LazySvc<ExtensionCompileReferenceService> extensionReference)\n    : ServiceBase(\"Sxc.RefAP\", connect: [dependenciesLoader, assemblyResolver, extensionReference]), IReferencedAssembliesProvider\n{\n    // cache of referenced assemblies per virtual path\n    private static readonly ConcurrentDictionary<string, List<string>> ReferencedAssembliesCache = new(InvariantCultureIgnoreCase);\n\n    public List<string> Locations(string virtualPath, HotBuildSpec spec)\n    {\n        var l = Log.Fn<List<string>>($\"for: '{virtualPath}'\");\n        if (ReferencedAssembliesCache.TryGetValue(virtualPath, out var cachedResult))\n            return l.Return(new(cachedResult), \"cached, re-wrapped in new list\");\n\n        var lTimer = Log.Fn(\"timer for AppRef\", timer: true);\n        var referencedAssemblies = new List<string>(AppReferencedAssemblies());\n        lTimer.Done();\n\n        // include assemblies from compilation section in web.config hierarchy\n        lTimer = Log.Fn(\"timer for Web Configuration Manager\", timer: true);\n        var compilationSection = (CompilationSection)WebConfigurationManager.GetSection(\"system.web/compilation\", virtualPath);\n        foreach (AssemblyInfo assembly in compilationSection.Assemblies)\n            ReferenceAssembly(referencedAssemblies, assembly.Assembly);\n        lTimer.Done();\n\n        // include assemblies from `\\AppCode\\Extensions\\[extension-name]\\compile.json`\n        lTimer = Log.Fn(\"timer for Extensions Reference Assemblies\", timer: true);\n        EnsureExtensionsReferenceAssemblies(referencedAssemblies, virtualPath);\n        lTimer.Done();\n\n        lTimer = Log.Fn(\"timer for Dependencies\", timer: true);\n        if (spec != null)\n        {\n            // TODO: need to invalidate this cache (_referencedAssembliesCache, _assemblyResolver, ...) if there is change in Dependencies folder\n            var (dependencies, _) = dependenciesLoader.TryGetOrFallback(spec);\n            assemblyResolver.AddAssemblies(dependencies);\n\n            // ReSharper disable once ConditionIsAlwaysTrueOrFalse\n            if (dependencies != null)\n                foreach (var dependency in dependencies)\n                    referencedAssemblies.Add(dependency.Location);\n        }\n        lTimer.Done();\n        \n        // deduplicate referencedAssemblies by filename, keep last duplicate\n        referencedAssemblies = referencedAssemblies\n            //.Where(IsValidAssembly)\n            .GroupBy(Path.GetFileName)\n            .Select(g => g.Last())\n            .ToList();\n\n        ReferencedAssembliesCache.TryAdd(virtualPath, referencedAssemblies);\n\n        return l.Return(new(referencedAssemblies), \"created, re-wrapped in new list\");\n    }\n\n    private void ReferenceAssembly(ICollection<string> referencedAssemblies, string assemblyName)\n    {\n        if (assemblyName.IsEmpty())\n            return;\n\n        var normalized = ExtensionCompileReferenceService.NormalizeAssemblyName(assemblyName);\n        if (HasAssembly(referencedAssemblies, $\"{normalized}.dll\"))\n            return;\n\n        // Process your assembly information here\n        try\n        {\n            referencedAssemblies.Add(Assembly.ReflectionOnlyLoad(normalized).Location);\n        }\n        catch\n        {\n            // sink\n        }\n    }\n\n\n    private void EnsureExtensionsReferenceAssemblies(ICollection<string> referencedAssemblies, string virtualPath)\n    {\n        //foreach (var assemblyName in GetExtensionsReferenceAssemblyNames)\n        //    referencedAssemblies.Add(Assembly.ReflectionOnlyLoad(assemblyName).Location);\n\n        var physicalPath = MapVirtualPath(virtualPath);\n        if (physicalPath.IsEmpty())\n            return;\n\n        var referenceReader = extensionReference.Value;\n        foreach (var reference in referenceReader.GetReferences(physicalPath, netFramework: true))\n        {\n            if (ExtensionCompileReferenceService.IsAssemblyName(reference.Value))\n            {\n                ReferenceAssembly(referencedAssemblies, reference.Value);\n                continue;\n            }\n\n            var resolvedPath = referenceReader.ResolveReferencePath(reference);\n            if (resolvedPath.IsEmpty() || !File.Exists(resolvedPath))\n            {\n                Log.W($\"Extension reference '{reference.Value}' in '{reference.ExtensionFolder}' not found or unreadable.\");\n                continue;\n            }\n\n            referencedAssemblies.Add(resolvedPath);\n        }\n    }\n\n    private static string MapVirtualPath(string virtualPath)\n    {\n        if (virtualPath.IsEmpty())\n            return string.Empty;\n\n        try\n        {\n            return HostingEnvironment.MapPath(virtualPath);\n        }\n        catch\n        {\n            return string.Empty;\n        }\n    }\n\n    private static bool HasAssembly(IEnumerable<string> referencedAssemblies, string fileName)\n        => referencedAssemblies.Any(path => string.Equals(Path.GetFileName(path), fileName, StringComparison.InvariantCultureIgnoreCase));\n\n    //private static readonly string[] GetExtensionsReferenceAssemblyNames =\n    //{\n    //    \"System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\"\n    //};\n\n    ///// <summary>\n    ///// We need to skip invalid assemblies to not break compile process\n    ///// </summary>\n    ///// <param name=\"filePath\"></param>\n    ///// <returns></returns>\n    //private static bool IsValidAssembly(string filePath)\n    //{\n    //    try\n    //    {\n    //        Assembly.ReflectionOnlyLoadFrom(filePath);\n    //        return true;\n    //    }\n    //    catch\n    //    {\n    //        return false;\n    //    }\n    //}\n\n    // static cached, because in case of dll change app will restart itself\n    private static IReadOnlyList<string> AppReferencedAssemblies()\n        => _appReferenceAssemblies ??= BuildManager.GetReferencedAssemblies().Cast<Assembly>().Select(assembly => assembly/*.WithPolicy()*/.Location).ToList().AsReadOnly();\n\n    private static IReadOnlyList<string> _appReferenceAssemblies;\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/Sys/AppJsonExtensions.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppJson;\n\nnamespace ToSic.Sxc.Dnn.Compile.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class AppJsonExtensions\n{\n\n    /// <summary>\n    /// Check that the app is configured in app.json to always use Roslyn compiler\n    /// </summary>\n    /// <param name=\"appJsonService\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    public static bool DnnCompilerAlwaysUseRoslyn(this IAppJsonConfigurationService appJsonService, int appId) \n        => appJsonService.GetAppJson(appId)?.DotNet?.Compiler?.Equals(\"roslyn\", StringComparison.OrdinalIgnoreCase) == true;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/Sys/CodeCompilerNetFull.cs",
    "content": "﻿using System.Web.Compilation;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\n\nnamespace ToSic.Sxc.Dnn.Compile.Sys;\n\n[PrivateApi]\ninternal class CodeCompilerNetFull(\n    IServiceProvider serviceProvider,\n    IRoslynBuildManager roslynBuildManager,\n    LazySvc<SourceAnalyzer> sourceAnalyzer,\n    LazySvc<IAppJsonConfigurationService> appJson)\n    : CodeCompiler(serviceProvider, connect: [roslynBuildManager, sourceAnalyzer, appJson])\n{\n    public override AssemblyResult GetAssembly(string relativePath, string className, HotBuildSpec spec)\n    {\n        var l = Log.Fn<AssemblyResult>($\"{nameof(relativePath)}: '{relativePath}'; {nameof(className)}: '{className}'; {spec}\", timer: true);\n\n        AssemblyResult ReportError(Exception ex, string additionalInfo)\n        {\n            var errorMessage =\n                $\"Can't compile '{className}' in {Path.GetFileName(relativePath)}. Details are logged into insights. {additionalInfo}\" +\n                ex.Message;\n            return new() { ErrorMessages = errorMessage, };\n        }\n\n        try\n        {\n            // TODO: SHOULD OPTIMIZE so the file doesn't need to read multiple times\n            var codeFileInfo = sourceAnalyzer.Value.TypeOfVirtualPath(relativePath);\n\n            try\n            {\n                if (appJson.Value.DnnCompilerAlwaysUseRoslyn(spec.AppId) || codeFileInfo.IsHotBuildSupported())\n                    return l.Return(roslynBuildManager.GetCompiledAssembly(codeFileInfo, className, spec),\n                        \"Ok, RoslynBuildManager\");\n            }\n            catch (Exception ex)\n            {\n                return l.ReturnAsError(ReportError(ex, \"using Roslyn compiler\"));\n            }\n\n            try\n            {\n                return l.Return(new(BuildManager.GetCompiledAssembly(relativePath)), \"Ok, BuildManager\");\n            }\n            catch (Exception ex)\n            {\n                return l.ReturnAsError(ReportError(ex, \"using BuildManager\"));\n            }\n        }\n        catch (Exception ex)\n        {\n            return l.ReturnAsError(ReportError(ex, \"\"));\n        }\n    }\n\n    protected override (Type Type, string ErrorMessage) GetCsHtmlType(string relativePath)\n    {\n        var compiledType = BuildManager.GetCompiledType(relativePath);\n        var errMsg = compiledType == null\n            ? $\"Couldn't create instance of {relativePath}. Compiled type == null\" : null;\n        return (compiledType, errMsg);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Compile/SysFeatureHelperRoslynCompiler.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn.Compile;\n\n[PrivateApi]\ninternal class RoslynCompilerCapability\n{\n    internal static bool CheckCsharpLangVersion(int version) => CsharpLangVersions.Contains(value: version);\n\n\n    private static int[] CsharpLangVersions => _csharpLangVersions ??= GetCsharpLangVersions();\n    private static volatile int[] _csharpLangVersions;\n\n    /// <summary>\n    /// Goal is that it can tell if the newer CodeDom library has been installed or not\n    /// used to build a config in the App, so the app can warn if a feature is missing\n    /// </summary>\n    /// <returns></returns>\n    /// <remarks>\n    /// This is optimized version, it is just checking for \"/bin/roslyn/Microsoft.CodeAnalysis.CSharp.dll\" file.\n    /// Older version where checking for Microsoft.CodeAnalysis.CSharp.LanguageVersion enum, but has performance problems\n    /// while using reflection on tmp loaded assembly in new application domain that can be unloaded,\n    /// also used a double-check locking pattern to ensure thread safety and performance.\n    /// </remarks>\n    private static int[] GetCsharpLangVersions() \n        => (!File.Exists(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, \"bin\", \"roslyn\", \"Microsoft.CodeAnalysis.CSharp.dll\")))\n            ? []\n            : [ 0, 1, 2, 3, 4, 5, 6, 7,\n                701, // 0x000002BD\n                702, // 0x000002BE\n                703, // 0x000002BF\n                800, // 0x00000320\n                2147483645, // LatestMajor - 0x7FFFFFFD\n                2147483646, // Preview - 0x7FFFFFFE\n                2147483647, // Latest - 0x7FFFFFFF\n              ];\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Context/DnnContext.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Tabs;\nusing DotNetNuke.Entities.Users;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Context.Sys.Module;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Dnn.Context;\n\ninternal class DnnContext : IDnnContext, INeedsExecutionContext\n{\n    /// <summary>\n    /// Build DNN Helper\n    /// Note that the context can be null, in which case it will have no module context, and default to the current portal\n    /// </summary>\n    public void ConnectToRoot(IExecutionContext exCtx)\n    {\n        var moduleContext = exCtx.GetContextOfBlock()?.Module;\n        Module = (moduleContext as Module<ModuleInfo>)?.GetContents();\n        // note: this may be a bug, I assume it should be Module.OwnerPortalId\n        Portal = PortalSettings.Current ?? \n                 (Module != null ? new PortalSettings(Module.PortalID): null);\n    }\n\n    public ModuleInfo Module { get; private set; }\n\n    public TabInfo Tab => Portal?.ActiveTab;\n\n    public PortalSettings Portal { get; private set; }\n\n    public UserInfo User => Portal.UserInfo;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Context/DnnISiteExtensions.cs",
    "content": "﻿using DotNetNuke.Common;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context;\n\nnamespace ToSic.Sxc.Dnn.Context;\n\ninternal static class DnnISiteExtensions\n{\n    internal static string SharedAppsRootRelative(this ISite site) => Path.Combine(Globals.HostPath, AppConstants.AppsRootFolder);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Context/DnnModule.cs",
    "content": "﻿using DotNetNuke.Common.Utilities;\nusing DotNetNuke.Entities.Modules;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys.Module;\nusing ISite = ToSic.Eav.Context.ISite;\n\nnamespace ToSic.Sxc.Dnn.Context;\n\n/// <summary>\n/// The DNN implementation of a Block Container (a Module).\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[PrivateApi(\"this is just internal, external users don't really have anything to do with this\")]\npublic class DnnModule(IAppsCatalog appsCatalog, LazySvc<AppFinder> appFinderLazy, ISite site)\n    : Module<ModuleInfo>(\"Dnn.Contnr\", connect: [appsCatalog, appFinderLazy, site])\n{\n    #region Constructors and DI\n\n    /// <summary>\n    /// We don't use a Constructor because of DI\n    /// So you must always call Init\n    /// </summary>\n    public new DnnModule Init(ModuleInfo item)\n    {\n        var l = Log.Fn<DnnModule>($\"{item?.ModuleID}\");\n        base.Init(item);\n        return l.ReturnAsOk(this);\n    }\n\n    /// <summary>\n    /// We don't use a Constructor because of DI\n    /// So you must always call Init\n    /// </summary>\n    public override IModule Init(int moduleId)\n    {\n        var l = Log.Fn<IModule>($\"{moduleId}\");\n        var mod = ModuleController.Instance.GetModule(moduleId, Null.NullInteger, false);\n        Init(mod);\n        return l.ReturnAsOk(this);\n    }\n\n    #endregion\n\n\n    /// <inheritdoc />\n    public override int Id => UnwrappedModule?.ModuleID ?? EavConstants.NullId;\n\n\n    /// <inheritdoc />\n    public override bool IsContent => (UnwrappedModule?.DesktopModule.ModuleName ?? \"2sxc\") == \"2sxc\";\n\n\n    /// <inheritdoc />\n    public override IBlockIdentifier BlockIdentifier\n    {\n        get\n        {\n            if (field != null)\n                return field;\n            if (UnwrappedModule == null)\n                return null;\n\n            // find ZoneId, AppId and prepare settings for next values\n            // note: this is the correct zone, even if the module is shared from another portal, because the Site is prepared correctly\n            var zoneId = site.ZoneId;\n            var (appId, appNameId) = GetInstanceAppIdAndName(zoneId);\n            var settings = UnwrappedModule.ModuleSettings;\n\n            // find block identifier\n            Guid.TryParse(settings[ModuleSettingNames.ContentGroup]?.ToString(), out var blockGuid);\n\n            // Check if we have preview-view identifier - for blocks which don't exist yet\n            var previewTemplateString = settings[ModuleSettingNames.PreviewView]?.ToString();\n            var overrideView = !string.IsNullOrEmpty(previewTemplateString)\n                ? Guid.Parse(previewTemplateString)\n                : new();\n\n            // Create identifier\n            return field = new BlockIdentifier(zoneId, appId, appNameId, blockGuid, overrideView);\n        }\n    }\n\n    private (int AppId, string AppNameId) GetInstanceAppIdAndName(int zoneId)\n    {\n        var l = Log.Fn<(int, string)>($\"{zoneId}\");\n        var module = UnwrappedModule ?? throw new(\"instance is not ModuleInfo\");\n        var msg = $\"get appid from instance for Z:{zoneId} Mod:{module.ModuleID}\";\n        if (IsContent)\n        {\n            var appId = appsCatalog.DefaultAppIdentity(zoneId).AppId;\n            return l.Return((appId, \"Content\"), $\"{msg} - use Default app: {appId}\");\n        }\n\n        if (module.ModuleSettings.ContainsKey(ModuleSettingNames.AppName))\n        {\n            var guid = module.ModuleSettings[ModuleSettingNames.AppName].ToString();\n            var appId = appFinderLazy.Value.FindAppId(zoneId, guid);\n            return l.Return((appId, guid), $\"{msg} AppG:{guid} = app:{appId}\");\n        }\n\n        Log.A($\"{msg} not found = null\");\n        return l.Return((KnownAppsConstants.AppIdEmpty, KnownAppsConstants.AppNameIdEmpty), \"not found\");\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Context/DnnPage.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Tabs;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Context.Sys.Page;\nusing ToSic.Sxc.Web.Sys.Http;\n\nnamespace ToSic.Sxc.Dnn.Context;\n\n/// <summary>\n/// A Dnn Page which will be auto-initialized on creation\n/// Important for scenarios where we don't have a module to fill in the details\n/// </summary>\ninternal class DnnPage: Page\n{\n    public DnnPage(LazySvc<IHttp> httpLazy) : base(httpLazy)\n    {\n        InitPageIdAndUrl(PortalSettings.Current?.ActiveTab, null);\n    }\n\n    internal string InitPageIdAndUrl(TabInfo activeTab, int? pageId)\n    {\n        Init(pageId ?? activeTab?.TabID ?? EavConstants.NullId);\n\n        // the FullUrl will throw an error in DNN search scenarios\n        try\n        {\n            // skip during search (usual HttpContext is missing for search)\n            if (System.Web.HttpContext.Current != null)\n                Url = activeTab?.FullUrl.TrimLastSlash();\n            else\n                return \"no http-context, can't add page\";\n        }\n        catch\n        {\n            /* ignore */\n        }\n\n        return Url;\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Context/DnnSite.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Services.Localization;\nusing System.Web;\nusing System.Web.Hosting;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context.Sys.Site;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Capabilities.Features;\nusing static ToSic.Eav.Context.Sys.ZoneCulture.IZoneCultureResolverExtensions;\nusing ISite = ToSic.Eav.Context.ISite;\n\nnamespace ToSic.Sxc.Dnn.Context;\n\n/// <summary>\n/// This is a DNN implementation of a Tenant-object. \n/// </summary>\ninternal sealed class DnnSite: Site<PortalSettings>, IZoneCultureResolverProWIP\n{\n\n    #region Constructors and DI\n\n    /// <summary>\n    /// DI Constructor, will get the current portal settings\n    /// #TodoDI not ideal yet, as PortalSettings.current is still retrieved from global\n    /// </summary>\n    public DnnSite(LazySvc<IZoneMapper> zoneMapperLazy, LazySvc<ILinkPaths> linkPathsLazy, LazySvc<ISysFeaturesService> featuresSvc)\n        : base(DnnConstants.LogName, connect: [featuresSvc, zoneMapperLazy, linkPathsLazy])\n    {\n        _featuresSvc = featuresSvc;\n        _zoneMapperLazy = zoneMapperLazy;\n        _linkPathsLazy = linkPathsLazy;\n        TryInitPortal(null);\n    }\n    private readonly LazySvc<IZoneMapper> _zoneMapperLazy;\n    private readonly LazySvc<ILinkPaths> _linkPathsLazy;\n    private readonly LazySvc<ISysFeaturesService> _featuresSvc;\n    private ILinkPaths LinkPaths => _linkPathsLazy.Value;\n\n    /// <inheritdoc />\n    public override ISite Init(int siteId, ILog parentLogOrNull)\n        => TryInitPortal(new(siteId), parentLogOrNull);\n\n    #endregion\n\n    #region Swap new Portal Settings into this object\n\n    internal DnnSite TryInitPortal(PortalSettings settings, ILog parentLogOrNull = default)\n    {\n        AttachToExternalLog(parentLogOrNull);\n\n        var l = Log.Fn<DnnSite>();\n        UnwrappedSite = KeepBestPortalSettings(settings);\n\n        // reset language info to be sure to get it from the latest source\n        _currentCulture.Reset(Log);\n        _currentCodeFallbacks.Reset(Log);\n        _defaultLanguage = null;\n        _zoneId = null;\n\n        return l.Return(this, $\"Site Id {Id}\");\n    }\n\n    internal DnnSite TryInitModule(ModuleInfo module, ILog extLog)\n    {\n        AttachToExternalLog(extLog);\n\n        var l = extLog.Fn<DnnSite>($\"Owner Site: {module?.OwnerPortalID}, Current Site: {module?.PortalID}\");\n        if (module == null) return l.Return(this, \"no module\");\n        if (module.OwnerPortalID < 0) return l.Return(this, \"no change, owner < 0\");\n\n        var modulePortalSettings = new PortalSettings(module.OwnerPortalID);\n        TryInitPortal(modulePortalSettings);\n        return l.Return(this, \"ok\");\n    }\n\n    private void AttachToExternalLog(ILog extLogOrNull)\n    {\n        if (extLogOrNull != null && extLogOrNull != Log)\n            this.LinkLog(extLogOrNull, forceConnect: true);\n    }\n\n\n    /// <summary>\n    /// Very special helper to work around a DNN issue\n    /// Reason is that PortalSettings.Current is always \"perfect\" and also contains root URLs and current Page\n    /// Other PortalSettings may not contain this (partially populated objects)\n    /// In case we're requesting a DnnTenant with incomplete PortalSettings\n    /// we want to correct this here\n    /// </summary>\n    /// <param name=\"settings\"></param>\n    /// <returns></returns>\n    private static PortalSettings KeepBestPortalSettings(PortalSettings settings, ILog extLogOrNull = null)\n    {\n        var l = extLogOrNull.Fn<PortalSettings>();\n        // in case we don't have an HTTP Context with current portal settings, don't try anything\n        if (PortalSettings.Current == null) return l.Return(settings, \"null, use given\");\n\n        // If we don't have settings, or they point to the same portal, then use that\n        if (settings == null) return l.Return(PortalSettings.Current, \"null, use current\");\n        if (settings == PortalSettings.Current) return l.Return(PortalSettings.Current, \"is current, use current\");\n        if (settings.PortalId == PortalSettings.Current.PortalId) return l.Return(PortalSettings.Current, \"id=current, use current\");\n\n        // fallback: use supplied settings\n        return l.Return(settings, \"use new settings\");\n    }\n\n\n    #endregion\n\n    #region Culture / Languages\n\n    /// <inheritdoc />\n    public override string DefaultCultureCode => (_defaultLanguage ??= UnwrappedSite?.DefaultLanguage?.ToLowerInvariant()) ?? string.Empty;\n    private string _defaultLanguage;\n\n\n    public override string CurrentCultureCode => _currentCulture.Get(GetCurrentCultureCode);\n    private readonly GetOnce<string> _currentCulture = new();\n\n    private string GetCurrentCultureCode()\n    {\n        var l = Log.Fn<string>();\n        // First check if we know more about the site\n        var portal = UnwrappedSite;\n        if (portal == null /* paranoid */)\n            return l.ReturnNull(\"no portal\");\n        var aliasCulture = portal.PortalAlias?.CultureCode ?? \"\";\n\n        if (aliasCulture.HasValue())\n        {\n            var aliasCult = aliasCulture.ToLowerInvariant();\n            return l.Return(aliasCult, $\"{nameof(portal.PortalAlias)}: {aliasCult}\");\n        }\n\n        // if alias is unknown, then we might be in search mode or something\n        var result = portal.CultureCode?.ToLowerInvariant();\n        return l.Return(result, $\"Portal.CultureCode: {result}\");\n    }\n\n    public List<string> CultureCodesWithFallbacks => _currentCodeFallbacks.Get(GetCultureCodesWithFallbacks);\n    private readonly GetOnce<List<string>> _currentCodeFallbacks = new();\n\n    private List<string> GetCultureCodesWithFallbacks()\n    {\n        var l = Log.Fn<List<string>>();\n        // 2023-08-31 2dm - new code, as it could contain risks, use try/catch/null to default\n        try\n        {\n            // If the feature is not enabled, return null so up-stream can handle defaults\n            if (!_featuresSvc.Value.IsEnabled(BuiltInFeatures.LanguagesAdvancedFallback.Guid))\n                return l.ReturnNull(\"feature not enabled\");\n\n            var lc = LocaleController.Instance;\n            if (lc == null)\n                return l.ReturnNull(\"no locale controller\");\n            var list = new List<string>();\n\n            // Top priority is current and fallbacks of it\n            // 2025-09-15 2dm: Dnn seems to do something wrong during WebApi calls.\n            // Internally it wants to prefer the `language` querystring param,\n            // but if it doesn't have it, then in a WebApi call it seems to not correctly take the current portal alias culture.\n            // So we can't use `GetCurrentLocale` but need to use `GetLocaleOrCurrent` with the current culture code.\n            var languageQuery = HttpContext.Current?.Request?.QueryString?[\"language\"]; // null-safe when no HTTP context\n            var current = !string.IsNullOrEmpty(languageQuery)\n                ? lc.GetCurrentLocale(Id) // This will use the querystring param if available, or work in Razor, but not in WebApi\n                : lc.GetLocaleOrCurrent(Id, CurrentCultureCode ?? DefaultCultureCode ?? System.Globalization.CultureInfo.CurrentCulture.Name); // Use known codes or thread culture when no HTTP context\n            if (current != null)\n            {\n                var currentCode = current.Code;\n                l.A($\"{nameof(currentCode)}: {currentCode}\");\n                ListBuildAddCodeIfNew(list, currentCode);\n\n                // Try to add fallbacks, and fallbacks of fallbacks...\n                var fallback = current.FallBackLocale;\n                for (var i = 0; i < 3 && fallback != null; i++)\n                {\n                    ListBuildAddCodeIfNew(list, fallback.Code);\n                    fallback = fallback.FallBackLocale;\n                }\n            }\n\n            // Always add the defaults as well\n            var def = lc.GetDefaultLocale(Id);\n            if (def != null)\n            {\n                var defCode = def.Code;\n                l.A($\"{nameof(defCode)}: {defCode}\");\n                ListBuildAddCodeIfNew(list, defCode);\n                // Default should never have another fallback; it's the default!\n            }\n\n            // If the list is empty, return null so upstream can fallback\n            return list.Any()\n                ? l.Return(list, $\"got: {list.Count}\")\n                : l.ReturnNull(\"no list\");\n        }\n        catch\n        {\n            return l.ReturnAsError(null);\n        }\n    }\n\n    #endregion\n\n    // ReSharper disable once InheritdocInvalidUsage\n    /// <inheritdoc />\n    public override int Id\n        => UnwrappedSite?.PortalId ?? EavConstants.NullId;\n\n    /// <inheritdoc />\n    public override string Name\n        => UnwrappedSite.PortalName;\n\n    public override string Url\n    {\n        get\n        {\n            if (field != null)\n                return field;\n            // PortalAlias in DNN is without protocol, so we need to add it from current request for consistency\n            // also without trailing slash\n            var parts = new UrlParts(LinkPaths.GetCurrentRequestUrl());\n            return field = $\"{parts.Protocol}{UrlRoot}\";\n        }\n    }\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>\n    /// Important special case: if the PortalSettings are not from the PortalSettings.Current, then the\n    /// PortalAlias are null!!!\n    /// I believe this should only matter in very special cases\n    /// Like when showing a module from another portal - in which case we don't need that alias\n    /// but the current one. Just keep this in mind in case anything ever breaks.\n    /// </remarks>\n    public override string UrlRoot\n        => _urlRoot ??= UnwrappedSite?.PortalAlias?.HTTPAlias\n                        ?? PortalSettings.Current?.PortalAlias?.HTTPAlias\n                        ?? \"err-portal-alias-not-loaded\";\n    private string _urlRoot;\n\n    [PrivateApi]\n    public override string AppsRootPhysical\n        => Path.Combine(UnwrappedSite.HomeDirectory, AppConstants.AppsRootFolder);\n\n\n    [PrivateApi]\n    public override string AppAssetsLinkTemplate\n        => AppsRootPhysical + \"/\" + AppConstants.AppFolderPlaceholder;\n        \n    [PrivateApi]\n    public override string AppsRootPhysicalFull\n        => HostingEnvironment.MapPath(AppsRootPhysical);\n\n    /// <inheritdoc />\n    public override string ContentPath\n        => UnwrappedSite.HomeDirectory;\n\n    public override int ZoneId\n    {\n        get { \n            if(_zoneId != null)\n                return _zoneId.Value;\n            // check if id is negative; 0 is a valid tenant id\n            if (Id < 0)\n                return (_zoneId = EavConstants.NullId).Value;\n            _zoneId = _zoneMapperLazy.Value.GetZoneId(Id);\n            return _zoneId.Value;\n        }\n    }\n    private int? _zoneId;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Context/DnnUser.cs",
    "content": "﻿using System.Web.Security;\nusing DotNetNuke.Common.Utilities;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Users;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sys.Users;\nusing ToSic.Sys.Users.Permissions;\n\nnamespace ToSic.Sxc.Dnn.Context;\n\ninternal class DnnUser(LazySvc<DnnSecurity> dnnSecurity)\n    : ServiceBase(\"dnnUsr\", connect: [dnnSecurity]), IUser<UserInfo>\n{\n    private string GetUserIdentityToken ()\n    {\n        var userId = Id;\n        var token = userId == -1 ? SxcUserConstants.Anonymous : $\"{DnnConstants.UserTokenPrefix}{userId}\";\n        return token;\n    }\n\n    public Guid Guid => Membership.GetUser()?.ProviderUserKey is Guid realGuid ? realGuid : default;\n\n    public string IdentityToken => GetUserIdentityToken();\n\n    public List<int> Roles => _roles.Get(BuildRoleList);\n    private readonly GetOnce<List<int>> _roles = new();\n\n    public bool IsSystemAdmin => DnnUserInfo?.IsSuperUser ?? false;\n\n    public bool IsSiteAdmin => EffectivePermissions?.IsSiteAdmin ?? false;\n    public bool IsContentAdmin => EffectivePermissions?.IsContentAdmin ?? false;\n    public bool IsContentEditor => EffectivePermissions?.IsContentEditor ?? false;\n    public bool IsSiteDeveloper => IsSystemAdmin;\n\n    private EffectivePermissions EffectivePermissions => _adminPermissions\n        ??= DnnUserInfo.NullOrGetWith(userInfo => dnnSecurity.Value.UserMayAdminThis(userInfo));\n    private EffectivePermissions _adminPermissions;\n\n\n    private UserInfo DnnUserInfo => _user.Get(() => PortalSettings.Current?.UserInfo);\n    private readonly GetOnce<UserInfo> _user = new();\n\n    public UserInfo GetContents() => DnnUserInfo;\n\n    private static List<int> BuildRoleList()\n    {\n        var psCurrent = PortalSettings.Current;\n        if (psCurrent == null)\n            return [];\n\n        var portalId = psCurrent.PortalId;\n        var user = psCurrent.UserInfo;\n        if (user == null)\n            return [];\n\n        var rc = new DotNetNuke.Security.Roles.RoleController();\n        return user.Roles\n            .Select(r => rc.GetRoleByName(portalId, r))\n            .Where(r => r != null)\n            .Select(r => r.RoleID)\n            .ToList();\n    }\n\n    public int Id => DnnUserInfo?.UserID ?? Null.NullInteger;\n\n    public bool IsAnonymous => Id == -1;\n\n    public string Username => DnnUserInfo?.Username ?? \"\";\n\n    public string Name => DnnUserInfo?.DisplayName ?? \"\";\n\n    public string Email => DnnUserInfo?.Email ?? \"\";\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DataSources/DataProviders/DnnPagesDsProvider.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Tabs;\nusing DotNetNuke.Security.Permissions;\nusing ToSic.Sxc.Cms.Pages.Sys;\nusing ToSic.Sxc.DataSources.Sys.Pages;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\n[PrivateApi]\ninternal class DnnPagesDsProvider() : PagesDataSourceProvider(\"Dnn.Pages\")\n{\n    private const int DnnNoParent = -1;\n    private const int DnnLevelOffset = 1;\n\n    public override List<PageModelRaw> GetPagesInternal(\n        NoParamOrder npo = default,\n        bool includeHidden = default,\n        bool includeDeleted = default,\n        bool includeAdmin = default,\n        bool includeSystem = default,\n        bool includeLinks = default,\n        bool requireViewPermissions = true,\n        bool requireEditPermissions = true)\n    {\n        var l = Log.Fn<List<PageModelRaw>>($\"PortalId: {PortalSettings.Current?.PortalId ?? -1}\");\n        List<TabInfo> pages;\n        try\n        {\n            var siteId = PortalSettings.Current?.PortalId ?? -1;\n            const bool addDummyNoneSpecifiedPage = false;\n            pages = TabController.GetPortalTabs(siteId, 0, addDummyNoneSpecifiedPage,\n                includeHidden, includeDeleted, includeLinks);\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return([], \"error\");\n        }\n\n        if (pages == null || !pages.Any()) return l.Return([], \"null/empty\");\n\n        try\n        {\n            IEnumerable<TabInfo> filtered = pages;\n\n            // Apply filters as needed\n            if (!includeAdmin)\n                filtered = filtered.Where(x => !x.IsSystem);\n            if (!includeSystem)\n                filtered = filtered.Where(x => !x.IsSuperTab);\n            if (requireViewPermissions)\n                filtered = filtered.Where(TabPermissionController.CanViewPage);\n            if (requireEditPermissions)\n                filtered = filtered.Where(TabPermissionController.CanAdminPage);\n\n            var final = filtered.ToList();\n\n            var result = final\n                .Select(p => new PageModelRaw\n                {\n                    Id = p.TabID,\n                    Guid = p.UniqueId,\n                    Title = p.Title.UseFallbackIfNoValue(p.TabName),\n                    Name = p.TabName,\n                    ParentId = p.ParentId == DnnNoParent ? NoParent : p.ParentId,\n                    Path = p.TabPath.FlattenMultipleForwardSlashes(),\n                    Url = p.FullUrl.TrimLastSlash(),\n                    Created = p.CreatedOnDate,\n                    Modified = p.LastModifiedOnDate,\n                    IsNavigation = p.IsVisible, // note: renamed in 19.01 to `IsNavigation` from `Visible`\n\n                    // New 15.01\n                    IsClickable = !p.DisableLink,\n                    HasChildren = p.HasChildren,\n                    IsDeleted = p.IsDeleted,\n                    Level = p.Level + DnnLevelOffset,\n                    Order = p.TabOrder,\n                    // New in 15.02\n                    LinkTarget = (string)p.TabSettings[\"LinkNewWindow\"] == true.ToString() ? \"_blank\": \"\",\n                })\n                .ToList();\n            return l.Return(result, $\"found {result.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return([], \"error\");\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DataSources/DataProviders/DnnRolesDsProvider.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing DotNetNuke.Security.Roles;\nusing ToSic.Sxc.Cms.Users.Sys;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Deliver a list of roles from the Dnn.\n/// </summary>\ninternal class DnnRolesDsProvider() : ServiceBase(\"Dnn.Roles\"), IUserRolesProvider\n{\n    public IEnumerable<UserRoleModel> GetRoles()\n    {\n        var l = Log.Fn<IEnumerable<UserRoleModel>>();\n        var siteId = PortalSettings.Current?.PortalId ?? -1;\n        l.A($\"Portal Id {siteId}\");\n        try\n        {\n            var dnnRoles = RoleController.Instance.GetRoles(portalId: siteId);\n            if (!dnnRoles.Any())\n                return l.Return(new List<UserRoleModel>(), \"null/empty\");\n\n            var result = dnnRoles\n                .Select(r => new UserRoleModel\n                {\n                    Id = r.RoleID,\n                    // Guid = r.\n                    Name = r.RoleName,\n                    Created = r.CreatedOnDate,\n                    Modified = r.LastModifiedOnDate,\n                })\n                .ToList();\n            return l.Return(result, \"found\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return(new List<UserRoleModel>(), \"error\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DataSources/DataProviders/DnnSitesDsProvider.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing ToSic.Sxc.Cms.Sites.Sys;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\n[PrivateApi]\ninternal class DnnSitesDsProvider(SitesDataSourceProvider.Dependencies services)\n    : SitesDataSourceProvider(services, \"Dnn.Sites\")\n{\n    public override List<SiteModel> GetSitesInternal()\n    {\n        var l = Log.Fn<List<SiteModel>>($\"PortalId: {PortalSettings.Current?.PortalId ?? -1}\");\n        var portals = PortalController.Instance\n            .GetPortals()\n            .OfType<PortalInfo>()\n            .ToList();\n\n        if (!portals.Any())\n            return l.Return([], \"null/empty\");\n\n        var result = portals\n            .Select(s => new SiteModel\n            {\n                Id = s.PortalID,\n                Guid = s.GUID,\n                Name = s.PortalName,\n                Url = GetUrl(s.PortalID, s.DefaultLanguage).TrimLastSlash(),\n                DefaultLanguage = s.DefaultLanguage.ToLower() ?? \"\",\n                Languages = GetLanguages(s.PortalID),\n                Created = s.CreatedOnDate,\n                Modified = s.LastModifiedOnDate,\n                ZoneId = GetZoneId(s.PortalID),\n                ContentAppId = GetDefaultAppId(s.PortalID),\n                PrimaryAppId = GetPrimaryAppId(s.PortalID)\n            })\n            .ToList();\n        return l.Return(result, $\"found {result.Count}\");\n\n    }\n\n    private string GetUrl(int portalId, string cultureCode)\n    {\n        var primaryPortalAlias = PortalAliasController.Instance\n            .GetPortalAliasesByPortalId(portalId)\n            .GetAliasByPortalIdAndSettings(portalId, result: null, cultureCode, settings: new(portalId));\n        return primaryPortalAlias.HTTPAlias;\n    }\n\n    //private bool AllowRegistration(int userRegistration) =>\n    //    userRegistration != (int)Globals.PortalRegistrationType.NoRegistration \n    //    && userRegistration != (int)Globals.PortalRegistrationType.PrivateRegistration;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DataSources/DataProviders/DnnStartUpDataSources.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.DataSources.Sys;\nusing ToSic.Sxc.Cms.Sites.Sys;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.DataSources.Sys.Pages;\nusing ToSic.Sxc.Dnn.DataSources;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\ninternal static class DnnStartUpDataSources\n{\n    public static IServiceCollection AddDnnSxcDataSources(this IServiceCollection services)\n    {\n        // DataSourceProvider model\n        services.TryAddTransient<IUserRolesProvider, DnnRolesDsProvider>();\n        services.TryAddTransient<IUsersProvider, DnnUsersProvider>();\n\n        // info class to ensure SQL knows about default connections\n        services.TryAddTransient<SqlPlatformInfo, DnnSqlPlatformInfo>();\n\n        // General data sources\n        services.TryAddTransient<DnnSql>();\n        services.TryAddTransient<DnnUserProfile>();\n        services.TryAddTransient<DnnUserProfile.Dependencies>();\n\n        services.TryAddTransient<PagesDataSourceProvider, DnnPagesDsProvider>();\n        services.TryAddTransient<SitesDataSourceProvider, DnnSitesDsProvider>();\n\n        return services;\n    }\n    public static IServiceCollection AddDnnDataSources(this IServiceCollection services)\n    {\n        // General data sources\n        services.TryAddTransient<DnnSql>();\n        services.TryAddTransient<DnnUserProfile>();\n        services.TryAddTransient<DnnUserProfile.Dependencies>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DataSources/DataProviders/DnnUsersProvider.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Users;\nusing DotNetNuke.Security.Membership;\nusing DotNetNuke.Security.Roles;\nusing System.Collections;\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Dnn;\nusing ToSic.Sxc.Dnn.Run;\nusing static DotNetNuke.Common.Utilities.Null;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\ninternal class DnnUsersProvider(LazySvc<DnnSecurity> dnnSecurity)\n    : ServiceBase(\"Dnn.Users\", connect: [dnnSecurity]), IUsersProvider\n{\n    #region Configuration\n    private UsersGetSpecs _specs;\n    private UsersGetSpecsParsed SpecsParsed => field ??= new(_specs);\n    #endregion\n\n    public string PlatformIdentityTokenPrefix => DnnConstants.UserTokenPrefix;\n\n    public IUserModel GetUser(int userId, int siteId)\n    {\n        var user = UserController.Instance.GetUserById(siteId, userId);\n        return user == null\n            ? null\n            : dnnSecurity.Value.CmsUserBuilder(user, siteId);\n    }\n\n    public IEnumerable<UserModel> GetUsers(UsersGetSpecs specs)\n    {\n        var l = Log.Fn<IEnumerable<UserModel>>($\"specs:{specs}\");\n        _specs = specs;\n        try\n        {\n            return l.Return(GetUsersInternal(), \"found\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return(new List<UserModel>(), \"error\");\n        }\n    }\n\n    private IEnumerable<UserModel> GetUsersInternal()\n    {\n        var l = Log.Fn<List<UserModel>>();\n        var siteId = PortalSettings.Current?.PortalId ?? NullInteger;\n        l.A($\"Portal Id {siteId}\");\n        try\n        {\n            var dnnUsers = new List<UserInfo>();\n\n            // Include users\n            if (_specs.UserIds.IsEmpty() && _specs.RoleIds.IsEmpty())\n            {\n                var dnnAllUsers = new ArrayList();\n\n                if (!_specs.IncludeSystemAdmins.EqualsInsensitive(UserConstants.IncludeRequired))\n                    // take all portal users (this should include superusers, but superusers are missing)\n                    dnnAllUsers.AddRange(UserController.GetUsers(portalId: siteId, includeDeleted: false, superUsersOnly: false));\n\n                if (!_specs.IncludeSystemAdmins.EqualsInsensitive(UserConstants.IncludeForbidden))\n                    // append all superusers\n                    dnnAllUsers.AddRange(UserController.GetUsers(portalId: -1, includeDeleted: false, superUsersOnly: true));\n\n                dnnUsers.AddRange(dnnAllUsers.Cast<UserInfo>().ToList());\n            }\n            else\n            {\n                // UserIds\n                dnnUsers.AddRange(SpecsParsed.UserIdFilter.Except(SpecsParsed.ExcludeUserIdsFilter)\n                    .Select(userId => UserController.GetUserById(siteId, userId)));\n\n                dnnUsers.AddRange(SpecsParsed.UserGuidFilter.Except(SpecsParsed.ExcludeUserGuidsFilter)\n                    .Select(membershipUserKey => GetUserByMembershipUserKey(siteId, membershipUserKey)));\n\n                // RoleIds\n                dnnUsers.AddRange(SpecsParsed.RolesFilter.Except(SpecsParsed.ExcludeRolesFilter)\n                    .SelectMany(roleId => GetUsersByRoleId(siteId, roleId)));\n            }\n\n            // Exclude users\n            dnnUsers = dnnUsers.Distinct().Where(user => !ExcludeUser(user)).ToList();\n\n            if (!dnnUsers.Any())\n                return l.Return([], \"null/empty\");\n\n            var users = dnnUsers\n                //.Where(user => !user.IsDeleted)\n                .Select(u => dnnSecurity.Value.CmsUserBuilder(u, siteId))\n                .ToList();\n\n            return l.Return(users, \"found\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return([], \"error\");\n        }\n    }\n\n    private bool ExcludeUser(UserInfo user)\n    {\n        if (user == null) return true;\n        if (SpecsParsed.ExcludeUserIdsFilter.Contains(user.UserID)) return true;\n        if (SpecsParsed.ExcludeUserGuidsFilter.Contains(dnnSecurity.Value.UserGuid(user))) return true;\n        if (SpecsParsed.ExcludeRolesFilter.Any(roleId => user.IsInRole(RoleController.Instance.GetRoleById(user.PortalID, roleId).RoleName))) return true;\n        if (_specs.IncludeSystemAdmins.EqualsInsensitive(UserConstants.IncludeForbidden) && user.IsSuperUser) return true;\n        if (_specs.IncludeSystemAdmins.EqualsInsensitive(UserConstants.IncludeRequired) && !user.IsSuperUser) return true;\n        return false;\n    }\n\n    private static IList<UserInfo> GetUsersByRoleId(int siteId, int roleId)\n        => UserController.Instance\n            .GetUsersAdvancedSearch(\n                portalId: siteId,\n                userId: NullInteger,\n                filterUserId: NullInteger,\n                filterRoleId: roleId,\n                relationTypeId: NullInteger,\n                isAdmin: false,\n                pageIndex: 0,\n                pageSize: NullInteger,\n                sortColumn: null,\n                sortAscending: true,\n                propertyNames: null,\n                propertyValues: null\n            )\n            .ToList();\n\n    private static UserInfo GetUserByMembershipUserKey(int portalId, Guid membershipUserKey)\n    {\n        var masterPortalId = PortalController.GetEffectivePortalId(portalId);\n        var user = MembershipProvider.Instance().GetUserByProviderUserKey(masterPortalId, membershipUserKey.ToString());\n        if (user != null)\n            user.PortalID = portalId;\n        return user;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DataSources/DnnSql.cs",
    "content": "﻿using ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Eav.DataSources;\n\nnamespace ToSic.Sxc.Dnn.DataSources;\n\n/// <summary>\n/// Retrieves data from SQL, specifically using the DNN Connection String\n/// </summary>\n[PublicApi]\n[VisualQuery(\n    NiceName = \"Dnn SQL\",\n    UiHint = \"Data from the Dnn database\",\n    Icon = DataSourceIcons.DynamicForm,\n    Type = DataSourceType.Source, \n    NameId = \"b9df1b84-7b50-418c-a476-1ce49193cd77\",\n    NameIds =\n    [\n        \"ToSic.Sxc.Dnn.DataSources.DnnSql, ToSic.Sxc.Dnn\",\n        \"ToSic.SexyContent.DataSources.DnnSqlDataSource, ToSic.SexyContent\",\n        \"ToSic.SexyContent.Environment.Dnn7.DataSources.DnnSqlDataSource, ToSic.SexyContent\"\n    ],\n    HelpLink = \"https://github.com/2sic/2sxc/wiki/DotNet-DataSource-DnnSqlDataSource\",\n    ConfigurationType = \"|Config ToSic.SexyContent.DataSources.DnnSqlDataSource\")]\npublic class DnnSql : Sql\n{\n    [PrivateApi]\n    public DnnSql(Dependencies services) : base(services)\n    {\n        ConnectionStringName = DnnSqlPlatformInfo.SiteSqlServer;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DataSources/DnnSqlPlatformInfo.cs",
    "content": "﻿using ToSic.Eav.DataSources.Sys;\n\nnamespace ToSic.Sxc.Dnn.DataSources;\n\npublic class DnnSqlPlatformInfo: SqlPlatformInfo\n{\n    // String \"SiteSqlServer\" isn't available in any constant in DNN\n    internal const string SiteSqlServer = \"SiteSqlServer\";\n\n    public override string DefaultConnectionStringName => SiteSqlServer;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DataSources/DnnUserProfileDataRaw.cs",
    "content": "﻿using DotNetNuke.Entities.Users;\nusing System.Collections;\nusing System.Collections.Immutable;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Dnn.Run;\n\nnamespace ToSic.Sxc.Dnn.DataSources;\n\n/// <summary>\n/// Get DNN user profiles as <see cref=\"IEntity\"/> objects of one or many users.\n/// </summary>\n[PublicApi]\n[VisualQuery(\n    NiceName = \"Dnn User Profiles\",\n    UiHint = \"Users profiles of specified users in Dnn\",\n    Icon = DataSourceIcons.Face,\n    Type = DataSourceType.Source, \n    NameId = \"34bbcbee-72cd-483f-8c42-c2e696b21b14\",\n    ConfigurationType = \"|Config ToSic.SexyContent.DataSources.DnnUserProfileDataSource\",\n    NameIds =\n    [\n        \"ToSic.Sxc.Dnn.DataSources.DnnUserProfile, ToSic.Sxc.Dnn\",\n        \"ToSic.SexyContent.Environment.Dnn7.DataSources.DnnUserProfileDataSource, ToSic.SexyContent\"\n    ]\n)]\npublic class DnnUserProfile : CustomDataSourceAdvanced\n{\n    #region Configuration-properties\n\n    /// <summary>\n    /// The user id list of users to retrieve, comma-separated\n    /// </summary>\n    [Configuration]\n    public string UserIds\n    {\n        get => _userIds ?? Configuration.GetThis();\n        set => _userIds = value;\n    }\n    private string _userIds;\n\n    /// <summary>\n    /// List of profile-properties to retrieve, comma-separated\n    /// </summary>\n    [Configuration(Fallback = \"DisplayName,Email,FirstName,LastName,Username\")]\n    public string Properties\n    {\n        get => _properties ?? Configuration.GetThis();\n        set => _properties = value;\n    }\n    private string _properties;\n\n    /// <summary>\n    /// Gets or sets the Name of the ContentType to simulate\n    /// </summary>\n    [Configuration(Field = \"ContentTypeName\", Fallback = DnnUserProfileDataRaw.TypeName)]\n    public string ContentType\n    {\n        get => _contentType ?? Configuration.GetThis();\n        set => _contentType = value;\n    }\n    private string _contentType;\n\n    /// <summary>\n    /// Gets or sets the Name of the Title Attribute of the DNN-UserInfo\n    /// </summary>\n    [Configuration(Field = \"TitleFieldName\", Fallback = \"DisplayName\")]\n    public string TitleField\n    {\n        get => _titleField ?? Configuration.GetThis();\n        set => _titleField = value;\n    }\n    private string _titleField;\n\n    #endregion\n\n    #region Constructor / DI\n\n    public new record Dependencies(CustomDataSourceAdvanced.Dependencies ParentServices, ISite Site, IZoneMapper ZoneMapper, LazySvc<DnnSecurity> DnnSecurity)\n        : DependenciesRecord(connect: [Site, ZoneMapper, DnnSecurity]);\n\n    public DnnUserProfile(Dependencies services) : base(services.ParentServices, \"Dnn.Profile\", connect: [services])\n    {\n        _services = services;\n        ProvideOut(GetList);\n    }\n\n    private readonly Dependencies _services;\n\n    #endregion\n\n    private IImmutableList<IEntity> GetList()\n    {\n        var l = Log.Fn<IImmutableList<IEntity>>();\n        Configuration.Parse();\n\n        var realTenant = _services.Site.Id != EavConstants.NullId\n            ? _services.Site\n            : _services.ZoneMapper.SiteOfApp(AppId);\n        l.A($\"realTenant {realTenant.Id}\");\n\n        var properties = Properties.CsvToArrayWithoutEmpty();\n        var portalId = realTenant.Id;\n\n        // read all user Profiles\n        ArrayList users;\n        if (!UserIds.HasValue() ||\n            UserIds == \"disabled\") // note: 'disabled' was the default text in <v15. can probably be removed, but not sure\n            users = UserController.GetUsers(portalId);\n        // read user Profiles of specified UserIds\n        else\n        {\n            var userIds = UserIds.Split(',').Select(n => Convert.ToInt32(n)).ToArray();\n            users = [];\n            foreach (var user in userIds.Select(userId => UserController.GetUserById(portalId, userId)))\n                users.Add(user);\n        }\n        l.A($\"users: {users.Count}\");\n\n        // convert Profiles to Entities\n        var results = new List<DnnUserProfileDataRaw>();\n        foreach (UserInfo user in users)\n        {\n            var dnnUserProfile = new DnnUserProfileDataRaw\n            {\n                Id = user.UserID,\n                Guid = _services.DnnSecurity.Value.UserGuid(user),\n                Name = GetDnnProfileValue(user, TitleField.ToLowerInvariant())\n            };\n\n            // add Profile-Properties\n            foreach (var property in properties)\n                dnnUserProfile.Properties.Add(property, GetDnnProfileValue(user, property));\n\n            results.Add(dnnUserProfile);\n        }\n        l.A($\"results: {results.Count}\");\n        var userProfileDataFactory = DataFactory.SpawnNew(options: DnnUserProfileDataRaw.Options with { TypeName = ContentType?.NullIfNoValue() });\n        return l.Return(userProfileDataFactory.Create(results), \"ok\");\n    }\n\n    private static string GetDnnProfileValue(UserInfo user, string property)\n    {\n        string value;\n        switch (property.ToLowerInvariant())\n        {\n            case \"displayname\":\n                value = user.DisplayName;\n                break;\n            case \"email\":\n                value = user.Email;\n                break;\n            case \"firstname\":\n                value = user.FirstName;\n                break;\n            case \"lastname\":\n                value = user.LastName;\n                break;\n            case \"username\":\n                value = user.Username;\n                break;\n            default:\n                value = user.Profile.GetPropertyValue(property);\n                break;\n        }\n        return value;\n    }\n}\n\n/// <summary>\n/// Internal class to hold all the information about the user profile,\n/// until it's converted to an IEntity in the <see cref=\"DnnUserProfile\"/> DataSource.\n///\n/// For detailed documentation, check the docs of the underlying objects:\n///\n/// * TODO:\n/// * TODO:\n/// Important: this is an internal object.\n/// We're just including in in the docs to better understand where the properties come from.\n/// We'll probably move it to another namespace some day.\n/// </summary>\n/// <remarks>\n/// Make sure the property names never change, as they are critical for the created Entity.\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic class DnnUserProfileDataRaw : IRawEntity\n{\n    internal const string TypeName = \"UserProfile\";\n\n    internal static DataFactoryOptions Options = new()\n    {\n        TypeName = TypeName,\n        TitleField = nameof(Name)\n    };\n    public int Id { get; set; }\n    public Guid Guid { get; set; }\n    public string Name { get; set; } // aka DisplayName\n\n    public DateTime Created { get; set; }\n    public DateTime Modified { get; set; }\n\n    public Dictionary<string, object> Properties { get; } = new();\n\n    /// <summary>\n    /// Data but without Id, Guid, Created, Modified\n    /// </summary>\n    [PrivateApi]\n    public IDictionary<string, object> Attributes(RawConvertOptions options) => new Dictionary<string, object>(Properties)\n    {\n        { AttributeNames.TitleNiceName, Name },\n        { nameof(Name), Name },\n    };\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DnnBusinessController.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Services.Search.Entities;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Dnn.Context;\nusing ToSic.Sxc.Dnn.Install;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Dnn.Search;\n\nnamespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// This is the connector-class which DNN consults when it needs to know things about a module\n/// It's used in the background, not when the page is loading\n/// </summary>\npublic class DnnBusinessController : ModuleSearchBase, IHasLog\n{\n    #region Constructor (not DI)\n\n    /// <summary>\n    /// Constructor overload for DotNetNuke\n    /// (BusinessController needs a parameterless constructor)\n    /// </summary>\n    public DnnBusinessController() => Log = new Log(\"DNN.BusCon\", null, \"starting\");\n\n    public ILog Log { get; }\n\n    #endregion\n\n\n    #region Service Providing\n\n    /// <summary>\n    /// Get the service provider only once - ideally in Dnn9.4 we will get it from Dnn\n    /// If we would get it multiple times, there are edge cases where it could be different each time! #2614\n    /// </summary>\n    private IServiceProvider ServiceProvider => _serviceProvider.Get(DnnStaticDi.GetPageScopedServiceProvider);\n    private readonly GetOnce<IServiceProvider> _serviceProvider = new();\n\n    #endregion\n\n    #region DNN Interface Members - search, upgrade, versionable\n\n    private IPagePublishing Publishing\n    {\n        get\n        {\n            if (field != null)\n                return Publishing;\n\n            // if publishing is used, make sure it's in the log-history\n            field = ServiceProvider.Build<IPagePublishing>(Log);\n            ServiceProvider.Build<ILogStore>().Add(\"dnn-publishing\", Log);\n            return field;\n        }\n    }\n\n\n    public int GetLatestVersion(int instanceId) => Publishing.GetLatestVersion(instanceId);\n\n    public int GetPublishedVersion(int instanceId) => Publishing.GetPublishedVersion(instanceId);\n\n    public void PublishVersion(int instanceId, int version)\n    {\n        Log.A($\"publish m#{instanceId}, v:{version}\");\n        Publishing.Publish(instanceId, version);\n\n        try\n        {\n            DnnLogging.LogToDnn(\"Publishing\", \"ok\", Log, force: true);\n        }\n        catch\n        {\n            // ignore\n        }\n    }\n\n\n\n    public void DeleteVersion(int instanceId, int version) \n        => Log.A(\"delete version is not supported\");\n\n    public int RollBackVersion(int instanceId, int version)\n    {\n        Log.A(\"DNN tried to rollback version \" + version + \", but 2sxc does not support this.\");\n\n        // Return the currently published version, because this is what the module's state is after this operation\n        return Publishing.GetPublishedVersion(instanceId);\n    }\n\n    /// <summary>\n    /// This is part of the IUpgradeable of DNN\n    /// </summary>\n    /// <param name=\"version\"></param>\n    /// <returns></returns>\n    public string UpgradeModule(string version)\n    {\n        var l = Log.Fn<string>($\"upgrade module - start for v:{version}\");\n        var installer = ServiceProvider.Build<DnnEnvironmentInstaller>(Log);\n        var res = installer.UpgradeModule(version, true);\n        Log.A($\"result:{res}\");\n        DnnLogging.LogToDnn(\"Upgrade\", \"ok\", Log, force: true); // always log, this often causes hidden problems\n        return l.ReturnAndLog(res);\n    }\n\n    public override IList<SearchDocument> GetModifiedSearchDocuments(ModuleInfo moduleInfo, DateTime beginDate)\n    {\n        try\n        {\n            return ServiceProvider.Build<SearchController>(Log)\n                .GetModifiedSearchDocuments(((DnnModule)ServiceProvider.Build<IModule>(Log)).Init(moduleInfo), beginDate);\n        }\n        catch (Exception e)\n        {\n            DnnEnvironmentLogger.AddSearchExceptionToLog(moduleInfo, e, nameof(DnnBusinessController));\n            return new List<SearchDocument>();\n        }\n    }\n\n    #endregion\n        \n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DnnConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn;\n\npublic class DnnConstants\n{\n    public const string LogName = \"Dnn\";\n\n    public const string ModuleNameContent = \"2sxc\";\n    public const string ModuleNameApp = \"2sxc-app\";\n\n    public const string SysFolderRootVirtual = \"~/desktopmodules/tosic.sxc/\"; // This is the new folder where 2sxc v20+ is installed in DNN\n    public const string OldSysFolderRootVirtual = \"~/desktopmodules/tosic_sexycontent/\"; // This is the old folder where 2sxc before v20 was installed in DNN\n\n    internal const string LogDirectory = SysFolderRootVirtual + \"Upgrade/Log/\";\n\n    public const string DnnContextKey = \"DnnContext\";\n\n    /// <summary>\n    /// The ID in the current HTTP request for storing the EAV log object\n    /// </summary>\n    public const string EavLogKey = \"EavLog\";\n\n    /// <summary>\n    /// Application Setting key to enable extended logging\n    /// </summary>\n    public const string AdvancedLoggingEnabledKey = \"2sxc-enable-extended-logging\";\n        \n    /// <summary>\n    /// Application Setting key to ensure extended logging will expire\n    /// </summary>\n    public const string AdvancedLoggingTillKey = \"2sxc-extended-logging-expires\";\n\n    /// <summary>\n    /// AntiForgery token header name\n    /// </summary>\n    public const string AntiForgeryTokenHeaderName = \"RequestVerificationToken\";\n\n    /// <summary>\n    /// Prefix for user identity token\n    /// </summary>\n    public const string UserTokenPrefix = \"dnn:userid=\";\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DnnEnvironmentLogger.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Services.Exceptions;\nusing ToSic.Eav.ImportExport.Integration;\nusing ToSic.Sxc.Dnn.Search;\n\nnamespace ToSic.Sxc.Dnn;\n\npublic class DnnEnvironmentLogger: IEnvironmentLogger\n{\n    public void LogException(Exception ex)\n        => Exceptions.LogException(ex);\n\n    #region Diagnostics stuff\n\n    public static int SearchErrorsMax = 10;\n\n    public static int SearchErrorsCount { get; set; }\n\n    #endregion\n\n    public static void AddSearchExceptionToLog(ModuleInfo moduleInfo, Exception e, string nameOfSource)\n    {\n        var errCount = SearchErrorsCount++;\n        // ignore errors after 10\n        if (errCount > SearchErrorsMax) return;\n\n        if (errCount == SearchErrorsMax)\n        {\n            Exceptions.LogException(new SearchIndexException(moduleInfo,\n                new(\n                    $\"Hit {SearchErrorsMax} SearchIndex exceptions in 2sxc modules, will stop reporting them to not flood the error log. \\n\" +\n                    $\"To start reporting again up to {SearchErrorsMax} just restart the application. \\n\" +\n                    $\"To show more errors change 'ToSic.Sxc.Dnn.{nameof(DnnBusinessController)}.{nameof(SearchErrorsMax)}' to a higher number in some code of yours like in a temporary razor view. \" +\n                    $\"Note that in the meantime, the count may already be higher. You can always get that from {nameof(SearchErrorsCount)}.\"),\n                nameOfSource, errCount, SearchErrorsMax));\n            return;\n        }\n\n        Exceptions.LogException(new SearchIndexException(moduleInfo, e, nameOfSource, errCount, SearchErrorsMax));\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DnnModuleAndBlockBuilder.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Portals;\nusing ToSic.Eav.Context.Sys.Site;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Dnn.Context;\n\nnamespace ToSic.Sxc.Dnn;\n\ninternal class DnnModuleAndBlockBuilder(\n    Generator<IModule> moduleGenerator,\n    Generator<IContextOfBlock> contextGenerator,\n    Generator<BlockOfModule> blockGenerator)\n    : ModuleAndBlockBuilder(blockGenerator, DnnConstants.LogName, connect: [moduleGenerator, contextGenerator])\n{\n    private ILog ParentLog => (Log as Log)?.Parent ?? Log;\n\n\n    public override IModule GetModule(int pageId, int moduleId)\n    {\n        var l = Log.Fn<IModule>($\"{nameof(pageId)}: {pageId}, {nameof(moduleId)}: {moduleId}\");\n        var moduleInfo = new ModuleController().GetModule(moduleId, pageId, false);\n\n        l.A($\"Page Id on DNN Module: {moduleInfo.TabID} - should be {pageId}\");\n\n        ThrowIfModuleIsNull(pageId, moduleId, moduleInfo);\n        var module = ((DnnModule)moduleGenerator.New()).Init(moduleInfo);\n\n        return l.Return(module, $\"Page Id on IModule: {module.BlockIdentifier} - should be {pageId}\");\n    }\n\n    protected override IContextOfBlock GetContextOfBlock(IModule module, int? pageId)\n        => GetContextOfBlock((module as DnnModule)?.GetContents(), pageId);\n\n\n    protected override IContextOfBlock GetContextOfBlock<TPlatformModule>(TPlatformModule module, int? pageId)\n    {\n        if (module == null) throw new ArgumentNullException(nameof(module));\n        if (module is not ModuleInfo dnnModule) throw new ArgumentException(\"Given data is not a module\");\n        Log.A($\"Module: {dnnModule.ModuleID}\");\n\n        var initializedCtx = InitDnnSiteModuleAndBlockContext(dnnModule, pageId);\n        return initializedCtx;\n    }\n\n    private IContextOfBlock InitDnnSiteModuleAndBlockContext(ModuleInfo dnnModule, int? pageId)\n    {\n        var l = Log.Fn<IContextOfBlock>($\"{nameof(pageId)}: {pageId}, {nameof(dnnModule.ModuleID)}: {dnnModule.ModuleID}\");\n        var context = contextGenerator.New();\n        l.A($\"Will try-swap module info of {dnnModule.ModuleID} into site\");\n        ((DnnSite)context.Site).TryInitModule(dnnModule, ParentLog);\n        l.A(\"Will init module\");\n        ((DnnModule)context.Module).Init(dnnModule);\n        return l.ReturnAsOk(InitPageOnly(context, pageId));\n    }\n\n    private IContextOfBlock InitPageOnly(IContextOfBlock context, int? pageId)\n    {\n        var l = Log.Fn<IContextOfBlock>($\"{nameof(pageId)}: {pageId}\");\n        // Collect / assemble page information\n        var activeTab = (context.Site as Site<PortalSettings>)?.GetContents()?.ActiveTab;\n        var page = (DnnPage)context.Page;\n        var url = page.InitPageIdAndUrl(activeTab, pageId);\n        return l.Return(context, url);\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DnnStaticDi.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing System.Web;\n\nnamespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// This is a temporary helper for Dnn 7+ to help with dependency injection which is\n/// patched unto Dnn.\n/// </summary>\npublic static class DnnStaticDi\n{\n    private static Func<IServiceProvider> _getGlobalDnnServiceProvider;\n\n    public static void StaticDiReady(Func<IServiceProvider> spFunc = null) \n        => _getGlobalDnnServiceProvider = spFunc ?? throw new(\"Can't start Static DI for old Dnn, because the ServiceCollection is null.\");\n\n    /// <summary>\n    /// This is a special internal resolver for static objects\n    /// Should only be used with extreme caution, as downstream objects\n    /// May need more scope-specific stuff, why may be missing\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <returns></returns>\n    [PrivateApi]\n    [Obsolete(\"Avoid using at all cost - only DNN and test-code may use this!\")]\n    public static T StaticBuild<T>(ILog parentLog = null)\n        => GetPageScopedServiceProvider().Build<T>(parentLog);\n\n    /// <summary>\n    /// Dictionary key for keeping the Scoped Injection Service Provider in the Http-Context\n    /// </summary>\n    /// <remarks>\n    /// In v13 we changed key to one used in DNN9 DI instead old one \"eav-scoped-serviceprovider\"\n    /// </remarks>\n    private static readonly Type ServiceScopeKey = typeof(IServiceScope);\n\n    public static IServiceProvider GetGlobalScopedServiceProvider()\n        => GetGlobalServiceProvider().CreateScope().ServiceProvider;\n\n    [PrivateApi(\"Very internal, to use at startup, so singletons are not lost\")]\n    private static IServiceProvider GetGlobalServiceProvider()\n        => Sp.Get(() => _getGlobalDnnServiceProvider?.Invoke() ?? throw new(\"can't access global DNN service provider\"));\n    private static readonly GetOnce<IServiceProvider> Sp = new();\n\n    [PrivateApi(\"This is just a temporary solution - shouldn't be used long term\")]\n    public static IServiceProvider GetPageScopedServiceProvider()\n    {\n        // Because 2sxc runs inside DNN as a webforms project and not asp.net core mvc, we have\n        // to make sure the service-provider object is disposed correctly. If we don't do this,\n        // connections to the database are kept open, and this leads to errors like \"SQL timeout:\n        // \"All pooled connections were in use\". https://github.com/2sic/2sxc/issues/1200\n        // Work-around for issue https://github.com/2sic/2sxc/issues/1200\n        // Scope service-provider based on request\n        var httpCtx = HttpContext.Current;\n        if (httpCtx == null)\n            return GetGlobalServiceProvider().CreateScope().ServiceProvider;\n\n        // This only runs in Dnn 7.4.2 - Dnn 9.3, because Dnn 9.4 provides this in the http context\n        if (!httpCtx.Items.Contains(ServiceScopeKey))\n        {\n            httpCtx.Items[ServiceScopeKey] = GetGlobalServiceProvider().CreateScope();\n\n            // Make sure service provider is disposed after request finishes\n            httpCtx.AddOnRequestCompleted(context => ((IDisposable)context.Items[ServiceScopeKey])?.Dispose());\n        }\n\n        return httpCtx.Items[ServiceScopeKey] is IServiceScope scope ? scope.ServiceProvider : null;\n    }\n\n    [PrivateApi]\n    public static IServiceProvider CreateModuleScopedServiceProvider()\n    {\n        var pageSp = GetPageScopedServiceProvider();\n        var moduleSp = pageSp.CreateScope().ServiceProvider;\n\n        // In the module scope, we initialize the scoped PageScope Accessor and give it the parent scope\n        // This is necessary for it to be able to give page-scoped objects\n        moduleSp.Build<PageScopeAccessor>().InitPageOfModule(pageSp);\n        return moduleSp;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DnnSxcSettings.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Dnn;\n\ninternal class DnnSxcSettings\n{\n\n    /// <summary>\n    /// Special user groups to determine if admins can really admin\n    /// </summary>\n    public static readonly string[] DnnGroupsSxcAdmins =\n    [\n        \"2sxc designers\",       // Old, original name since ca. 2sxc 4+\n        \"2sxcAdministrators\",   // New in v13.03 - to replace the old name for clarity\n    ];\n\n    public const string DnnAdminRoleDefaultName = \"Administrators\";\n\n    /// <summary>\n    /// Content Editors Advanced Role Name.\n    /// </summary>\n    /// <remarks>\n    /// AdvancedPermissionProvider in DNN v10\n    /// </remarks>\n    public const string DnnContentEditors = \"Content Editors\";\n\n    /// <summary>\n    /// Content Managers Advanced Role Name.\n    /// </summary>\n    /// <remarks>\n    /// AdvancedPermissionProvider in DNN v10\n    /// </remarks>\n    public const string DnnContentManagers = \"Content Managers\";\n\n    public static class Installation\n    {\n        // This list is just used to run code-upgrades in DNN\n        // So we only need the versions which do have code upgrades - which is very uncommon\n        // todo: Maybe this list can somehow be extracted from the module manifest or placed there...\n        internal static readonly string[] UpgradeVersionList =\n        [\n            // new installer of 2sxc v20 doesn't upgrade versions before v15, so removed all those versions\n            \"15.00.00\",\n            \"15.02.00\",\n            \"20.00.00\",\n            \"20.00.01\",\n            EavSystemInfo.VersionString,\n        ];\n\n        // this is the last version which must run server-side change-code\n        // it's not sql-code, as the SqlDataProvider files are imported by DNN, not by our code\n        internal const string LastVersionWithServerChanges = \"20.00.01\";\n        internal const string LastVersionWithDnnDbChanges = \"21.00.00\"; // just fyi, not used anywhere\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/DynamicCode.cs",
    "content": "﻿using ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.Run;\n\nnamespace ToSic.Sxc.Dnn;\n\n// ReSharper disable once UnusedMember.Global\n/// <summary>\n/// This is a base class for custom code files with context. <br/>\n/// If you create a class file for dynamic use and inherit from this, then the compiler will automatically add objects like Link, Dnn, etc.\n/// The class then also has AsDynamic(...) and AsList(...) commands like a normal razor page.\n/// </summary>\n[PublicApi]\npublic abstract class DynamicCode : Sxc.Code.DynamicCode, IHasDnn\n{\n    /// <inheritdoc />\n    public IDnnContext Dnn => (ExCtxOrNull as IHasDnn)?.Dnn;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Features/DnnBuiltInFeatures.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Dnn.Features;\n\ninternal partial class DnnBuiltInFeatures\n{\n    public static void Register(FeaturesCatalog cat) =>\n        cat.Register(\n            DnnPageWorkflow\n        );\n\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Features/DnnBuiltInFeatures_CorePlus.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Dnn.Features;\n\npartial class DnnBuiltInFeatures\n{\n    public static readonly Feature DnnPageWorkflow = new()\n    {\n        NameId = \"DnnPageWorkflow\",\n        Guid = new(\"da68d954-5220-4f9c-a485-86f16b98629a\"),\n        Name = \"Support for Dnn / Evoq Page Workflow\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Enables support for Page Workflow in Evoq; on by default. It seems that in Evoq ca. v9.4+ it has become buggy. So you can disable it now. \",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = BuiltInFeatures.ForCorePlusEnabled\n    };\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Features/DnnRequirements.cs",
    "content": "﻿using ToSic.Eav.Metadata.Requirements.Sys;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sys.Capabilities.SysFeatures;\nusing ToSic.Sys.Requirements;\n\nnamespace ToSic.Sxc.Dnn.Features;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DnnRequirements(IRequirementsService requirements) : EngineRequirementsBase(\"Eng.DnnReq\", connect: [requirements])\n{\n    internal bool RequirementsMet() \n        => !RequirementsStatus().SafeAny();\n\n    private ICollection<RequirementStatus> RequirementsStatus()\n        => requirements.UnfulfilledRequirements([SysFeatureSuggestions.CSharp08]);\n\n    internal RenderEngineResult GetMessageForRequirements()\n    {\n        var l = Log.Fn<RenderEngineResult>();\n\n        if (RequirementsMet())\n            return l.ReturnNull(\"all seems ok\");\n\n        var result = BuildRenderEngineResult(RequirementsStatus());\n        return l.Return(result, \"error\");\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Features/SysFeatureDetectorBlazor.cs",
    "content": "﻿using ToSic.Sys.Capabilities.SysFeatures;\nusing static ToSic.Sys.Capabilities.SysFeatures.SysFeatureSuggestions;\n\nnamespace ToSic.Sxc.Dnn.Features;\n\ninternal class SysFeatureDetectorBlazor()\n    : SysFeatureDetector(Blazor with { Name = Blazor.Name + \" (not available in Dnn)\" }, false);"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Features/SysFeatureDetectorCSharpInDnn.cs",
    "content": "﻿using ToSic.Sys.Capabilities.SysFeatures;\nusing static ToSic.Sys.Capabilities.SysFeatures.SysFeatureSuggestions;\nusing static ToSic.Sxc.Dnn.Compile.RoslynCompilerCapability;\n\nnamespace ToSic.Sxc.Dnn.Features;\n\ninternal class SysFeatureDetectorCSharp6() : SysFeatureDetector(CSharp06 with { Name = \" required for 2sxc 17\" })\n{\n    public override bool IsEnabled => _isEnabledCache ??= CheckCsharpLangVersion(6); // C# 6\n    private static bool? _isEnabledCache;\n}\n\ninternal class SysFeatureDetectorCSharp7() : SysFeatureDetector(CSharp07 with { Name = $\"{CSharp07.Name} required for 2sxc 17\" })\n{\n    public override bool IsEnabled => _isEnabledCache ??= CheckCsharpLangVersion(703); // C# 7.3;\n    private static bool? _isEnabledCache;\n}\n\ninternal class SysFeatureDetectorCSharp8() : SysFeatureDetector(CSharp08 with { Name = $\"{CSharp08.Name} required for 2sxc 17\" })\n{\n    public override bool IsEnabled => _isEnabledCache ??= CheckCsharpLangVersion(800); // C# 8; - code is 800\n    private static bool? _isEnabledCache;\n}\n\ninternal class SysFeatureDetectorCSharp9() : SysFeatureDetector(CSharp09 with { Name = $\"{CSharp09.Name} (not available in Dnn)\" });\n\ninternal class SysFeatureDetectorCSharp10() : SysFeatureDetector(CSharp10 with { Name = $\"{CSharp10.Name} (not available in Dnn)\" });\n\ninternal class SysFeatureDetectorCSharp11() : SysFeatureDetector(CSharp11 with { Name = $\"{CSharp11.Name} (not available in Dnn)\" });\n\ninternal class SysFeatureDetectorCSharp12() : SysFeatureDetector(CSharp12 with { Name = $\"{CSharp12.Name} (not available in Dnn)\" });"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Features/SysFeatureDnn.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Capabilities.SysFeatures;\n\nnamespace ToSic.Sxc.Dnn.Features;\n\n// ReSharper disable once UnusedMember.Global - since it's used by reflection\ninternal class SysFeatureDnn() : SysFeatureDetector(DefStatic, true)\n{\n    private static readonly SysFeature DefStatic = new()\n    {\n        NameId = \"Dnn\",\n        Guid = new(\"00cb8d98-bfac-4a18-b7de-b1237498f183\"),\n        Name = \"Dnn\",\n        LicenseRules = BuiltInLicenseRules.SystemEnabled,\n    };\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/ImportExport/DnnImportExportEnvironment.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing DotNetNuke.Services.Exceptions;\nusing DotNetNuke.Services.FileSystem;\nusing ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Sxc.Sys.Integration;\n\nnamespace ToSic.Sxc.Dnn.ImportExport;\n\ninternal class DnnImportExportEnvironment : SxcImportExportEnvironmentBase\n{\n    #region Constructors\n\n    /// <summary>\n    /// DI Constructor\n    /// </summary>\n    public DnnImportExportEnvironment(Dependencies services) : base(services, \"Dnn.ImExEn\") { }\n\n    #endregion\n\n    /// <inheritdoc />\n    /// <summary>\n    /// Copy all files from SourceFolder to DestinationFolder\n    /// </summary>\n    /// <param name=\"sourceFolder\"></param>\n    /// <param name=\"destinationFolder\">The portal-relative path where the files should be copied to</param>\n    public override List<Message> TransferFilesToSite(string sourceFolder, string destinationFolder)\n    {\n        var l = Log.Fn<List<Message>>($\"{sourceFolder}, {destinationFolder}\");\n        var messages = new List<Message>();\n        var files = Directory.GetFiles(sourceFolder, \"*.*\");\n\n        var dnnFileManager = FileManager.Instance;\n        var dnnFolderManager = FolderManager.Instance;\n        var siteId = Site.Id;\n\n        if (!dnnFolderManager.FolderExists(siteId, destinationFolder))\n        {\n            l.A($\"Must create {destinationFolder} in site {siteId}\");\n            dnnFolderManager.AddFolder(siteId, destinationFolder);\n        }\n        var folderInfo = dnnFolderManager.GetFolder(siteId, destinationFolder);\n\n        void MassLog(string msg, Exception exception)\n        {\n            l.A(msg);\n            if (exception == null) return;\n            messages.Add(exception is InvalidFileExtensionException\n                ? new(msg, Message.MessageTypes.Error)\n                : new Message(msg, Message.MessageTypes.Warning));\n\n            Exceptions.LogException(exception);\n        }\n\n        foreach (var sourceFilePath in files)\n        {\n            var destinationFileName = Path.GetFileName(sourceFilePath);\n            l.A($\"Try to copy '{sourceFilePath}' to '{destinationFileName}'\");\n\n            if (!dnnFileManager.FileExists(folderInfo, destinationFileName))\n            {\n                try\n                {\n                    using var stream = File.OpenRead(sourceFilePath);\n                    var fileInfo = dnnFileManager.AddFile(folderInfo, destinationFileName, stream, false);\n                    MassLog($\"Transferred '{destinationFileName}', dnn-id is now {fileInfo?.FileId}\", null);\n                }\n                catch (InvalidFileExtensionException e)\n                {\n                    MassLog($\"Error: '{destinationFileName}' not copied because the file extension is not allowed.\", e);\n                }\n                catch (Exception e)\n                {\n                    MassLog($\"Error: Can't copy '{destinationFileName}' because of an unknown error. \" +\n                            \"It's likely that your files and folders are not in sync with DNN, usually re-syncing will fix the issue.\", e);\n                }\n            }\n            else\n                messages.Add(new(\"File '\" + destinationFileName + \"' not copied because it already exists\", Message.MessageTypes.Warning));\n        }\n\n        // Call the method recursively to handle subdirectories\n        foreach (var sourceFolderPath in Directory.GetDirectories(sourceFolder))\n        {\n            l.A($\"subfolder:{sourceFolderPath}\");\n            var newDestinationFolder = Path.Combine(destinationFolder, sourceFolderPath.Replace(sourceFolder, \"\")\n                    .TrimStart('\\\\'))\n                .Replace('\\\\', '/');\n            TransferFilesToSite(sourceFolderPath, newDestinationFolder);\n        }\n\n        return l.ReturnAsOk(messages);\n    }\n\n    public override Version TenantVersion => typeof(PortalSettings).Assembly.GetName().Version;\n\n    #region stuff we need for Import\n\n    public override void MapExistingFilesToImportSet(Dictionary<int, string> filesAndPaths, Dictionary<int, int> fileIdMap)\n    {\n        var l = Log.Fn($\"files: {filesAndPaths.Count}, map size: {fileIdMap.Count}\");\n        var siteId = Site.Id;\n        var fileManager = FileManager.Instance;\n        var folderManager = FolderManager.Instance;\n\n        foreach (var file in filesAndPaths)\n        {\n            var fileId = file.Key;\n            var relativePath = file.Value;\n\n            var fileName = Path.GetFileName(relativePath);\n            var directory = Path.GetDirectoryName(relativePath)?.Replace('\\\\', '/');\n            if (directory == null)\n            {\n                l.A($\"Warning: File '{relativePath}', folder doesn't exist on drive\");\n                continue;\n            }\n\n            if (!folderManager.FolderExists(siteId, directory))\n            {\n                l.A($\"Warning: File '{relativePath}', folder doesn't exist in DNN DB\");\n                continue;\n            }\n\n            var folderInfo = folderManager.GetFolder(siteId, directory);\n\n            if (!fileManager.FileExists(folderInfo, fileName))\n            {\n                l.A($\"Warning: File '{relativePath}', file doesn't exist in DNN DB\");\n                continue;\n            }\n\n            var fileInfo = fileManager.GetFile(folderInfo, fileName);\n            fileIdMap.Add(fileId, fileInfo.FileId);\n            l.A($\"Map: {fileId} will be {fileInfo.FileId} ({relativePath})\");\n        }\n\n        l.Done();\n    }\n\n    public override void CreateFoldersAndMapToImportIds(Dictionary<int, string> foldersAndPath, Dictionary<int, int> folderIdCorrectionList, List<Message> importLog) \n    {\n        var l = Log.Fn($\"folders and paths: {foldersAndPath.Count}\");\n        var siteId = Site.Id;\n        var folderManager = FolderManager.Instance;\n\n        foreach (var folder in foldersAndPath)\n            try\n            {\n                if (string.IsNullOrEmpty(folder.Value))\n                {\n                    l.A($\"{folder.Key} / {folder.Value} is empty\");\n                    continue;\n                }\n\n                var directory = Path.GetDirectoryName(folder.Value)?.Replace('\\\\', '/');\n                if (directory == null)\n                {\n                    l.A($\"Parent folder of folder {folder.Value} doesn't exist\");\n                    continue;\n                }\n\n                // if not exist, create - important because we need for metadata assignment\n                var exists = folderManager.FolderExists(siteId, directory);\n                var folderInfo = !exists\n                    ? folderManager.AddFolder(siteId, directory)\n                    : folderManager.GetFolder(siteId, directory);\n\n                folderIdCorrectionList.Add(folder.Key, folderInfo.FolderID);\n                l.A($\"Folder original #{folder.Key}/{folder.Value} - exists:{exists} placed in folder #{folderInfo.FolderID}\");\n            }\n            catch (Exception)\n            {\n                var msg = $\"Had problem with folder '{folder.Key}' path '{folder.Value}' - you'll have to figure out yourself if this is a problem\";\n                l.A(msg);\n                importLog.Add(new(msg, Message.MessageTypes.Warning));\n            }\n\n        l.Done($\"done - final count {folderIdCorrectionList.Count}\");\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/ImportExport/DnnXmlExporter.cs",
    "content": "﻿using DotNetNuke.Services.FileSystem;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.ImportExport.Sys.Xml;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.ExportImport.Sys;\nusing FileManager = DotNetNuke.Services.FileSystem.FileManager;\n\nnamespace ToSic.Sxc.Dnn.ImportExport;\n\ninternal class DnnXmlExporter(\n    AdamManager adamManager,\n    ISxcCurrentContextService ctxService,\n    XmlSerializer xmlSerializer,\n    IAppsCatalog appsCat)\n    : SxcXmlExporter(xmlSerializer, appsCat, ctxService, DnnConstants.LogName, connect: [adamManager])\n{\n    #region Constructor / DI\n\n    private readonly IFileManager _dnnFiles = FileManager.Instance;\n\n    protected override void PostContextInit(IContextOfApp appContext)\n    {\n        adamManager.Init(appCtx: appContext, compatibility: CompatibilityLevels.CompatibilityLevel10);\n    }\n\n    #endregion\n\n    public override void AddFilesToExportQueue()\n    {\n        // Add Adam Files To Export Queue\n        var exportList = new AdamExportListHelper<int, int>(adamManager);\n        var adamIds = exportList.AppFiles;\n        adamIds.ForEach(AddFileAndFolderToQueue);\n\n        // also add folders in adam - because empty folders may also have metadata assigned\n        var adamFolders = exportList.AppFolders;\n        adamFolders.ForEach(ReferencedFolderIds.Add);\n    }\n\n    protected override void AddFileAndFolderToQueue(int fileNum)\n    {\n        try\n        {\n            ReferencedFileIds.Add(fileNum);\n\n            // also try to remember the folder\n            try\n            {\n                var file = _dnnFiles.GetFile(fileNum);\n                ReferencedFolderIds.Add(file.FolderId);\n            }\n            catch\n            {\n                // don't do anything, because if the file doesn't exist, its FOLDER should also not land in the queue\n            }\n        }\n        catch\n        {\n            // don't do anything, because if the file doesn't exist, it should also not land in the queue\n        }\n    }\n\n    protected override string ResolveFolderId(int folderId)\n    {\n        var folderController = FolderManager.Instance;\n        var folder = folderController.GetFolder(folderId);\n        return folder?.FolderPath;\n    }\n\n    protected override TenantFileItem ResolveFile(int fileId)\n    {\n        var fileController = FileManager.Instance;\n        var file = fileController.GetFile(fileId);\n        return new()\n        {\n            Id = fileId,\n            RelativePath = file?.RelativePath.Replace('/', '\\\\'),\n            Path = file?.PhysicalPath\n        };\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnEnvironmentInstaller.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Sxc.Sys.Integration.Installation;\nusing ToSic.Sys.Configuration;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\ninternal partial class DnnEnvironmentInstaller : ServiceBase, IEnvironmentInstaller\n{\n    public static bool SaveUnimportantDetails = true;\n\n    private readonly DnnInstallLogger _installLogger;\n    private readonly LazySvc<IGlobalConfiguration> _globalConfiguration;\n    private readonly LazySvc<IAppJsonConfigurationService> _appJsonService;\n\n    /// <summary>\n    /// Instance initializers...\n    /// </summary>\n    public DnnEnvironmentInstaller(ILogStore logStore, DnnInstallLogger installLogger, LazySvc<IGlobalConfiguration> globalConfiguration, LazySvc<IAppJsonConfigurationService> appJsonService)\n        : base(\"Dnn.InstCo\", connect: [appJsonService, installLogger, globalConfiguration])\n    {\n        _appJsonService = appJsonService;\n        _installLogger = installLogger;\n        _globalConfiguration = globalConfiguration;\n        logStore.Add(LogNames.LogStoreInstallation, Log);\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnEnvironmentInstaller_IsRunning.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing System.Web.Hosting;\nusing static ToSic.Sxc.Dnn.DnnSxcSettings.Installation;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\npartial class DnnEnvironmentInstaller\n{\n    public string UpgradeMessages()\n    {\n        // Upgrade success check - show message if upgrade did not run successfully\n        if (UpgradeComplete(false))\n            return null;\n\n        return IsUpgradeRunning\n            ? \"It looks like an upgrade is currently running. Please wait for the operation to complete, the upgrade may take a few minutes.\"\n            : PortalSettings.Current.UserInfo.IsSuperUser\n                ? \"Module upgrade did not complete (<a href='http://2sxc.org/en/help/tag/install' target='_blank'>read more</a>). \" +\n                  \"Click to complete: <br><a class='dnnPrimaryAction' onclick='$2sxc.system.finishUpgrade(this)'>complete upgrade</a>\"\n                : \"Module upgrade did not complete successfully. Please login as host user to finish the upgrade.\";\n    }\n\n    private bool UpgradeComplete(bool alwaysLogToFile)\n        => UpgradeCompleteCache.Get(() => IsUpgradeComplete(LastVersionWithServerChanges, alwaysLogToFile, \"- first check\"));\n    private static readonly GetOnce<bool> UpgradeCompleteCache = new();\n\n    private bool IsUpgradeComplete(string version, bool alwaysLogToFile, string note = \"\")\n    {\n        var l = Log.Fn<bool>(message: $\"{note} Log to file even if all is ok: {alwaysLogToFile}\", timer: true);\n        var logger = new DnnInstallLoggerForVersion(_installLogger, version);\n\n        // 2023-03-23 2dm\n        // Previously this created a file on every startup, because it logged trying to find the status.\n        // This sometimes resulted in exceptions simply because the file was locked - so to avoid this\n        // I'll stop logging to the file by default\n        // This should also reduce the amount of files created in the log file.\n        // The only downside is that we cannot easily see how often the server restarted.\n        var complete = false;\n        try\n        {\n            var versionFilePath = HostingEnvironment.MapPath($\"{DnnConstants.LogDirectory}{version}.resources\");\n            l.A($\"Checking upgrade marker: '{versionFilePath}'\");\n\n            if (alwaysLogToFile)\n                logger.LogUnimportant($\"Check upgrade marker file {note}\");\n\n            complete = File.Exists(versionFilePath);\n\n            if (alwaysLogToFile || !complete)\n            {\n                logger.LogAuto($\"Upgrade marker {(complete ? \"exists\" : \"not found\")}: '{versionFilePath}'\");\n                logger.LogUnimportant($\"Upgrade complete: {complete}\");\n            }\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            try\n            {\n                logger.LogAuto(\"Error checking upgrade marker file (install status unknown)\");\n            }\n            catch { /* ignore */ }\n        }\n        return l.ReturnAndLog(complete);\n    }\n\n    // cache the status\n    private static bool? _running;\n    /// <summary>\n    /// Set / Check if it's running, by storing the static info but also creating/releasing a lock-file\n    /// We need the lock file in case another system would try to read the status, which doesn't share\n    /// this running static instance\n    /// </summary>\n    private bool IsUpgradeRunning\n    {\n        get\n        {\n            var l = Log.Fn<bool>($\"Cached value set: {_running.HasValue}\");\n            var result = _running ??= new DnnFileLock().IsSet;\n            return l.ReturnAndLog(result);\n        }\n\n        set\n        {\n            var logger = new DnnInstallLoggerForVersion(_installLogger, \"\");\n            logger.LogAuto($\"Upgrade running flag => {value}\");\n\n            try\n            {\n                var fileLock = new DnnFileLock();\n                if (value)\n                    fileLock.Set();\n                else\n                    fileLock.Release();\n            }\n            catch (Exception ex)\n            {\n                logger.LogAuto($\"Upgrade running flag => {value} (error: {ex.GetType().Name}: {ex.Message})\");\n                throw;\n            }\n\n            _running = value;\n            logger.LogAuto($\"Upgrade running flag => {value} (done)\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnEnvironmentInstaller_Manual.cs",
    "content": "﻿using System.Web;\nusing static ToSic.Sxc.Dnn.DnnSxcSettings.Installation;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\npartial class DnnEnvironmentInstaller\n{\n\n    public bool ResumeAbortedUpgrade()\n    {\n        var l = Log.Fn<bool>();\n        if (IsUpgradeRunning)\n        {\n            l.A(\"Upgrade is still running\");\n            throw l.Done(new Exception(\"There seems to be an upgrade running - please wait. If you still see this message after 3-4 minutes, please restart the web application.\"));\n        }\n\n        var logger = new DnnInstallLoggerForVersion(_installLogger, \"\");\n        logger.LogUnimportant(\"FinishAbortedUpgrade starting\");\n        logger.LogAuto(\"Will handle \" + UpgradeVersionList.Length + \" versions\");\n        // Run upgrade again for all versions that do not have a corresponding logfile\n        foreach (var upgradeVersion in UpgradeVersionList)\n        {\n            var complete = IsUpgradeComplete(upgradeVersion, true, \"- check for FinishAbortedUpgrade\");\n            logger.LogAuto($\"Upgrade marker for {upgradeVersion}: {(complete ? \"exists\" : \"not found\")}\");\n            if (!complete)\n                UpgradeModule(upgradeVersion, false);\n        }\n\n        logger.LogUnimportant(\"FinishAbortedUpgrade done\");\n\n        _installLogger.CloseLogFiles();\n        // Restart application\n        HttpRuntime.UnloadAppDomain();\n        return l.ReturnTrue(\"ok\");\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnEnvironmentInstaller_UpgradeModule.cs",
    "content": "﻿using DotNetNuke.Collections;\nusing DotNetNuke.Common.Utilities;\nusing DotNetNuke.Entities.Controllers;\nusing System.Configuration;\nusing System.Data.SqlClient;\nusing System.Web.Hosting;\nusing ToSic.Eav.Sys;\nusing ToSic.Sys.Configuration;\nusing Exception = System.Exception;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\npartial class DnnEnvironmentInstaller\n{\n    internal string UpgradeModule(string version, bool closeWhenDone)\n    {\n        var l = Log.Fn<string>($\"{nameof(version)}: {version}, {nameof(closeWhenDone)}: {closeWhenDone}\");\n\n        var logger = new DnnInstallLoggerForVersion(_installLogger, version);\n\n        // if upgrade has to run\n        if (!OldFolderExists() && (new Version(version) <= new Version(20, 0, 0)))\n        {\n            logger.LogAuto(\"Upgrade skipped because clean Install detected (installation of everything until and including 20.00.00 has been done by 00.00.01.SqlDataProvider)\");\n            _installLogger.LogVersionCompletedToPreventRerunningTheUpgrade(version);\n            return version;\n        }\n        logger.LogUnimportant(\"UpgradeModule starting\");\n\n        // Abort upgrade if it's already done - if version is 01.00.00, the module has probably been uninstalled - continue in this case.\n        if (/*version != \"01.00.00\" &&*/ IsUpgradeComplete(version, true, \"- Check on Start UpgradeModule\"))\n        {\n            logger.LogAuto(\"Upgrade already completed for this version (marker exists); skipping\");\n            if (closeWhenDone)\n                _installLogger.CloseLogFiles();\n            return l.ReturnAndLog(version);\n        }\n        logger.LogAuto(\"Upgrade status check OK (marker not found yet, so upgrade should run)\");\n\n        l.A(\"Will check if IsUpgradeRunning\");\n        if (IsUpgradeRunning)\n        {\n            logger.LogAuto(\"Another upgrade process appears to be running, will abort\");\n            throw new(\"2sxc upgrade for version \" + version +\n                      \" started, but the upgrade is already running. Aborting upgrade.\");\n        }\n        logger.LogAuto(\"Upgrade running check OK (no concurrent upgrade detected)\");\n\n        IsUpgradeRunning = true;\n        logger.LogAuto(\"----- Upgrade to \" + version + \" started -----\");\n\n        try\n        {\n            switch (version)\n            {\n                case \"01.00.00\":\n                    MigrateUpgradeFolder(logger);\n                    AddObsoleteFile(logger);\n                    AddObsolete2SxcJs(logger);\n                    break;\n\n                // case \"15.00.00\": // moved to 15.02 because of we accidentally skipped upgrades in 15.01 - see bug #2997\n                // case \"15.02.00\": // originally moved to here, but the Settings.Installation.LastVersionWithServerChanges had not been upgraded\n                //                  this results in no file being created for 15.02, so the \"IsUpgradeComplete\" always fails\n                case \"15.02.00\":    // Set to 15.04 because otherwise the log file is not created if you already have a 15.02+ (necessary to verify UpgradeComplete)\n                    MigrateOldDataFoldersAndRelatedV15_02_00(logger);\n                    DataTimelineCleaningDataAndChangeSchemaForCJsonV15_02_00(logger);\n                    break;\n\n                case \"20.00.00\":\n                    MigrateSystemCustomFolderV20_00_00(logger);\n                    break;\n\n                case \"20.00.01\":\n                    MigrateAppExtensionsFolderV20_00_01(logger);\n                    break;\n\n                // Do v21, 22 etc. here before v23\n\n                // In future v23, remove the old /DesktopModules/ToSic_SexyContent folder completely\n                case \"23.00.00\":\n                    DeleteFolderToSic_SexyContent_ObsoleteV23Future(logger, version);\n                    break;\n\n                    // case \"20.xx.xx\":\n                    // IMPORTANT: when you add a new case, make sure you\n                    // 1. upgrade the version number on Settings.Installation.LastVersionWithServerChanges!!!\n                    // 2. add it to the Settings.Installation.UpgradeVersionList\n                    // If you don't do these two things, various problems will appear\n\n            }\n            logger.LogUnimportant(\"version-list check / switch done\");\n\n            // Increase ClientDependency version upon each upgrade (System and all Portals)\n            // prevents browsers caching old JS and CSS files for editing, which could cause several errors\n            // only set this on the last upgraded version, to prevent crazy updating the client-resource-cache while upgrading\n            if (version == EavSystemInfo.VersionString)\n            {\n                IncreaseClientDependencyVersion(logger);\n\n                // Reset Upgrade complete so it's regenerated\n                UpgradeCompleteCache.Reset();\n                var getNewStatus = UpgradeComplete(true);\n                logger.LogAuto($\"updated upgrade-complete status to {getNewStatus}\");\n            }\n\n            _installLogger.LogVersionCompletedToPreventRerunningTheUpgrade(version);\n            logger.LogAuto(\"----- Upgrade to \" + version + \" completed -----\");\n\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto(\"Upgrade failed - \" + e.Message);\n            throw;\n        }\n        finally\n        {\n            IsUpgradeRunning = false;\n        }\n        logger.LogAuto(\"UpgradeModule done / returning\");\n        if (closeWhenDone)\n            _installLogger.CloseLogFiles();\n\n        return l.ReturnAndLog(version);\n    }\n\n    private bool OldFolderExists() => _isUpgrade\n        ??= Directory.Exists(HostingEnvironment.MapPath(DnnConstants.OldSysFolderRootVirtual).TrimLastSlash());\n    private bool? _isUpgrade;\n\n    private string OldSysFolderRootFullPath(DnnInstallLoggerForVersion logger) => _oldSysFolderRootFullPath\n        ??= GetOldSysFolder(logger);\n    private static string _oldSysFolderRootFullPath;\n\n    private void DataTimelineCleaningDataAndChangeSchemaForCJsonV15_02_00(DnnInstallLoggerForVersion logger)\n    {\n        // ToSic_EAV_DataTimeline cleaning data and change schema for CJson\n        try\n        {\n            const string sql150000 = @\"                         \n            -- remove trigger generated data from 'ToSIC_EAV_DataTimeline' in batches\n\n            IF OBJECT_ID('dbo.ToSIC_EAV_DataTimeline', 'U') IS NOT NULL\n            BEGIN\n                WHILE (SELECT COUNT(*) FROM [dbo].[ToSIC_EAV_DataTimeline] WHERE [SourceTable] IN ('ToSIC_EAV_Values', 'ToSIC_EAV_EntityRelationships', 'ToSIC_EAV_ValuesDimensions')) > 0\n                BEGIN\n                    ;WITH CTE AS\n                    (\n\t                    SELECT TOP 100000 * \n\t                    FROM [dbo].[ToSIC_EAV_DataTimeline] \n\t                    WHERE [SourceTable] IN ('ToSIC_EAV_Values', 'ToSIC_EAV_EntityRelationships', 'ToSIC_EAV_ValuesDimensions')\n\t                    )\n                    DELETE FROM CTE;\n                END;\n\n                -- drop NewData column from 'ToSIC_EAV_DataTimeline'\n                IF EXISTS (SELECT * FROM sys.columns WHERE Name = 'NewData' AND Object_ID = OBJECT_ID('ToSIC_EAV_DataTimeline'))\n                BEGIN\n                    ALTER TABLE ToSIC_EAV_DataTimeline DROP COLUMN NewData;\n                END;\n\n                -- add CJson column to 'ToSIC_EAV_DataTimeline'\n                IF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'CJson' AND Object_ID = OBJECT_ID('ToSIC_EAV_DataTimeline'))\n                BEGIN\n                    ALTER TABLE ToSIC_EAV_DataTimeline ADD CJson varbinary(max) NULL;\n                END;\n            END;\";\n            using var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings[\"SiteSqlServer\"].ConnectionString);\n            sqlConnection.Open();\n            using var sqlCommand150000 = new SqlCommand(sql150000, sqlConnection);\n            sqlCommand150000.CommandTimeout = 0; // disable sql execution command timeout on sql server\n            sqlCommand150000.ExecuteNonQuery();\n\n            logger.LogAuto(\"Data cleaning and schema change for CJson completed successfully.\");\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during timeline data cleaning - {e.Message}\");\n        }\n    }\n\n    private void MigrateOldDataFoldersAndRelatedV15_02_00(DnnInstallLoggerForVersion logger)\n    {\n        try\n        {\n            // move app.json template from old to new location\n            _appJsonService.Value.MoveAppJsonTemplateFromOldToNewLocation();\n\n            // migrate old .data-custom folder\n            var globalFolder = _globalConfiguration.Value.GlobalFolder();\n            var oldDataCustomFolder = Path.Combine(Path.Combine(globalFolder, \".data-custom\"));\n            var dataCustomFolder = _globalConfiguration.Value.DataCustomFolder();\n            if (Directory.Exists(oldDataCustomFolder) && !Directory.Exists(dataCustomFolder))\n            {\n                Directory.Move(oldDataCustomFolder, dataCustomFolder);\n                logger.LogAuto($\"Old .data-custom folder migrated to new location: '{dataCustomFolder}'\");\n            }\n\n            // migrate old .databeta folder\n            var oldDataBetaFolder = Path.Combine(Path.Combine(globalFolder, \".databeta\"));\n            var dataBetaFolder = _globalConfiguration.Value.DataBetaFolder();\n            if (Directory.Exists(oldDataBetaFolder) && !Directory.Exists(dataBetaFolder))\n            {\n                Directory.Move(oldDataBetaFolder, dataBetaFolder);\n                logger.LogAuto($\"Old .databeta folder migrated to new location: '{dataBetaFolder}'\");\n            }\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during migration of old data folders - {e.Message}\");\n        }\n    }\n\n    private string GetOldSysFolder(DnnInstallLoggerForVersion logger)\n    {\n        var oldSysFolderRootFullPath = HostingEnvironment.MapPath(DnnConstants.OldSysFolderRootVirtual).TrimLastSlash();\n        try\n        {\n            if (Directory.Exists(oldSysFolderRootFullPath))\n            {\n                logger.LogAuto(\"Old system folder.\");\n                return oldSysFolderRootFullPath;\n            }\n            logger.LogAuto(\"Old system folder does not exist.\");\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during migration - {e.Message}\\n\" +\n                $\"{e.Source}\\n\" +\n                $\"{e.InnerException?.Message}\");\n        }\n        return oldSysFolderRootFullPath;\n    }\n\n    private void AddObsoleteFile(DnnInstallLoggerForVersion logger)\n    {\n        var obsoleteFilename = \"OBSOLETE.txt\";\n\n        try\n        {\n            // add OBSOLETE.txt with appropriate text - remove folder in v21\n            var obsoleteFilePath = Path.Combine(OldSysFolderRootFullPath(logger), obsoleteFilename);\n            if (!File.Exists(obsoleteFilePath))\n            {\n                var obsoleteText = $\"This folder is OBSOLETE as of 2sxc v20.\\n\" +\n                                   $\"It will be removed in v23.\\n\" +\n                                   $\"The folder was marked as obsolete on {DateTime.Now:yyyy-MM-dd HH:mm:ss} for backup purposes, but it is no longer in use.\\n\";\n\n                File.WriteAllText(obsoleteFilePath, obsoleteText);\n\n                logger.LogAuto($\"{obsoleteFilename} created with text:\\n{obsoleteText}\");\n            }\n            else\n                logger.LogAuto($\"{obsoleteFilename} already exists, nothing to do.\");\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during migration - {e.Message}.\");\n        }\n    }\n\n    private void AddObsolete2SxcJs(DnnInstallLoggerForVersion logger)\n    {\n        var obsoleteFilename = @\"js\\2sxc.api.min.js\";\n\n        try\n        {\n            // add 2sxc.api.min.js appropriate text - remove folder in v21\n            var obsoleteFilePath = Path.Combine(OldSysFolderRootFullPath(logger), obsoleteFilename);\n            if (File.Exists(obsoleteFilePath))\n            {\n                var obsoleteText =\n                    $@\"// IMPORTANT: This file is obsolete and will be deleted in a future 2sxc release.\n// You are using '2sxc.api.min.js' from the old, obsolete folder:\n//   'DesktopModules/ToSIC_SexyContent/js/2sxc.api.min.js'\n// Please update your code to use the new path:\n//   'DesktopModules/ToSic.Sxc/js/2sxc.api.min.js'\n// For more info, see: https://docs.2sxc.org/abyss/releases/history/v20/breaking.html\n// This notice was created on {DateTime.Now:yyyy-MM-dd HH:mm:ss}.\n\n(function() {{\n    alert('''2sxc.api.min.js'' is obsolete and will be removed soon.\\n\\nUpdate your code to use:\\n''DesktopModules/ToSic.Sxc/js/2sxc.api.min.js''');\n}})();\n\";\n                File.WriteAllText(obsoleteFilePath, obsoleteText); // overwrite existing content\n\n                logger.LogAuto($\"'{obsoleteFilename}' overwrite existing content with text:\\n{obsoleteText}\");\n            }\n            else\n                logger.LogAuto($\"'{obsoleteFilename}' not exists, nothing to do.\");\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during migration - {e.Message}.\");\n        }\n    }\n    private void MigrateSystemCustomFolderV20_00_00(DnnInstallLoggerForVersion logger)\n    {\n        try\n        {\n            var oldSystemCustomFolder = Path.Combine(\n                OldSysFolderRootFullPath(logger),\n                FolderConstants.DataFolderProtected,\n                FolderConstants.DataSubFolderSystemCustom\n            );\n\n            var systemCustomFolder = _globalConfiguration.Value.DataCustomFolder();\n\n            if (Directory.Exists(oldSystemCustomFolder))\n            {\n                Helpers.DirectoryCopy(oldSystemCustomFolder, systemCustomFolder, true);\n                logger.LogAuto($\"Old '{FolderConstants.DataSubFolderSystemCustom}' folder migrated to new location: \" + systemCustomFolder);\n            }\n            else\n                logger.LogAuto($\"Old '{FolderConstants.DataSubFolderSystemCustom}' folder does not exist.\");\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during migration - {e.Message}\");\n        }\n    }\n\n    // Migrate the 'system' (AppExtensions) folder\n    private void MigrateAppExtensionsFolderV20_00_01(DnnInstallLoggerForVersion logger)\n    {\n        try\n        {\n            var oldAppExtensionsFolder = Path.Combine(\n                OldSysFolderRootFullPath(logger),\n                FolderConstants.AppExtensionsLegacyFolder\n            );\n\n            var newAppExtensionsFolder = Path.Combine(\n                _globalConfiguration.Value.GlobalFolder(),\n                FolderConstants.AppExtensionsLegacyFolder\n            );\n\n            if (Directory.Exists(oldAppExtensionsFolder))\n            {\n                Helpers.DirectoryCopy(oldAppExtensionsFolder, newAppExtensionsFolder, true);\n                logger.LogAuto($\"Old '{FolderConstants.AppExtensionsLegacyFolder}' folder migrated to new location: {newAppExtensionsFolder}\");\n\n                RenameAllOldDataSubfolders(logger, newAppExtensionsFolder);\n            }\n            else\n                logger.LogAuto($\"Old '{FolderConstants.AppExtensionsLegacyFolder}' folder does not exist.\");\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during migration - {e.Message}\");\n        }\n    }\n\n    // Rename all old '.data' subfolders to 'App_Data' that are in appExtension subfolders in 'system' folder\n    private void RenameAllOldDataSubfolders(DnnInstallLoggerForVersion logger, string newAppExtensionsFolder)\n    {\n        logger.LogAuto($\"Start renaming in app extensions subfolders from '{FolderConstants.DataFolderProtected}' to '{FolderConstants.DataFolderProtected}'\");\n\n        new DirectoryInfo(newAppExtensionsFolder).GetDirectories()\n            .SelectMany(appExtensionDirectory => appExtensionDirectory.GetDirectories(FolderConstants.DataFolderOld))\n            .ForEach(oldDotDataDirectory => RenameOldDotDataToAppData(logger, oldDotDataDirectory));\n\n        logger.LogAuto($\"Finish renaming in app extensions subfolders from '{FolderConstants.DataFolderProtected}' to '{FolderConstants.DataFolderProtected}'\");\n    }\n\n    // Rename old '.data' folder to 'App_Data'\n    private void RenameOldDotDataToAppData(DnnInstallLoggerForVersion logger, DirectoryInfo oldDotDataDirectory)\n    {\n        var destDirName = Path.Combine(oldDotDataDirectory.Parent!.FullName, FolderConstants.DataFolderProtected);\n        try\n        {\n            if (!Directory.Exists(destDirName))\n            {\n                oldDotDataDirectory.MoveTo(destDirName);\n                logger.LogAuto($\"Renamed: '{oldDotDataDirectory.FullName}'\");\n            }\n            else\n            {\n                // fallback strategy if directory already exists\n                Helpers.DirectoryCopy(oldDotDataDirectory.FullName, destDirName, true);\n                oldDotDataDirectory.Delete(true);\n                logger.LogAuto($\"Coped and deleted: '{oldDotDataDirectory.FullName}'\");\n            }\n            \n        }\n        catch (Exception ex)\n        {\n            logger.LogAuto($\"Error during renaming: '{oldDotDataDirectory.FullName}' - {ex.Message}\");\n        }\n    }\n\n    private void MigrateUpgradeFolder(DnnInstallLoggerForVersion logger)\n    {\n        try\n        {\n            const string upgrade = \"Upgrade\";\n            var oldUpgradeFolder = Path.Combine(\n                OldSysFolderRootFullPath(logger),\n                upgrade\n                );\n\n            var upgradeFolder = Path.Combine(\n                _globalConfiguration.Value.GlobalFolder(),\n                upgrade\n                );\n\n            if (Directory.Exists(oldUpgradeFolder))\n            {\n                Helpers.DirectoryCopy(oldUpgradeFolder, upgradeFolder, true);\n                logger.LogAuto($\"Old system '{upgrade}' folder migrated to new location: \" + upgradeFolder);\n            }\n            else\n                logger.LogAuto($\"Old system '{upgrade}' folder does not exist.\");\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during migration - {e.Message}\");\n        }\n    }\n\n    /// <summary>\n    /// Clean up special /system folder which was moved in v20 and is obsolete now.\n    /// At v20 we don't remove everything, so people can still find their code if they had anything custom.\n    /// But we will do a clean-up in v23 or later.\n    /// </summary>\n    /// <param name=\"logger\"></param>\n    /// <param name=\"version\"></param>\n    private void DeleteFolderToSic_SexyContent_ObsoleteV23Future(DnnInstallLoggerForVersion logger, string version)\n    {\n        var oldSysFolderRootFullPath = HostingEnvironment.MapPath(DnnConstants.OldSysFolderRootVirtual).TrimLastSlash();\n        logger.LogAuto($\"Attempting to delete old system folder: '{oldSysFolderRootFullPath}'.\");\n        try\n        {\n            if (Directory.Exists(oldSysFolderRootFullPath))\n            {\n                Directory.Delete(oldSysFolderRootFullPath, true);\n                logger.LogAuto($\"Old system folder deleted successfully.\");\n            }\n            else\n            {\n                logger.LogAuto($\"Old system folder does not exist, nothing to delete.\");\n            }\n        }\n        catch (Exception e)\n        {\n            logger.LogAuto($\"Error during deletion of old system folder - {e.Message}\");\n        }\n    }\n\n    private void IncreaseClientDependencyVersion(DnnInstallLoggerForVersion logger)\n    {\n        logger.LogAuto(\"ClientResourceManager- seems to be last item in version-list, will clear\");\n\n        HostController.Instance.IncrementCrmVersion(true);\n        DataCache.ClearCache();\n\n        logger.LogAuto(\"ClientResourceManager- done clearing\");\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnFileLock.cs",
    "content": "﻿using System.Web.Hosting;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\ninternal class DnnFileLock\n{\n    internal string LockFileName => HostingEnvironment.MapPath(DnnConstants.LogDirectory + \"lock.resources\");\n    internal string LockFolder => HostingEnvironment.MapPath(DnnConstants.LogDirectory);\n\n    private static readonly object LockObj = new();\n    private static FileStream _lockFile;\n\n    // Acquire lock\n    internal FileStream Set()\n    {\n        lock (LockObj)\n        {\n            return _lockFile ??= new(LockFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);\n        }\n    }\n\n    // Close and dispose lock\n    internal void Release()\n    {\n        lock (LockObj)\n        {\n            _lockFile?.Close();\n            _lockFile?.Dispose();\n            _lockFile = null;\n        }\n\n        try\n        {\n            // try delete\n            File.Delete(LockFileName);\n        }\n        catch\n        {\n            // ignored\n        }\n    }\n\n    internal bool IsSet\n    {\n        get\n        {\n            Directory.CreateDirectory(LockFolder); // create if it doesn't exist (doesn't need checking beforehand)\n\n            var lockFilePath = LockFileName;\n            if (!File.Exists(lockFilePath))\n                return false;\n\n            try\n            {\n                using (var stream = new FileStream(lockFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))\n                {\n                    // FileStream opened successfully, meaning the file is not locked\n                }\n                File.Delete(lockFilePath);\n            }\n            catch (IOException)\n            {\n                // The file is unavailable because it is:\n                // - being processed by another thread\n                // - does not exist (has already been processed)\n                return true;\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnInstallLogger.cs",
    "content": "﻿using System.Text;\nusing System.Web.Hosting;\nusing static System.IO.Directory;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\ninternal class DnnInstallLogger: ServiceBase\n{\n    private readonly bool _saveUnimportantDetails;\n\n    public DnnInstallLogger(): base(\"Dnn.InstLg\")\n    {\n        var l = Log.Fn();\n        _saveUnimportantDetails = DnnEnvironmentInstaller.SaveUnimportantDetails;\n        l.A($\"{nameof(_saveUnimportantDetails)}: {_saveUnimportantDetails}\");\n        l.Done();\n    }\n\n    internal void CloseLogFiles()\n    {\n        var l = Log.Fn($\"Closing: {DateTime.Now.Ticks}\");\n        if (_fileStreamWriterCached == null)\n            return;\n\n        _fileStreamWriterCached.Close();\n        _fileStreamWriterCached.Dispose();\n        _fileStreamWriterCached = null;\n        l.Done();\n    }\n\n    private StreamWriter FileStreamWriter => _fileStreamWriterCached ??= OpenLogFiles(0);\n    private StreamWriter _fileStreamWriterCached;\n\n\n    internal StreamWriter OpenLogFiles(int attempts)\n    {\n        var l = Log.Fn<StreamWriter>($\"Opening: {DateTime.Now.Ticks}; {nameof(attempts)}: {attempts}\");\n        EnsureLogDirectoryExists();\n\n        var logFileNameBase = DnnConstants.LogDirectory +\n                              DateTime.UtcNow.ToString(@\"yyyy-MM-dd HH-mm-ss-fffffff\")\n                              + \"-\" + System.Diagnostics.Process.GetCurrentProcess().Id\n                              + \"-\" + AppDomain.CurrentDomain.Id\n                              + (attempts == 0 ? \"\" : $\"-{attempts}\");\n\n        var logFileName = HostingEnvironment.MapPath($\"{logFileNameBase}.log.resources\")!;\n        l.A($\"{nameof(logFileName)}: {logFileName}\");\n\n        StreamWriter streamWriter = null;\n        try\n        {\n            var fileHandle = new FileStream(logFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite,\n                FileShare.Read);\n            streamWriter = new(fileHandle);\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            l.A($\"{nameof(streamWriter)} is null : {streamWriter is null}\");\n            if (streamWriter != null)\n            {\n                streamWriter.Close();\n                streamWriter.Dispose();\n                streamWriter = null;\n            }\n            l.A($\"Will try again, current attempt count is {attempts}\");\n            if (attempts < 3)\n                return OpenLogFiles(++attempts);\n        }\n\n        return l.Return(streamWriter);\n    }\n\n\n    internal void LogStep(string version, string message, bool isImportant = true)\n    {\n        var l = Log.Fn($\"{nameof(version)} '{version}': {message}\");\n        var niceLine = FormatLogMessage(version, message);\n\n        if (!isImportant && !_saveUnimportantDetails)\n            return;\n\n        FileStreamWriter.WriteLine(niceLine);\n        FileStreamWriter.Flush();\n        l.Done();\n    }\n\n    private string FormatLogMessage(string version, string message)\n        => DateTime.UtcNow.ToString(@\"yyyy-MM-ddTHH\\:mm\\:ss\") + \" \" + version + \" - \" + message;\n\n    internal void LogVersionCompletedToPreventRerunningTheUpgrade(string version)\n    {\n        var l = Log.Fn();\n        EnsureLogDirectoryExists();\n\n        var logFilePath = HostingEnvironment.MapPath(DnnConstants.LogDirectory + version + \".resources\")!;\n        if (!File.Exists(logFilePath))\n            File.AppendAllText(logFilePath, DateTime.UtcNow.ToString(@\"yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz\"), Encoding.UTF8);\n        l.Done();\n    }\n\n    private static void EnsureLogDirectoryExists()\n        => CreateDirectory(HostingEnvironment.MapPath(DnnConstants.LogDirectory)!);\n\n    internal void DeleteAllLogFiles()\n    {\n        if (!Exists(HostingEnvironment.MapPath(DnnConstants.LogDirectory)))\n            return;\n\n        var files = new List<string>(GetFiles(HostingEnvironment.MapPath(DnnConstants.LogDirectory)!));\n        foreach (var x in files)\n        {\n            try\n            {\n                File.Delete(x);\n            }\n            catch { /* ignore */ }\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnInstallLoggerForVersion.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\ninternal class DnnInstallLoggerForVersion(DnnInstallLogger logger, string version)\n{\n    public void LogAuto(string message, [CallerMemberName] string cname = null)\n        => logger.LogStep(version, message, true);\n\n    public void LogUnimportant(string message, [CallerMemberName] string cname = null)\n        => logger.LogStep(version, $\"{cname} - {message}\", false);\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnPlatformAppInstaller.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Apps.Sys.Installation;\nusing ToSic.Sxc.Apps.Sys.Work;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Dnn.Context;\nusing ToSic.Sxc.WebApi.Sys.ExternalLinks;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\ninternal class DnnPlatformAppInstaller(\n    LazySvc<IAppsCatalog> appsCatalog,\n    GenWorkPlus<WorkViews> workViews,\n    LazySvc<ExternalLinksService> remoteRouterLazy)\n    : ServiceBase(\"Dnn.AppIns\", connect: [workViews, appsCatalog, remoteRouterLazy]), IPlatformAppInstaller\n{\n    public string GetAutoInstallPackagesUiUrl(ISite site, IModule module, bool forContentApp)\n    {\n        var l = Log.Fn<string>();\n        var moduleInfo = (module as DnnModule)?.GetContents();\n        var portal = (site as DnnSite)?.GetContents();\n        if (moduleInfo == null || portal == null)\n            throw l.Done(new ArgumentException(\"missing portal/module\"));\n\n        // new: check if it should allow this\n        // it should only be allowed, if the current situation is either\n        // Content - and no views exist (even invisible ones)\n        // App - and no apps exist - this is already checked on client side, so I won't include a check here\n        if (forContentApp)\n            try\n            {\n                var primaryAppId = appsCatalog.Value.DefaultAppIdentity(site.ZoneId);\n                // we'll usually run into errors if nothing is installed yet, so on errors, we'll continue\n                var contentViews = workViews.New(primaryAppId).GetAll();\n                if (contentViews.Any())\n                    return null;\n            }\n            catch\n            {\n                /* ignore */\n            }\n\n        var gettingStartedSrc = remoteRouterLazy.Value.LinkToDestination(\n            ExternalSxcDestinations.AutoConfigure,\n            site,\n            module.Id,\n            appSpecsOrNull: null,\n            forContentApp\n        );\n\n        // Set src to iframe\n        return l.ReturnAsOk(gettingStartedSrc);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/DnnReadyCheckTurbo.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing System.Collections.Concurrent;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Dnn.Install;\n\n/// <summary>\n/// Helper class to ensure that an app is ready.\n/// It will have to do various file accesses - so once it knows a module is ready, it will cache the result.\n/// </summary>\ninternal class DnnReadyCheckTurbo(LazySvc<AppFolderInitializer> appFolderInitializerLazy)\n    : ServiceBase(\"Dnn.PreChk\", connect: [appFolderInitializerLazy])\n{\n    /// <summary>\n    /// Fast static check to see if the check had previously completed. \n    /// </summary>\n    /// <param name=\"module\"></param>\n    /// <param name=\"log\"></param>\n    public static bool QuickCheckSiteAndAppFoldersAreReady(PortalModuleBase module, ILog log)\n    {\n        var l = log.Fn<bool>($\"module: {module.ModuleId}; page: {module.TabId}\");\n        return CachedModuleResults.TryGetValue(module.ModuleId, out var exists) && exists\n            ? l.ReturnTrue(\"quick-check: ready\")\n            : l.ReturnFalse(\"deep-check: not ready, must do extensive check\");\n    }\n\n    /// <summary>\n    /// Verify that the portal is ready, otherwise show a good error\n    /// </summary>\n    public bool EnsureSiteAndAppFoldersAreReady(PortalModuleBase module, IBlock block)\n    {\n        var l = Log.Fn<bool>(timer: true, message: $\"module {module.ModuleId} on page {module.TabId}\");\n        if (CachedModuleResults.TryGetValue(module.ModuleId, out var exists) && exists)\n            return l.ReturnTrue(\"Previous check completed, will skip\");\n\n        // throw better error if SxcInstance isn't available\n        // not sure if this doesn't have side effects...\n        if (block == null)\n            throw l.Done(new Exception(\"Error - can't find 2sxc instance configuration. \" +\n                                       \"Probably trying to show an app or content that has been deleted or not yet installed. \" +\n                                       \"You may also have EnterpriseCMS features enabled but are missing the license activation (but this is super rare). \"));\n\n        // check things if it's a module of this portal (ensure everything is ok, etc.)\n        var isSharedModule = module.ModuleConfiguration.PortalID != module.ModuleConfiguration.OwnerPortalID;\n        if (isSharedModule)\n            return l.ReturnFalse(\"skip, shared\");\n\n        // If the block is referencing data, then also check that the app folder exists\n        if (block.AppIsReady)\n        {\n            l.A(\"Will check if site is ready and app folder exists\");\n            EnsureSiteIsConfiguredAndTemplateFolderExists(module, block);\n\n            // If no exception was raised inside, everything is fine - must cache\n            CachedModuleResults.AddOrUpdate(module.ModuleId, true, (_, _) => true);\n        }\n        else\n            l.A(\"skip, content-block not ready\");\n\n        return l.ReturnTrue(\"ok\");\n    }\n\n    /// <summary>\n    /// Returns true if the Portal HomeDirectory Contains the 2sxc Folder and this folder contains the web.config and a Content folder\n    /// </summary>\n    private void EnsureSiteIsConfiguredAndTemplateFolderExists(PortalModuleBase module, IBlock block)\n    {\n        var l = Log.Fn($\"module {module.ModuleId} on page {module.TabId}\");\n        var sxcFolder = new DirectoryInfo(block.Context.Site.AppsRootPhysicalFull);\n        var contentFolder = new DirectoryInfo(Path.Combine(sxcFolder.FullName, KnownAppsConstants.ContentAppFolder));\n        if (!(sxcFolder.Exists && contentFolder.Exists))\n        {\n            // configure it\n            var tm = appFolderInitializerLazy.Value;\n            tm.EnsureTemplateFolderExists(block.Context.AppReaderRequired.Specs.Folder, false);\n        }\n\n        l.Done($\"Completed init App {block.AppId}\");\n    }\n\n    internal static ConcurrentDictionary<int, bool> CachedModuleResults = new();\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Install/Helpers.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn.Install;\n\ninternal class Helpers\n{\n    /// <summary>\n    /// Copy a Directory recursive\n    /// </summary>\n    /// <remarks>Source: http://msdn.microsoft.com/en-us/library/bb762914(v=vs.110).aspx </remarks>\n    internal static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)\n    {\n        try\n        {\n            // Get the subdirectories for the specified directory.\n            var dir = new DirectoryInfo(sourceDirName);\n\n            if (!dir.Exists)\n            {\n                throw new DirectoryNotFoundException(\"Source directory does not exist or could not be found: \" + sourceDirName);\n            }\n\n            // If the destination directory doesn't exist, create it. \n            if (!Directory.Exists(destDirName))\n            {\n                Directory.CreateDirectory(destDirName);\n            }\n\n            // Get the files in the directory and copy them to the new location.\n            var files = dir.GetFiles();\n            foreach (var file in files)\n            {\n                var temppath = Path.Combine(destDirName, file.Name);\n                // Skip if the file already exists in destination\n                if (File.Exists(temppath))\n                {\n                    continue;\n                }\n\n                try\n                {\n                    file.CopyTo(temppath, false);\n                }\n                catch (IOException)\n                {\n                    // If copy fails (e.g., if file was created between our check and copy),\n                    // just continue with the next file\n                    continue;\n                }\n            }\n\n            // If copying subdirectories, copy them and their contents to new location. \n            if (copySubDirs)\n            {\n                foreach (var subdir in dir.GetDirectories())\n                {\n                    var temppath = Path.Combine(destDirName, subdir.Name);\n                    DirectoryCopy(subdir.FullName, temppath, copySubDirs);\n                }\n            }\n\n        }\n        catch (UnauthorizedAccessException)\n        {\n            // Handle access denied errors gracefully\n            // This could be logged or handled according to your requirements\n            throw;\n        }\n        catch (Exception)\n        {\n            // Handle other unexpected errors\n            // This could be logged or re-thrown according to your requirements\n            throw;\n        }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/LookUp/DnnLookUpEngineResolver.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.LookUp;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Eav.LookUp.Sys;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.LookUp.Sys;\nusing ToSic.Sxc.Web.Sys.Http;\nusing static ToSic.Sxc.LookUp.Sys.LookUpConstants;\n\nnamespace ToSic.Sxc.Dnn.LookUp;\n\n/// <summary>\n/// Retrieves the current engine for a specific module. <br/>\n/// Internally it asks DNN for the current Property-Access objects and prepares them for use in EAV.\n/// </summary>\ninternal class DnnLookUpEngineResolver(IZoneCultureResolver cultureResolver, LazySvc<IHttp> httpLazy, LazySvc<IEnumerable<ILookUp>> builtInSources)\n    : LookUpEngineResolverBase(builtInSources, \"Dnn.LookUp\", connect: [cultureResolver, httpLazy])\n{\n    protected override LookUpEngine BuildLookupEngine(int moduleId)\n    {\n        var l = Log.Fn<LookUpEngine>($\"{nameof(moduleId)}:{moduleId}\");\n        return PortalSettings.Current == null\n            ? l.Return(base.BuildLookupEngine(moduleId), \"no context, use base\")\n            : l.Return(BuildDnnBasedLookupEngine(PortalSettings.Current, moduleId), \"with site\");\n    }\n\n    [PrivateApi]\n    public LookUpEngine LookUpEngineOfPortalSettings(PortalSettings portalSettings, int moduleId)\n    {\n        var l = Log.Fn<LookUpEngine>($\"{nameof(moduleId)}: {moduleId}\");\n\n        //// if we already have a list of shared sources, return that\n        //// as the sources don't change per request, but per module\n        if (TryReuseFromCache(moduleId, out var cached))\n            return l.Return(cached, $\"reuse {cached.Sources} sources\");\n\n        var lookupEngine = BuildDnnBasedLookupEngine(portalSettings, moduleId);\n\n        return l.ReturnAsOk(AddToCache(moduleId, lookupEngine));\n    }\n\n    [PrivateApi]\n    private LookUpEngine BuildDnnBasedLookupEngine(PortalSettings portalSettings, int moduleId)\n    {\n        var l = Log.Fn<LookUpEngine>($\"{nameof(moduleId)}: {moduleId}\");\n\n        // Otherwise build using Dnn Built-In Sources and HttpSources and more\n        var dnnUsr = portalSettings.UserInfo;\n        var dnnCult = cultureResolver.SafeCurrentCultureInfo();\n        var dnn = new DnnTokenReplace(moduleId, portalSettings, dnnUsr);\n        var stdSources = dnn.PropertySources;\n\n        var lookUps = stdSources\n            .Select(s => new LookUpInDnnPropertyAccess(s.Key, s.Value, dnnUsr, dnnCult) as ILookUp)\n            .ToList();\n\n        // must already add, as we'll later check if some specific ones exist\n        var httpAndDiAdditions = AddHttpAndDiSources(lookUps);\n        var sources = lookUps.Concat(httpAndDiAdditions).ToList();\n\n        //var lookupEngine = new LookUpEngine(Log, sources: sources);\n        //AddHttpAndDiSources(/*lookupEngine,*/ lookUps).DoIfNotNull(lookupEngine.Add);\n\n        // Expand the Lookup for \"module\" to also have an \"id\" property\n        var additions = new List<ILookUp>();\n        if (sources.HasSource(SourceModule))\n        {\n            var original = sources.GetSource(SourceModule)!;\n            var modAdditional = new LookUpInDictionary(SourceModule, new Dictionary<string, string>\n            {\n                { KeyId, original.Get(OldDnnModuleId) }\n            });\n            additions.Add(new LookUpInLookUps(SourceModule, [modAdditional, original]));\n        }\n\n        // Create the lookup for \"site\" based on the \"portal\" and only give it \"id\" & \"guid\"\n        if (sources.HasSource(OldDnnSiteSource))\n            additions.Add(new LookUpInDictionary(SourceSite, new Dictionary<string, string>\n            {\n                { KeyId, sources.GetSource(OldDnnSiteSource)!.Get(OldDnnSiteId) },\n                { KeyGuid, $\"{DotNetNuke.Common.Globals.GetPortalSettings()?.GUID}\" }\n            }));\n\n        // Create the lookup for \"page\" based on the \"tab\" and only give it \"id\" & \"guid\"\n        if (sources.HasSource(OldDnnPageSource))\n            additions.Add(new LookUpInDictionary(SourcePage, new Dictionary<string, string>\n            {\n                { KeyId, sources.GetSource(OldDnnPageSource)!.Get(OldDnnPageId) },\n                { KeyGuid, $\"{DotNetNuke.Common.Globals.GetPortalSettings()?.ActiveTab?.UniqueId}\" }\n            }));\n\n\n        //lookupEngine.Add(additions);\n\n        // 2024-05-06 2dm - this code never had an effect, so I believe I can assume\n        // ...that it hasn't worked for a very long time, so I'll comment out to clean up EOY 2024\n        //// Add \"form\" source if it's not already there, and we have a request.Form\n        //// request is sometimes null (e.g. in DNN scheduled task)\n        //// Note that \"Form\" is only available on Dnn, not on Oqtane\n        //if (!lookupEngine.HasSource(\"form\") && httpLazy.Value.Request?.Form != null)\n        //    additions.Add(new LookUpInNameValueCollection(\"form\", httpLazy.Value.Request.Form));\n\n        var lookupEngine = new LookUpEngine(Log, sources: [.. sources, .. additions]);\n\n\n        // Note: Not implemented in Dnn: \"Tenant\" source\n        return l.ReturnAsOk(lookupEngine);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/LookUp/DocsPlaceholder.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn.LookUp;\n\n/// <inheritdoc />\n[PublicApi]\npublic class DocsPlaceholder: DocumentationPlaceholder;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/LookUp/LookUpInDnnPropertyAccess.cs",
    "content": "﻿using System.Globalization;\nusing DotNetNuke.Entities.Users;\nusing DotNetNuke.Services.Tokens;\nusing ToSic.Eav.LookUp.Sources;\n\nnamespace ToSic.Sxc.Dnn.LookUp;\n\n/// <summary>\n/// Translator component which creates a LookUp object and internally accesses\n/// DNN PropertyAccess objects (which DNN uses for the same concept as LookUp)\n/// </summary>\ninternal class LookUpInDnnPropertyAccess(string name, IPropertyAccess source, UserInfo user, CultureInfo localization) : LookUpBase(name, $\"LookUp in Dnn PropertyAccess source of type {source?.GetType().Name}\")\n{\n    public override string Get(string key, string format)\n    {\n        var blnNotFound = false;\n        var result = source.GetProperty(key, format, localization, user, Scope.DefaultSettings, ref blnNotFound);\n        return blnNotFound ? string.Empty : result;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/LookUp/TokenReplaceDnn.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Users;\nusing DotNetNuke.Services.Tokens;\nusing DotNetNuke.Common.Utilities;\n\nnamespace ToSic.Sxc.Dnn.LookUp;\n\n/// <summary>\n/// This class is mainly here to deliver all standard DNN-token lists to 2sxc. \n/// So it mainly initializes the normal DNN Token provider and offers a property called Property-Access which then contains all value-resolvers\n/// </summary>\n[PrivateApi(\"not for public use, it's an internal class just needed to retrieve DNN stuff\")]\ninternal sealed class DnnTokenReplace : TokenReplace\n{\n    /// <param name=\"instanceId\"></param>\n    /// <param name=\"ps\"></param>\n    /// <param name=\"userInfo\"></param>\n    public DnnTokenReplace(int instanceId, PortalSettings ps, UserInfo userInfo)\n        : base(Scope.DefaultSettings, \"\", ps, userInfo, instanceId == 0 ? Null.NullInteger : instanceId)\n    {\n        ModuleId = instanceId;\n        PortalSettings = ps;\n        try\n        {\n            // The first replace also initializes it...\n            // So this must be executed, otherwise the list doesn't get built\n            // But we've seen cases where something fails in here, hence the try/catch\n            ReplaceTokens(\"InitializePropertySources\");\n        }\n        catch\n        {\n            // In DNN 9.11 we have some issues which seem to error in the Token Lookup\n            // But the reason is not clear.\n            // So ATM we just ignore.\n            /* ignore */\n            //throw;\n        }\n\n        //try\n        //{\n        //    var minfo = TestModuleInfo;\n        //    TestReplaceTokens(\"test\");\n        //    ReplaceTokens(\"test\");\n        //}\n        //catch\n        //{\n        //    throw;\n        //}\n    }\n\n    /// <summary>\n    /// Make the protected PropertySource available to outside...\n    /// </summary>\n    public Dictionary<string, IPropertyAccess> PropertySources => PropertySource;\n\n\n\n\n\n    //public ModuleInfo TestModuleInfo\n    //{\n    //    get\n    //    {\n    //        if (ModuleId > int.MinValue && (_moduleInfo == null || _moduleInfo.ModuleID != ModuleId))\n    //            _moduleInfo = PortalSettings == null || PortalSettings.ActiveTab == null ? ServiceLocator<IModuleController, ModuleController>.Instance.GetModule(ModuleId, Null.NullInteger, true) : ServiceLocator<IModuleController, ModuleController>.Instance.GetModule(ModuleId, PortalSettings.ActiveTab.TabID, false);\n    //        return _moduleInfo;\n    //    }\n    //    set => _moduleInfo = value;\n    //}\n\n    //private ModuleInfo _moduleInfo;\n\n    //private string TestReplaceTokens(string sourceText)\n    //{\n    //    if (sourceText == null)\n    //        return string.Empty;\n    //    StringBuilder stringBuilder = new StringBuilder();\n    //    foreach (Match match in TokenizerRegex.Matches(sourceText))\n    //    {\n    //        string objectName = match.Result(\"${object}\");\n    //        if (!string.IsNullOrEmpty(objectName))\n    //        {\n    //            if (objectName == \"[\")\n    //                objectName = \"no_object\";\n    //            string propertyName = match.Result(\"${property}\");\n    //            string format = match.Result(\"${format}\");\n    //            string str1 = match.Result(\"${ifEmpty}\");\n    //            string str2 = replacedTokenValue(objectName, propertyName, format);\n    //            if (!string.IsNullOrEmpty(str1) && string.IsNullOrEmpty(str2))\n    //                str2 = str1;\n    //            stringBuilder.Append(str2);\n    //        }\n    //        else\n    //            stringBuilder.Append(match.Result(\"${text}\"));\n    //    }\n    //    return stringBuilder.ToString();\n    //}\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Pages/DnnPages.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Tabs;\nusing ToSic.Sxc.Blocks;\n\nnamespace ToSic.Sxc.Dnn.Pages;\n\n/// <summary>\n/// Temporary solutions - minor service which ATM is only used in WebAPI.\n/// Goal is that this will be more standardized and work across all platforms.\n/// So when we do that, this should implement that interface and become internal.\n/// </summary>\ninternal class DnnPages(ILog parentLog) : HelperBase(parentLog, \"Dnn.Pages\")\n{\n    internal List<ModuleWithContent> AllModulesWithContent(int portalId)\n    {\n        var l = Log.Fn<List<ModuleWithContent>>($\"{portalId}\");\n        var mc = ModuleController.Instance;\n        var tabC = TabController.Instance;\n\n        // create an array with all modules\n        var modules2Sxc = mc.GetModulesByDefinition(portalId, DnnConstants.ModuleNameContent)\n            .ToArray()\n            .Cast<ModuleInfo>()\n            .ToList();\n        var dnnMod2SxcApp = mc.GetModulesByDefinition(portalId, DnnConstants.ModuleNameApp)\n            .ToArray()\n            .Cast<ModuleInfo>()\n            .ToList();\n        var all = modules2Sxc.Union(dnnMod2SxcApp).ToList();\n        Log.A($\"Mods for Content: {modules2Sxc.Count}, App: {dnnMod2SxcApp.Count}, Total: {all.Count}\");\n\n        // filter the results\n        var allMods = all\n            .Where(m => m.DefaultLanguageModule == null)\n            .Where(m => m.ModuleSettings.ContainsKey(ModuleSettingNames.ContentGroup))\n            .ToList();\n\n        var result = allMods.Select(m => new ModuleWithContent\n            {\n                Module = m,\n                ContentGroup = Guid.TryParse(m.ModuleSettings[ModuleSettingNames.ContentGroup].ToString(),\n                    out var g)\n                    ? g\n                    : Guid.Empty,\n                Page = tabC.GetTab(m.TabID, portalId)\n            })\n            .Where(set => set.ContentGroup != Guid.Empty)\n            .ToList();\n\n        return l.Return(result, $\"{allMods.Count}\");\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Pages/ModuleWithContent.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Tabs;\n\nnamespace ToSic.Sxc.Dnn.Pages;\n\ninternal class ModuleWithContent\n{\n    public Guid ContentGroup;\n    public ModuleInfo Module;\n    public TabInfo Page;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Run/DnnEnvironmentPermission.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Security;\nusing DotNetNuke.Security.Permissions;\nusing ToSic.Eav.Environment.Sys.Permissions;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Context.Sys.Module;\n\nnamespace ToSic.Sxc.Dnn.Run;\n\ninternal class DnnEnvironmentPermission() : EnvironmentPermission(DnnConstants.LogName)\n{\n    public string CustomPermissionKey = \"\"; // \"CONTENT\";\n\n    /// <summary>\n    /// The DNN module on the container\n    /// </summary>\n    /// <remarks>\n    /// In some cases the container is a ContainerNull object without ModuleInfo, so we must really do null-checks\n    /// </remarks>\n    protected ModuleInfo Module => _module.Get(\n        () => ((Context as IContextOfBlock)?.Module as Module<ModuleInfo>)?.GetContents());\n    private readonly GetOnce<ModuleInfo> _module = new();\n\n    public override bool VerifyConditionOfEnvironment(string condition)\n    {\n        var l = Log.Fn<bool>($\"condition: {condition}\");\n        var fullPrefix = (SalPrefix + \".\").ToLowerInvariant();\n        if (!condition.StartsWith(fullPrefix, StringComparison.InvariantCultureIgnoreCase))\n            return l.ReturnFalse(\"unknown condition: false\");\n\n        var salWord = condition.Substring(fullPrefix.Length);\n        var sal = (SecurityAccessLevel)Enum.Parse(typeof(SecurityAccessLevel), salWord);\n        // check anonymous - this is always valid, even if not in a module context\n        if (sal == SecurityAccessLevel.Anonymous)\n            return l.ReturnTrue(\"anonymous, always true\");\n\n        // check within module context\n        if (Module != null)\n        {\n            // TODO: STV WHERE DOES THE MODULE COME FROM?\n            // IT APPEARS THAT IT'S MISSING IN NORMAL REST CALLS\n            var result = ModulePermissionController.HasModuleAccess(sal, CustomPermissionKey, Module);\n            return l.Return(result, $\"module: {result}\");\n        }\n\n        l.A(\"trying to check permission \" + fullPrefix + \", but don't have module in context\");\n        return l.ReturnFalse(\"can't verify: false\");\n    }\n\n    protected override bool UserIsModuleAdmin()\n    {\n        var l = Log.Fn<bool>();\n        return l.ReturnAsOk(Module != null && ModulePermissionController.CanAdminModule(Module));\n    }\n \n\n    protected override bool UserIsModuleEditor()\n    {\n        var l = Log.Fn<bool>();\n        if (Module == null)\n            return false;\n\n        // This seems to throw errors during search :(\n        try\n        {\n            // skip during search (usual HttpContext is missing for search)\n            if (System.Web.HttpContext.Current == null)\n                return l.ReturnFalse();\n\n            var isEditor = ModulePermissionController.HasModuleAccess(SecurityAccessLevel.Edit, \"\", Module)\n                           || ModulePermissionController.CanEditModuleContent(Module);\n            return l.ReturnAndLog(isEditor);\n        }\n        catch (Exception e)\n        {\n            l.Ex(e);\n            return l.ReturnFalse(\"error\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Run/DnnLogging.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Web.Http;\nusing DotNetNuke.Services.Log.EventLog;\nusing ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Dnn.Run;\n\ninternal static class DnnLogging\n{\n    public const int MaxDuration = 10;\n\n    public static void LogToDnn(string key, string message, ILog log = null, IDnnContext dnnContext = null, bool force = false)\n    {\n        if (!force || !EnableLogging(GlobalConfiguration.Configuration.Properties)) return;\n\n        // note: this code has a lot of try/catch, to ensure that most of it works and that\n        // it doesn't interfere with other functionality\n        try\n        {\n            var logInfo = new LogInfo\n            {\n                LogTypeKey = EventLogController.EventLogType.ADMIN_ALERT.ToString()\n            };\n\n            // the initial message should come first, as it's visible in the summary\n            if(!string.IsNullOrEmpty(message))\n                logInfo.AddProperty(key, message);\n\n            AttachDnnStateIfPossible(dnnContext, logInfo);\n\n            (log as Log)?.Entries.ForEach(e => logInfo.AddProperty(e.Source, e.Message));\n\n            new EventLogController().AddLog(logInfo);\n        }\n        catch\n        {\n            TryToReportLoggingFailure(\"logging\");\n        }\n    }\n\n    /// <summary>\n    /// try to at least report, that something failed\n    /// </summary>\n    /// <param name=\"source\"></param>\n    public static void TryToReportLoggingFailure(string source)\n    {\n        try\n        {\n            new EventLogController().AddLog(\"2sxc logging\",\n                $\"failed to add log from {source}, something in the logging failed\", EventLogController.EventLogType.ADMIN_ALERT);\n        }\n        catch { /* ignore */ }\n    }\n\n    private static void AttachDnnStateIfPossible(IDnnContext dnn, LogInfo logInfo)\n    {\n        try\n        {\n            if (dnn != null)\n            {\n                logInfo.LogUserName = dnn.User?.DisplayName ?? EavConstants.NullNameId;\n                logInfo.LogUserID = dnn.User?.UserID ?? -1;\n                logInfo.LogPortalID = dnn.Portal.PortalId;\n                logInfo.AddProperty(\"Module Id\", dnn.Module?.ModuleID.ToString() ?? EavConstants.NullNameId);\n            }\n        }\n        catch { /* ignore */ }\n    }\n\n    public static bool EnableLogging(ConcurrentDictionary<object, object> props)\n    {\n        if (props == null) return false;\n        if (!props.TryGetValue(DnnConstants.AdvancedLoggingEnabledKey, out var enabled)) return false;\n        if (enabled is not true) return false;\n\n        if (!props.TryGetValue(DnnConstants.AdvancedLoggingTillKey, out var till)) return false;\n        return till is DateTime dtmTill && dtmTill.CompareTo(DateTime.Now) > 0;\n    }\n\n    /// <summary>\n    /// Activate extended logging for a specific duration\n    /// </summary>\n    /// <param name=\"duration\"></param>\n    /// <returns></returns>\n    public static string ActivateForDuration(int duration)\n    {\n        if (duration > MaxDuration)\n            duration = MaxDuration;\n\n        var prop = GlobalConfiguration.Configuration.Properties;\n        prop.GetOrAdd(DnnConstants.AdvancedLoggingEnabledKey, duration > 0);\n        var timeout = DateTime.Now.AddMinutes(duration);\n        prop.AddOrUpdate(DnnConstants.AdvancedLoggingTillKey, timeout, (_, _) => timeout);\n        return $\"Extended logging activated for {duration} minutes to {timeout}\";\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Run/DnnPlatformContext.cs",
    "content": "﻿using DotNetNuke.Application;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys.Platform;\nusing ToSic.Sys.Capabilities.Platform;\n\nnamespace ToSic.Sxc.Dnn.Run;\n\ninternal class DnnPlatformContext: Platform, IPlatformInfo\n{\n    public override PlatformType Type => PlatformType.Dnn;\n\n    public override Version Version => DotNetNukeContext.Current.Application.Version;\n\n    string IPlatformInfo.Identity => DotNetNuke.Entities.Host.Host.GUID;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Run/DnnSecurity.cs",
    "content": "﻿using System.Web.Security;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Users;\nusing DotNetNuke.Security.Permissions;\nusing DotNetNuke.Security.Roles;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sys.Users.Permissions;\nusing static ToSic.Sxc.Dnn.DnnSxcSettings;\n\nnamespace ToSic.Sxc.Dnn.Run;\n\n// TODO: probably change this to use an interface so we can make it internal\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[PrivateApi]\npublic class DnnSecurity(LazySvc<RoleController> roleController) : ServiceBase(\"dnnSec\", connect: [roleController])\n{\n    /// <summary>\n    /// Returns true if a DotNetNuke User Group \"2sxc Designers\" / \"2sxcAdministrators\" exists\n    /// </summary>\n    /// <param name=\"portalId\"></param>\n    /// <returns></returns>\n    private bool PortalHasExplicitAdminGroups(int portalId)\n        => DnnGroupsSxcAdmins.Any(grpName => PortalHasGroup(portalId, grpName));\n\n    private bool IsExplicitAdmin(UserInfo user)\n        => !IsNullOrAnonymous(user) && DnnGroupsSxcAdmins.Any(user.IsInRole);\n\n\n    private bool PortalHasGroup(int portalId, string groupName)\n        => roleController.Value.GetRoleByName(portalId, groupName) != null;\n\n    private bool IsNullOrAnonymous(UserInfo user)\n        => user == null || user.UserID == -1;\n\n\n    internal EffectivePermissions UserMayAdminThis(UserInfo user)\n    {\n        // Null-Check\n        if (IsNullOrAnonymous(user))\n            return new(false);\n\n        // Super always AppAdmin\n        if (user.IsSuperUser)\n            return new(true);\n\n        var portal = PortalSettings.Current;\n\n        // Skip the remaining tests if the portal isn't known\n        if (portal == null)\n            return new(false);\n\n        var dnnPermissionProvider = PermissionProvider.Instance();\n        if (!dnnPermissionProvider.IsPortalEditor())\n            return new(false);\n\n        // Non-SuperUsers must be PortalEditor AND in the group SxcAppAdmins\n        var hasSpecialGroup = PortalHasExplicitAdminGroups(portal.PortalId);\n        if (hasSpecialGroup && IsExplicitAdmin(user))\n            return new(true);\n\n        // If the special group doesn't exist, then the admin-state (which is true - since he got here) is valid\n        // or if the special group exist, then all administrators will be treated as ContentAdmins (has fewer permissions).\n        if (user.IsInRole(portal.AdministratorRoleName ?? DnnAdminRoleDefaultName))\n            return new(isSiteAdmin: !hasSpecialGroup, isContentAdmin: true);\n\n        // ... for \"Content Managers\"\n        if (user.IsInRole(DnnContentManagers))\n            return new(false, true);\n\n        // ... for \"Content Editors\"\n        if (user.IsInRole(DnnContentEditors))\n            return new(false, false, true, true);\n\n        // this should not happen\n        return new(false);\n    }\n\n    private List<UserRoleModel> UserRoles(UserInfo user, int? portalId = null)\n        => IsNullOrAnonymous(user)\n            ? []\n            : user.Roles\n                .Select(r => RoleController.Instance.GetRoleByName(portalId ?? user.PortalID, r))\n                .Where(r => r != null)\n                .Select(r => new UserRoleModel\n                {\n                    Id = r.RoleID,\n                    Name = r.RoleName,\n                    Created = r.CreatedOnDate,\n                    Modified = r.LastModifiedOnDate,\n                })\n                .ToList();\n\n    internal Guid UserGuid(UserInfo user)\n        => Membership.GetUser(user.Username)?.ProviderUserKey as Guid?\n           ?? Guid.Empty;\n\n    internal string UserIdentityToken(UserInfo user)\n        => IsNullOrAnonymous(user)\n            ? SxcUserConstants.Anonymous\n            : DnnConstants.UserTokenPrefix + user.UserID;\n\n    internal UserModel CmsUserBuilder(UserInfo user, int siteId)\n    {\n        var adminInfo = UserMayAdminThis(user);\n        return new()\n        {\n            Id = user.UserID,\n            Guid = UserGuid(user),\n            NameId = UserIdentityToken(user),\n            Roles = UserRoles(user, portalId: siteId),\n            IsSystemAdmin = user.IsSuperUser,\n            IsSiteAdmin = adminInfo.IsSiteAdmin,\n            IsContentAdmin = adminInfo.IsContentAdmin,\n            IsContentEditor = adminInfo.IsContentEditor,\n            IsAnonymous = IsNullOrAnonymous(user),\n            Created = user.CreatedOnDate,\n            Modified = user.LastModifiedOnDate,\n            //\n            Username = user.Username,\n            Email = user.Email,\n            Name = user.DisplayName\n        };\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Run/DnnValueConverter.cs",
    "content": "﻿using DotNetNuke.Abstractions;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Tabs;\nusing DotNetNuke.Services.Exceptions;\nusing DotNetNuke.Services.FileSystem;\nusing DotNetNuke.Services.Localization;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Sxc.Adam.Sys.Security;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Dnn.Run;\n\n/// <summary>\n/// The DNN implementation of the <see cref=\"IValueConverter\"/> which converts \"file:22\" or \"page:5\" to the url,\n/// </summary>\n[PrivateApi(\"Hide implementation - not useful for external documentation\")]\ninternal class DnnValueConverter(\n    ISite site,\n    LazySvc<ISysFeaturesService> featuresLazy,\n    LazySvc<PageScopedService<ISite>> siteFromPageLazy,\n    LazySvc<INavigationManager> navigationManager)\n    : ValueConverterBase($\"{DnnConstants.LogName}.ValCnv\",\n        connect: [site, featuresLazy, siteFromPageLazy, navigationManager])\n{\n    public const string CurrentLanguage = \"current\";\n\n    #region DI Constructor\n\n    private int PageSiteId => siteFromPageLazy.Value.Value.Id; // PortalId from page di scope\n\n    #endregion\n\n    /// <inheritdoc />\n    public override string ToReference(string value)\n        => TryToResolveOneLinkToInternalDnnCode(value);\n\n    /// <inheritdoc />\n    public override string ToValue(string reference, Guid itemGuid = default)\n        => TryToResolveCodeToLink(itemGuid, reference);\n\n    /// <summary>\n    /// Will take a link like http:\\\\... to a file or page and try to return a DNN-style info like\n    /// Page:35 or File:43003\n    /// </summary>\n    /// <param name=\"potentialFilePath\"></param>\n    /// <remarks>\n    /// note: this can always use the current context, because this should happen\n    /// when saving etc. - which is always expected to happen in the owning portal\n    /// </remarks>\n    /// <returns></returns>\n    private string TryToResolveOneLinkToInternalDnnCode(string potentialFilePath)\n    {\n        // Try file reference\n        var fileInfo = FileManager.Instance.GetFile(site.Id, potentialFilePath) // PortalId from module di scope\n                       ?? FileManager.Instance.GetFile(PageSiteId, potentialFilePath); // PortalId from page di scope (module sharing on different site)\n        if (fileInfo != null) return PrefixFile + Separator + fileInfo.FileId;\n\n        // Try page / tab ID\n        var tabController = new TabController();\n        var tabInfo = tabController.GetTabsByPortal(site.Id).Select(tab => tab.Value)\n                          .FirstOrDefault(tab => tab.TabPath == potentialFilePath)// PortalId from module di scope\n                      ?? tabController.GetTabsByPortal(PageSiteId).Select(tab => tab.Value)\n                          .FirstOrDefault(tab => tab.TabPath == potentialFilePath);// PortalId from page di scope (module sharing on different site)\n\n        return tabInfo != null\n            ? PrefixPage + Separator + tabInfo.TabID\n            : potentialFilePath;\n    }\n        \n\n    protected override void LogConversionExceptions(string originalValue, Exception e)\n    {\n        var wrappedEx = new Exception(\"Error when trying to lookup a friendly url of \\\"\" + originalValue + \"\\\"\", e);\n        Exceptions.LogException(wrappedEx);\n    }\n\n    protected override string ResolveFileLink(int linkId, Guid itemGuid)\n    {\n        var fileInfo = FileManager.Instance.GetFile(linkId);\n        if (fileInfo == null)\n            return null;\n\n        #region special handling of issues in case something in the background is broken\n        // there are cases where the PortalSettings will be null or something, and in these cases the serializer would break down\n        // so this is to just ensure that if it can't be converted, it'll just fall back to default\n        try\n        {\n            var filePath = Path.Combine(new PortalSettings(fileInfo.PortalId).HomeDirectory ?? \"\", fileInfo.RelativePath ?? \"\");\n\n            // return linkclick url for secure and other not standard folder locations\n            var result = fileInfo.StorageLocation == 0 ? filePath : FileLinkClickController.Instance.GetFileLinkClick(fileInfo);\n\n            // optionally do extra security checks (new in 10.02)\n            if (!featuresLazy.Value.IsEnabled(BuiltInFeatures.AdamRestrictLookupToEntity.Guid)) return result;\n\n            // check if it's in this item. We won't check the field, just the item, so the field is \"\"\n            return !AdamSecurity.PathIsInItemAdam(itemGuid, \"\", filePath)\n                ? null\n                : result;\n        }\n        catch\n        {\n            return null;\n        }\n        #endregion\n    }\n\n    protected override string ResolvePageLink(int id) => ResolvePageLink(id, CurrentLanguage, []);\n\n    /// <summary>\n    /// Resolve URL to Page with TabId, but handles more situations than DNN framework:\n    /// - supports module sharing scenarios, when module is on different portal\n    /// - return localized page TabId, instead of requested TabId\n    /// </summary>\n    /// <param name=\"id\">TabId to page</param>\n    /// <param name=\"language\">\"current\" is required to ensure expected behavior (to try to find current language localized TabId)</param>\n    /// <param name=\"additionalParameters\">query string parameters</param>\n    /// <returns>return string url to page</returns>\n    internal string ResolvePageLink(int id, string language = null, params string[] additionalParameters)\n    {\n        var tabController = new TabController();\n\n        var tabInfo = tabController.GetTab(id, site.Id) // PortalId from module di scope\n                      ?? tabController.GetTab(id, PageSiteId); // PortalId from page di scope (module sharing on different site)\n        if (tabInfo == null) return null;\n\n        var psCurrent = PortalSettings.Current;\n        var psPage = psCurrent;\n\n        // Get full PortalSettings (with portal alias) if module sharing is active\n        if (psCurrent != null && psCurrent.PortalId != tabInfo.PortalID)\n            psPage = PortalSettingsForNavigateUrl(tabInfo.PortalID);\n\n        if (psPage == null) return null;\n\n        // try to change TabID to localized version when language == CurrentLanguage\n        if (language == CurrentLanguage && tabInfo.CultureCode != \"\" && psCurrent != null && tabInfo.CultureCode != psCurrent.CultureCode)\n        {\n            var cultureTabInfo = tabController\n                .GetTabByCulture(tabInfo.TabID, tabInfo.PortalID,\n                    LocaleController.Instance.GetLocale(psCurrent.CultureCode));\n\n            if (cultureTabInfo != null)\n                tabInfo = cultureTabInfo;\n        }\n\n        // Exception in AdvancedURLProvider because ownerPortalSettings.PortalAlias is null\n        return navigationManager.Value.NavigateURL(tabInfo.TabID, psPage, \"\", additionalParameters);\n\n    }\n\n    private static PortalSettings PortalSettingsForNavigateUrl(int portalId)\n    {\n        var psPage = new PortalSettings(portalId);\n\n        // PortalAlias is required for NavigateURL in AdvancedURLProvider,\n        // but sometimes is missing (module sharing)\n        if (psPage.PortalAlias == null)\n            psPage.PortalAlias = PortalAliasForNavigateUrl(portalId);\n\n        return psPage;\n    }\n\n    private static PortalAliasInfo PortalAliasForNavigateUrl(int portalId) =>\n        PortalAliasController.Instance.GetPortalAliasesByPortalId(portalId)\n            .FirstOrDefault(alias => alias.IsPrimary); // get primary alias\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Run/DnnZoneMapper.cs",
    "content": "﻿using DotNetNuke.Entities.Portals;\nusing DotNetNuke.Services.Localization;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Sxc.Cms;\nusing ToSic.Sxc.Dnn.Context;\nusing ToSic.Sys.Locking;\n\nnamespace ToSic.Sxc.Dnn.Run;\n\ninternal class DnnZoneMapper(Generator<ISite> site, LazySvc<ZoneCreator> zoneCreatorLazy, IAppsCatalog appsCatalog)\n    : ZoneMapperBase(appsCatalog, \"DNN.ZoneMp\", connect: [site, zoneCreatorLazy])\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// Will get the EAV ZoneId for the current tenant\n    /// Always returns a valid value, as it will otherwise create one if it was missing\n    /// ...if the tenant/portal exists\n    /// </summary>\n    /// <param name=\"siteId\"></param>\n    /// <returns></returns>\n    public override int GetZoneId(int siteId)\n    {\n        // Additional protection against invalid portalId\n        if (siteId < 0)\n            throw new ArgumentException(\"Can't get zone for invalid portal ID: \" + siteId);\n\n        // Attempt to retrieve existing Zone ID\n        var existingZoneId = GetExistingZoneId(siteId);\n        if (existingZoneId.HasValue)\n            return existingZoneId.Value;\n\n        // Use TryLockTryDo to prevent race condition during zone creation\n        var zoneIdResult = _zoneCreateLocker.Call(\n            conditionToGenerate: () => !GetExistingZoneId(siteId).HasValue,\n            generator: () => CreateNewZone(siteId),\n            cacheOrFallback: () =>\n            {\n                // Retrieve existing Zone ID if it was created by another thread\n                var fallbackZoneId = GetExistingZoneId(siteId);\n                if (fallbackZoneId.HasValue)\n                    return fallbackZoneId.Value;\n                throw new InvalidOperationException(\"Failed to retrieve or create Zone ID.\");\n            });\n\n        return zoneIdResult.Result;\n    }\n    // Instance of TryLockTryDo for synchronization\n    private readonly TryLockTryDo _zoneCreateLocker = new();\n\n    private static int? GetExistingZoneId(int siteId)\n    {\n        var portalSettings = PortalController.Instance.GetPortalSettings(siteId);\n        if (portalSettings.TryGetValue(SiteSettingNames.SiteKeyForZoneId, out var value) && int.TryParse(value, out var zoneId))\n            return zoneId;\n        return null;\n    }\n\n    private int CreateNewZone(int siteId)\n    {\n        var portalInfo = new PortalSettings(siteId);\n        var newZoneId = zoneCreatorLazy.Value.Create($\"{portalInfo.PortalName} (Portal {siteId})\");\n        PortalController.UpdatePortalSetting(siteId, SiteSettingNames.SiteKeyForZoneId, newZoneId.ToString());\n        return newZoneId;\n    }\n\n    public override ISite SiteOfZone(int zoneId)\n    {\n        var l = Log.Fn<ISite>($\"{zoneId}\");\n        var portalController = PortalController.Instance;\n        var portals = portalController.GetPortals();\n        l.A($\"Sites/Portals Count: {portals.Count}\");\n        var found = portals\n            .Cast<PortalInfo>()\n            .Select(p =>\n            {\n                var pSettings = portalController.GetPortalSettings(p.PortalID);\n                if (!pSettings.TryGetValue(SiteSettingNames.SiteKeyForZoneId, out var portalZoneId)) return null;\n                if (!int.TryParse(portalZoneId, out var zid)) return null;\n                return zid == zoneId ? new PortalSettings(p) : null;\n            })\n            .FirstOrDefault(f => f != null);\n\n        return found == null\n            ? l.ReturnNull(\"not found\")\n            : l.Return(((DnnSite)site.New()).TryInitPortal(found, Log), $\"found {found.PortalId}\");\n    }\n\n    /// <inheritdoc />\n    public override List<ISiteLanguageState> CulturesWithState(ISite ofSite)\n    {\n        if (_supportedCultures != null)\n            return _supportedCultures;\n\n        var availableEavLanguages = AppsCatalog.Zone(ofSite.ZoneId).Languages;\n        var defaultLanguageCode = ofSite.DefaultCultureCode;\n\n        return _supportedCultures = LocaleController.Instance.GetLocales(ofSite.Id)\n            .Select(c => new SiteLanguageState(\n                c.Value.Code, \n                c.Value.Text,\n                availableEavLanguages.Any(a => a.Active && a.Matches(c.Value.Code))))\n            .OrderByDescending(c => c.Code == defaultLanguageCode)\n            .ThenBy(c => c.Code)\n            .Cast<ISiteLanguageState>()\n            .ToList();\n    }\n    private List<ISiteLanguageState> _supportedCultures;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Run/IDnnContext.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Entities.Tabs;\nusing DotNetNuke.Entities.Users;\n\nnamespace ToSic.Sxc.Dnn.Run;\n// Internal note: this is being used publicly, so as we phase it out, make sure the Namespace etc. doesn't change!\n\n/// <summary>\n/// Provides information about the current context within DNN.\n/// This only applies to 2sxc running inside DNN, not inside another platform.\n///\n/// This object is the root `Dnn` object, used mainly in older Razor.\n/// If possible, try to use `CmsContext` instead.\n/// </summary>\n/// <remarks>\n/// It is currently on `ToSic.Sxc.Run.IDnnContext` but we plan to move it elsewhere\n/// </remarks>\n[PublicApi(\"This is DNN only, if possibly, try to use the hybrid CmsContext (v14) / MyContext (v16+) instead.\")]\npublic interface IDnnContext\n{\n    /// <summary>\n    /// The current DNN ModuleInfo - Dnn specific and with all the specials of the Dnn APIs.\n    ///\n    /// If possible, try to use [CmsContext.Module](xref:ToSic.Sxc.Context.ICmsModule) instead. \n    /// </summary>\n    ModuleInfo Module { get; }\n\n    /// <summary>\n    /// The current DNN TabInfo (page). \n    /// We also don't like the name Tab, but that's the DNN convention.\n    ///\n    /// If possible, try to use [CmsContext.Page](xref:ToSic.Sxc.Context.ICmsPage) instead. \n    /// </summary>\n    TabInfo Tab { get; }\n\n    /// <summary>\n    /// The current DNN Portal Settings.\n    ///\n    /// If possible, try to use [CmsContext.Site](xref:ToSic.Sxc.Context.ICmsSite) instead. \n    /// </summary>\n    PortalSettings Portal { get; }\n\n    /// <summary>\n    /// The current DNN User.\n    ///\n    /// If possible, try to use [CmsContext.User](xref:ToSic.Sxc.Context.ICmsUser) instead.\n    /// </summary>\n    UserInfo User { get; }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Search/SearchController.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Services.Search.Entities;\nusing System.Text.RegularExpressions;\nusing System.Web;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Caching;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys.Module;\nusing ToSic.Sxc.Dnn.Context;\nusing ToSic.Sxc.Dnn.LookUp;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Sxc.Search;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing static System.StringComparer;\n\nnamespace ToSic.Sxc.Dnn.Search;\n\n/// <summary>\n/// This will construct data for the search indexer in DNN.\n/// It's created once for each module which will be indexed\n/// </summary>\n/// <remarks>\n/// ATM it's DNN only (because Oqtane doesn't have search indexing)\n/// But the code is 99% clean, so it would be easy to split into dnn/Oqtane versions once ready.\n/// The only difference seems to be exception logging. \n/// </remarks>\ninternal class SearchController(\n    AppsCacheSwitch appsCache,\n    Generator<CodeCompiler> codeCompiler,\n    Generator<IExecutionContextFactory> exCtxFactory,\n    Generator<ISite> siteGenerator,\n    LazySvc<IModuleAndBlockBuilder> moduleAndBlockBuilder,\n    LazySvc<ILookUpEngineResolver> dnnLookUpEngineResolver,\n    EngineFactory engineFactory,\n    LazySvc<ILogStore> logStore,\n    PolymorphConfigReader polymorphism)\n    : ServiceBase(\"DNN.Search\",\n        connect:\n        [\n            appsCache, codeCompiler, exCtxFactory, siteGenerator, engineFactory, dnnLookUpEngineResolver,\n            moduleAndBlockBuilder, logStore, polymorphism\n        ])\n{\n    /// <summary>\n    /// Initialize all values which are needed - or return a text with the info why we must stop.\n    /// For example, check if the block is in a ready state to provide data.\n    /// </summary>\n    /// <param name=\"module\"></param>\n    /// <returns></returns>\n    private string InitAllAndVerifyIfOk(IModule module)\n    {\n        var l = Log.Fn<string>();\n        // Start by getting the module info\n        DnnModule = (module as Module<ModuleInfo>)?.GetContents();\n        l.A($\"start search for mod#{DnnModule?.ModuleID}\");\n        if (DnnModule == null) return l.ReturnAsOk(\"no module\");\n\n        // This changes site in whole scope\n        DnnSite = ((DnnSite)siteGenerator.New()).TryInitModule(DnnModule, Log);\n\n        // New Context because Portal-Settings.Current is null\n        var appId = module.BlockIdentifier.AppId;\n        if (appId is AppConstants.AppIdNotFound or EavConstants.NullId)\n            return l.ReturnAsOk(\"no app id\");\n\n        // Ensure cache builds up with correct primary language\n        // In case it's not loaded yet\n        appsCache.Value.Load(module.BlockIdentifier.PureIdentity(), DnnSite.DefaultCultureCode, appsCache.AppLoaderTools);\n\n        Block = moduleAndBlockBuilder.Value.BuildBlock(DnnModule, null);\n\n        if (!Block.DataIsReady || !Block.ViewIsReady)\n            return \"no data or view\";\n\n        if (Block.View.SearchIndexingDisabled)\n            return \"search disabled\"; // new in 12.02\n\n\n        // Attach DNN Lookup Providers so query-params like [DateTime:Now] or [Portal:PortalId] will work\n        AttachDnnLookUpsToData(Block.Data, DnnSite, DnnModule);\n\n        // Get all streams to index\n        var streamsToIndex = GetStreamsToIndex();\n        if (!streamsToIndex.Any())\n            return l.ReturnAsOk(\"no streams to index\");\n\n        // Figure out the current edition - if none, stop here\n        // New 2023-03-20 - if the view comes with a preset edition, it's an ajax-preview which should be respected\n        _edition = polymorphism.UseViewEditionOrGet(Block);\n\n        // Convert DNN SearchDocuments from 2sxc SearchInfos\n        SearchItems = BuildInitialSearchInfos(streamsToIndex, DnnModule);\n\n        // all ok - return null so upstream knows no errors\n        return l.ReturnNull();\n    }\n\n    /// <summary>The DnnModule will be initialized, and must exist for the search-index to provide data.</summary>\n    public ModuleInfo DnnModule;\n    /// <summary>The DnnSite will be initialized, and must exist for the search-index to provide data.</summary>\n    public DnnSite DnnSite;\n    /// <summary>The Block will be initialized, and must exist for the search-index to provide data.</summary>\n    public IBlock Block;\n    /// <summary>The SearchItems will be initialized, and must exist for the search-index to provide data.</summary>\n    public Dictionary<string, List<ISearchItem>> SearchItems;\n\n    private string _edition;\n\n    /// <summary>\n    /// Get search info for each dnn module containing 2sxc data\n    /// </summary>\n    /// <returns></returns>\n    public IList<SearchDocument> GetModifiedSearchDocuments(IModule module, DateTime beginDate)\n    {\n        var l = Log.Fn<List<SearchDocument>>();\n        // Turn off logging into history by default - the template code can reactivate this if desired\n        var logWithPreserve = Log as Log;\n        logWithPreserve?.Preserve = false;\n\n        // Log with infos, to ensure errors are caught\n        var exitMessage = InitAllAndVerifyIfOk(module);\n        if (exitMessage != null)\n            return l.Return([], exitMessage);\n\n        var view = Block.View!;\n        try\n        {\n            var useCustomViewController = !string.IsNullOrWhiteSpace(view.ViewController); // new in 12.02\n            l.A($\"Use new Custom View Controller: {useCustomViewController}\");\n            if (useCustomViewController)\n            {\n                /* New mode in 12.02 using a custom ViewController */\n                var customizeSearch = CreateAndInitViewController(DnnSite, Block);\n                if (customizeSearch == null)\n                    return l.Return([], \"exit\");\n\n                // Call CustomizeSearch in a try/catch\n                l.A(\"execute CustomizeSearch\");\n                customizeSearch.CustomizeSearch(SearchItems, Block.Context.Module, beginDate);\n                l.A(\"Executed CustomizeSearch\");\n            }\n            // 2026-01-27 2dm v21 - old search implementation has been deprecated in v20\n            //else\n            //{\n            //    /* Old mode v06.02 - 12.01 using the Engine or Razor which customizes */\n            //    // Build the engine, as that's responsible for calling inner search stuff\n            //    var engine = engineFactory.CreateEngine(view);\n            //    engine.Init(Block);\n\n            //}\n        }\n        catch (Exception e)\n        {\n            return l.Return(LogErrorForExit(e, DnnModule),\n                \"error, so return nothing to ensure we don't bleed unexpected infos\");\n        }\n\n        // At the of the code, add it to insights / history. This must happen at the end.\n        // It will only be preserved, if the inner code ran a Log.Preserve = true;\n        if (logWithPreserve?.Preserve ?? false)\n            logStore.Value.Add(\"dnn-search\", Log);\n\n        // reduce load by only keeping recently modified items\n        var searchDocuments = KeepOnlyChangesSinceLastIndex(beginDate, SearchItems);\n\n        return l.Return(searchDocuments, $\"{searchDocuments.Count}\");\n    }\n\n        \n        \n    private List<SearchDocument> LogErrorForExit(Exception e, ModuleInfo modInfo)\n    {\n        DnnEnvironmentLogger.AddSearchExceptionToLog(modInfo, e, nameof(SearchController));\n        Log.Ex(e);\n        return [];\n    }\n        \n        \n\n    /// <summary>\n    /// Reduce load by only keeping recently modified items\n    /// </summary>\n    /// <param name=\"beginDate\"></param>\n    /// <param name=\"searchInfoDictionary\"></param>\n    /// <returns></returns>\n    private static List<SearchDocument> KeepOnlyChangesSinceLastIndex(DateTime beginDate, Dictionary<string, List<ISearchItem>> searchInfoDictionary)\n    {\n        var searchDocuments = new List<SearchDocument>();\n        foreach (var searchInfoList in searchInfoDictionary)\n        {\n            // Filter by Date - take only SearchDocuments that changed since beginDate\n            var searchDocumentsToAdd = searchInfoList.Value.Where(p => p.ModifiedTimeUtc >= beginDate.ToUniversalTime())\n                .Select(p => (SearchDocument) p);\n            searchDocuments.AddRange(searchDocumentsToAdd);\n        }\n\n        return searchDocuments;\n    }\n\n\n    /// <summary>\n    /// Convert DNN SearchDocuments from 2sxc SearchInfos\n    /// </summary>\n    private Dictionary<string, List<ISearchItem>> BuildInitialSearchInfos(KeyValuePair<string, IDataStream>[] streamsToIndex, ModuleInfo dnnModule)\n    {\n        var l = Log.Fn<Dictionary<string, List<ISearchItem>>>();\n        var language = dnnModule.CultureCode;\n        var searchInfoDictionary = new Dictionary<string, List<ISearchItem>>();\n        foreach (var stream in streamsToIndex)\n        {\n            var entities = stream.Value.List.ToListOpt();\n            var searchInfoList = searchInfoDictionary[stream.Key] = [];\n\n            var additions = entities\n                .Select(entity => new SearchItem\n                {\n                    Entity = entity,\n                    Url = \"\",\n                    Description = \"\",\n                    Body = GetJoinedAttributes(entity, language),\n                    Title = entity.Title?[language]?.ToString() ?? \"(no title)\",\n                    ModifiedTimeUtc = (entity.Modified == DateTime.MinValue\n                        ? DateTime.Now.Date.AddHours(DateTime.Now.Hour)\n                        : entity.Modified).ToUniversalTime(),\n                    UniqueKey = \"2sxc-\" + dnnModule.ModuleID + \"-\" + (entity.EntityGuid != new Guid()\n                        ? entity.EntityGuid.ToString()\n                        : stream.Key + \"-\" + entity.EntityId),\n                    IsActive = true,\n                    TabId = dnnModule.TabID,\n                    PortalId = dnnModule.PortalID\n                })\n                .ToListOpt();\n\n            searchInfoList.AddRange(additions);\n        }\n\n        return l.Return(searchInfoDictionary, $\"{searchInfoDictionary.Count}\");\n    }\n\n    /// <summary>\n    /// Attach DNN Lookup Providers so query-params like [DateTime:Now] or [Portal:PortalId] will work\n    /// </summary>\n    private void AttachDnnLookUpsToData(IDataSource dataSource, DnnSite site, ModuleInfo dnnModule)\n    {\n        if (dataSource.Configuration?.LookUpEngine == null)\n            return;\n\n        Log.A(\"Will try to attach dnn providers to DataSource LookUps\");\n        try\n        {\n            var getLookups = dnnLookUpEngineResolver.Value;\n            var dnnLookUps = (getLookups as DnnLookUpEngineResolver)?.LookUpEngineOfPortalSettings(site.GetContents(), dnnModule.ModuleID);\n            ((LookUpEngine) dataSource.Configuration.LookUpEngine).Link(dnnLookUps);\n        }\n        catch (Exception e)\n        {\n            // Log but keep going, as it's bad, but the lookups may not be important for this module\n            Log.Ex(e);\n        }\n    }\n\n    /// <summary>\n    /// Get original streams and if the settings restrict which ones to keep, apply that. \n    /// </summary>\n    private KeyValuePair<string, IDataStream>[] GetStreamsToIndex()\n    {\n        var l = Log.Fn<KeyValuePair<string, IDataStream>[]>();\n        // Check if we should filter the streams - new in 12.02\n        var streamsToKeep = Block.View.SearchIndexingStreams\n            .Split(',')\n            .Select(s => s.Trim())\n            .Where(s => !string.IsNullOrEmpty(s))\n            .ToArray();\n\n        // Decide what streams to keep - new in 12.02\n        var streamsToIndex = Block.Data.Out\n            .Where(p => p.Key != ViewParts.Presentation && p.Key != ViewParts.ListPresentation)\n            .ToArray();\n\n        if (streamsToKeep.Any())\n            streamsToIndex = streamsToIndex\n                .Where(s => streamsToKeep.Contains(s.Key, InvariantCultureIgnoreCase))\n                .ToArray();\n\n        return l.Return(streamsToIndex, $\"{streamsToIndex.Length}\");\n    }\n\n    private ICustomizeSearch CreateAndInitViewController(ISite site, IBlock block)\n    {\n        var l = Log.Fn<ICustomizeSearch>();\n        // 1. Get and compile the view.ViewController\n        var path = Path\n            .Combine(Block.View.IsShared ? site.SharedAppsRootRelative() : site.AppsRootPhysical, block.Context.AppReaderRequired.Specs.Folder)\n            .ForwardSlash();\n        l.A($\"compile ViewController class on path: {path}/{Block.View.ViewController}\");\n        var spec = new HotBuildSpec(block.AppId, _edition, block.App.Name);\n        l.A($\"prepare spec: {spec}\");\n        var instance = codeCompiler.New().InstantiateClass(virtualPath: block.View.ViewController, spec: spec, className: null, relativePath: path, throwOnError: true);\n        l.A(\"got instance of compiled ViewController class\");\n\n        // 2. Check if it implements ToSic.Sxc.Search.ICustomizeSearch - otherwise just return the empty search results as shown above\n        if (instance is not ICustomizeSearch customizeSearch)\n            return l.ReturnNull(\"exit, class do not implements ICustomizeSearch\");\n\n        // 3. Make sure it has the full context if it's based on DynamicCode (like Code12)\n        if (instance is INeedsExecutionContext instanceWithContext)\n        {\n            l.A($\"attach DynamicCode context to class instance\");\n            var parentDynamicCodeRoot = exCtxFactory.New().New(new()\n            {\n                OwnerOrNull = null,\n                BlockOrNull = block,\n                ParentLog = Log,\n                CompatibilityFallback = CompatibilityLevels.CompatibilityLevel10,\n            });\n            instanceWithContext.ConnectToRoot(parentDynamicCodeRoot);\n        }\n\n        return l.Return(customizeSearch, \"instance ok\");\n    }\n\n    private string StripHtmlAndHtmlDecode(string text) => HttpUtility.HtmlDecode(Regex.Replace(text, \"<.*?>\", string.Empty));\n\n    /// <summary>\n    /// Gets a string that represents all entities joined with a comma , separator\n    /// Does just include String and Number fields\n    /// </summary>\n    /// <param name=\"entity\"></param>\n    /// <param name=\"language\"></param>\n    /// <returns></returns>\n    private string GetJoinedAttributes(IEntity entity, string language)\n    {\n        return string.Join(\", \",\n            entity.Attributes\n                .Where(x => x.Value.Type == ValueTypes.String || x.Value.Type == ValueTypes.Number)\n                .Select(x => x.Value[language])\n                .Where(a => a != null)\n                .Select(a => StripHtmlAndHtmlDecode(a.ToString()))\n                .Where(x => !string.IsNullOrEmpty(x))) + \" \";\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Search/SearchIndexException.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\n\nnamespace ToSic.Sxc.Dnn.Search;\n\n/// <summary>\n/// Special search exception, so these exceptions can be handled in a special way if necessary.\n/// </summary>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"this is just fyi\")]\ninternal class SearchIndexException(ModuleInfo module, Exception innerException, string source, int count, int max)\n    : Exception(\n        $\"Search: Error #{count} of {max} in '{source}' while indexing module {module.ModuleID} on tab {module.TabID}, portal {module.PortalID}\",\n        innerException);"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Search/SearchItem.cs",
    "content": "﻿using DotNetNuke.Services.Search.Entities;\nusing ToSic.Eav.Data;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Search;\n\n/// <summary>\n/// A search item which is passed around before handed over to the indexing system\n/// </summary>\n[PublicApi]\npublic class SearchItem : SearchDocument, ISearchItem\n{\n    public IEntity Entity { get; set; }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Search/readme.md",
    "content": "﻿# Search - for DNN\n\nThis is the search interface / implementation for DNN only. "
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Services/DnnLinkService.cs",
    "content": "﻿using DotNetNuke.Abstractions;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Dnn.Web;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Link.Sys;\nusing ToSic.Sxc.Sys.Integration.Paths;\n\nnamespace ToSic.Sxc.Dnn.Services;\n\n/// <summary>\n/// The DNN implementation of the <see cref=\"ILinkService\"/>.\n/// </summary>\n[PrivateApi(\"This implementation shouldn't be visible\")]\ninternal class DnnLinkService(\n    ImgResizeLinker imgLinker,\n    LazySvc<IValueConverter> dnnValueConverterLazy,\n    LazySvc<ILinkPaths> linkPathsLazy,\n    LazySvc<INavigationManager> navigationManager)\n    : LinkServiceBase(imgLinker, linkPathsLazy, connect: [dnnValueConverterLazy, navigationManager])\n{\n    [PrivateApi] private IDnnContext Dnn => field ??= ExCtx.GetService<IDnnContext>();\n    [PrivateApi] private DnnValueConverter DnnValueConverter => field ??= dnnValueConverterLazy.Value as DnnValueConverter;\n\n    protected override string ToApi(string api, string parameters = null) \n        => Api(path: CombineApiWithQueryString(api.TrimPrefixSlash(), parameters));\n\n    protected override string ToPage(int? pageId, string parameters = null, string language = null)\n    {\n        if (pageId.HasValue)\n        {\n            var url = DnnValueConverter.ResolvePageLink(pageId.Value, language, parameters);\n            if (!string.IsNullOrEmpty(url)) return url;\n        }\n            \n        var currentPageUrl = parameters == null\n            ? Dnn.Tab.FullUrl\n            : navigationManager.Value.NavigateURL(Dnn.Tab.TabID, \"\", parameters); // NavigateURL returns absolute links\n\n        return CurrentPageUrlWithEventualHashError(pageId, currentPageUrl);\n    }\n\n\n    private string Api(NoParamOrder npo = default, string path = null)\n    {\n        if (string.IsNullOrEmpty(path))\n            return string.Empty;\n\n        path = path.ForwardSlash();\n        path = path.TrimPrefixSlash();\n\n        if (path.PrefixSlash().ToLowerInvariant().Contains(\"/app/\"))\n            throw new ArgumentException(\"Error, path shouldn't have \\\"app\\\" part in it. It is expected to be relative to application root.\");\n\n        if (!path.PrefixSlash().ToLowerInvariant().Contains(\"/api/\"))\n            throw new ArgumentException(\"Error, path should have \\\"api\\\" part in it.\");\n\n        var apiRoot = DnnJsApiService.GetApiRoots().AppApiRoot.TrimLastSlash();\n\n        var relativePath = $\"{apiRoot}/app/{AppFolder}/{path}\";    \n\n        return relativePath;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Services/DnnLogService.cs",
    "content": "﻿using DotNetNuke.Services.Log.EventLog;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Dnn.Services;\n\ninternal class DnnSystemLogService : ISystemLogService,\n    ILogService // for compatibility\n{\n    public void Add(string title, string message)\n    {\n        var logInfo = new LogInfo\n        {\n            LogTypeKey = EventLogController.EventLogType.ADMIN_ALERT.ToString()\n        };\n        logInfo.AddProperty(title, message);\n        EventLogController.Instance.AddLog(logInfo);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Services/DnnMailService.cs",
    "content": "﻿using System.Configuration;\nusing System.Net;\nusing System.Net.Mail;\nusing DotNetNuke.Entities.Host;\nusing ToSic.Sxc.Services.Mail.Sys;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Dnn.Services;\n\ninternal class DnnMailService(LazySvc<IUser> userLazy) : MailServiceBase(userLazy)\n{\n    protected override SmtpClient SmtpClient()\n    {\n        var smtpServer = Host.SMTPServer;\n        if (string.IsNullOrEmpty(smtpServer)) \n            throw new ConfigurationErrorsException(DotNetNuke.Services.Localization.Localization.GetString(\"SMTPConfigurationProblem\"));\n\n        try\n        {\n            var client = new SmtpClient();\n\n            var strArray = smtpServer.Split(':');\n            client.Host = strArray[0];\n            client.Port = strArray.Length > 1 ? Convert.ToInt32(strArray[1]) : 25;\n            client.ServicePoint.MaxIdleTime = Host.SMTPMaxIdleTime;\n            client.ServicePoint.ConnectionLimit = Host.SMTPConnectionLimit;\n\n            var smtpAuthentication = Host.SMTPAuthentication;\n            var smtpUsername = Host.SMTPUsername;\n            var smtpPassword = Host.SMTPPassword;\n\n            switch (smtpAuthentication)\n            {\n                case \"1\":\n                    if (!string.IsNullOrEmpty(smtpUsername) && !string.IsNullOrEmpty(smtpPassword))\n                    {\n                        client.UseDefaultCredentials = false;\n                        client.Credentials = (ICredentialsByHost)new NetworkCredential(smtpUsername, smtpPassword);\n                        break;\n                    }\n                    break;\n                case \"2\":\n                    client.UseDefaultCredentials = true;\n                    break;\n            }\n\n            client.EnableSsl = Host.EnableSMTPSSL;\n\n            return client;\n        }\n        catch (Exception ex)\n        {\n            throw new ConfigurationErrorsException(DotNetNuke.Services.Localization.Localization.GetString(\"SMTPConfigurationProblem\"), ex);\n        }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Services/DnnPageChanges.cs",
    "content": "﻿using DotNetNuke.Web.Client.ClientResourceManagement;\nusing DotNetNuke.Web.Client.Providers;\nusing System.Web;\nusing System.Web.UI;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Dnn;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.ClientAssets;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing static ToSic.Sxc.Render.Sys.Output.ClientAssetConstants;\n\nnamespace ToSic.Sxc.Dnn.Services;\n\ninternal class DnnPageChanges(LazySvc<IFeaturesService> featuresService, Generator<CspOfPage> pageCspGenerator)\n    : ServiceBase($\"{DnnConstants.LogName}.PgeCng\", connect: [featuresService, pageCspGenerator])\n{\n    public int Apply(Page page, IRenderResult renderResult)\n    {\n        var l = Log.Fn<int>(\"Will apply PageChanges\");\n\n        if (renderResult == null)\n            return 0;\n\n        var dnnPage = new DnnHtmlPage();\n\n        AttachAssets(renderResult.Assets, page);\n        var count = Apply(dnnPage, renderResult.PageChanges);\n\n        var headChanges = ApplyToHead(dnnPage, renderResult.HeadChanges);\n\n        var resourceFeatures = ResourceFeatures(dnnPage, renderResult.FeaturesFromResources);\n\n        try\n        {\n            var httpHeaderChanges = ApplyHttpHeaders(page, renderResult);\n            count += httpHeaderChanges;\n        }\n        catch { /* ignore BETA feature */ }\n\n        l.A(\"Will apply Header Status-Code changes if needed\");\n        ApplyHttpStatus(page, renderResult);\n\n        count += headChanges + resourceFeatures;\n        return l.Return(count, $\"Applied {count} changes\");\n    }\n\n    private int Apply(DnnHtmlPage dnnPage, IList<PagePropertyChange> props)\n    {\n        var l = Log.Fn<int>($\"{props.Count} props\");\n        // 2022-05-03 2dm - don't think the props are ever null, requiring access to the shared data\n        // props = props ?? PageServiceShared.GetPropertyChangesAndFlush(Log);\n        foreach (var p in props)\n            switch (p.Property)\n            {\n                case PageProperties.Base:\n                    dnnPage.AddBase(p.Value);\n                    break;\n                case PageProperties.Title:\n                    dnnPage.Title = Helpers.UpdateProperty(dnnPage.Title, p);\n                    break;\n                case PageProperties.Description:\n                    dnnPage.Description = Helpers.UpdateProperty(dnnPage.Description, p);\n                    break;\n                case PageProperties.Keywords:\n                    dnnPage.Keywords = Helpers.UpdateProperty(dnnPage.Keywords, p);\n                    break;\n            }\n\n        var count = props.Count;\n\n        return l.Return(count, $\"{count}\");\n    }\n\n    private static int ResourceFeatures(DnnHtmlPage dnnPage, IList<PageFeatureFromSettings> feats)\n    {\n        // New in 12.04 - Add features which have HTML only\n        // In the page the code would be like this (v14):\n        // Kit.Page.Activate(\"fancybox4\");\n        // This will add a header for the sources of these features\n        foreach (var f in feats)\n            dnnPage.AddToHead(Tag.Custom(f.Html));\n        return feats.Count;\n    }\n\n    private int ApplyToHead(DnnHtmlPage dnnPage, IList<HeadChange> headChanges)\n    {\n        // Note: we're not implementing replace etc. in DNN\n        // ATM there's no reason to, maybe some other time\n        //var headChanges = PageServiceShared.GetHeadChangesAndFlush();\n        foreach (var h in headChanges)\n            dnnPage.AddToHead(h.Tag as TagBase);\n        return headChanges.Count;\n    }\n\n    private int ApplyHttpHeaders(Page page, IRenderResult result)\n    {\n        var l = Log.Fn<int>();\n        var httpHeaders = result.HttpHeaders;\n\n        // Register CSP changes for applying once all modules have been prepared\n        // Note that in cached scenarios, CspEnabled is true, but it may have been turned off since\n        if (result.CspEnabled && featuresService.Value.IsEnabled(SxcFeatures.ContentSecurityPolicy.NameId))\n            PageCsp(result.CspEnforced).Add(result.CspParameters ?? []);\n\n        if (page?.Response == null)\n            return l.Return(0, \"error, HttpResponse is null\");\n        if (page.Response.HeadersWritten)\n            return l.Return(0, \"error, to late for adding http headers\");\n        if (httpHeaders.SafeNone())\n            return l.Return(0, \"ok, no headers to add\");\n\n        foreach (var httpHeader in httpHeaders)\n        {\n            if (string.IsNullOrWhiteSpace(httpHeader.Name))\n                continue;\n            Log.A($\"add http header: {httpHeader.Name}:{httpHeader.Value}\");\n            // TODO: The CSP header can only exist once\n            // So to do this well, we'll need to merge them in future, \n            // Ideally combining the existing one with any additional ones added here\n            page.Response.Headers[httpHeader.Name] = httpHeader.Value;\n        }\n\n        return l.ReturnAsOk(httpHeaders.Count);\n    }\n\n    private CspOfPage PageCsp(bool enforced)\n    {\n        var key = \"2sxcPageLevelCsp\";\n\n        // If it's already registered, then the add-on-sending has already been added too\n        // So we shouldn't repeat it, just return the cache which will be used later\n        if (HttpContext.Current.Items.Contains(key))\n            return (CspOfPage)HttpContext.Current.Items[key];\n\n        // Not yet registered. Create, and register for on-end of request\n        var pageLevelCsp = pageCspGenerator.New();// new CspOfPage();\n        HttpContext.Current.Items[key] = pageLevelCsp;\n\n        // Register event to attach headers once the request is done and all Apps have registered their Csp\n        HttpContext.Current.Response.AddOnSendingHeaders(context =>\n        {\n            try\n            {\n                var headers = pageLevelCsp.CspHttpHeader();\n                if (headers != null)\n                    context.Response.Headers[pageLevelCsp.HeaderName(enforced)] = headers;\n            }\n            catch\n            {\n                /* ignore */\n            }\n        });\n        return pageLevelCsp;\n    }\n\n\n    private void ApplyHttpStatus(Page page, IRenderResult result)\n    {\n        try\n        {\n            if (page?.Response == null || result?.HttpStatusCode == null)\n                return;\n        }\n        catch (Exception ex)\n        {\n            // FIX: handles \"Response is not available in this context.\" in edge case for 404 page in DNN\n            // https://github.com/2sic/2sxc/issues/2986\n            Log.Ex(ex);\n            return;\n        }\n\n        var code = result.HttpStatusCode.Value;\n        Log.A($\"Custom status code '{code}'. Will set and also {nameof(page.Response.TrySkipIisCustomErrors)}\");\n        page.Response.StatusCode = code;\n        // Skip IIS & upstream redirects to a custom 404 so the Dnn page is preserved\n        page.Response.TrySkipIisCustomErrors = true;\n        if (result.HttpStatusMessage == null)\n            return;\n\n        Log.A($\"Custom status Description '{result.HttpStatusMessage}'.\");\n        page.Response.StatusDescription = result.HttpStatusMessage;\n    }\n\n    public void AttachAssets(IList<ClientAsset> ass, Page page)\n        => ass.ToList().ForEach(a =>\n        {\n            if (a.IsJs)\n                ClientResourceManager.RegisterScript(page, a.Url, a.Priority, DnnProviderName(a.PosInPage), a.HtmlAttributes);\n            else\n                ClientResourceManager.RegisterStyleSheet(page, a.Url, a.Priority, DnnProviderName(a.PosInPage));\n        });\n    \n    private static string DnnProviderName(string position)\n        => position.ToLowerInvariant() switch\n        {\n            AddToBody => DnnBodyProvider.DefaultName,\n            AddToHead => DnnPageHeaderProvider.DefaultName,\n            AddToBottom => DnnFormBottomProvider.DefaultName,\n            _ => \"\"\n        };\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Services/DnnRenderService.cs",
    "content": "﻿using System.Web;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Dnn.Web;\nusing ToSic.Sxc.Render.Sys;\nusing Page = System.Web.UI.Page;\n\nnamespace ToSic.Sxc.Dnn.Services;\n\ninternal class DnnRenderService : RenderService\n{\n    private readonly LazySvc<DnnPageChanges> _dnnPageChanges;\n    private readonly LazySvc<DnnClientResources> _dnnClientResources;\n    private readonly Generator<IContextOfBlock> _context;\n\n    public DnnRenderService(\n        Dependencies services,\n        LazySvc<DnnPageChanges> dnnPageChanges,\n        LazySvc<DnnClientResources> dnnClientResources,\n        Generator<IContextOfBlock> context\n    ) : base(services)\n    {\n        ConnectLogs([\n            _dnnPageChanges = dnnPageChanges,\n            _dnnClientResources = dnnClientResources,\n            _context = context\n        ]);\n    }\n\n    public override IRenderResult Module(int pageId, int moduleId,\n        NoParamOrder npo = default,\n        object data = null)\n    {\n        var l = Log.Fn<IRenderResult>($\"{nameof(pageId)}: {pageId}, {nameof(moduleId)}: {moduleId}\");\n        var result = base.Module(pageId, moduleId, npo, data);\n\n        // this code should be executed in PreRender of page (ensure when calling) or it is too late\n        if (HttpContext.Current?.Handler is Page dnnHandler) // detect if we are on the page\n            if (_context.New().Module.BlockIdentifier == null) // find if is in module (because in module it's already handled)\n                DnnPageProcess(dnnHandler, result);\n\n        return l.ReturnAsOk(result);\n    }\n\n    private void DnnPageProcess(Page dnnPage, IRenderResult result)\n    {\n        _dnnPageChanges.Value.Apply(dnnPage, result);\n        // #RemovedV20 #OldDnnAutoJQuery\n        _dnnClientResources.Value.Init(dnnPage, /*null,*/ null).AddEverything(result.Features);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Startup/DnnBootFeaturesRegistration.cs",
    "content": "﻿using ToSic.Sxc.Dnn.Features;\nusing ToSic.Sys.Boot;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Dnn.StartUp;\n\ninternal class DnnBootFeaturesRegistration(FeaturesCatalog featuresCatalog)\n    : BootProcessBase(\"DnnFts\", bootPhase: BootPhase.Registrations, connect: [featuresCatalog]), IBootProcess\n{\n    /// <summary>\n    /// Register Dnn features before loading\n    /// </summary>\n    public override void Run() => DnnBuiltInFeatures.Register(featuresCatalog);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Startup/StartUpDnnCore.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Eav.ImportExport.Integration;\nusing ToSic.Eav.ImportExport.Sys.XmlExport;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam.Sys.FileSystem;\nusing ToSic.Sxc.Apps.Sys.Installation;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Dnn.Adam;\nusing ToSic.Sxc.Dnn.Cms;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sxc.Dnn.Compile.Sys;\nusing ToSic.Sxc.Dnn.Context;\nusing ToSic.Sxc.Dnn.Features;\nusing ToSic.Sxc.Dnn.ImportExport;\nusing ToSic.Sxc.Dnn.Install;\nusing ToSic.Sxc.Dnn.LookUp;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Dnn.Search;\nusing ToSic.Sxc.Dnn.Services;\nusing ToSic.Sxc.Dnn.StartUp;\nusing ToSic.Sxc.Dnn.Web;\nusing ToSic.Sxc.Integration.Modules;\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Sys.Integration.Installation;\nusing ToSic.Sxc.Web.Sys.Http;\nusing ToSic.Sys.Boot;\nusing ToSic.Sys.Capabilities.Platform;\nusing ToSic.Sys.Security.Permissions;\nusing ToSic.Sys.Users;\nusing ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;\n\nnamespace ToSic.Sxc.Dnn.Startup;\n\ninternal static class StartUpDnnCore\n{\n    public static IServiceCollection AddDnnCore(this IServiceCollection services)\n    {\n        // Core Runtime Context Objects\n        services.TryAddScoped<IUser, DnnUser>();\n        services.TryAddScoped<DnnSecurity>();\n        // Make sure that ISite and IZoneCultureResolver use the same singleton!\n        services.TryAddScoped<ISite, DnnSite>();    // this must come first!\n        services.TryAddScoped<IZoneCultureResolver>(x => x.GetRequiredService<ISite>());\n\n        // Module cannot yet be scoped, until we have a per-module scope at some time\n        services.TryAddTransient<IModule, DnnModule>();\n        services.TryAddTransient<IPage, DnnPage>();\n        services.TryAddTransient<IValueConverter, DnnValueConverter>();\n\n        services.TryAddTransient<XmlExporter, DnnXmlExporter>();\n        services.TryAddTransient<IImportExportEnvironment, DnnImportExportEnvironment>();\n\n        services.TryAddTransient<IZoneMapper, DnnZoneMapper>();\n\n        services.TryAddTransient<IBlockResourceExtractor, DnnBlockResourceExtractor>();\n        services.TryAddTransient<IEnvironmentPermission, DnnEnvironmentPermission>();\n\n        services.TryAddTransient<IDnnContext, DnnContext>();\n        services.TryAddTransient<ILinkService, DnnLinkService>();\n        services.TryAddTransient<IPlatformModuleUpdater, DnnModuleUpdater>();\n        services.TryAddTransient<IEnvironmentInstaller, DnnEnvironmentInstaller>();\n        services.TryAddTransient<IPlatformAppInstaller, DnnPlatformAppInstaller>();\n        services.TryAddTransient<DnnEnvironmentInstaller>(); // Dnn Only\n        services.TryAddTransient<DnnInstallLogger>();\n\n\n        services.TryAddTransient<ExecutionContext, DnnExecutionContext>();\n        services.TryAddTransient<DnnExecutionContext>();\n        // New v14\n        services.TryAddTransient(typeof(ExecutionContext<,>), typeof(DnnExecutionContext<,>));\n\n        // ADAM\n        services.TryAddTransient<IAdamFileSystem, DnnAdamFileSystem>();\n\n        services.TryAddTransient<ILookUpEngineResolver, DnnLookUpEngineResolver>();\n        services.TryAddTransient<DnnLookUpEngineResolver>();\n        services.TryAddTransient<IPlatformInfo, DnnPlatformContext>();\n\n        // new in 11.07 - exception logger\n        services.TryAddTransient<IEnvironmentLogger, DnnEnvironmentLogger>();\n\n        // new in 11.08 - provide Razor Engine and platform\n        services.TryAddSingleton<IPlatform, DnnPlatformContext>();\n\n        // add page publishing\n        services.TryAddTransient<IPagePublishing, DnnPagePublishing>();\n\n        // v13 option to not use page publishing... #SwitchServicePagePublishingResolver #2749\n        services.AddTransient<IPagePublishingGetSettings, DnnPagePublishingGetSettings>();\n\n        // new in v12 - .net specific code compiler\n        services.TryAddTransient<CodeCompiler, CodeCompilerNetFull>();\n        services.TryAddTransient<IClassCompiler, CodeCompilerNetFull>();\n\n        // new in v12.02 - RazorBlade DI\n        services.TryAddScoped<DnnPageChanges>();\n        services.TryAddTransient<DnnClientResources>();\n        services.TryAddScoped<DnnJsApiHeader>(); // v16.01\n        services.TryAddScoped<IJsApiService, DnnJsApiService>(); // v16.01\n\n        // v12.04 - proper DI for SearchController\n        services.TryAddTransient<SearchController>();\n\n        // v12.05 custom Http for Dnn which only keeps the URL parameters really provided, and not the internally generated ones\n        services.TryAddTransient<IHttp, DnnHttp>();\n\n        // v12.05\n        services.TryAddTransient<ISystemLogService, DnnSystemLogService>();\n        services.TryAddTransient<IMailService, DnnMailService>();\n\n        // v13\n        services.TryAddTransient<IModuleAndBlockBuilder, DnnModuleAndBlockBuilder>();\n\n        // v13.12\n        services.AddTransient<IBootProcess, DnnBootFeaturesRegistration>();   // must be Add, not TryAdd\n\n        // v14\n        services.TryAddTransient<IDynamicCodeService, DnnDynamicCodeService>();\n        services.TryAddTransient<DnnDynamicCodeService.MyScopedServices>();   // new v15\n        services.TryAddTransient<IRenderService, DnnRenderService>();\n\n        // v15 - move ready check turbo into a service\n        services.TryAddTransient<DnnReadyCheckTurbo>();\n        //services.TryAddScoped<CodeRootFactory, DnnCodeRootFactory>();\n\n        // v17 - Assembly compilation and caching infrastructure\n        services.TryAddSingleton<IHostingEnvironmentWrapper, HostingEnvironmentWrapper>();\n        services.TryAddTransient<IReferencedAssembliesProvider, ReferencedAssembliesProvider>();\n        services.TryAddTransient<AppCodeCompiler, AppCodeCompilerNetFull>();\n        \n        //v17.01\n        services.TryAddTransient<DnnRequirements>();\n\n        // v20.03 - Shared assembly disk cache infrastructure (for both Razor and AppCode)\n        services.TryAddTransient<AssemblyDiskCache>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Web/DnnBlockResourceExtractor.cs",
    "content": "﻿using DotNetNuke.Web.Client;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Render.Sys.ResourceExtractor;\nusing ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Dnn.Web;\n\ninternal class DnnBlockResourceExtractor(IPageServiceShared pageServiceShared)\n    : BlockResourceExtractor(pageServiceShared)\n{\n    private const bool DebugDetails = true;\n\n    protected override ClientAssetsExtractSettings DefaultSettings => _settings.Get(() => new(\n        extractAll: false,\n        cssPriority: (int)FileOrder.Css.DefaultPriority,\n        jsPriority: (int)FileOrder.Js.DefaultPriority));\n    private readonly GetOnce<ClientAssetsExtractSettings> _settings = new();\n\n\n    protected override (string Template, bool Include2sxcJs) ExtractFromHtml(string html, ClientAssetsExtractSettings settings)\n    {\n        var l = Log.Fn<(string, bool)>();\n        var include2SxcJs = false;\n            \n        // Handle Client Dependency injection\n        html = ExtractExternalScripts(html, ref include2SxcJs, settings, logDetails: DebugDetails); // 2025-09-04 2dm having some difficulties, want to log details\n\n        // Handle Scripts\n        html = ExtractStyles(html, settings);\n\n        return l.ReturnAsOk((html, include2SxcJs));\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Web/DnnClientResources.cs",
    "content": "﻿using DotNetNuke.Framework.JavaScriptLibraries;\nusing DotNetNuke.Web.Client;\nusing DotNetNuke.Web.Client.ClientResourceManagement;\nusing DotNetNuke.Web.Client.Providers;\nusing System.Web.UI;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Dnn.Features;\nusing ToSic.Sxc.Render.Sys.RenderBlock;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Dnn.Web;\n\ninternal class DnnClientResources(DnnJsApiHeader dnnJsApiHeader, DnnRequirements dnnRequirements)\n    : ServiceBase($\"{DnnConstants.LogName}.JsCss\", connect: [dnnJsApiHeader, dnnRequirements])\n{\n    // #RemovedV20 #OldDnnAutoJQuery\n    public DnnClientResources Init(Page page, /*bool? forcePre1025Behavior,*/ IBlockBuilder blockBuilder)\n    {\n        //_forcePre1025Behavior = forcePre1025Behavior;\n        _page = page;\n        _blockBuilder = blockBuilder;\n        return this;\n    }\n    private IBlockBuilder _blockBuilder;\n    private Page _page;\n    //private bool? _forcePre1025Behavior;\n\n    internal IList<IPageFeature> Features => field ??= _blockBuilder?.Run(true, specs: new())?.Features ?? new List<IPageFeature>();\n\n    public IList<IPageFeature> AddEverything(IList<IPageFeature> features = null)\n    {\n        var l = Log.Fn<IList<IPageFeature>>();\n        // temporary solution, till the features are correctly activated in the block\n        // auto-detect BlockBuilder params\n        features ??= Features;\n\n        // normal scripts\n        var editJs = features.Contains(SxcPageFeatures.JsCmsInternal);\n        var readJs = features.Contains(SxcPageFeatures.JsCore);\n        var editCss = features.Contains(SxcPageFeatures.ToolbarsInternal);\n\n        if (!readJs && !editJs && !editCss && !features.Any())\n            return l.Return(features, \"nothing to add\");\n\n        l.A(\"user is editor, or template requested js/css, will add client material\");\n\n        // register scripts and css\n        RegisterClientDependencies(_page, readJs, editJs, editCss, features);\n\n        // New in 11.11.02 - DNN has a strange behavior where the current language isn't known till PreRender\n        // so we have to move adding the header to here.\n        // MustAddHeaders may have been set earlier by the engine, or now by the various js added\n        l.A($\"{nameof(MustAddHeaders)}={MustAddHeaders}\");\n        if (MustAddHeaders)\n            dnnJsApiHeader.AddHeaders();\n\n        return l.ReturnAsOk(features);\n    }\n\n\n    // #RemovedV20 #OldDnnAutoJQuery\n    ///// <summary>\n    ///// new in 10.25 - by default jQuery isn't loaded any more\n    ///// but older razor templates might still expect it\n    ///// and any other old behaviour, incl. no-view defined, etc. should activate compatibility\n    ///// </summary>\n    //public void EnforcePre1025Behavior()\n    //{\n    //    var l = Log.Fn(\"Activate Anti-Forgery for compatibility with old behavior\");\n    //    ServicesFramework.Instance.RequestAjaxAntiForgerySupport();\n    //    MustAddHeaders = true;\n    //    l.Done();\n    //}\n\n    // #RemovedV20 #OldDnnAutoJQuery\n    ///// <summary>\n    ///// new in 10.25 - by default now jQuery isn't loaded!\n    ///// but any old behaviour, incl. no-view defined, etc. should activate compatibility\n    ///// </summary>\n    ///// <returns></returns>\n    //public bool NeedsPre1025Behavior() => _forcePre1025Behavior\n    //                                      ?? (dnnRequirements.RequirementsMet() ? (_blockBuilder?.GetEngine() as IEngineDnnOldCompatibility)?.OldAutoLoadJQueryAndRvt : null)\n    //                                      ?? true;\n\n\n    public void RegisterClientDependencies(Page page, bool readJs, bool editJs, bool editCss, IList<IPageFeature> overrideFeatures = null)\n    {\n        var l = Log.Fn($\"-, {nameof(readJs)}:{readJs}, {nameof(editJs)}:{editJs}, {nameof(editCss)}:{editCss}\");\n        \n        var features = overrideFeatures ?? Features;\n\n        var root = DnnConstants.SysFolderRootVirtual;\n        root = page.ResolveUrl(root);\n        var ver = EavSystemInfo.VersionWithStartUpBuild;\n        const int priority = (int)FileOrder.Js.DefaultPriority - 2;\n\n        // add edit-mode CSS\n        if (editCss) RegisterCss(page, $\"{root}{SxcPageFeatures.ToolbarsInternal.UrlInDist}\");\n\n        // add read-js\n        if (readJs || editJs)\n        {\n            l.A(\"add $2sxc api and headers\");\n            RegisterJs(page, ver, $\"{root}{SxcPageFeatures.JsCore.UrlInDist}\", true, priority);\n            MustAddHeaders = true;\n        }\n\n        // add edit-js (commands, manage, etc.)\n        if (editJs)\n        {\n            l.A(\"add 2sxc edit api; also needs anti-forgery\");\n            // note: the inpage only works if it's not in the head, so we're adding it below\n            RegisterJs(page, ver, $\"{root}{SxcPageFeatures.JsCmsInternal.UrlInDist}\", false, priority + 1);\n        }\n\n        if (features.Contains(SxcPageFeatures.JQuery))\n            JavaScript.RequestRegistration(CommonJs.jQuery);\n\n        if (features.Contains(SxcPageFeatures.TurnOn))\n            RegisterJs(page, ver, $\"{root}{SxcPageFeatures.TurnOn.UrlInDist}\", true, priority + 10);\n\n        if (features.Contains(SxcPageFeatures.CmsWysiwyg))\n            RegisterCss(page, $\"{root}{SxcPageFeatures.CmsWysiwyg.UrlInDist}\");\n\n        l.Done();\n    }\n\n\n    #region DNN Bug with Current Culture\n\n    // We must add the _js header but we must wait beyond the initial page-load until Pre-Render\n    // Because for reasons unknown DNN (at least in V7.4+ but I think also in 9) doesn't have \n    // the right PortalAlias and language set until then. \n    // before that it assumes the PortalAlias is a the default alias, even if the url clearly shows another language\n\n    private bool MustAddHeaders { get; set; }\n\n    #endregion\n\n\n    #region add scripts / css with bypassing the official ClientResourceManager\n\n    private static void RegisterJs(Page page, string version, string path, bool toHead, int priority)\n    {\n        if (string.IsNullOrWhiteSpace(path))\n            return;\n\n        var url = UrlHelpers.QuickAddUrlParameter(path, \"v\", version);\n        if (toHead)\n            ClientResourceManager.RegisterScript(page, url, priority, DnnPageHeaderProvider.DefaultName);\n        else\n            page.ClientScript.RegisterClientScriptInclude(typeof(Page), path, url);\n    }\n\n    private static void RegisterCss(Page page, string path)\n        => ClientResourceManager.RegisterStyleSheet(page, path);\n\n    #endregion\n\n\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Web/DnnHttp.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Web.Sys.Http;\n\nnamespace ToSic.Sxc.Dnn.Web;\n\n/// <summary>\n/// Special class to provide HttpRequest parameters in DNN\n///\n/// It needs this, because DNN automatically creates invisible parameters like tabid=323 and language=en-US\n/// But if we want to create a link to the same page again, then this would result in wrong paths. \n/// </summary>\ninternal class DnnHttp: HttpHybrid\n{\n    public override NameValueCollection QueryStringParams\n    {\n        get\n        {\n            if (field != null)\n                return field;\n\n            // This would be the better way, but it doesn't work, because DNN will often create paths like\n            // /value/27 instead of ?value=27\n            //var separator = Request.RawUrl.IndexOf('?');\n            //if (separator == -1) return _queryStringValues = new NameValueCollection();\n            //var queryPart = Request.RawUrl.Substring(separator);\n            //var lightList = HttpUtility.ParseQueryString(queryPart);\n\n            var rewrapped = new NameValueCollection(base.QueryStringParams);\n            return field = FilterOutDnnParams(rewrapped);\n        }\n    }\n\n    private NameValueCollection FilterOutDnnParams(NameValueCollection original)\n    {\n        const string tabId = \"TabId\";\n        const string language = \"language\";\n        const string skinSrc = \"SkinSrc\"; // auto-added\n\n        // DNN adds these automatically, but does it with exactly this spelling, so that's the only one we'll catch\n        original.Remove(tabId);\n        original.Remove(language);\n        original.Remove(skinSrc);\n        return original;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Web/DnnJsApiHeader.cs",
    "content": "﻿using DotNetNuke.Common;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Render.Sys.JsContext;\n\nnamespace ToSic.Sxc.Dnn.Web;\n\ninternal class DnnJsApiHeader(IJsApiService dnnJsApiService, ILog parentLog = null) : HelperBase(parentLog, \"Dnn.JsApiH\")\n{\n    public bool AddHeaders()\n    {\n        var l = Log.Fn<bool>();\n        // ensure we only do this once\n        if (MarkAddedAndReturnIfAlreadyDone()) return l.ReturnFalse(\"already\");\n\n        var json = dnnJsApiService.GetJsApiJson(pageId: null, siteRoot: null, rvt: null, withPublicKey: false);\n        if (json == null) return l.ReturnFalse(\"no path\");\n\n#pragma warning disable CS0618\n        HtmlPage.AddMeta(JsApi.MetaName, json);\n#pragma warning restore CS0618\n        return l.ReturnTrue(\"added\");\n    }\n  \n    private const string KeyToMarkAdded = \"2sxcApiHeadersAdded\";\n\n    private static bool MarkAddedAndReturnIfAlreadyDone()\n    {\n        var alreadyAdded = HttpContextSource.Current.Items.Contains(KeyToMarkAdded);\n        HttpContextSource.Current.Items[KeyToMarkAdded] = true;\n        return alreadyAdded;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn/Web/DnnJsApiService.cs",
    "content": "﻿using System.Text.Json;\nusing DotNetNuke.Entities.Portals;\nusing DotNetNuke.Framework;\nusing System.Text.RegularExpressions;\nusing System.Web;\nusing System.Web.Helpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sys.Security.Encryption;\n\nnamespace ToSic.Sxc.Dnn.Web;\n\ninternal class DnnJsApiService(JsApiCacheService jsApiCache, RsaCryptographyService rsaCryptographyService)\n    : ServiceBase(\"DnnJsAPi\", connect: [jsApiCache, rsaCryptographyService]), IJsApiService\n{\n    public const string PortalIdParamName = \"portalId\";\n\n    public string GetJsApiJson(int? pageId = null, string siteRoot = null, string rvt = null, bool withPublicKey = false) \n        => JsonSerializer.Serialize(GetJsApi(pageId, siteRoot, rvt, withPublicKey: withPublicKey));\n\n    public JsApi GetJsApi(int? pageId, string siteRoot, string rvt, bool withPublicKey)\n    {\n        // pageId and siteRoot are normally null when called from razor, api, custom cs\n        // pageId and siteRoot are provided only in very special case for EditUI in /DesktopModules/.../...aspx\n\n        return jsApiCache.JsApiJson(\n            platform: PlatformType.Dnn.ToString(),\n            pageId: pageId ?? PortalSettings.Current.ActiveTab.TabID,\n            siteRoot: SiteRootFn,\n            apiRoot: () => GetApiRoots(SiteRootFn()).SiteApiRoot,\n            appApiRoot: () => GetApiRoots(SiteRootFn()).AppApiRoot,\n            uiRoot: () => VirtualPathUtility.ToAbsolute(DnnConstants.SysFolderRootVirtual),\n            rvtHeader: DnnConstants.AntiForgeryTokenHeaderName,\n            rvt: AntiForgeryToken,\n            withPublicKey: withPublicKey,\n            secureEndpointPublicKey: () => rsaCryptographyService.PublicKey,\n            dialogQuery: $\"{PortalIdParamName}={PortalSettings.Current.PortalId}\"\n        );\n\n        string SiteRootFn() => siteRoot ?? ServicesFramework.GetServiceFrameworkRoot();\n    }\n\n    internal static (string SiteApiRoot, string AppApiRoot) GetApiRoots(string siteRoot = null)\n    {\n        siteRoot = siteRoot ?? ServicesFramework.GetServiceFrameworkRoot();\n        var apiRoot = siteRoot + $\"api/{JsApi.ExtensionPlaceholder}/\";\n            \n        // appApiRoot is the same as apiRoot - the UI will add \"app\" to it later on \n        // but app-api root shouldn't contain generic modules-name, as it's always 2sxc\n        var appApiRoot = apiRoot;\n        appApiRoot = appApiRoot.Replace(JsApi.ExtensionPlaceholder, \"2sxc\");\n\n        return (apiRoot, appApiRoot);\n    }\n\n    private static string AntiForgeryToken()\n    {\n        var tag = AntiForgery.GetHtml().ToString();\n        return GetAttribute(tag, \"value\");\n    }\n\n    private static string GetAttribute(string tag, string attribute)\n    {\n        return new Regex(@\"(?<=\\b\" + attribute + @\"=\"\")[^\"\"]*\")\n            .Match(tag).Value;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn940/RegisterWebApiActivator.cs",
    "content": "﻿using DotNetNuke.Web.Api;\nusing System.Web.Http;\nusing System.Web.Http.Dispatcher;\n\n// This is a special workaround for DNN 9.4\n// Review the readme.md to understand how and why\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Dnn940;\n\n// ReSharper disable once UnusedMember.Global\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class RegisterWebApiActivator : IServiceRouteMapper\n{\n    /// <summary>\n    /// Put our class activator in front of the standard DNN activator\n    /// </summary>\n    /// <param name=\"mapRouteManager\"></param>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public void RegisterRoutes(IMapRoute mapRouteManager)\n    {\n        var config = System.Web.Http.GlobalConfiguration.Configuration;\n\n        // only override the existing one, if a special one was registered\n        if (config.Services.GetService(typeof(IHttpControllerActivator)) is IHttpControllerActivator dnnActivator)\n            GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator),\n                new WebApiHttpControllerActivator {PreviousActivator = dnnActivator});\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn940/WebApiHttpControllerActivator.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing System.Net.Http;\nusing System.Web.Http.Controllers;\nusing System.Web.Http.Dispatcher;\nusing ToSic.Sxc.Dnn;\nusing ToSic.Sxc.WebApi;\n\n// This is a special workaround for DNN 9.4\n// Review the readme.md to understand how and why\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Dnn940;\n\ninternal class WebApiHttpControllerActivator : IHttpControllerActivator\n{\n    public IHttpControllerActivator PreviousActivator { get; set; }\n\n    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\n    {\n        // first try to just get it from the DI - if it's there\n        // note that the PreviousActivator doesn't exist\n        // but skip for dynamically compiled controller type from a .cs file with IDynamicWebApi interface\n        // because this Activator can't create instance of controllerType with DI parameters in constructor\n        if (!typeof(IDynamicWebApi).IsAssignableFrom(controllerType))\n        {\n            var resultFromDnnActivator = PreviousActivator?.Create(request, controllerDescriptor, controllerType);\n            if (resultFromDnnActivator != null) return resultFromDnnActivator;\n        }\n\n        // If it's not found (null), then it's probably a dynamically compiled type from a .cs file or similar\n        // Such types are never registered in the DI catalog, as they may change on-the-fly.\n        // In this case we must use ActivatorUtilities, which will create the object and if it expects \n        // any DI parameters, they will come from the DependencyInjection as should be best practice\n        //var dnnGlobalDi = DnnStaticDi.GetGlobalServiceProvider(); // 2022-08-11 2dm cleaned up, shouldn't use duplicate code to get dnn internal object\n        var dnnGlobalDi = DnnStaticDi.GetGlobalScopedServiceProvider(); // 2023-06-15 2dm - trying this instead, so we always have a scope and nothing bleeds out\n        var resultFromUtilities = (IHttpController)ActivatorUtilities.CreateInstance(dnnGlobalDi, controllerType);\n        return resultFromUtilities;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Dnn940/readme.md",
    "content": "﻿# Workaround for DNN 9.4 Breaking Changes\n\nThis is a special workaround for DNN 9.4 breaking changes. \n\n## How it works\n\nOur code does the following\n1. the setup-code runs automatically in `RegisterWebApiActivator.cs` - this happens, because our method `RegisterRoutes` is called automatically \n\t1. it checks if we're running DNN 9.4+ \n\t1. if this is the case, it injects our activator `WebApiHttpControllerActivator.cs` and give it the previous activator\n1. our activater will\n\t1. try to activate using the DNN mechanisms - because it has the previous activator\n\t1. if that fails (returns null) it will use .net core dependency injection to activate dynamically compiled classes\n\nSidenote: since 2sxc is compiled for DNN 7.4.2+ it doesn't know some of the newer DNN 9 properties. So in this case it uses reflection to finish it's work.\n\n## Why we did this\n\nDNN 9.4 added .net core dependency injection - which is great - but they forgot an important use case: dynamically compiled WebApi endpoints. \n\n2sxc uses these in all custom Apps which have their own WebApis. The system is simple, as 2sxc compiles these on the fly and publishes them on HTTP. \n\nThis works great, and to fix it it would have only needed a simple extra line in DNN. \nFor currently unknown reasons, the DNN core team felt that this breaks dependency injection (to which we strongly disagree). \nBecause of this, we decided to extend DNN to again support dynamically compiled endpoints. \n\n## See also\n\n1. 2sxc github issue on this: https://github.com/2sic/2sxc/issues/1830\n1. Discussion on DNN Platform: https://github.com/dnnsoftware/Dnn.Platform/issues/3045"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Linq;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Performance;\nglobal using ToSic.Sys.Utils;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/Properties/InternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Razor\")]\n\n// Unit tests\n[assembly: InternalsVisibleTo(\"ToSic.Dnn.Tests\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.SystemTests\")]\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/ToSic.Sxc.Dnn.Core.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-NetFramework.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <AssemblyName>ToSic.Sxc.Dnn.Core</AssemblyName>\n    <TargetFrameworkProfile />\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);MSB3277</NoWarn>\n    <!-- ignore warning that Dnn was loaded 2x - ATM necessary for MS build? @STV -->\n    <NoWarn>$(NoWarn);MSB4011</NoWarn>\n    <!-- ignore warning that it's using a dangerous version of Dnn (v9.6.1) @2dm -->\n    <NoWarn>$(NoWarn);NU1902</NoWarn>\n    <!--<LangVersion>preview</LangVersion>-->\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Dnn.ClientDependency\" Version=\"1.9.10\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.Abstractions\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.Core\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.Web\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.Web.Client\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.CodeDom.Providers.DotNetCompilerPlatform\" Version=\"3.6.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions\" Version=\"2.1.1\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.AspNet.WebApi.Core\" Version=\"5.2.9\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.AspNet.WebApi.WebHost\" Version=\"5.2.9\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"System.Collections.Immutable\" Version=\"9.0.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.ComponentModel.Composition\" />\n    <Reference Include=\"System.configuration\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Numerics\" />\n    <Reference Include=\"System.Runtime.Caching\" />\n    <Reference Include=\"System.Web\" />\n    <Reference Include=\"System.Web.ApplicationServices\" />\n    <Reference Include=\"System.Web.WebPages\">\n      <HintPath>..\\..\\..\\Dependencies\\System.Web\\System.Web.WebPages.dll</HintPath>\n      <Private>False</Private>\n      <SpecificVersion>False</SpecificVersion>\n    </Reference>\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"ToSic.Razor.Dnn\">\n      <HintPath>..\\ToSic.Sxc.Dnn\\razorblade\\bin\\ToSic.Razor.Dnn.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.DataSources\\ToSic.Eav.DataSources.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Engines\\ToSic.Sxc.Engines.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Images\\ToSic.Sxc.Images.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Web\\ToSic.Sxc.Web.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/ToSic.Sxc.Dnn.Core.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cdependencyinjection/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cextensions/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/ToSic.Sxc.Dnn.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cimplementations/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cinterfaces/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Crun/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Crun2/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cweb/@EntryIndexedValue\">False</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Core/ToSic.Sxc.Services/DnnExtensions.cs",
    "content": "﻿using System.Web;\nusing DotNetNuke.Common.Extensions;\nusing ToSic.Sxc.Dnn;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Provides extension methods for DNN Skins (Themes) and Modules.\n/// It only exists on the Dnn platform, not on Oqtane.\n/// </summary>\n/// <remarks>\n/// Created v14\n/// </remarks>\n[PublicApi]\npublic static class DnnExtensions\n{\n    /// <summary>\n    /// Helper extension method to get a scoped service on a skin/theme or module.\n    ///\n    /// To call it you must prefix it with `this.` like `this.GetScopedService...`\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"skinOrModule\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// This requires an `HttpContext.Current` to exist, so it will not work within a search controller.\n    ///\n    /// History\n    /// - Created in v14\n    /// </remarks>\n    public static T GetScopedService<T>(this System.Web.UI.UserControl skinOrModule) => GetScopedService<T>();\n\n    /// <summary>\n    /// Get a service from the current HTTP Scope.\n    /// This is the standalone method.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <returns>\n    /// A service of type `T` - if it can be found. Otherwise it will throw an error.\n    /// </returns>\n    /// <remarks>\n    /// This requires an `HttpContext.Current` to exist, so it will not work within a search controller.\n    ///\n    /// History\n    /// - Created in v14\n    /// - In v15.03 added special patch so it work on 404 pages where the service provider is broken/not available\n    /// </remarks>\n    public static T GetScopedService<T>()\n    {\n        var serviceScope = HttpContext.Current.GetScope();\n        // Check if the service scope is broken (typical on 404 pages) and do workaround\n        // Should be removed once the minimum DNN is upgraded to a version where it is fixed\n        // As of 2022-02-20 DNN 9.11.0 it's still broken\n        return serviceScope == null\n#pragma warning disable CS0618\n            ? DnnStaticDi.StaticBuild<T>() // handles edge case for 404 page in DNN where scope is missing, fix https://github.com/2sic/2sxc/issues/2986\n#pragma warning restore CS0618\n            : serviceScope.ServiceProvider.Build<T>();\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Compatibility/DesignTimeCompat/MetadataUpdateAttributes.Compat.cs",
    "content": "#if NETFRAMEWORK\n\n\n// ReSharper disable once CheckNamespace\nnamespace System.Runtime.CompilerServices\n{\n    /// <summary>\n    /// Symbol-only compatibility attribute for newer Razor design-time / hot-reload metadata emitted by tooling.\n    /// </summary>\n    /// <remarks>\n    /// This does not enable Hot Reload on DNN / .NET Framework.\n    /// It only allows generated design-time code to resolve the expected symbol while editing <c>.cshtml</c> files.\n    /// The type is public because the design-time helper project that compiles the generated Razor code is a different assembly.\n    /// Keep this shim .NET Framework-only to avoid colliding with the real BCL type on modern runtimes.\n    /// </remarks>\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]\n    public sealed class CreateNewOnMetadataUpdateAttribute : Attribute\n    {\n    }\n}\n\n\n// ReSharper disable once CheckNamespace\nnamespace System.Reflection.Metadata\n{\n    /// <summary>\n    /// Symbol-only compatibility attribute for metadata update handlers referenced by newer tooling.\n    /// </summary>\n    /// <remarks>\n    /// This shim carries only the type shape required for design-time compilation.\n    /// It does not provide active runtime Hot Reload behavior in DNN / .NET Framework.\n    /// The type is public because generated design-time Razor code is compiled outside this assembly.\n    /// Keep this shim .NET Framework-only to avoid colliding with the real BCL type on modern runtimes.\n    /// </remarks>\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]\n    public sealed class MetadataUpdateHandlerAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes the compatibility attribute with the handler type expected by generated design-time code.\n        /// </summary>\n        public MetadataUpdateHandlerAttribute(Type handlerType)\n        {\n            HandlerType = handlerType;\n        }\n\n        /// <summary>\n        /// Gets the handler type referenced by generated design-time metadata update wiring.\n        /// </summary>\n        public Type HandlerType { get; }\n    }\n}\n\n\n#endif\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Compatibility/DesignTimeCompat/RazorComponentBase.DesignTimeCompat.cs",
    "content": "#if NETFRAMEWORK\n\n\nusing System.Runtime.CompilerServices;\n\n// ReSharper disable once CheckNamespace\n// ReSharper disable UnusedMember.Global\nnamespace ToSic.Sxc.Web;\n\n/// <summary>\n/// Design-time compatibility shim for newer editor-generated Razor classes on .NET Framework.\n/// </summary>\n/// <remarks>\n/// DNN runtime rendering still uses legacy <c>System.Web.Razor</c> code generation, which emits classic\n/// <c>Execute</c>/<c>Write</c>/<c>WriteLiteral</c> calls through <c>WebPageExecutingBase</c>.\n/// The members below only exist so VS Code / Roslyn design-time generated classes can bind against\n/// <see cref=\"RazorComponentBase\"/> during analysis of <c>.cshtml</c> files.\n/// They must not become part of the production execution path.\n/// If any of them is invoked at runtime, it means the runtime Razor compiler/code generator has drifted into\n/// an unsupported shape or a non-generated subclass relied on this shim instead of providing real behavior.\n/// In that case a fail-fast exception is safer than silently rendering wrong HTML.\n/// </remarks>\npublic abstract partial class RazorComponentBase\n{\n    /// <summary>\n    /// Newer design-time generated Razor classes may override <c>ExecuteAsync</c>.\n    /// The real DNN runtime path should continue to use legacy <c>Execute</c>-based code generation.\n    /// </summary>\n    public virtual Task ExecuteAsync()\n        => throw CreateUnexpectedRuntimeInvocation();\n\n    /// <summary>\n    /// Bridges classic Razor's abstract <c>Execute</c> contract to the design-time <c>ExecuteAsync</c> pattern.\n    /// If this base implementation is ever reached in production, fail fast with a clear message.\n    ///\n    /// Note that the asp.net Framework implementation only has an abstract `Execute` method,\n    /// which is only added at the last layer during real compile.\n    /// The design-time environment complains about this, so we need to provide a concrete implementation here, even though it should never be called at runtime.\n    /// </summary>\n    public override void Execute()\n        => throw CreateUnexpectedRuntimeInvocation();\n\n    /// <summary>\n    /// Placeholder symbol for newer design-time generated attribute writer calls.\n    /// Legacy DNN runtime code generation should keep using <c>WriteAttribute</c> instead.\n    /// </summary>\n    protected virtual void BeginWriteAttribute(string name, string prefix, int prefixOffset, string suffix, int suffixOffset, int attributeValuesCount)\n        => throw CreateUnexpectedRuntimeInvocation();\n\n    /// <summary>\n    /// Placeholder symbol for newer design-time generated attribute writer calls.\n    /// Legacy DNN runtime code generation should keep using <c>WriteAttribute</c> instead.\n    /// </summary>\n    protected virtual void WriteAttributeValue(string prefix, int prefixOffset, object value, int valueOffset, int valueLength, bool isLiteral)\n        => throw CreateUnexpectedRuntimeInvocation();\n\n    /// <summary>\n    /// Placeholder symbol for newer design-time generated attribute writer calls.\n    /// Legacy DNN runtime code generation should keep using <c>WriteAttribute</c> instead.\n    /// </summary>\n    protected virtual void EndWriteAttribute()\n        => throw CreateUnexpectedRuntimeInvocation();\n\n    private InvalidOperationException CreateUnexpectedRuntimeInvocation([CallerMemberName] string memberName = default)\n        => new(\n            $\"The design-time compatibility member '{GetType().Name}.{memberName}' was invoked at runtime. \" +\n            \"This shim exists only to satisfy newer editor-generated Razor code for VS Code IntelliSense on .NET Framework. \" +\n            \"The DNN runtime should continue using legacy System.Web.Razor code generation (Execute/Write/WriteLiteral and WriteAttribute). \" +\n            \"If this exception occurs, the runtime Razor compiler/code generator has started emitting unsupported design-time members \" +\n            \"or a non-generated subclass relied on the compat shim instead of implementing real runtime behavior.\");\n}\n#endif\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Compatibility/Dnn8Bugs.cs",
    "content": "﻿/*\n    This is a special file to handle DNN 8 bugs\n\n    Background: DNN 8.0.0 delivers a special web.config in the /Portals/ folder, which\n    expects the namespace Dnn.Modules.DynamicContentViewer.Helpers\n\n    But this namespace doesn't exist in that version of DNN - it's a leftover of previous\n    experiments trying to create a DCC (Dynamic Content Creator)\n\n    So the razor engine complains. Because of this, I'm adding stuff to these namespaces,\n    just to make sure the namespace actually exists\n\n*/\n\n// ReSharper disable once CheckNamespace\nnamespace Dnn.Modules.DynamicContentViewer.Helpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\nclass Dnn8Bugs;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Compatibility/RazorPermissions/RazorPermissions.cs",
    "content": "﻿namespace ToSic.Sxc.Compatibility.RazorPermissions;\n\n/// <summary>\n/// This is a compatibility leftover from old code - new code uses Edit.Enabled\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class RazorPermissions\n{\n    internal RazorPermissions(bool editAllowed) => UserMayEditContent = editAllowed;\n\n    /// <summary>\n    /// This property is used publicly, so it must exist\n    /// </summary>\n    // ReSharper disable once UnusedMember.Global\n    public bool UserMayEditContent { get; }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Compatibility/ToSic.Eav.Run.IContainer.Obsolete.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Eav.Run;\n\n/// <summary>\n/// This interface is used in the Dnn RazorComponent of v10, so we must still support it.\n/// The only use case is in an overridable CustomizeSearch, so it is never really called,\n/// but just defined by a razor page.\n/// </summary>\n[PrivateApi(\"Obsolete\")]\n[Obsolete(\"this was replaced by IModule\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IContainer;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Compatibility/ToSic.SexyContent/SexyContentWebPage.cs",
    "content": "﻿using Custom.Hybrid;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeApiService;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Compatibility.RazorPermissions;\nusing ToSic.Sxc.Compatibility.Sxc;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing ToSic.Sxc.Dnn;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.Help;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\n\n// ReSharper disable InheritdocInvalidUsage\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.SexyContent.Razor;\n\n/// <summary>\n/// The core page type for delivering a 2sxc page\n/// Provides context infos like the Dnn object, helpers like Edit and much more. \n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class SexyContentWebPage : \n    RazorComponentBase,\n    ICreateInstance,\n    IHasDnn,\n    IDynamicCode,\n    IHasCodeHelp\n{\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    #region Core Properties which should appear in docs\n\n    /// <inheritdoc />\n    public override ICodeLog Log => RzrHlp.CodeLog;\n\n    /// <inheritdoc />\n    public override IHtmlHelper Html => RzrHlp.Html;\n\n    #endregion\n\n    #region Helpers linked through AppAndData Helpers\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    [PrivateApi]\n    public dynamic DynamicModel => throw new NotSupportedException($\"{nameof(DynamicModel)} not implemented on {nameof(SexyContentWebPage)}. {RazorComponent.NotImplementedUseCustomBase}\");\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi.Edit;\n\n    public IDnnContext Dnn => (ExCtx as IHasDnn)?.Dnn;\n\n#pragma warning disable 612\n    /// <inheritdoc />\n    [PrivateApi(\"never public, shouldn't be in use elsewhere\")]\n    [Obsolete]\n    [field: Obsolete]\n    public SxcHelper Sxc => field\n        ??= new(CodeApi.Block?.Context.Permissions.IsContentAdmin ?? false, GetService<IConvertToEavLight>());\n#pragma warning restore 612\n\n    /// <summary>\n    /// Old API - probably never used, but we shouldn't remove it as we could break some existing code out there\n    /// </summary>\n    [PrivateApi] public IBlock Block => CodeApi.Block;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    [PrivateApi] public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel9Old;\n\n    /// <inheritdoc />\n    public new IApp App => CodeApi.App;\n\n    #region Data - with old interface #DataInAddWontWork\n\n    /// <inheritdoc />\n    public IDataSource Data => /*(IBlockDataSource)*/CodeApi.Data;\n\n    //// This is explicitly implemented so the interfaces don't complain\n    //// but actually we're not showing this - in reality we're showing the Old (see above)\n    //IBlockDataSource IAppAndDataHelpers.Data => (IBlockDataSource)_CodeApiSvc.Data;\n        \n    #endregion\n\n    //// Explicit implementation of expected interface, but it should not work in the normal code\n    //// as the old code sometimes expects Data.Cache.GetContentType\n    ///// <inheritdoc />\n    //IDataSource IDynamicCode.Data => CodeApi.Data;\n\n    public RazorPermissions Permissions => new(CodeApi.Block?.Context.Permissions.IsContentAdmin ?? false);\n\n    #region AsDynamic in many variations\n\n    /// <inheritdoc />\n    [Obsolete]\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n\n    /// <inheritdoc />\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc />\n    [PublicApi(\"Careful - still Experimental in 12.02\")]\n    public dynamic AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    // todo: only in \"old\" controller, not in new one\n    /// <inheritdoc />\n    [Obsolete]\n    public dynamic AsDynamic(KeyValuePair<int, IEntity> entityKeyValuePair) => CodeApi.Cdf.CodeAsDyn(entityKeyValuePair.Value);\n\n\n\n    /// <inheritdoc />\n    [Obsolete]\n    public IEnumerable<dynamic> AsDynamic(IDataStream stream) => CodeApi.Cdf.CodeAsDynList(stream.List);\n\n    /// <inheritdoc />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n\n    /// <inheritdoc />\n    [Obsolete]\n    public IEnumerable<dynamic> AsDynamic(IEnumerable<IEntity> entities) => CodeApi.Cdf.CodeAsDynList(entities);\n\n    #endregion\n\n    #region Future features: AsList / Settings / Resources\n\n    [PrivateApi]\n    public IEnumerable<dynamic> AsList(object list)\n        => throw new(\"AsList is a newer feature in 2sxc. To use it, change your template type to \" + nameof(Razor12) + \" see https://go.2sxc.org/RazorComponent\");\n\n    [PrivateApi]\n    public dynamic Resources\n        => throw new(\"Resources is a newer feature in 2sxc. To use it, change your template type to \" + nameof(Razor12) + \" see https://go.2sxc.org/RazorComponent\");\n\n    [PrivateApi]\n    public dynamic Settings\n        => throw new(\"Settings is a newer feature in 2sxc. To use it, change your template type to \" + nameof(Razor12) + \" see https://go.2sxc.org/RazorComponent\");\n\n    #endregion\n\n    #region Not supported, not captured new features (like Convert-Service) - because they would break old code\n    //[PrivateApi] \n    //public IConvertService Convert => throw new NotSupportedException($\"{nameof(Convert)} not implemented on {nameof(SexyContentWebPage)}. {RazorComponent.NotImplementedUseCustomBase}\");\n    #endregion\n\n\n    #region Compatibility with Eav.Interfaces.IEntity - introduced in 10.10 - Removed in v20\n    //[PrivateApi]\n    //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(Eav.Interfaces.IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity as IEntity);\n\n\n    //[PrivateApi]\n    //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(KeyValuePair<int, Eav.Interfaces.IEntity> entityKeyValuePair) => CodeApi.Cdf.CodeAsDyn(entityKeyValuePair.Value as IEntity);\n\n    //[PrivateApi]\n    //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public IEnumerable<dynamic> AsDynamic(IEnumerable<Eav.Interfaces.IEntity> entities) => CodeApi.Cdf.CodeAsDynList(entities.Cast<IEntity>());\n    #endregion\n\n\n    #region Data Source Stuff\n    /// <inheritdoc />\n    [Obsolete]\n    public IDataSource CreateSource(string typeName = \"\", IDataSource inSource = null, ILookUpEngine configurationProvider = null)\n        => new CodeApiServiceObsolete(ExCtx).CreateSource(typeName, inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    [Obsolete(\"this is the old implementation with ILookUp Engine, don't think it was ever used publicly because people couldn't create these engines\")]\n    public T CreateSource<T>(IDataSource inSource = default, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    #endregion\n\n\n    #region Content, Header, etc. and List\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic Content => CodeApi.Content;\n\n    [Obsolete(\"use Content.Presentation instead\")]\n    [PrivateApi]\n    public dynamic Presentation => CodeApi.Content?.Presentation;\n\n    /// <summary>\n    /// We are blocking this property on purpose, so that people will want to migrate to the new RazorComponent\n    /// </summary>\n    [PrivateApi]\n    public dynamic Header => throw new(\"The header property is a new feature in 2sxc 10.20. \" +\n                                       \"To use it, change your template type to inherit from \" +\n                                       nameof(RazorComponent) + \" see https://go.2sxc.org/RazorComponent\");\n\n#pragma warning disable 618\n    [Obsolete(\"Use Header instead\")]\n    public dynamic ListContent => CodeApi.Header;\n\n    [Obsolete(\"Use Header.Presentation instead\")]\n    public dynamic ListPresentation => CodeApi.Header?.Presentation;\n\n    // #RemovedV20 #Element\n    //[Obsolete(\"This is an old way used to loop things - shouldn't be used any more - will be removed in a future version\")]\n    //[field: Obsolete(\"don't use any more\")]\n    //public List<Element> List => field ??= new CodeApiServiceObsolete(ExCtx).ElementList;\n#pragma warning restore 618\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(string json, string fallback = WrapperConstants.EmptyJson)\n        => throw new(\"The AsDynamic(string) is a new feature in 2sxc 10.20. To use it, change your template type to inherit from \" \n                     + nameof(RazorComponent) + \" see https://go.2sxc.org/RazorComponent\");\n\n    #endregion\n\n    #endregion\n\n    #region Adam \n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    #endregion\n\n    #region CmsContext\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    #endregion\n\n    #region CreateInstance\n\n    [PrivateApi] string IGetCodePath.CreateInstancePath { get; set; }\n\n    /// <inheritdoc />\n    public virtual dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => RzrHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    #endregion\n\n    // Added this in v20 to show uses of GetBestValue; but much of it may not be applicable, in which case we should create a separate list for SexyContentWebPage and Dnn.RazorComponent\n    [PrivateApi] List<CodeHelp> IHasCodeHelp.ErrorHelpers => HelpDbRazor.CompileRazorOrCode12;\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Compatibility/ToSic.SexyContent/SexyContentWebPageOfT.cs",
    "content": "﻿// ReSharper disable once CheckNamespace\nnamespace ToSic.SexyContent.Razor;\n\n/// <summary>\n/// this is just a generic variation of SexyContentWebPage\n/// We need it for the Razor Engine - which in V5+ explicitly expects a generic type\n/// We have no need for the internal type, so there is no code except for the inheritance\n/// </summary>\n/// <typeparam name=\"T\"></typeparam>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class SexyContentWebPage<T>:SexyContentWebPage;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Dnn/Razor12.cs",
    "content": "﻿using Custom.Razor.Sys;\nusing ToSic.Sxc.Dnn;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.Run;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Dnn;\n\n/// <summary>\n/// The base class for Razor-Components in 2sxc 12+ <br/>\n/// Provides context infos like the Dnn object, helpers like Edit and much more. <br/>\n/// </summary>\n[PublicApi]\npublic abstract class Razor12 : Hybrid.Razor12, IHasDnn, IRazor12, IDnnRazorCompatibility\n{\n    /// <inheritdoc />\n    public IDnnContext Dnn => (ExCtx as IHasDnn)?.Dnn;\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/Razor12.cs",
    "content": "﻿using Custom.Razor.Sys;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Dnn.Razor;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.Help;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// The base class for Hybrid Razor-Components in 2sxc 12 <br/>\n/// Provides context objects like CmsContext, helpers like Edit and much more. <br/>\n/// </summary>\n[PublicApi]\npublic abstract partial class Razor12 : RazorComponentBase, IRazor12, IHasCodeHelp, ICreateInstance\n{\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc cref=\"DnnRazorHelper.RenderPageNotSupported\"/>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public override HelperResult RenderPage(string path, params object[] data) \n        => RzrHlp.RenderPageNotSupported();\n\n    #region Core Properties which should appear in docs\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public override ICodeLog Log => RzrHlp.CodeLog;\n\n    /// <inheritdoc />\n    public override IHtmlHelper Html => RzrHlp.Html;\n\n    #endregion\n\n\n    #region Link, Edit, Dnn, App, Data\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi.Edit;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    [PrivateApi] public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n    /// <inheritdoc />\n    public new IApp App => CodeApi.App;\n\n    /// <inheritdoc />\n    public IDataSource Data => CodeApi.Data;\n\n    #endregion\n\n    #region AsDynamic in many variations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(string json, string fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    [PublicApi(\"Careful - still Experimental in 12.02\")]\n    public dynamic AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    #endregion\n\n    #region AsEntity\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region Convert-Service\n\n    /// <inheritdoc />\n    public IConvertService Convert => field ??= CodeApi.Convert;\n\n    #endregion\n\n\n    #region Data Source Stuff\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    #endregion\n\n    #region Content, Header, etc. and List\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic Content => CodeApi.Content;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic Header => CodeApi.Header;\n\n    #endregion\n\n\n\n\n\n    #region Adam \n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    #endregion\n\n    #region v11 properties CmsContext\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n    #endregion\n\n    #region v12 properties Resources, Settings, Path\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    public dynamic Settings => CodeApi.Settings;\n\n    [PrivateApi(\"Not yet ready\")]\n    public IDevTools DevTools => CodeApi.DevTools;\n\n    ///// <inheritdoc />\n    //public string Path => VirtualPath;\n\n    [PrivateApi] List<CodeHelp> IHasCodeHelp.ErrorHelpers => HelpDbRazor.CompileRazorOrCode12;\n\n    #endregion\n\n    #region CreateInstance\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstancePath\"/>\n    [PrivateApi] string IGetCodePath.CreateInstancePath { get; set; }\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\"/>\n    public virtual dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => RzrHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/Razor12_DynamicModel.cs",
    "content": "﻿using ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Render.Sys.Specs;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\npartial class Razor12: ISetDynamicModel\n{\n    /// <inheritdoc cref=\"Custom.Razor.Sys.IRazor14{TModel,TServiceKit}.DynamicModel\"/>\n    [PublicApi]\n    public dynamic DynamicModel => RzrHlp.DynamicModel;\n\n    [PrivateApi]\n    void ISetDynamicModel.SetDynamicModel(RenderSpecs viewData) => RzrHlp.SetDynamicModel(viewData);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/Razor12_Obsolete.cs",
    "content": "﻿using static ToSic.Sxc.Code.Sys.CodeErrorHelp.RazorExceptions;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid; \n\n// Important Note\n// The new hybrid implementation doesn't actually need this\n// But if we add these overloads in an inherited class, they will be preferred to the real working ones\n// which would result in errors on AsDynamic(some-object) even though it should just work\npartial class Razor12\n{\n    // Obsolete stuff - not supported any more in RazorPage10 - maybe re-activate to show helpful error messages\n\n    #region Shared Code Block between RazorComponent_Obsolete and ApiController_Obsolete\n\n    #region Compatibility with Eav.Interfaces.IEntity - introduced in 10.10 - Removed in v20\n\n    //[PrivateApi]\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(ToSic.Eav.Interfaces.IEntity entity)\n    //    => ExAsDynamicInterfacesIEntity();\n\n\n    //[PrivateApi]\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(KeyValuePair<int, ToSic.Eav.Interfaces.IEntity> entityKeyValuePair)\n    //    => AsDynamicKvpInterfacesIEntity();\n\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //[PrivateApi]\n    //public IEnumerable<dynamic> AsDynamic(IEnumerable<ToSic.Eav.Interfaces.IEntity> entities)\n    //    => AsDynamicIEnumInterfacesIEntity();\n\n    #endregion\n\n    #region AsDynamic<int, IEntity>\n\n    [PrivateApi]\n    [Obsolete(\"throws error with fix-instructions. Use AsDynamic(IEnumerable<IEntity>...)\")]\n    public dynamic AsDynamic(KeyValuePair<int, IEntity> entityKeyValuePair) => ExAsDynamicKvp();\n\n    #endregion\n\n\n    #endregion\n\n    //[PrivateApi(\"this is the old signature, should still be supported\")]\n    // we're not creating an error/overload here, because it may lead to signature issues \n    // where two methods have almost the same signature\n    //public virtual void CustomizeSearch(Dictionary<string, List<ISearchInfo>> searchInfos, ModuleInfo moduleInfo, DateTime beginDate)\n    //    => throw new Exception($\"ListPresentation {NotSupportedIn10}. Use Header.Presentation\");\n\n    #region Old AsDynamic with correct warnings\n\n    [PrivateApi] public IEnumerable<dynamic> AsDynamic(IDataStream stream) => ExAsDynamicForList();\n    [PrivateApi] public IEnumerable<dynamic> AsDynamic(IDataSource source) => ExAsDynamicForList();\n    [PrivateApi] public IEnumerable<dynamic> AsDynamic(IEnumerable<IEntity> entities) => ExAsDynamicForList();\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/Razor14.cs",
    "content": "﻿using Custom.Razor.Sys;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Dnn.Razor;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.Help;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Base class for v14 Dynamic Razor files.\n/// Will provide the <see cref=\"ServiceKit14\"/> on property `Kit`.\n/// This contains all the popular services used in v14, so that your code can be lighter. \n/// </summary>\n/// <remarks>\n/// Important: The property `Convert` which exited on Razor12 was removed. use `Kit.Convert` instead.\n/// </remarks>\n[PublicApi]\npublic abstract partial class Razor14: RazorComponentBase, IRazor14<object, ServiceKit14>, IHasCodeHelp, ICreateInstance\n{\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc cref=\"DnnRazorHelper.RenderPageNotSupported\"/>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public override HelperResult RenderPage(string path, params object[] data)\n        => RzrHlp.RenderPageNotSupported();\n\n\n    [PrivateApi] public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n\n    public ServiceKit14 Kit => field ??= CodeApi.ServiceKit14;\n\n\n    #region Core Properties which should appear in docs\n\n    /// <inheritdoc />\n    public override ICodeLog Log => RzrHlp.CodeLog;\n\n    /// <inheritdoc />\n    public override IHtmlHelper Html => RzrHlp.Html;\n\n    #endregion\n\n\n    #region Link, Edit\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi.Edit;\n\n    #endregion\n\n\n    #region CmsContext\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    #endregion\n\n\n    #region Content, Header, etc. and List\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic Content => CodeApi.Content;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic Header => CodeApi.Header;\n\n    /// <inheritdoc />\n    public IDataSource Data => CodeApi.Data;\n\n    #endregion\n\n    #region CreateSource Stuff\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    #endregion\n\n\n\n    #region Dev Tools & Dev Helpers\n\n    [PrivateApi(\"Not yet ready\")]\n    public IDevTools DevTools => CodeApi.DevTools;\n\n    [PrivateApi] List<CodeHelp> IHasCodeHelp.ErrorHelpers => HelpDbRazor.CompileRazorOrCode14;\n\n    #endregion\n\n    #region CreateInstance\n\n    [PrivateApi] string IGetCodePath.CreateInstancePath { get; set; }\n\n    /// <inheritdoc />\n    public virtual dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => RzrHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    [PrivateApi(\"added in 16.05, but not sure if it should be public\")]\n    public dynamic GetCode(string path, NoParamOrder npo = default, string className = default)\n        => RzrHlp.GetCode(path: path, className: className);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/Razor14_AppSetRes.cs",
    "content": "﻿using ToSic.Sxc.Apps;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\nabstract partial class Razor14\n{\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public new IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic Settings => CodeApi.Settings;\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/Razor14_AsConversions.cs",
    "content": "﻿using ToSic.Sxc.Adam;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\nabstract partial class Razor14\n{\n    #region AsDynamic in many variations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(string json, string fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public dynamic AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    #endregion\n\n    #region AsEntity\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/Razor14_DynamicModel.cs",
    "content": "﻿using ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Render.Sys.Specs;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n// ReSharper disable once UnusedMember.Global\nabstract partial class Razor14: ISetDynamicModel\n{\n    /// <inheritdoc cref=\"Custom.Razor.Sys.IRazor14{TModel,TServiceKit}.DynamicModel\"/>\n    [PublicApi]\n    public dynamic DynamicModel => RzrHlp.DynamicModel;\n\n    [PrivateApi]\n    void ISetDynamicModel.SetDynamicModel(RenderSpecs viewData) => RzrHlp.SetDynamicModel(viewData);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/RazorTyped.cs",
    "content": "﻿using Custom.Razor.Sys;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Razor;\nusing ToSic.Sxc.Code.Razor.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Dnn.Razor;\nusing ToSic.Sxc.Dnn.Razor.Sys;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.Help;\nusing static System.StringComparer;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Base class for v16 [Typed](xref:NetCode.TypedCode.Index) Razor files.\n/// Use it to create custom CS code in your App.\n/// \n/// It provides the <see cref=\"ServiceKit16\"/> on property `Kit` which contains all the popular services to create amazing stuff.\n/// </summary>\n/// <remarks>\n/// Important: This is very different from Razor12 or Razor14, as it doesn't rely on `dynamic` code.\n/// Be aware of this since the APIs are very different - see [Typed Code](xref:NetCode.TypedCode.Index).\n/// </remarks>\n[PublicApi]\npublic abstract class RazorTyped: RazorComponentBase, IRazor, ITypedCode16, IHasCodeHelp, IGetCodePath, ISetDynamicModel, ICanUseRoslynCompiler\n{\n    #region Constructor, Setup, Helpers\n\n    internal ICodeTypedApiHelper CodeApi => field\n        ??= ExCtx.GetTypedApi();\n\n\n    /// <inheritdoc cref=\"DnnRazorHelper.RenderPageNotSupported\"/>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public override HelperResult RenderPage(string path, params object[] data)\n        => RzrHlp.RenderPageNotSupported();\n\n\n    /// <inheritdoc cref=\"ICompatibilityLevel.CompatibilityLevel\"/>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel16;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    /// <inheritdoc cref=\"ITypedCode16.GetService{TService}(NoParamOrder, string?)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TService GetService<TService>(NoParamOrder npo = default, string typeName = default) where TService : class\n        => AppCodeGetNamedServiceHelper.GetService<TService>(owner: this, CodeHelper.Specs, typeName);\n\n    /// <inheritdoc cref=\"IHasKit{TServiceKit}.Kit\"/>\n    public ServiceKit16 Kit => field ??= CodeApi.ServiceKit16;\n\n    internal TypedCode16Helper CodeHelper => field ??= CreateCodeHelper();\n\n    /// <inheritdoc cref=\"CodeTyped.Customize\"/>\n    protected ICodeCustomizer Customize => field ??= CodeApi.GetService<ICodeCustomizer>(reuse: true);\n\n    void ISetDynamicModel.SetDynamicModel(RenderSpecs viewData)\n    {\n        _renderSpecs = viewData;\n\n        // Only overwrite if data is not null\n        if (viewData.Data != null)\n            _overridePageData = viewData.Data;\n    }\n\n    private RenderSpecs _renderSpecs;\n\n    private RenderSpecs GetRenderSpecs()\n    {\n        return _renderSpecs ??= PageData.Values.FirstOrDefault(value => value is RenderSpecs) as RenderSpecs;\n    }\n    private object _overridePageData;\n\n    private TypedCode16Helper CreateCodeHelper() =>\n        new(\n            new(ExCtx, true, Path),\n            getRazorModel: () => _overridePageData\n                                 // the default/only value would be on a 0 key\n                                 ?? (PageData?.TryGetValue(0, out var zeroData) ?? false ? zeroData as object : null),\n            () => GetRenderSpecs()?.DataDic\n                  ?? PageData?\n                      .Where(pair => pair.Key is string)\n                      .ToDictionary(pair => pair.Key.ToString(), pair => pair.Value, InvariantCultureIgnoreCase)\n        );\n\n    #endregion\n\n\n    #region Core Properties which should appear in docs\n\n    /// <inheritdoc />\n    public override ICodeLog Log => RzrHlp.CodeLog;\n\n    /// <inheritdoc />\n    public override IHtmlHelper Html => RzrHlp.Html;\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    public dynamic GetCode(string path, NoParamOrder npo = default, string className = default)\n        => RzrHlp.GetCode(path: path, className: className);\n\n    #endregion\n\n    #region Link\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    #endregion\n\n\n    #region New App, Settings, Resources\n\n    /// <inheritdoc />\n    public new IAppTyped App => CodeApi.AppTyped;\n\n    /// <inheritdoc cref=\"ITypedApi.AllResources\" />\n    public ITypedStack AllResources => CodeHelper.AllResources;\n\n    /// <inheritdoc cref=\"ITypedApi.AllSettings\" />\n    public ITypedStack AllSettings => CodeHelper.AllSettings;\n\n    #endregion\n\n    #region My Data Stuff\n\n    /// <inheritdoc />\n    public ITypedItem MyItem => CodeHelper.MyItem;\n\n    /// <inheritdoc />\n    public IEnumerable<ITypedItem> MyItems => CodeHelper.MyItems;\n\n    /// <inheritdoc />\n    public ITypedItem MyHeader => CodeHelper.MyHeader;\n\n    /// <inheritdoc />\n    public IDataSource MyData => CodeApi.Data;\n\n    /// <inheritdoc />\n    public ITypedRazorModel MyModel => CodeHelper.MyModel;\n\n    #endregion\n\n\n    #region MyContext & UniqueKey\n\n    /// <inheritdoc cref=\"ITypedApi.MyContext\" />\n    public ICmsContext MyContext => CodeApi.CmsContext;\n\n    /// <inheritdoc cref=\"ITypedApi.MyPage\" />\n    public ICmsPage MyPage => CodeApi.CmsContext.Page;\n\n    /// <inheritdoc cref=\"ITypedApi.MyUser\" />\n    public ICmsUser MyUser => CodeApi.CmsContext.User;\n\n    /// <inheritdoc cref=\"ITypedApi.MyView\" />\n    public ICmsView MyView => CodeApi.CmsContext.View;\n\n    /// <inheritdoc cref=\"ITypedApi.UniqueKey\" />\n    public string UniqueKey => Kit.Key.UniqueKey;\n\n    #endregion\n\n    #region As Conversions\n\n    /// <inheritdoc cref=\"ITypedApi.AsItem\" />\n    public ITypedItem AsItem(object data, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsItem(data, new() { ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsItems\" />\n    public IEnumerable<ITypedItem> AsItems(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsItems(list, new() { ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsEntity\" />\n    public IEntity AsEntity(ICanBeEntity thing)\n        => CodeApi.Cdf.AsEntity(thing);\n\n    /// <inheritdoc cref=\"ITypedApi.AsTyped\" />\n    public ITyped AsTyped(object original, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsTyped(original, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsTypedList\" />\n    public IEnumerable<ITyped> AsTypedList(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsTypedList(list, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack\" />\n    public ITypedStack AsStack(params object[] items)\n        => CodeApi.Cdf.AsStack(items);\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack{T}\" />\n    public T AsStack<T>(params object[] items)\n        where T : class, IModelFromData, new()\n        => CodeApi.Cdf.AsStack<T>(items);\n\n    #endregion\n\n\n    #region Dev Tools & Dev Helpers\n\n    [PrivateApi(\"Not yet ready\")]\n    public IDevTools DevTools => CodeHelper.DevTools;\n\n    [PrivateApi] List<CodeHelp> IHasCodeHelp.ErrorHelpers => HelpDbRazor.Compile16;\n\n    #endregion\n\n    #region CreateInstance\n\n    [PrivateApi] string IGetCodePath.CreateInstancePath { get; set; }\n\n    #endregion\n\n    #region As / AsList WIP v17\n\n    /// <inheritdoc />\n    public T As<T>(object source, NoParamOrder npo = default)\n        where T : class, IModelFromData\n        => CodeApi.Cdf.AsCustom<T>(source: source);\n\n    /// <inheritdoc />\n    public IEnumerable<T> AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData\n        => CodeApi.Cdf.AsCustomList<T>(source: source, npo: npo, nullIfNull: nullIfNull);\n\n    #endregion\n\n\n    #region Experimental Configuration\n\n    [WorkInProgressApi(\"not yet public or final, WIP v20.00.0x\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    // [field: AllowNull, MaybeNull]\n    public IRazorConfiguration Configuration => field ??= new RazorConfiguration(GetRenderSpecs(), RzrHlp.Log);\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/Hybrid/RazorTyped_TModel.cs",
    "content": "﻿// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// New base class with custom model.\n/// The rest of this is identical to <see cref=\"RazorTyped\"/>.\n/// </summary>\n/// <typeparam name=\"TModel\">Model type - like `string` or a class from your `AppCode`</typeparam>\n/// <remarks>\n/// Introduced in v17.03\n/// </remarks>\n[PublicApi]\npublic abstract class RazorTyped<TModel> : RazorTyped\n{\n    /// <summary>\n    /// The model for this Razor file.\n    /// Typed according to the `@inherits` statement.\n    /// </summary>\n    public TModel Model => CodeHelper.GetModel<TModel>();\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Custom/readme.md",
    "content": "﻿# ToSic.Sxc.Hybrid for DNN\n\nThis folder should contain the DNN implementations of the hybrid stuff. \n\n## Notes / Best Practices\n\n* We'll create subfolders for managing the code\n* but all the objects for the custom work should be in the `ToSic.Sxc.Hybrid` namespace  \n  don't use sub-namespaces because it just makes the docs harder to read / organize. \n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/IDnnRazor11.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDnnRazor11\n{\n    /// <summary>\n    /// Code-Behind of this .cshtml file - located in a file with the same name but ending in .code.cshtml\n    /// </summary>\n    dynamic Code { get; }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/IDnnRazorCompatibility.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// Modify any objects on DNN Razor to match the newer .net core conventions.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDnnRazorCompatibility\n{\n    /// <summary>\n    /// Helper for Html.Raw - for creating raw html output which doesn't encode &gt; and &lt;.\n    /// Also has helpers such as `.Partial(...)`\n    /// </summary>\n    IHtmlHelper Html { get; }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Integration/StartUpDnnRazor.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sxc.Dnn.Razor;\nusing ToSic.Sxc.Dnn.Razor.Sys;\nusing ToSic.Sxc.Engines;\n\nnamespace ToSic.Sxc.Dnn.Integration;\n\npublic static class StartUpDnnRazor\n{\n    public static IServiceCollection AddDnnRazor(this IServiceCollection services)\n    {\n        services.TryAddTransient<IRazorEngine, DnnRazorEngine>();\n        services.TryAddTransient<DnnRazorCompiler>();\n\n        services.TryAddTransient<HtmlHelper>();\n\n        services.TryAddTransient<IRoslynBuildManager, RoslynBuildManager>();\n        services.TryAddTransient<RoslynCompilationRunner>();\n        services.TryAddTransient<RoslynCacheFallbackHandler>();\n        services.TryAddTransient<IAssemblyDiskCacheService, AssemblyDiskCacheService>();\n        services.TryAddTransient<TemplateCacheService>();\n        services.TryAddTransient<RazorCompilerService>();\n        services.TryAddTransient<CSharpCompilerService>();\n        services.TryAddTransient<AssemblyUtilities>();\n\n        return services;\n    }\n\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/DnnRazorEngine.cs",
    "content": "﻿using System.Configuration;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Dnn.Razor.Sys;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Render.Sys.Specs;\n\nnamespace ToSic.Sxc.Dnn.Razor;\n\n/// <summary>\n/// The razor engine, which compiles / runs engine templates\n/// </summary>\n/// <remarks>\n/// This is the glue-ware to the \"Engine\". It just ensures API compatibility with the core Engine.\n/// Internally it will use the DnnRazorCompiler to compile and run the Razor templates.\n///\n/// It also manages the EntryRazorComponent, which is the main Razor component for this engine.\n/// </remarks>\n[PrivateApi(\"used to be InternalApi_DoNotUse_MayChangeWithoutNotice till v16.09\")]\n[EngineDefinition(Name = \"Razor\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n// ReSharper disable once UnusedMember.Global\ninternal class DnnRazorEngine(\n    EngineSpecsService engineSpecsService,\n    IBlockResourceExtractor blockResourceExtractor,\n    EngineAppRequirements engineAppRequirements,\n    DnnRazorCompiler razorCompiler)\n    : ServiceBase(\"Dnn.RzEng\", connect: [engineSpecsService, blockResourceExtractor, engineAppRequirements, razorCompiler]),\n        IRazorEngine\n{\n    /// <inheritdoc />\n    public RenderEngineResult Render(IBlock block, RenderSpecs specs)\n    {\n        var l = Log.Fn<RenderEngineResult>(timer: true);\n\n        // Prepare #1: Specs\n        var engineSpecs = engineSpecsService.GetSpecs(block);\n\n        // Preflight: check if rendering is possible, or throw exceptions...\n        var preFlightResult = engineAppRequirements.CheckExpectedNoRenderConditions(engineSpecs);\n        if (preFlightResult != null)\n            return l.ReturnAsError(preFlightResult);\n\n        // Prepare #2: after Base.init also init the compiler (requires objects which were set up in base.Init)\n        razorCompiler.SetupCompiler(engineSpecs);\n\n        // Prepare #3: The entry component\n        RazorComponentBase entryRazorComponent;\n        try\n        {\n            var razorBuild = razorCompiler.InitWebpage(engineSpecs.TemplatePath, exitIfNoHotBuild: false);\n            entryRazorComponent = razorBuild.Instance;\n        }\n        catch (ConfigurationErrorsException exc)    // Catch web.config Error on DNNs upgraded to 7\n        {\n            throw l.Done(new Exception(\"Configuration Error. Your web.config seems to be wrong in the 2sxc folder.\", exc));\n        }\n\n        // Render and process / return\n        var renderedTemplate = DnnRenderImplementation(entryRazorComponent, specs);\n        var result = blockResourceExtractor.Process(renderedTemplate);\n        return l.ReturnAsOk(result);\n    }\n\n\n    private RenderEngineResultRaw DnnRenderImplementation(RazorComponentBase webpage, RenderSpecs specs)\n    {\n        ILogCall<(TextWriter writer, List<Exception> exceptions)> l = Log.Fn<(TextWriter, List<Exception>)>();\n        var (writer, exceptions) = razorCompiler.Render(webpage, new StringWriter(), specs);\n        return new ()\n        {\n            Html = writer.ToString(),\n            ExceptionsOrNull = exceptions\n        };\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/DnnRazorHelper.cs",
    "content": "﻿using System.Web.Hosting;\nusing Custom.Razor.Sys;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.Help;\nusing ToSic.Sys.Exceptions;\n\nnamespace ToSic.Sxc.Dnn.Razor;\n\n[PrivateApi]\ninternal class DnnRazorHelper() : RazorHelperBase(\"Sxc.RzrHlp\")\n{\n    #region Constructor / Init\n\n    public DnnRazorHelper Init(RazorComponentBase page)\n    {\n        Page = page;\n        return this;\n    }\n\n    public RazorComponentBase Page { get; private set; }\n\n    #endregion\n\n    #region Error Forwarding\n\n    internal void ConfigurePage(WebPageBase parentPage, string virtualPath)\n    {\n        // Child pages need to get their context from the Parent\n        // ...but we're not quite sure why :) - maybe this isn't actually needed\n        Page.Context = parentPage.Context;\n\n        // Return if parent page is not a SexyContentWebPage\n        if (parentPage is not RazorComponentBase typedParent) return;\n\n        ParentPage = typedParent;\n\n        // Only call the Page.ConnectToRoot, as it will call-back this objects ConnectToRoot\n        // So don't call: ConnectToRoot(typedParent._DynCodeRoot);\n        Page.ConnectToRoot(typedParent.ExCtx);\n\n        Log.A($\"{nameof(virtualPath)} for Render etc.:{virtualPath}\");\n    }\n\n    internal RazorComponentBase ParentPage { get; set; }\n\n    #endregion\n\n    #region Html Helper\n\n    internal IHtmlHelper Html => field\n        ??= ExCtx.GetService<HtmlHelper>().Init(Page, this, ExCtx.GetContextOfBlock()?.User.IsSystemAdmin ?? false);\n\n    #endregion\n\n    #region RenderPage\n\n    /// <summary>\n    /// RenderPage is disabled in Razor12+ to force designers to use Html.Partial\n    /// </summary>\n    internal HelperResult RenderPageNotSupported()\n        => throw new NotSupportedException(\"RenderPage(...) is not supported in Hybrid Razor. Use Html.Partial(...) instead.\");\n\n\n    #endregion\n\n    #region Create Instance\n\n    protected override string GetCodeNormalizePath(string virtualPath) \n        => Page.NormalizePath(virtualPath);\n\n    protected override object GetCodeCshtml(string path)\n    {\n        // ReSharper disable once ConvertTypeCheckToNullCheck\n        if (Page is not IHasDnn)\n            throw new ExceptionWithHelp(new CodeHelp\n            {\n                Name = \"create-instance-cshtml-only-in-old-code\",\n                Detect = null,\n                UiMessage = \"CreateInstance(*.cshtml) is not supported in Hybrid Razor. Use .cs files instead.\"\n            });\n        var pageAsCode = WebPageBase.CreateInstanceFromVirtualPath(path);\n        var pageAsRcb = pageAsCode as RazorComponentBase;\n        pageAsRcb?.RzrHlp.ConfigurePage(Page, pageAsRcb.VirtualPath);\n        return pageAsCode;\n    }\n\n    protected override string GetCodeFullPathForExistsCheck(string path)\n    {\n        var l = Log.Fn<string>(path);\n        var fullPath = HostingEnvironment.MapPath(path);\n        return l.ReturnAndLog(fullPath);\n    }\n\n    #endregion\n\n    #region DynamicModel and Factory\n\n    private ICodeDataPoCoWrapperService CodeDataWrapper => _dynJacketFactory.Get(() => ExCtx.GetService<ICodeDataPoCoWrapperService>());\n    private readonly GetOnce<ICodeDataPoCoWrapperService> _dynJacketFactory = new();\n\n    /// <inheritdoc cref=\"IRazor14{TModel,TServiceKit}.DynamicModel\"/>\n    public dynamic DynamicModel => _dynamicModel ??= CodeDataWrapper.FromDictionary(Page.PageData);\n    private dynamic _dynamicModel;\n\n    internal void SetDynamicModel(RenderSpecs viewData)\n    {\n        var l = Log.Fn();\n        _dynamicModel = CodeDataWrapper.DynamicFromObject(viewData.Data, WrapperSettings.Dyn(children: false, realObjectsToo: false));\n        l.Done();\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/HtmlHelper.cs",
    "content": "﻿using System.Web;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Dnn.Razor.Sys;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing IFeaturesService = ToSic.Sxc.Services.IFeaturesService;\n\nnamespace ToSic.Sxc.Dnn.Razor;\n\n/// <summary>\n/// Helper in Dnn to replace the HtmlHelper for the `@Html.Raw()` or `@Html.Partial()`\n/// </summary>\n[PrivateApi]\ninternal class HtmlHelper(\n    LazySvc<CodeErrorHelpService> codeErrService,\n    LazySvc<IFeaturesService> featureSvc,\n    LazySvc<SourceAnalyzer> codeAnalysis,\n    Generator<IRenderingHelper> renderingHelperGenerator)\n    : ServiceBase(\"Dnn.HtmHlp\", connect: [codeErrService, featureSvc, codeAnalysis, renderingHelperGenerator]), IHtmlHelper\n{\n    public HtmlHelper Init(RazorComponentBase page, DnnRazorHelper helper, bool isSystemAdmin)\n    {\n        _page = page;\n        _helper = helper;\n        _errorHelper = new(page, isSystemAdmin, helper, featureSvc, codeAnalysis, codeErrService, renderingHelperGenerator);\n        return this;\n    }\n    private RazorComponentBase _page;\n    private DnnRazorHelper _helper;\n    private HtmlHelperErrorHelper _errorHelper;\n\n    private HtmlHelperTimeKeeper TimeKeeper { get; } = new();\n\n    /// <inheritdoc/>\n    public IHtmlString Raw(object stringHtml)\n        => stringHtml switch\n        {\n            null => new HtmlString(\"\"),\n            string s => new HtmlString(s),\n            IHtmlString h => h,\n            _ => throw _helper.Add(new ArgumentException($@\"Html.Raw does not support type '{stringHtml.GetType().Name}'.\", nameof(stringHtml)))\n        };\n\n    /// <summary>\n    /// This should duplicate the way .net core does RenderPage - and should become the standard way of doing it in 2sxc\n    /// </summary>\n    /// <param name=\"relativePath\"></param>\n    /// <param name=\"data\"></param>\n    /// <returns></returns>\n    public IHtmlString Partial(string relativePath, object data = default)\n    {\n        // Figure out the real path, and make sure it's lower case\n        // so the ID in a cache remains the same no matter how it was called\n        var normalizedPath = _page.NormalizePath(relativePath).ToLowerInvariant();\n\n        var l = Log.Fn<IHtmlString>($\"{nameof(relativePath)}: '{relativePath}', {nameof(normalizedPath)}: '{normalizedPath}', {nameof(data)}: {data != null}\", timer: true);\n        var fullTime = TimeKeeper.Start(normalizedPath);\n\n        // Prepare RenderSpecs with data, since it may be needed to check if caching is relevant\n        // Do it like this, to avoid multiple conversions of the same data\n        var renderSpecs = new RenderSpecs { Data = data };\n\n        var cacheHelper = new RazorPartialCachingHelper(_page.ExCtx.GetAppId(), normalizedPath, renderSpecs.DataDic, _page.ExCtx, featureSvc.Value, Log);\n\n        var cached = cacheHelper.TryGetFromCache();\n        if (cached != null)\n        {\n            cacheHelper.PageService.ReplayCachedChanges((RenderResult)cached);\n            return l.Return(new HtmlString(cached.Html), \"Returning cached result\");\n        }\n\n        try\n        {\n            // Attach any specs which the cshtml may need and possibly modify to configure caching\n            renderSpecs = renderSpecs with { PartialSpecs = cacheHelper.RenderPartialSpecsForRazor };\n\n            // This will get a HelperResult object, which is often not executed yet\n            var result = RenderWithRoslynOrClassic(relativePath, normalizedPath, renderSpecs);\n\n            // In case we should throw a nice error, we must get the HTML now, to possibly cause the error and show an alternate message\n            // This will also not allow partial caching\n            if (!_errorHelper.ThrowPartialError)\n                return l.Return(result);\n\n            // We want to capture the rendering of the result, so we can show nice errors and cache the result if needed.\n            // We must create another render result, to delay our work.\n            // Otherwise, the Razor-Engine may do some strange things and not show anything at all (instead of the error)\n            var wrappedResult = new HelperResult(writer =>\n            {\n                try\n                {\n                    fullTime.Start();\n                    var asString = result.ToHtmlString();\n                    writer.Write(asString); // Use Write instead of WriteLine, to not introduce any extra lines/whitespace\n                    fullTime.Stop();\n                    l.A($\"Done rendering {normalizedPath}; Length: {asString.Length}; accumulated time for this partial: {fullTime.ElapsedMilliseconds}ms\");\n                    // Add to cache - should only run if no exceptions were thrown\n                    cacheHelper.SaveToCacheIfEnabled(asString);\n                }\n                catch (Exception renderException)\n                {\n                    var nice = _errorHelper.TryToLogAndReWrapError(renderException, relativePath, true);\n                    writer.WriteLine(nice);\n                }\n            });\n            fullTime.Stop();\n            return l.Return(wrappedResult, $\"will add to cache: {cacheHelper.IsFullyEnabled}; accumulated time: {fullTime.ElapsedMilliseconds}ms\");\n        }\n        catch (Exception compileException)\n        {\n            // Ensure our error paths exist, to only report this in the system-logs once\n            //_errorPaths ??= new(InvariantCultureIgnoreCase);\n            var isFirstOccurrence = !_errorHelper.ErrorPaths.Contains(relativePath);\n            _errorHelper.ErrorPaths.Add(relativePath);\n\n            // Report if first time\n            var nice = _errorHelper.TryToLogAndReWrapError(compileException, relativePath, isFirstOccurrence, \"Special exception handling - only show message\");\n            var htmlError = new HtmlString(nice);\n            return l.Return(htmlError, \"compile error\");\n        }\n    }\n\n    /// <summary>\n    /// Determine if we should use Roslyn or the classic way of rendering and do it.\n    /// </summary>\n    /// <param name=\"relativePath\"></param>\n    /// <param name=\"normalizedPath\"></param>\n    /// <param name=\"renderSpecs\"></param>\n    /// <returns></returns>\n    private HelperResult RenderWithRoslynOrClassic(string relativePath, string normalizedPath, RenderSpecs renderSpecs)\n    {\n        var useRoslyn = _page is ICanUseRoslynCompiler;\n        var l = Log.Fn<HelperResult>($\"{nameof(useRoslyn)}: {useRoslyn}\");\n\n        // We can use Roslyn\n        // Classic setup without Roslyn, use the built-in RenderPage\n        if (!useRoslyn)\n            return l.Return(_page.BaseRenderPage(relativePath, renderSpecs), $\"default render {(renderSpecs.Data == null ? \"no\" : \"with\")} data\");\n\n        // Try to compile with Roslyn\n        // Will exit if the child has an old base class which would expect PageData[\"...\"] properties\n        // Because that would be empty https://github.com/2sic/2sxc/issues/3260\n        var preparations = DnnRazorCompiler.PrepareForRoslyn(_page, normalizedPath, renderSpecs.Data);\n\n        // Exit if we don't use HotBuild, because then we must revert back to classic render\n        // Reason is that otherwise the PageData property - used on very old classes - would not be populated\n        // Doing this from our compiler is super-hard, because it would use a lot of internal Microsoft APIs\n        if (preparations.SubPage.UsesHotBuild)\n        {\n            var probablyHotBuild = DnnRazorCompiler.ExecuteWithRoslyn(preparations, _page, renderSpecs);\n            \n            //if (probablyHotBuild.UsesHotBuild)\n            return l.Return(probablyHotBuild.Instance, \"used HotBuild\");\n        }\n\n        l.A(\"Tried to use Roslyn, but detected old base class so will use classic Razor Engine so PageData continues to work.\");\n        return l.Return(_page.BaseRenderPage(relativePath, renderSpecs), $\"default render {(renderSpecs.Data == null ? \"no\" : \"with\")} data\");\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/HtmlHelperErrorHelper.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Dnn.Razor;\ninternal class HtmlHelperErrorHelper(RazorComponentBase page, bool isSystemAdmin, DnnRazorHelper helper,\n    LazySvc<IFeaturesService> featureSvc, LazySvc<SourceAnalyzer> codeAnalysis, LazySvc<CodeErrorHelpService> codeErrService, Generator<IRenderingHelper> renderingHelperGenerator)\n{\n    internal HashSet<string> ErrorPaths = new(StringComparer.InvariantCultureIgnoreCase);\n\n    /// <summary>\n    /// This exception is usually thrown when a thread is aborted, e.g. by Response.End in classic ASP.NET.\n    /// It happens on Response.Redirect(...) calls.\n    /// </summary>\n    private const bool IgnoreThreadAbortException = true;\n\n    internal string TryToLogAndReWrapError(Exception renderException, string path, bool reportToDnn, string additionalLog = null)\n    {\n        if (IgnoreThreadAbortException && renderException is ThreadAbortException)\n            return \"thread aborted; probably Response.Redirect called\";\n\n        // Important to know: Once this fires, the page will stop rendering more templates\n        if (reportToDnn)\n            page.Log.GetContents().Ex(renderException);\n        if (additionalLog != null)\n            page.Log.GetContents().A(additionalLog);\n\n        // If it's a compile issue, try to find explicit help for that\n        var pathOfPage = page.NormalizePath(path);\n        var razorType = codeAnalysis.Value.TypeOfVirtualPath(pathOfPage);\n        var exWithHelp = codeErrService.Value.AddHelpForCompileProblems(renderException, razorType);\n\n\n        // Show a nice / ugly error depending on user permissions\n        // Note that if anything breaks here, it will just use the normal error - but for what breaks in here\n        // Note that if withHelp already has help, it won't be extended anymore\n        exWithHelp = codeErrService.Value.AddHelpIfKnownError(exWithHelp, page);\n        var block = page.ExCtx.GetBlock();\n        var renderHelper = renderingHelperGenerator.New().Init(block);\n        var nice = renderHelper.DesignErrorMessage([exWithHelp], true);\n        helper.Add(exWithHelp);\n        return nice;\n    }\n\n\n    internal bool ThrowPartialError => _throwPartialError.Get(()\n        => featureSvc.Value.IsEnabled(SxcFeatures.RazorThrowPartial.NameId) ||\n           isSystemAdmin && featureSvc.Value.IsEnabled(SxcFeatures.RenderThrowPartialSystemAdmin.NameId));\n    private readonly GetOnce<bool> _throwPartialError = new();\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/HtmlHelperTimeKeeper.cs",
    "content": "﻿using System.Diagnostics;\n\nnamespace ToSic.Sxc.Dnn.Razor;\n\n/// <summary>\n/// Helper to track the total time spent on each partial, especially when a partial is used many, many times (like in lists).\n/// </summary>\ninternal class HtmlHelperTimeKeeper\n{\n    public Dictionary<string, Stopwatch> Partials = new();\n\n    public Stopwatch Start(string partialName)\n    {\n        if (!Partials.TryGetValue(partialName, out var sw))\n            return Partials[partialName] = Stopwatch.StartNew();\n        \n        sw.Start();\n        return sw;\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/AssemblyDiskCacheService.cs",
    "content": "using System.Reflection;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sys.Configuration;\nusing ISite = ToSic.Eav.Context.ISite;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Service for persisting and retrieving compiled Razor assemblies from disk cache.\n/// Implements disk-based caching layer below memory cache for improved restart performance.\n/// Delegates to shared AssemblyDiskCache for platform-neutral file operations.\n/// </summary>\n[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]\npublic class AssemblyDiskCacheService(\n    LazySvc<IFeaturesService> featureService,\n    IGlobalConfiguration globalConfiguration,\n    AssemblyDiskCache diskCache,\n    AssemblyUtilities assemblyUtilities,\n    AssemblyResolver assemblyResolver,\n    IAppReaderFactory appReadFac,\n    LazySvc<IAppPathsMicroSvc> appPathsLazy,\n    ISite site)\n  : ServiceBase(\"Dnn.AsmDskCch\", connect: [featureService, globalConfiguration, diskCache, assemblyUtilities, assemblyResolver, appReadFac, appPathsLazy, site]), IAssemblyDiskCacheService\n{\n    /// <summary>\n    /// Attempts to load a cached assembly from disk for the specified template.\n    /// </summary>\n    public AssemblyResult TryLoadFromCache(\n        HotBuildSpec spec,\n        string templateRelativePath,\n        string contentHash,\n        string appCodeHash,\n        AssemblyResult appCodeDependency,\n        CodeFileInfo codeFileInfo)\n    {\n        var l = Log.Fn<AssemblyResult>($\"app:{spec.AppId}, edition:{spec.Edition}, template:{templateRelativePath}\", timer: true);\n\n        // Generate cache key\n        var cachePath = GetCacheFilePath(spec, templateRelativePath, contentHash, appCodeHash);\n\n        // Ensure assembly resolver can provide AppCode dependencies when the cached assembly is loaded\n        if (appCodeDependency?.Assembly != null)\n            assemblyResolver.AddAssembly(appCodeDependency.Assembly, GetAppRelativePath(spec));\n\n        // Load assembly bytes from disk using shared cache service\n        var assembly = diskCache.TryLoadFromCache(\n            cachePath,\n            loadAssembly: assemblyBytes => Assembly.Load(File.ReadAllBytes(assemblyBytes)),\n            featureFlagCheck: IsEnabled);\n\n        if (assembly == null)\n            return l.ReturnNull();\n\n        try\n        {\n            // Create AssemblyResult with MainType and AppCodeDependency populated\n            var className = assemblyUtilities.GetSafeClassName(templateRelativePath);\n            var mainType = assemblyUtilities.FindMainType(assembly, className, isCshtml: true);\n\n            if (mainType == null)\n            {\n                l.A($\"Warning: Could not find main type {className} in assembly\");\n                return l.ReturnNull();\n            }\n\n            var result = new AssemblyResult(assembly)\n            {\n                MainType = mainType,\n                AppCodeDependency = appCodeDependency\n            };\n\n            return l.Return(result, \"Cache hit - loaded from disk\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            l.A(\"Error processing cached assembly - will trigger recompilation\");\n            return l.ReturnNull();\n        }\n    }\n\n    /// <summary>\n    /// Saves a compiled assembly to disk cache for future reuse.\n    /// </summary>\n    public bool TrySaveToCache(\n        HotBuildSpec spec,\n        string templateRelativePath,\n        string contentHash,\n        string appCodeHash,\n        AssemblyResult assemblyResult)\n    {\n        var l = Log.Fn<bool>($\"app:{spec.AppId}, edition:{spec.Edition}, template:{templateRelativePath}\", timer: true);\n\n        // Generate cache key\n        var cachePath = GetCacheFilePath(spec, templateRelativePath, contentHash, appCodeHash);\n\n        // Get source assembly path\n        var sourceAssemblyPath = assemblyResult.Assembly?.Location;\n\n        // Delegate to shared disk cache service\n        var saved = diskCache.TrySaveToCache(\n            sourceAssemblyPath,\n            cachePath,\n            featureFlagCheck: IsEnabled);\n\n        return saved\n            ? l.ReturnTrue(\"saved\")\n            : l.ReturnFalse(\"failed\");\n    }\n\n    /// <summary>\n    /// Builds the full cache file path for the given template/spec combination.\n    /// </summary>\n    public string GetCacheFilePath(\n        HotBuildSpec spec,\n        string templateRelativePath,\n        string contentHash,\n        string appCodeHash)\n    {\n        var cacheKey = BuildCacheKey(spec, templateRelativePath, contentHash, appCodeHash);\n        return cacheKey.GetFilePath(GetCacheDirectoryPath());\n    }\n\n    private CacheKey BuildCacheKey(HotBuildSpec spec, string templateRelativePath, string contentHash, string appCodeHash)\n        => new(spec.AppId, spec.Edition, templateRelativePath, contentHash, appCodeHash, GetAppRelativePath(spec));\n\n    private string GetAppRelativePath(HotBuildSpec spec)\n    {\n        if (spec.AppId <= 0)\n            return string.Empty;\n\n        return appPathsLazy.Value.Get(appReadFac.Get(spec.AppId), site).RelativePath;\n    }\n\n    /// <summary>\n    /// Invalidates (deletes) cached assemblies for a specific template.\n    /// </summary>\n    public void InvalidateCache(string templateRelativePath, string edition, string appPath = null)\n    {\n        var l = Log.Fn($\"template:{templateRelativePath}\");\n\n        var cacheDir = GetCacheDirectoryPath();\n        var normalizedPath = CacheKey.NormalizePath(templateRelativePath, edition, appPath);\n        var searchPattern = $\"*-{normalizedPath}-*.dll\";\n\n        var deletedCount = diskCache.InvalidateCache(cacheDir, searchPattern, SearchOption.AllDirectories);\n        l.A($\"Invalidated {deletedCount} cache files for template {templateRelativePath}\");\n\n        l.Done();\n    }\n\n    /// <summary>\n    /// Invalidates all cached assemblies for a specific app and edition.\n    /// </summary>\n    public void InvalidateAppCache(int appId, string edition)\n    {\n        var l = Log.Fn($\"app:{appId}, edition:{edition}\");\n\n        var cacheDir = GetCacheDirectoryPath();\n        var appDir = Path.Combine(cacheDir, CacheKey.GetAppFolder(appId, edition));\n\n        var deletedCount = Directory.Exists(appDir)\n            ? diskCache.InvalidateCache(appDir, \"*.dll\", SearchOption.AllDirectories)\n            : 0;\n        l.A($\"Invalidated {deletedCount} cache files for app {appId} edition {edition}\");\n\n        l.Done();\n    }\n\n    /// <summary>\n    /// Checks if disk caching is enabled based on feature flag.\n    /// </summary>\n    public bool IsEnabled()\n        // Not cached - check on every call for runtime toggle support\n        => featureService.Value.IsEnabled(Sxc.Sys.Configuration.SxcFeatures.RazorCacheCompiledToDisk.NameId);\n\n    /// <summary>\n    /// Gets the physical path to the cache directory.\n    /// </summary>\n    public string GetCacheDirectoryPath()\n        // App_Data/2sxc.bin.cshtml\n        => globalConfiguration.CshtmlAssemblyFolder();\n\n    /// <summary>\n    /// Computes SHA256 hash of the given content string.\n    /// </summary>\n    /// <remarks>\n    /// SHA256 is FIPS-compliant and performant for typical template sizes.\n    /// </remarks>\n    public string ComputeContentHash(string sourceCode)\n        => diskCache.ComputeContentHash(sourceCode);\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/AssemblyUtilities.cs",
    "content": "using System.Reflection;\nusing System.Text;\nusing System.CodeDom.Compiler;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Helper utilities for working with assemblies and class names.\n/// </summary>\n[PrivateApi]\npublic class AssemblyUtilities() : ServiceBase(\"Dnn.RzAmUt\")\n{\n    internal const string DefaultNamespace = \"RazorHost\";\n\n    /// <summary>\n    /// Find the main type in a generated assembly.\n    /// </summary>\n    internal Type FindMainType(Assembly generatedAssembly, string className, bool isCshtml)\n    {\n        var l = Log.Fn<Type>($\"className: '{className}'; isCshtml: {isCshtml}\", timer: true);\n        \n        if (generatedAssembly == null) \n            return l.ReturnAsError(null, \"generatedAssembly is null\");\n\n        var mainType = generatedAssembly.GetType(\n            isCshtml ? $\"{DefaultNamespace}.{className}\" : className, \n            false, \n            true);\n        \n        if (mainType != null) \n            return l.ReturnAsOk(mainType);\n\n        l.A(\"can't find MainType in standard way, fallback #1 - search by classname, ignoring namespace\");\n        foreach (var mainTypeFallback1 in generatedAssembly.GetTypes())\n            if (mainTypeFallback1.Name.Equals(className, StringComparison.OrdinalIgnoreCase))\n                return l.ReturnAsOk(mainTypeFallback1);\n\n        l.A(\"can't find mainTypeFallback1, fallback #2 - just return first type\");\n        var mainTypeFallback2 = generatedAssembly.GetTypes().FirstOrDefault();\n        return l.ReturnAsOk(mainTypeFallback2);\n    }\n\n    /// <summary>\n    /// Generate a safe class name from a template file path.\n    /// </summary>\n    internal string GetSafeClassName(string templateFullPath)\n    {\n        if (!string.IsNullOrWhiteSpace(templateFullPath))\n            return \"RazorView\" + GetSafeString(Path.GetFileNameWithoutExtension(templateFullPath));\n\n        return \"RazorView\" + Guid.NewGuid().ToString(\"N\");\n    }\n\n    private string GetSafeString(string input)\n    {\n        var safeChars = input.Where(c => char.IsLetterOrDigit(c) || c == '_').ToArray();\n        var safeString = new string(safeChars);\n\n        if (!char.IsLetter(safeString.FirstOrDefault()) && safeString.FirstOrDefault() != '_')\n            safeString = \"_\" + safeString;\n\n        return safeString;\n    }\n\n    /// <summary>\n    /// Format compiler errors into a readable error message.\n    /// </summary>\n    internal string FormatCompilerErrors(List<CompilerError> errors)\n    {\n        var compileErrors = new StringBuilder();\n        foreach (var error in errors)\n            compileErrors.AppendLine($\"Line: {error.Line}, Column: {error.Column}, Error: {error.ErrorText}\");\n        return compileErrors.ToString();\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/CSharpCompilerService.cs",
    "content": "using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;\nusing System.CodeDom.Compiler;\nusing System.Reflection;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Service responsible for compiling C# code files into assemblies.\n/// </summary>\npublic class CSharpCompilerService(\n    MemoryCacheService memoryCacheService,\n    IAssemblyDiskCacheService diskCacheService)\n    : ServiceBase(\"Dnn.CsCmpSvc\", connect: [memoryCacheService, diskCacheService])\n{\n    private const string CSharpCodeProviderCacheKey = \"Sxc-Dnn-CSharpCodeProvider\";\n    private const int CSharpCodeProviderCacheMinutes = 5;\n\n    /// <summary>\n    /// Compiles C# source code into an assembly.\n    /// </summary>\n    public (Assembly Assembly, List<CompilerError> Errors) Compile(\n        string sourceCode, \n        List<string> referencedAssemblies, \n        string outputAssemblyPath = null)\n    {\n        var l = Log.Fn<(Assembly, List<CompilerError>)>(timer: true, parameters: $\"sourceCode: {sourceCode.Length} chars\");\n\n        var lTimer = Log.Fn(\"Compiler Params\", timer: true);\n        var compilerParameters = CreateCompilerParameters(referencedAssemblies, outputAssemblyPath);\n        lTimer.Done();\n\n        var compiler = GetCSharpCodeProvider();\n        lTimer = Log.Fn(\"Compile\", timer: true);\n        var compilerResults = compiler.CompileAssemblyFromSource(compilerParameters, sourceCode);\n        lTimer.Done();\n\n        if (compilerResults.Errors.Count <= 0)\n            return l.ReturnAsOk((compilerResults.CompiledAssembly, null));\n\n        var errorList = compilerResults.Errors.Cast<CompilerError>().Where(e => !e.IsWarning).ToList();\n\n        return (!errorList.Any())\n            ? l.ReturnAsOk((compilerResults.CompiledAssembly, null))\n            : l.ReturnAsError((null, errorList), \"error\");\n    }\n\n    private CSharpCodeProvider GetCSharpCodeProvider()\n    {\n        var l = Log.Fn<CSharpCodeProvider>(timer: true);\n\n        if (memoryCacheService.TryGet<CSharpCodeProvider>(CSharpCodeProviderCacheKey, out var fromCache))\n            return l.Return(fromCache, \"from cached\");\n\n        var codeProvider = new CSharpCodeProvider();\n        memoryCacheService.Set(CSharpCodeProviderCacheKey, codeProvider, p => p.SetSlidingExpiration(CSharpCodeProviderCacheMinutes * 60));\n\n        return l.Return(codeProvider, \"created new and cached\");\n    }\n\n    private CompilerParameters CreateCompilerParameters(List<string> referencedAssemblies, string outputAssemblyPath)\n    {\n        var compilerParameters = new CompilerParameters([.. referencedAssemblies])\n        {\n            GenerateInMemory = !diskCacheService.IsEnabled() && string.IsNullOrEmpty(outputAssemblyPath),\n            IncludeDebugInformation = true,\n            TreatWarningsAsErrors = false,\n            CompilerOptions = DnnRoslynConstants.CompilerOptions,\n        };\n\n        if (diskCacheService.IsEnabled() && outputAssemblyPath.HasValue())\n        {\n            var outDir = Path.GetDirectoryName(outputAssemblyPath);\n            if (outDir.HasValue())\n                Directory.CreateDirectory(outDir);\n\n            compilerParameters.OutputAssembly = outputAssemblyPath;\n            compilerParameters.TempFiles = new TempFileCollection(EnsureTempDir());\n        }\n\n        return compilerParameters;\n    }\n\n    private string EnsureTempDir()\n    {\n        var cacheRoot = diskCacheService.GetCacheDirectoryPath();\n        var tempDir = Path.Combine(cacheRoot, \"temp\");\n        if (!Directory.Exists(tempDir))\n            Directory.CreateDirectory(tempDir);\n        return tempDir;\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/CacheKey.cs",
    "content": "namespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Value object representing a disk cache key for compiled Razor assemblies.\n/// Immutable structure containing all components needed for cache lookup and invalidation.\n/// </summary>\n/// <remarks>\n/// Thread-safe by design (immutable).\n/// </remarks>\npublic sealed class CacheKey : IEquatable<CacheKey>\n{\n    /// <summary>\n    /// Application identifier\n    /// </summary>\n    public int AppId { get; }\n\n    /// <summary>\n    /// App edition (e.g., \"live\", \"staging\"). Never null; defaults to \"root\" if not provided.\n    /// </summary>\n    public string Edition { get; }\n\n    /// <summary>\n    /// Normalized template path (sanitized relative path + hash for uniqueness).\n    /// </summary>\n    public string NormalizedPath { get; }\n\n    /// <summary>\n    /// SHA256 hash of template source code content\n    /// </summary>\n    public string ContentHash { get; }\n\n    /// <summary>\n    /// SHA256 hash of AppCode assembly (includes version info)\n    /// </summary>\n    public string AppCodeHash { get; }\n\n    /// <summary>\n    /// Creates a new cache key with the specified components.\n    /// </summary>\n    public CacheKey(int appId, string edition, string templatePath, string contentHash, string appCodeHash, string appPath = default)\n    {\n        if (appId <= 0)\n            throw new ArgumentException(\"AppId must be positive\", nameof(appId));\n        if (string.IsNullOrWhiteSpace(templatePath))\n            throw new ArgumentNullException(nameof(templatePath));\n        if (string.IsNullOrWhiteSpace(contentHash))\n            throw new ArgumentNullException(nameof(contentHash));\n        if (string.IsNullOrWhiteSpace(appCodeHash))\n            throw new ArgumentNullException(nameof(appCodeHash));\n\n        var normalizedEdition = CacheKeyPathUtils.NormalizeEdition(edition);\n\n        AppId = appId;\n        Edition = normalizedEdition;\n        NormalizedPath = CacheKeyPathUtils.NormalizePath(templatePath, normalizedEdition, appPath);\n        ContentHash = contentHash;\n        AppCodeHash = appCodeHash;\n    }\n\n    /// <summary>\n    /// Generates the cache key file name in the format:\n    /// {normalizedPath}-{contentHash}-{appCodeHash}.dll\n    /// </summary>\n    /// <example>\n    /// views-default-cshtml-6995bfe9-a1b2c3-x9y8z7.dll\n    /// </example>\n    public override string ToString()\n    {\n        // Truncate hashes to first 6 characters for readability\n        var contentHashShort = ContentHash.Length > 6 ? ContentHash.Substring(0, 6) : ContentHash;\n        var appCodeHashShort = AppCodeHash.Length > 6 ? AppCodeHash.Substring(0, 6) : AppCodeHash;\n        \n        return $\"{NormalizedPath}-{contentHashShort}-{appCodeHashShort}.dll\";\n    }\n\n    /// <summary>\n    /// Gets the full file system path for this cache key in the specified directory.\n    /// </summary>\n    /// <param name=\"cacheDirectory\">Root cache directory path</param>\n    /// <returns>Full path to the cached DLL file</returns>\n    public string GetFilePath(string cacheDirectory)\n    {\n        if (!cacheDirectory.HasValue())\n            throw new ArgumentNullException(nameof(cacheDirectory));\n\n        var directory = Path.Combine(cacheDirectory, CacheKeyPathUtils.GetAppFolder(AppId, Edition));\n        return Path.Combine(directory, ToString());\n    }\n\n    /// <summary>\n    /// Normalizes a template path for use in cache keys.\n    /// </summary>\n    /// <param name=\"templatePath\">Original template path (may have mixed case, forward/back slashes)</param>\n    /// <param name=\"edition\">Edition segment used to remove the app root portion</param>\n    /// <param name=\"appPath\">app path</param>\n    /// <returns>Normalized path combining the sanitized relative path (trimmed to the app/edition scope) and an 8-character hash</returns>\n    /// <example>\n    /// Input: \"Views/Default.cshtml\" → Output: \"views-default-cshtml-6995bfe9\"\n    /// </example>\n    public static string NormalizePath(string templatePath, string edition, string appPath = default)\n        => CacheKeyPathUtils.NormalizePath(templatePath, edition, appPath);\n\n    // API compatibility: keep existing callers working\n    internal static string GetAppFolder(int appId, string edition)\n        => CacheKeyPathUtils.GetAppFolder(appId, edition);\n\n    #region Equality Members\n\n    public bool Equals(CacheKey other)\n    {\n        if (ReferenceEquals(null, other))\n            return false;\n        if (ReferenceEquals(this, other))\n            return true;\n        return AppId == other.AppId \n            && Edition == other.Edition \n            && NormalizedPath == other.NormalizedPath \n            && ContentHash == other.ContentHash \n            && AppCodeHash == other.AppCodeHash;\n    }\n\n    public override bool Equals(object obj) \n        => ReferenceEquals(this, obj) || obj is CacheKey other\n            && Equals(other);\n\n    /// <summary>\n    /// Provide a fast, well-distributed hash for CacheKey so it can be used in hash-based collections (Dictionary, HashSet) consistent with Equals.\n    /// </summary>\n    /// <returns></returns>\n    public override int GetHashCode()\n    {\n        // How it works:\n        // - Seeds with AppId(an int), then mixes in all other fields with a prime multiplier 397 and XOR.\n        // - unchecked avoids overflow exceptions during arithmetic(overflow is fine for hash codes).\n        // - Uses all identity fields: AppId, Edition, NormalizedPath, ContentHash, AppCodeHash.\n        //   This matches the Equals implementation, preserving the contract: equal objects must produce equal hash codes.\n        unchecked\n        {\n            var hashCode = AppId;\n            hashCode = (hashCode * 397) ^ Edition.GetHashCode();\n            hashCode = (hashCode * 397) ^ NormalizedPath.GetHashCode();\n            hashCode = (hashCode * 397) ^ ContentHash.GetHashCode();\n            hashCode = (hashCode * 397) ^ AppCodeHash.GetHashCode();\n            return hashCode;\n        }\n    }\n\n    public static bool operator ==(CacheKey left, CacheKey right)\n        => Equals(left, right);\n\n    public static bool operator !=(CacheKey left, CacheKey right)\n        => !Equals(left, right);\n\n    #endregion\n}\n\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/CacheKeyPathUtils.cs",
    "content": "using System.Security.Cryptography;\nusing System.Text;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Internal helper for computing normalized cache key path segments and hashes.\n/// Extracted from <see cref=\"CacheKey\"/> to keep the class small and SRP-focused.\n/// </summary>\ninternal static class CacheKeyPathUtils\n{\n    internal const string RootEdition = \"root\";\n\n    internal static string NormalizePath(string templatePath, string edition, string appPath = null)\n    {\n        if (!templatePath.HasValue())\n            throw new ArgumentNullException(nameof(templatePath));\n\n        var normalizedTemplatePath = NormalizePathInt(templatePath); // lower-case, forward slashes, trimmed\n        var normalizedEdition = NormalizeEdition(edition);\n        var normalizedAppPath = NormalizePathInt(appPath);\n        var trimmedForAppScope = TrimToAppScope(normalizedTemplatePath, normalizedEdition, normalizedAppPath);\n        var sanitizedFullPath = SanitizeRelativePath(trimmedForAppScope);\n        var hash = ComputePathHash(normalizedTemplatePath);\n\n        return $\"{sanitizedFullPath}-{hash}\";\n    }\n\n    internal static string GetAppFolder(int appId, string edition)\n        => $\"{appId:0000}-{NormalizeEdition(edition)}\";\n\n    internal static string NormalizeEdition(string edition)\n        => edition.HasValue()\n            ? SanitizeSegment(edition, RootEdition)\n            : RootEdition;\n\n    private static string SanitizeSegment(string value, string fallback)\n    {\n        if (!value.HasValue())\n            return fallback;\n        var invalidChars = Path.GetInvalidFileNameChars();\n        var cleaned = new string(value.Select(ch => invalidChars.Contains(ch) ? '-' : ch).ToArray());\n        return cleaned.HasValue()\n            ? cleaned :\n            fallback;\n    }\n\n    private static string SanitizeRelativePath(string normalizedPath)\n    {\n        var sanitized = normalizedPath\n            .Replace('/', '-')\n            .Replace('\\\\', '-')\n            .Replace(\".cshtml\", \"-cshtml\")\n            .Replace('.', '-')\n            .Replace(' ', '-')\n            .Trim('-');\n\n        return SanitizeSegment(sanitized, \"template\");\n    }\n\n    private static string ComputePathHash(string normalizedPath)\n    {\n        var bytes = Encoding.UTF8.GetBytes(normalizedPath);\n        using var sha256 = SHA256.Create();\n        var hashBytes = sha256.ComputeHash(bytes);\n        var hash = BitConverter.ToString(hashBytes).Replace(\"-\", \"\").ToLowerInvariant();\n        return hash.Substring(0, 8);\n    }\n\n    private static string NormalizePathInt(string path)\n    {\n        if (!path.HasValue())\n            return null;\n\n        return path\n            .ForwardSlash()\n            .Trim('/')\n            .ToLowerInvariant();\n    }\n\n    private static string TrimToAppScope(string templatePath, string edition, string appPath)\n    {\n        var pathInAppScope = TrimAppRoot(templatePath, appPath);\n\n        if (edition.HasValue() && !string.Equals(edition, RootEdition, StringComparison.Ordinal))\n        {\n            var editionPrefix = $\"{edition}/\";\n            if (pathInAppScope.StartsWith(editionPrefix, StringComparison.Ordinal))\n                return pathInAppScope.Substring(editionPrefix.Length);\n\n            var editionSegment = $\"/{edition}/\";\n            var editionIndex = pathInAppScope.IndexOf(editionSegment, StringComparison.Ordinal);\n            if (editionIndex >= 0)\n                return pathInAppScope.Substring(editionIndex + editionSegment.Length);\n\n            var editionSuffix = $\"/{edition}\";\n            if (string.Equals(pathInAppScope, edition, StringComparison.Ordinal) || pathInAppScope.EndsWith(editionSuffix, StringComparison.Ordinal))\n                return string.Empty;\n        }\n\n        return pathInAppScope;\n    }\n\n    private static string TrimAppRoot(string templatePath, string appPath)\n    {\n        if (appPath.HasValue())\n        {\n            if (templatePath.StartsWith(appPath + \"/\", StringComparison.Ordinal))\n                return templatePath.Substring(appPath.Length + 1);\n\n            if (string.Equals(templatePath, appPath, StringComparison.Ordinal))\n                return string.Empty;\n        }\n\n        // fallback\n        const string marker = \"/2sxc/\";\n        var markerIndex = templatePath.IndexOf(marker, StringComparison.Ordinal);\n        if (markerIndex < 0)\n            return templatePath;\n\n        var appFolderStart = markerIndex + marker.Length;\n        var appFolderEnd = templatePath.IndexOf('/', appFolderStart);\n        if (appFolderEnd < 0)\n            return templatePath;\n\n        // Remove everything up to and including the app folder so the remaining path starts at the edition or deeper folders.\n        return templatePath.Substring(appFolderEnd + 1);\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/DnnRazorCompiler.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing System.Runtime.ExceptionServices;\nusing System.Web;\nusing System.Web.Compilation;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sxc.Dnn.Compile.Sys;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Caching.PiggyBack;\nusing ToSic.Sys.Exceptions;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// The Razor compiler for Razor templates.\n/// It's used in ca. 3 scenarios:\n/// \n/// 1. Render the main razor template of a module - in this case there is no `data`\n///    - it may use Roslyn or the built-in compiler\n/// 2. It's then attached to the CodeApiService as a piggyback, so it can be used to render sub-components\n/// 3. Render sub-components which need Roslyn\n///    but exit early if Roslyn isn't necessary because of problems\n///    with `data` being in `PageData` of the RazorComponent. \n/// </summary>\n[PrivateApi(\"used to be InternalApi_DoNotUse_MayChangeWithoutNotice till v16.09\")]\n[EngineDefinition(Name = \"Razor\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n// ReSharper disable once UnusedMember.Global\ninternal class DnnRazorCompiler(\n    IExecutionContextFactory exCtxFactory,\n    LazySvc<CodeErrorHelpService> errorHelp,\n    LazySvc<SourceAnalyzer> sourceAnalyzer,\n    LazySvc<IRoslynBuildManager> roslynBuildManager,\n    LazySvc<IAppJsonConfigurationService> appJson)\n    : ServiceBase(\"Dnn.RzComp\", connect: [exCtxFactory, errorHelp, sourceAnalyzer, roslynBuildManager, appJson])\n{\n    protected HotBuildSpec HotBuildSpecs;\n    [PrivateApi] protected IBlock Block;\n\n    internal void SetupCompiler(EngineSpecs engineSpecs)\n    {\n        HotBuildSpecs = engineSpecs.ToHotBuildSpec();\n        Block = engineSpecs.Block;\n    }\n\n\n    [PrivateApi]\n    private HttpContextBase HttpContextCurrent =>\n        _httpContext.Get(() => HttpContext.Current.NullOrGetWith(h => new HttpContextWrapper(h)));\n    private readonly GetOnce<HttpContextBase> _httpContext = new();\n\n    [PrivateApi]\n    internal (TextWriter writer, List<Exception> exceptions) Render(RazorComponentBase page, TextWriter writer, RenderSpecs renderSpecs)\n    {\n        var l = Log.Fn<(TextWriter writer, List<Exception> exception)>(message: \"will render into TextWriter\");\n        try\n        {\n            if (page is ISetDynamicModel setDyn)\n                setDyn.SetDynamicModel(renderSpecs);\n        }\n        catch (Exception e)\n        {\n            l.Ex(\"Problem with setting dynamic model, error will be ignored.\", e);\n        }\n\n        try\n        {\n            var webPageContext = new WebPageContext(HttpContextCurrent, page, renderSpecs.Data);\n            page.ExecutePageHierarchy(webPageContext, writer, page);\n        }\n        catch (Exception maybeIEntityCast)\n        {\n            var ex = l.Ex(errorHelp.Value.AddHelpIfKnownError(maybeIEntityCast, page));\n            // Special form of throw to preserve details about the call stack\n            ExceptionDispatchInfo.Capture(ex).Throw();\n            throw; // fake throw, just so the code shows what happens\n        }\n\n        return l.Return((writer, page.RzrHlp.ExceptionsOrNull));\n    }\n\n\n    private (TextWriter writer, List<Exception> exceptions) RenderImplementation(RazorComponentBase webpage, RenderSpecs specs)\n    {\n        ILogCall<(TextWriter writer, List<Exception> exceptions)> l = Log.Fn<(TextWriter, List<Exception>)>();\n        var writer = new StringWriter();\n        var result = Render(webpage, writer, specs);\n        return l.ReturnAsOk(result);\n    }\n\n    private RazorBuildTempResult<object> CreateWebPageInstance(string templatePath)\n    {\n        var l = Log.Fn<RazorBuildTempResult<object>>(templatePath);\n        object page = null;\n\n        Type compiledType;\n\n        // TODO: @STV SHOULD OPTIMIZE so the file doesn't need to read multiple times\n        var codeFileInfo = sourceAnalyzer.Value.TypeOfVirtualPath(templatePath);\n        \n        var useHotBuild = appJson.Value.DnnCompilerAlwaysUseRoslyn(HotBuildSpecs.AppId) || codeFileInfo.IsHotBuildSupported();\n        l.A($\"{nameof(HotBuildSpecs)} prepare spec: {HotBuildSpecs}; {nameof(useHotBuild)}: {useHotBuild}\");\n        try\n        {\n            compiledType = useHotBuild\n                ? roslynBuildManager.Value.GetCompiledType(codeFileInfo, HotBuildSpecs)\n                : BuildManager.GetCompiledType(templatePath);\n        }\n        catch (Exception compileEx)\n        {\n            // TODO: ADD MORE compile error help\n            // 1. Read file\n            // 2. Try to find base type - or warn if not found\n            // 3. ...\n            \n            l.A($\"Razor Type: {codeFileInfo}\");\n            var ex = l.Ex(errorHelp.Value.AddHelpForCompileProblems(compileEx, codeFileInfo));\n            // Special form of throw to preserve details about the call stack\n            ExceptionDispatchInfo.Capture(ex).Throw();\n            throw; // fake throw, just so the code shows what happens\n        }\n\n        try\n        {\n            if (compiledType == null)\n                return l.ReturnNull(\"type not found\");\n\n            page = TypeFactory.CreateInstance(compiledType);\n            var pageObjectValue = RuntimeHelpers.GetObjectValue(page);  // seems to do unboxing, why???\n            return l.ReturnAsOk(new(pageObjectValue, useHotBuild));\n        }\n        catch (Exception createInstanceException)\n        {\n            var ex = l.Ex(errorHelp.Value.AddHelpIfKnownError(createInstanceException, page));\n            // Special form of throw to preserve details about the call stack\n            ExceptionDispatchInfo.Capture(ex).Throw();\n            throw; // fake throw, just so the code shows what happens\n        }\n    }\n\n    public RazorBuildTempResult<RazorComponentBase> InitWebpage(string templatePath, bool exitIfNoHotBuild)\n    {\n        var l = Log.Fn<RazorBuildTempResult<RazorComponentBase>>();\n        if (string.IsNullOrEmpty(templatePath))\n            return l.ReturnNull(\"null path\");\n\n        // Try to build, but exit if we don't use HotBuild\n        var razorBuild = CreateWebPageInstance(templatePath);\n        if (exitIfNoHotBuild && !razorBuild.UsesHotBuild)\n            return l.Return(new(null, false));\n\n        var objectValue = RuntimeHelpers.GetObjectValue(razorBuild.Instance);\n        // ReSharper disable once JoinNullCheckWithUsage\n        if (objectValue == null)\n            throw new InvalidOperationException($\"The webpage found at '{templatePath}' was not created.\");\n\n        if (objectValue is not RazorComponentBase pageToInit)\n            throw new ExceptionWithHelp(HelpDbRazor.AutoInheritsMissingAfterV20,\n                new InvalidOperationException($\"The webpage at '{templatePath}' must derive from RazorComponentBase.\"));\n\n        pageToInit.Context = HttpContextCurrent;\n        pageToInit.VirtualPath = templatePath;\n        \n        InitHelpers(pageToInit);\n        return l.ReturnAsOk(new(pageToInit, razorBuild.UsesHotBuild));\n    }\n\n    private void InitHelpers(RazorComponentBase webPage)\n    {\n        var l = Log.Fn();\n        // Only generate this for the first / top EntryRazorComponent\n        // All children which are then generated here should re-use that CodeApiService\n        if (_sharedCodeApiService == null)\n        {\n            _sharedCodeApiService = exCtxFactory.New(new()\n            {\n                OwnerOrNull = webPage,\n                BlockOrNull = Block,\n                ParentLog = Log,\n                CompatibilityFallback = CompatibilityLevels.CompatibilityLevel9Old,\n            });\n\n            // Since we just created a new CodeApiService, we must add this razor engine to it's piggyback\n            _sharedCodeApiService.GetPiggyBack(nameof(DnnRazorCompiler), () => this);\n        }\n\n        webPage.ConnectToRoot(_sharedCodeApiService);\n        l.Done();\n    }\n\n    /// <summary>\n    /// Reused CodeApiService for all Razor pages.\n    /// </summary>\n    private IExecutionContext _sharedCodeApiService;\n\n    #region Helpers for Rendering Sub-Components\n\n    internal record PrepToExecute(\n        string BestPath,\n        RazorBuildTempResult<RazorComponentBase> SubPage,\n        DnnRazorCompiler Compiler);\n\n    internal static PrepToExecute PrepareForRoslyn(RazorComponentBase parent, string templatePath, object data)\n    {\n        var l = (parent as IHasLog).Log.Fn<PrepToExecute>();\n\n        // Find the RazorEngine which MUST be on the CodeApiService PiggyBack, or throw an error\n        var razorCompiler = parent.ExCtx.PiggyBack.GetOrGenerate(nameof(DnnRazorCompiler), DnnRazorCompiler () => null)\n                            ?? throw l.Ex(new Exception($\"Error finding {nameof(DnnRazorCompiler)}. This is very unexpected.\"));\n\n        var subPage = razorCompiler.InitWebpage(templatePath, true);\n\n        return l.Return(new(templatePath, subPage, razorCompiler));\n\n    }\n\n    internal static RazorBuildTempResult<HelperResult> ExecuteWithRoslyn(PrepToExecute preparations, RazorComponentBase parent, RenderSpecs renderSpecs)\n    {\n        var l = (parent as IHasLog).Log.Fn<RazorBuildTempResult<HelperResult>>();\n\n        var (writer, exceptions) = preparations.Compiler.RenderImplementation(preparations.SubPage.Instance, renderSpecs);\n\n        // Log any exceptions which may have occurred\n        if (exceptions.SafeAny())\n            exceptions.ForEach(e => l.Ex(e));\n\n        return l.ReturnAsOk(new(new(w => w.Write(writer)), true));\n    }\n    internal static RazorBuildTempResult<HelperResult> RenderPartialWithRoslyn(RazorComponentBase parent, string templatePath, object data, RenderSpecs renderSpecs)\n    {\n        var l = (parent as IHasLog).Log.Fn<RazorBuildTempResult<HelperResult>>();\n\n        // Find the RazorEngine which MUST be on the CodeApiService PiggyBack, or throw an error\n        var razorCompiler = parent.ExCtx.PiggyBack.GetOrGenerate(nameof(DnnRazorCompiler), DnnRazorCompiler () => null)\n                          ?? throw l.Ex(new Exception($\"Error finding {nameof(DnnRazorCompiler)}. This is very unexpected.\"));\n\n        // Figure out the real path, and make sure it's lower case\n        // so the ID in a cache remains the same no matter how it was called\n        var path = parent.NormalizePath(templatePath).ToLowerInvariant();\n\n        var subPage = razorCompiler.InitWebpage(path, true);\n\n        // Exit if we don't use HotBuild, because then we must revert back to classic render\n        // Reason is that otherwise the PageData property - used on very old classes - would not be populated\n        // Doing this from our compiler is super-hard, because it would use a lot of internal Microsoft APIs\n        if (!subPage.UsesHotBuild)\n            return l.Return(new(null, false), \"exit, not HotBuild\");\n\n        var (writer, exceptions) = razorCompiler.RenderImplementation(subPage.Instance, renderSpecs);\n\n        // Log any exceptions which may have occurred\n        if (exceptions.SafeAny())\n            exceptions.ForEach(e => l.Ex(e));\n\n        return l.ReturnAsOk(new(new(w => w.Write(writer)), true));\n    }\n\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/IAssemblyDiskCacheService.cs",
    "content": "using ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Abstraction for persisting compiled assemblies for Razor/code files.\n/// </summary>\npublic interface IAssemblyDiskCacheService\n{\n    /// <summary>\n    /// Attempts to load a cached assembly from disk for the specified template.\n    /// </summary>\n    AssemblyResult TryLoadFromCache(\n        HotBuildSpec spec,\n        string templateRelativePath,\n        string contentHash,\n        string appCodeHash,\n        AssemblyResult appCodeDependency,\n        CodeFileInfo codeFileInfo);\n\n    /// <summary>\n    /// Saves a compiled assembly to disk cache for future reuse.\n    /// </summary>\n    bool TrySaveToCache(\n        HotBuildSpec spec,\n        string templateRelativePath,\n        string contentHash,\n        string appCodeHash,\n        AssemblyResult assemblyResult);\n\n    /// <summary>\n    /// Builds the full cache file path for the given template/spec combination.\n    /// </summary>\n    string GetCacheFilePath(\n        HotBuildSpec spec,\n        string templateRelativePath,\n        string contentHash,\n        string appCodeHash);\n\n    /// <summary>\n    /// Invalidates cached assemblies for a specific template path / edition combination.\n    /// </summary>\n    void InvalidateCache(string templateRelativePath, string edition, string appPath = null);\n\n    /// <summary>\n    /// Invalidates (deletes) cached assemblies for a specific app and edition.\n    /// </summary>\n    void InvalidateAppCache(int appId, string edition);\n\n    /// <summary>\n    /// Checks if disk caching is enabled based on feature flag.\n    /// </summary>\n    bool IsEnabled();\n\n    /// <summary>\n    /// Gets the physical path to the cache directory.\n    /// </summary>\n    string GetCacheDirectoryPath();\n\n    /// <summary>\n    /// Computes SHA256 hash of the given content string.\n    /// </summary>\n    string ComputeContentHash(string sourceCode);\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/ICanUseRoslynCompiler.cs",
    "content": "﻿\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Marker interface so the system knows that this is a Razor file which can use Roslyn compiler\n/// </summary>\ninternal interface ICanUseRoslynCompiler;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/RazorBuildTempResult.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn.Razor.Sys;\n\ninternal class RazorBuildTempResult<T>(T instance, bool usesHotBuild)\n{\n    public T Instance { get; set; } = instance;\n    public bool UsesHotBuild { get; set; } = usesHotBuild;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/RazorCompilerService.cs",
    "content": "using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;\nusing System.CodeDom.Compiler;\nusing System.Reflection;\nusing System.Text.RegularExpressions;\nusing System.Web.Razor;\nusing System.Web.Razor.Generator;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Service responsible for compiling Razor templates (.cshtml) into assemblies.\n/// </summary>\npublic class RazorCompilerService(\n    MemoryCacheService memoryCacheService,\n    IAssemblyDiskCacheService diskCacheService)\n    : ServiceBase(\"Dnn.RzrCmpSvc\", connect: [memoryCacheService, diskCacheService])\n{\n    private const string FallbackBaseClass = \"System.Web.WebPages.WebPageBase\";\n    private const string CSharpCodeProviderCacheKey = \"Sxc-Dnn-CSharpCodeProvider\";\n    private const int CSharpCodeProviderCacheMinutes = 5;\n\n    internal const string DefaultNamespace = \"RazorHost\";\n\n    /// <summary>\n    /// Compiles Razor source code into an assembly.\n    /// </summary>\n    public (Assembly Assembly, List<CompilerError> Errors) Compile(\n        string sourceCode, \n        List<string> referencedAssemblies, \n        string className, \n        string sourceFileName, \n        string outputAssemblyPath = null)\n    {\n        var l = Log.Fn<(Assembly, List<CompilerError>)>(timer: true, parameters: $\"sourceCode: {sourceCode.Length} chars\");\n\n        var baseClass = FindBaseClass(sourceCode);\n        l.A($\"Base class: {baseClass}\");\n\n        var engine = CreateRazorTemplateEngine(className, baseClass, DefaultNamespace);\n\n        // Generate C# code from Razor template\n        var lTimer = Log.Fn(\"Generate Code\", timer: true);\n        using var reader = new StringReader(sourceCode);\n        var razorResults = engine.GenerateCode(reader, className, DefaultNamespace, sourceFileName);\n        lTimer.Done();\n\n        // Compile the template into an assembly\n        var compiler = GetCSharpCodeProvider();\n        lTimer = Log.Fn(\"Compile\", timer: true);\n        var compilerParameters = CreateCompilerParameters(referencedAssemblies, outputAssemblyPath);\n        var compilerResults = compiler.CompileAssemblyFromDom(compilerParameters, razorResults.GeneratedCode);\n        lTimer.Done();\n\n        if (compilerResults.Errors.Count <= 0)\n            return l.ReturnAsOk((compilerResults.CompiledAssembly, null));\n\n        var errorList = compilerResults.Errors.Cast<CompilerError>().Where(e => !e.IsWarning).ToList();\n\n        return (!errorList.Any())\n            ? l.ReturnAsOk((compilerResults.CompiledAssembly, null))\n            : l.ReturnAsError((null, errorList), \"error\");\n    }\n\n    private string FindBaseClass(string template)\n    {\n        var l = Log.Fn<string>($\"template: {template.Length} chars\");\n        \n        try\n        {\n            var inheritsMatch = Regex.Match(template, @\"@inherits\\s+(?<BaseName>[\\w\\.]+)\", RegexOptions.Multiline);\n\n            if (!inheritsMatch.Success)\n                return l.Return(FallbackBaseClass, $\"no @inherits found, fallback to '{FallbackBaseClass}'\");\n\n            var baseClass = inheritsMatch.Groups[\"BaseName\"].Value;\n            if (baseClass.IsEmptyOrWs())\n                return l.Return(FallbackBaseClass, $\"@inherits empty string, fallback to '{FallbackBaseClass}'\");\n\n            return l.ReturnAsOk(baseClass);\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnAsError(FallbackBaseClass, \"error\");\n        }\n    }\n\n    private RazorTemplateEngine CreateRazorTemplateEngine(string className, string baseClass, string defaultNamespace)\n    {\n        var l = Log.Fn<RazorTemplateEngine>($\"className: '{className}'; baseClass: '{baseClass}'\", timer: true);\n\n        var host = new RazorEngineHost(new CSharpRazorCodeLanguage())\n        {\n            DefaultBaseClass = baseClass,\n            DefaultClassName = className,\n            DefaultNamespace = defaultNamespace\n        };\n\n        var context = new GeneratedClassContext(\n            \"Execute\",\n            \"Write\",\n            \"WriteLiteral\",\n            \"WriteTo\",\n            \"WriteLiteralTo\",\n            typeof(HelperResult).FullName,\n            \"DefineSection\")\n        {\n            ResolveUrlMethodName = \"ResolveUrl\"\n        };\n\n        host.GeneratedClassContext = context;\n\n        // add implicit usings\n        foreach (var ns in ImplicitUsings.ForRazor) \n            host.NamespaceImports.Add(ns);\n\n        var engine = new RazorTemplateEngine(host);\n        return l.ReturnAsOk(engine);\n    }\n\n    private CSharpCodeProvider GetCSharpCodeProvider()\n    {\n        var l = Log.Fn<CSharpCodeProvider>(timer: true);\n        \n        if (memoryCacheService.TryGet<CSharpCodeProvider>(CSharpCodeProviderCacheKey, out var fromCache))\n            return l.Return(fromCache, \"from cached\");\n\n        var codeProvider = new CSharpCodeProvider();\n        memoryCacheService.Set(CSharpCodeProviderCacheKey, codeProvider, p => p.SetSlidingExpiration(CSharpCodeProviderCacheMinutes * 60));\n\n        return l.Return(codeProvider, \"created new and cached\");\n    }\n\n    private CompilerParameters CreateCompilerParameters(List<string> referencedAssemblies, string outputAssemblyPath)\n    {\n        var compilerParameters = new CompilerParameters([.. referencedAssemblies])\n        {\n            GenerateInMemory = !diskCacheService.IsEnabled() && string.IsNullOrEmpty(outputAssemblyPath),\n            IncludeDebugInformation = true,\n            TreatWarningsAsErrors = false,\n            CompilerOptions = DnnRoslynConstants.CompilerOptions,\n        };\n\n        if (diskCacheService.IsEnabled() && !string.IsNullOrEmpty(outputAssemblyPath))\n        {\n            var outDir = Path.GetDirectoryName(outputAssemblyPath);\n            if (outDir.HasValue()) \n                Directory.CreateDirectory(outDir);\n            \n            compilerParameters.OutputAssembly = outputAssemblyPath;\n            compilerParameters.TempFiles = new TempFileCollection(EnsureTempDir());\n        }\n\n        return compilerParameters;\n    }\n\n    private string EnsureTempDir()\n    {\n        var cacheRoot = diskCacheService.GetCacheDirectoryPath();\n        var tempDir = Path.Combine(cacheRoot, \"temp\");\n        if (!Directory.Exists(tempDir))\n            Directory.CreateDirectory(tempDir);\n        return tempDir;\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/RoslynBuildManager.cs",
    "content": "using ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sys.Locking;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Coordinates Razor compilation by delegating heavy work to <see cref=\"RoslynCompilationRunner\"/>.\n/// Ensures caching/locking concerns stay isolated.\n/// </summary>\npublic class RoslynBuildManager(\n    TemplateCacheService cacheService,\n    RoslynCompilationRunner compilationRunner)\n    : ServiceBase(\"Dnn.RoslynBuildManager\", connect: [cacheService, compilationRunner]),\n        IRoslynBuildManager\n{\n    private static readonly NamedLocks CompileAssemblyLocks = new();\n\n    /// <summary>\n    /// Manage template compilations, cache the assembly and return the generated type.\n    /// </summary>\n    public Type GetCompiledType(CodeFileInfo codeFileInfo, HotBuildSpec spec)\n        => GetCompiledAssembly(codeFileInfo, null, spec)?.MainType;\n\n    public AssemblyResult GetCompiledAssembly(CodeFileInfo codeFileInfo, string className, HotBuildSpec spec)\n    {\n        var l = Log.Fn<AssemblyResult>($\"{codeFileInfo}; {spec};\");\n        var lockObject = CompileAssemblyLocks.Get(codeFileInfo.FullPath!);\n        var cachedResult = cacheService.TryGetFromCache(codeFileInfo, spec);\n        var cacheMissLogged = false;\n\n        var (result, generated, message) = new TryLockTryDo(lockObject).Call(\n            conditionToGenerate: ShouldGenerate,\n            generator: () => compilationRunner.Compile(codeFileInfo, className, spec),\n            cacheOrFallback: CacheOrFallback);\n\n        if (!generated)\n            LogCacheFallback(result, message, codeFileInfo, l);\n\n        return l.Return(result, message);\n\n        AssemblyResult CacheOrFallback()\n            => cachedResult ?? cacheService.TryGetFromCache(codeFileInfo, spec);\n\n        bool ShouldGenerate()\n        {\n            if (cachedResult?.MainType != null)\n                return false;\n\n            cachedResult = cacheService.TryGetFromCache(codeFileInfo, spec);\n            if (cachedResult?.MainType != null)\n                return false;\n\n            if (!cacheMissLogged)\n            {\n                l.A(\"Cache miss - will compile template\");\n                cacheMissLogged = true;\n            }\n\n            return true;\n        }\n    }\n\n    private static void LogCacheFallback(AssemblyResult result, string message, CodeFileInfo codeFileInfo, ILog l)\n    {\n        l.A(\"Object retrieved from cache during lock wait\");\n        l.A($\"{nameof(result)}: {result}\");\n        l.A($\"{nameof(result.MainType)}: {result?.MainType}\");\n        l.A($\"{nameof(result.HasAssembly)}: {result?.HasAssembly}\");\n        l.A($\"{nameof(message)}: {message}\");\n        l.A($\"{nameof(codeFileInfo)}: {codeFileInfo}\");\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/RoslynCacheFallbackHandler.cs",
    "content": "using System.CodeDom.Compiler;\nusing System.Reflection;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Handles reuse of existing assemblies when the compiler cannot overwrite locked files.\n/// </summary>\npublic class RoslynCacheFallbackHandler(\n    IAssemblyDiskCacheService diskCacheService,\n    TemplateCacheService cacheService,\n    AssemblyDiskCache diskCache)\n    : ServiceBase(\"Dnn.RzCacheFb\", connect: [diskCacheService, cacheService, diskCache])\n{\n    public AssemblyResult TryUseExisting(\n        CodeFileInfo codeFileInfo,\n        HotBuildSpec spec,\n        string className,\n        bool isCshtml,\n        string contentHash,\n        TemplateCacheService.AppCodeCacheInfo appCodeInfo,\n        string outputAssemblyPath,\n        List<CompilerError> errors,\n        AssemblyResult appCodeAssemblyResult,\n        Func<Assembly, AssemblyResult> createResult)\n    {\n        var l = Log.Fn<AssemblyResult>(timer: true);\n\n        if (errors == null || !IsWriteLockError(errors))\n            return l.ReturnNull();\n\n        var cached = diskCacheService.TryLoadFromCache(\n            spec,\n            codeFileInfo.RelativePath,\n            contentHash,\n            appCodeInfo.Hash,\n            appCodeInfo.AssemblyResult,\n            codeFileInfo);\n\n        if (cached != null)\n        {\n            l.A($\"Compiler couldn't write to '{outputAssemblyPath}' (locked). Using cached assembly (hash match).\");\n            cacheService.AddToCache(codeFileInfo, spec, cached, contentHash, appCodeInfo.Hash, appCodeInfo.AssemblyResult);\n            return l.ReturnAsOk(cached);\n        }\n\n        if (!outputAssemblyPath.HasValue() || !File.Exists(outputAssemblyPath) || !diskCacheService.IsEnabled())\n            return l.ReturnNull();\n\n        l.A($\"Attempting to load locked assembly directly from '{outputAssemblyPath}'.\");\n\n        Assembly loaded;\n        try\n        {\n            loaded = diskCache.LoadWithRetry(\n                outputAssemblyPath,\n                loadAssembly: path => Assembly.Load(File.ReadAllBytes(path)));\n        }\n        catch (Exception ex)\n        {\n            Log.Ex(ex);\n            l.E($\"Failed to load locked assembly '{outputAssemblyPath}' via retry helper: {ex.Message}\");\n            return l.ReturnNull();\n        }\n\n        //// ReSharper disable once ConditionIsAlwaysTrueOrFalse\n        //if (loaded == null)\n        //    return l.ReturnNull();\n\n        var result = createResult(loaded);\n        cacheService.AddToCache(codeFileInfo, spec, result, contentHash, appCodeInfo.Hash, appCodeInfo.AssemblyResult);\n        l.A($\"Loaded locked assembly from '{outputAssemblyPath}' after write error.\");\n        return l.ReturnAsOk(result);\n    }\n\n    private static bool IsWriteLockError(IEnumerable<CompilerError> errors)\n        => errors.Where(e => !e.IsWarning).Any(error\n            => string.Equals(error.ErrorNumber, \"CS0016\", StringComparison.OrdinalIgnoreCase)\n            || error.ErrorText?.IndexOf(\"because it is being used by another process\", StringComparison.OrdinalIgnoreCase) >= 0\n            || (error.ErrorText?.IndexOf(\"Cannot open\", StringComparison.OrdinalIgnoreCase) >= 0\n                && error.ErrorText?.IndexOf(\"for writing\", StringComparison.OrdinalIgnoreCase) >= 0));\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/RoslynCompilationRunner.cs",
    "content": "using System.Reflection;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Dnn.Compile;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Handles the heavy lifting of compiling Razor templates and managing cache fallbacks.\n/// Keeps <see cref=\"RoslynBuildManager\"/> small and focused on orchestration.\n/// </summary>\npublic class RoslynCompilationRunner(\n    TemplateCacheService cacheService,\n    RazorCompilerService razorCompiler,\n    CSharpCompilerService csharpCompiler,\n    IAssemblyDiskCacheService diskCacheService,\n    IReferencedAssembliesProvider referencedAssembliesProvider,\n    AssemblyUtilities assemblyUtilities,\n    AssemblyResolver assemblyResolver,\n    LazySvc<AppCodeLoader> appCodeLoader,\n    RoslynCacheFallbackHandler fallbackHandler)\n    : ServiceBase(\"Dnn.RzCmpRun\", connect: [cacheService, razorCompiler, csharpCompiler, diskCacheService, referencedAssembliesProvider, assemblyUtilities, assemblyResolver, appCodeLoader, fallbackHandler])\n{\n    public AssemblyResult Compile(CodeFileInfo codeFileInfo, string className, HotBuildSpec spec)\n    {\n        var l = Log.Fn<AssemblyResult>($\"{codeFileInfo}; {spec};\", timer: true);\n\n        var appCodeInfo = cacheService.GetAppCodeCacheInfo(spec);\n        var (referencedAssemblies, appCodeAssemblyResult) = GetReferencedAssemblies(codeFileInfo, spec, appCodeInfo.AssemblyResult);\n\n        var contentHash = diskCacheService.ComputeContentHash(codeFileInfo.SourceCode);\n        var outputAssemblyPath = GetOutputAssemblyPath(codeFileInfo, spec, contentHash, appCodeInfo.Hash);\n        var pathLowerCase = codeFileInfo.RelativePath!.ToLowerInvariant();\n        var isCshtml = pathLowerCase.EndsWith(SourceCodeConstants.CsHtmlFileExtension, StringComparison.OrdinalIgnoreCase);\n\n        if (isCshtml)\n            className = assemblyUtilities.GetSafeClassName(codeFileInfo.FullPath);\n\n        l.A($\"Compiling template. Class: {className}; IsCshtml: {isCshtml}; Output: {outputAssemblyPath}\");\n\n        var (generatedAssembly, errors) = isCshtml\n            ? razorCompiler.Compile(codeFileInfo.SourceCode, referencedAssemblies, className, codeFileInfo.FullPath, outputAssemblyPath)\n            : csharpCompiler.Compile(codeFileInfo.SourceCode, referencedAssemblies, outputAssemblyPath);\n\n        if (generatedAssembly == null)\n        {\n            var fallback = fallbackHandler.TryUseExisting(\n                codeFileInfo,\n                spec,\n                className,\n                isCshtml,\n                contentHash,\n                appCodeInfo,\n                outputAssemblyPath,\n                errors,\n                appCodeAssemblyResult,\n                assembly => CreateAssemblyResult(assembly, className, isCshtml, codeFileInfo, appCodeAssemblyResult));\n\n            if (fallback != null)\n                return l.ReturnAsOk(fallback);\n\n            throw l.Ex(new Exception(\n                $\"Found {errors.Count} errors compiling '{codeFileInfo.FullPath}' \" +\n                $\"(length: {codeFileInfo.SourceCode!.Length}, lines: {codeFileInfo.SourceCode.Split('\\n').Length}): \" +\n                $\"{assemblyUtilities.FormatCompilerErrors(errors)}\")\n            );\n        }\n\n        var assemblyResult = CreateAssemblyResult(generatedAssembly, className, isCshtml, codeFileInfo, appCodeAssemblyResult);\n        cacheService.AddToCache(codeFileInfo, spec, assemblyResult, contentHash, appCodeInfo.Hash, appCodeAssemblyResult);\n        return l.ReturnAsOk(assemblyResult);\n    }\n\n    private string GetOutputAssemblyPath(CodeFileInfo codeFileInfo, HotBuildSpec spec, string contentHash, string appCodeHash)\n    {\n        var l = Log.Fn<string>(timer: true);\n\n        if (!diskCacheService.IsEnabled())\n            return l.ReturnNull();\n\n        var outputPath = diskCacheService.GetCacheFilePath(spec, codeFileInfo.RelativePath, contentHash, appCodeHash);\n        if (!outputPath.HasValue())\n            return l.ReturnNull($\"{nameof(outputPath)} is null/empty\");\n\n        var directoryName = Path.GetDirectoryName(outputPath);\n        if (directoryName.HasValue())\n            Directory.CreateDirectory(directoryName!);\n\n        return l.ReturnAsOk(outputPath);\n    }\n\n    private (List<string>, AssemblyResult) GetReferencedAssemblies(CodeFileInfo codeFileInfo, HotBuildSpec spec, AssemblyResult preloadedAppCode)\n    {\n        var l = Log.Fn<(List<string>, AssemblyResult)>(timer: true);\n\n        var referencedAssemblies = referencedAssembliesProvider.Locations(codeFileInfo.RelativePath, spec) ?? [];\n        var appCodeAssemblyResult = EnsureAppCodeAssembly(preloadedAppCode, spec);\n\n        assemblyResolver.AddAssembly(appCodeAssemblyResult?.Assembly);\n\n        var appCodeAssembly = appCodeAssemblyResult?.Assembly;\n        if (appCodeAssembly?.Location is { } assemblyLocation && !referencedAssemblies.Contains(assemblyLocation, StringComparer.OrdinalIgnoreCase))\n        {\n            referencedAssemblies.Add(assemblyLocation);\n            l.A($\"Added reference to AppCode assembly: {assemblyLocation}\");\n        }\n\n        return l.ReturnAsOk((referencedAssemblies, appCodeAssemblyResult));\n    }\n\n    private AssemblyResult EnsureAppCodeAssembly(AssemblyResult appCodeAssemblyResult, HotBuildSpec spec)\n    {\n        var l = Log.Fn<AssemblyResult>(timer: true);\n\n        if (appCodeAssemblyResult != null)\n            return l.Return(appCodeAssemblyResult, $\"OK, {nameof(appCodeAssemblyResult)} has value.\");\n\n        var (loaded, _) = appCodeLoader.Value.GetAppCode(spec);\n        return l.Return(loaded, $\"{nameof(loaded)}\");\n    }\n\n    private AssemblyResult CreateAssemblyResult(Assembly generatedAssembly, string className, bool isCshtml, CodeFileInfo codeFileInfo, AssemblyResult appCodeAssemblyResult)\n    {\n        var l = Log.Fn<AssemblyResult>(timer: true);\n\n        var mainType = assemblyUtilities.FindMainType(generatedAssembly, className, isCshtml);\n        l.A($\"Main type: {mainType}\");\n\n        var assemblyResult = new AssemblyResult(generatedAssembly)\n        {\n            SafeClassName = className,\n            MainType = mainType,\n            CacheDependencyId = AssemblyCacheManager.KeyTemplate(codeFileInfo.FullPath!),\n            AppCodeDependency = appCodeAssemblyResult\n        };\n\n        return l.ReturnAsOk(assemblyResult);\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Razor/Sys/TemplateCacheService.cs",
    "content": "using System.Reflection;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Dnn.Razor.Sys;\n\n/// <summary>\n/// Service responsible for managing template cache operations (memory and disk).\n/// </summary>\npublic class TemplateCacheService(\n    AssemblyCacheManager assemblyCacheManager,\n    IAssemblyDiskCacheService diskCacheService,\n    LazySvc<AppCodeLoader> appCodeLoader)\n    : ServiceBase(\"Dnn.TmpCchSvc\", connect: [assemblyCacheManager, diskCacheService, appCodeLoader])\n{\n    /// <summary>\n    /// Try to get cached assembly from memory or disk cache.\n    /// </summary>\n    public AssemblyResult TryGetFromCache(CodeFileInfo codeFileInfo, HotBuildSpec spec)\n    {\n        var l = Log.Fn<AssemblyResult>($\"{codeFileInfo}\");\n\n        // Check memory cache first\n        var memoryResult = assemblyCacheManager.TryGetTemplate(codeFileInfo.FullPath!);\n        if (memoryResult?.MainType != null)\n            return l.Return(memoryResult, \"from memory cache\");\n\n        // Memory cache miss - try disk cache\n        l.A(\"Memory cache miss - checking disk cache\");\n\n        if (!diskCacheService.IsEnabled())\n        {\n            l.A(\"Disk cache disabled via feature flag\");\n            return l.ReturnNull(\"disk cache disabled\");\n        }\n\n        // Use the same AppCode snapshot (hash + dependency) for disk lookups and later caching\n        var appCodeInfo = GetAppCodeCacheInfo(spec);\n        var contentHash = diskCacheService.ComputeContentHash(codeFileInfo.SourceCode);\n        var diskResult = diskCacheService.TryLoadFromCache(\n            spec,\n            codeFileInfo.RelativePath,\n            contentHash,\n            appCodeInfo.Hash,\n            appCodeInfo.AssemblyResult,\n            codeFileInfo);\n        \n        if (diskResult == null)\n            return l.ReturnNull(\"disk cache miss\");\n\n        l.A($\"Disk cache hit for template: {codeFileInfo.RelativePath}\");\n        \n        // Add to memory cache for faster subsequent access\n        AddToMemoryCache(codeFileInfo, diskResult, [codeFileInfo.FullPath], diskResult.AppCodeDependency == null ? null : [diskResult.AppCodeDependency]);\n        \n        return l.Return(diskResult, \"from disk cache\");\n    }\n\n    /// <summary>\n    /// Add compiled assembly to memory and disk cache.\n    /// </summary>\n    public void AddToCache(CodeFileInfo codeFileInfo, HotBuildSpec spec, AssemblyResult assemblyResult, \n        string contentHash, string appCodeHash, AssemblyResult appCodeAssemblyResult)\n    {\n        var l = Log.Fn($\"{codeFileInfo}\");\n\n        // Add to memory cache\n        var dependencies = appCodeAssemblyResult == null ? null : new ICanBeCacheDependency[] { appCodeAssemblyResult };\n        AddToMemoryCache(codeFileInfo, assemblyResult, [codeFileInfo.FullPath], dependencies);\n\n        // Save to disk cache\n        diskCacheService.TrySaveToCache(spec, codeFileInfo.RelativePath, contentHash, appCodeHash, assemblyResult);\n\n        l.Done();\n    }\n\n    /// <summary>\n    /// Gets the hash of the AppCode assembly for cache invalidation.\n    /// </summary>\n    public string GetAppCodeHash(HotBuildSpec spec)\n        => GetAppCodeCacheInfo(spec).Hash;\n\n    internal AppCodeCacheInfo GetAppCodeCacheInfo(HotBuildSpec spec)\n    {\n        var l = Log.Fn<AppCodeCacheInfo>($\"{spec}\");\n\n        var (appCodeAssemblyResult, _) = appCodeLoader.Value.GetAppCode(spec);\n        var hash = ComputeAppCodeHash(appCodeAssemblyResult?.Assembly);\n\n        return l.Return(new AppCodeCacheInfo(appCodeAssemblyResult, hash));\n    }\n\n    private static string ComputeAppCodeHash(Assembly appCodeAssembly)\n    {\n        if (appCodeAssembly == null)\n            return string.Empty;\n\n        var assemblyFullName = appCodeAssembly.FullName ?? string.Empty;\n\n        using var sha256 = System.Security.Cryptography.SHA256.Create();\n        var bytes = System.Text.Encoding.UTF8.GetBytes(assemblyFullName);\n        var hashBytes = sha256.ComputeHash(bytes);\n        return BitConverter.ToString(hashBytes).Replace(\"-\", \"\").ToLowerInvariant();\n    }\n\n    private void AddToMemoryCache(CodeFileInfo codeFileInfo, AssemblyResult assemblyResult, \n        string[] filePaths, ICanBeCacheDependency[] dependencies = null)\n    {\n        assemblyResult.CacheDependencyId = AssemblyCacheManager.KeyTemplate(codeFileInfo.FullPath!);\n        assemblyCacheManager.Add(\n            cacheKey: assemblyResult.CacheDependencyId,\n            data: assemblyResult,\n            slidingDuration: CacheConstants.DurationRazorAndCode,\n            filePaths: filePaths,\n            dependencies: dependencies\n        );\n    }\n\n    public sealed class AppCodeCacheInfo(AssemblyResult assemblyResult, string hash)\n    {\n        public AssemblyResult AssemblyResult { get; } = assemblyResult;\n        public string Hash { get; } = hash;\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/RazorCodeManager.cs",
    "content": "﻿using System.Web;\nusing ToSic.Razor.Blade;\n\n#pragma warning disable CS0618\n\nnamespace ToSic.Sxc.Dnn;\n\ninternal class RazorCodeManager(RazorComponentBase parent, ILog parentLog) : HelperBase(parentLog, \"Rzr.Code\")\n{\n    public RazorComponentBase Parent = parent;\n\n    /// <summary>\n    /// The compiled code - or null\n    /// </summary>\n    private object _code;\n\n    /// <summary>\n    /// Determines if code has been compiled (or at least attempted)\n    /// </summary>\n    protected bool BuildComplete;\n\n    /// <summary>\n    /// Copy of any exception thrown when compiling the code\n    /// </summary>\n    protected Exception BuildException;\n\n    /// <summary>\n    ///  This tries to get the code and will show an exception if not ready. \n    /// </summary>\n    public dynamic CodeOrException\n    {\n        get\n        {\n            TryToBuildCode();\n            if (BuildException == null) return _code;\n            throw ImproveExceptionMessage(BuildException);\n        }\n    }\n\n    /// <summary>\n    /// Internal accessor for the code, which does not throw exceptions but returns a null if not available\n    /// </summary>\n    internal dynamic CodeOrNull\n    {\n        get\n        {\n            TryToBuildCode();\n            return _code;\n        }\n    }\n\n    /// <summary>\n    /// Try to build the code. If something fails, remember the exception in case we need it later.\n    /// </summary>\n    private bool TryToBuildCode()\n    {\n        var l = Log.Fn<bool>();\n        if (BuildComplete) return l.Return(true);\n        var codeFile = Parent.VirtualPath.Replace(\".cshtml\", \".code.cshtml\").Backslash().AfterLast(\"\\\\\");\n        l.A($\"Will try to load code from '{codeFile}\");\n        try\n        {\n            var compiled = Parent.RzrHlp.CreateInstance(codeFile);\n            if (compiled != null && compiled is not RazorComponentCode)\n                throw new(\n                    $\"Tried to compile the .Code file, but the type is '{compiled.GetType().Name}'. \" +\n                    $\"Expected that it inherits from '{nameof(RazorComponentCode)}'. \" +\n                    \"Please add '@inherits ToSic.Sxc.Dnn.RazorComponentCode' to the beginning of the 'xxx.code.cshtml' file. \");\n\n            _code = compiled;\n        }\n        catch (Exception e)\n        {\n            BuildException = e;\n        }\n\n        BuildComplete = true;\n        return l.Return(true, \"code completed\" + (BuildException == null ? \"\" : \" with BuildExceptions\"));\n    }\n\n    private static Exception ImproveExceptionMessage(Exception innerException)\n    {\n        switch (innerException)\n        {\n            case FileNotFoundException _:\n                return new(\"Tried to compile matching .Code file - but couldn't find it. \\n\", innerException);\n            case HttpCompileException _:\n                return new(\"Error compiling .Code file. \\n\", innerException);\n            default:\n                return innerException;\n        }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/RazorComponent.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// The base class for Razor-Components in 2sxc 10+ to 2sxc 11 - deprecated now<br/>\n/// Provides context infos like the Dnn object, helpers like Edit and much more. <br/>\n/// </summary>\n[PublicApi(\"...but deprecated! use Razor14, RazorTyped or newer\")]\npublic abstract partial class RazorComponent : RazorComponentBase,\n    IDynamicCode,\n    IHasDnn,\n    // previous\n    IDnnRazorCompatibility,\n    IDnnRazor11,\n    ICreateInstance,\n    // new\n    IHasCodeHelp\n{\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc />\n    public IDnnContext Dnn => (ExCtx as IHasDnn)?.Dnn;\n\n    public const string NotImplementedUseCustomBase = \"Use a newer base class like Custom.Hybrid.Razor12 or Custom.Dnn.Razor12 to leverage this.\";\n\n    #region Core Properties which should appear in docs\n\n    /// <inheritdoc />\n    public override ICodeLog Log => RzrHlp.CodeLog;\n\n    /// <inheritdoc />\n    public override IHtmlHelper Html => RzrHlp.Html;\n\n    #endregion\n\n    #region Link, Edit, Dnn, App, Data\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi.Edit;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    [PrivateApi] public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel10;\n\n    /// <inheritdoc />\n    public new IApp App => CodeApi.App;\n\n    #endregion\n\n    #region Data - with old interface #DataInAddWontWork\n\n    [PrivateApi]\n    public IDataSource Data => /*(IBlockDataSource)*/CodeApi.Data;\n\n    //// This is explicitly implemented so the interfaces don't complain\n    //// but actually we're not showing this - in reality we're showing the Old (see above)\n    //IDataSource IDynamicCode.Data => CodeApi.Data;\n\n    #endregion\n\n\n    #region AsDynamic in many variations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(string json, string fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    #endregion\n\n    #region AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n\n    #region Data Source Stuff\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    #endregion\n\n\n    #region Content, Header, etc. and List\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic Content => CodeApi.Content;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic Header => CodeApi.Header;\n\n    #endregion\n\n\n    #region Adam \n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    #endregion\n\n    #region CmsContext\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    #endregion\n\n    #region CreateInstance\n\n    [PrivateApi] string IGetCodePath.CreateInstancePath { get; set; }\n\n    /// <inheritdoc />\n    public virtual dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => RzrHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    #endregion\n\n    // Added this in v20 to show uses of GetBestValue; but much of it may not be applicable, in which case we should create a separate list for SexyContentWebPage and Dnn.RazorComponent\n    [PrivateApi] List<CodeHelp> IHasCodeHelp.ErrorHelpers => HelpDbRazor.CompileRazorOrCode12;\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/RazorComponentCode.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// This is the type used by code-behind classes of razor components.\n/// Use it to move logic / functions etc. into a kind of code-behind razor instead of as part of your view-template.\n/// </summary>\n[PrivateApi(\"Made private in v16.02 since it shouldn't be used any more\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[Obsolete(\"Shouldn't be used any more, but will continue to work for indefinitely. There are now better ways of doing this\")]\npublic abstract class RazorComponentCode: RazorComponent;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/RazorComponent_Code.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn;\n\nabstract partial class RazorComponent\n{\n    #region Code Behind - a Dnn feature which probably won't exist in Oqtane\n\n    [PrivateApi]\n    internal RazorCodeManager CodeManager => field ??= new(this, Log?.GetContents());\n\n    /// <inheritdoc />\n    public dynamic Code => CodeManager.CodeOrException;\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Dnn/Web/IHtmlHelper.cs",
    "content": "﻿using System.Web;\n\nnamespace ToSic.Sxc.Dnn.Web;\n\n/// <summary>\n/// Helper to quickly \"raw\" some html.\n/// **Important**: When using Oqtane, the Html object has many more features - check the .net documentation. \n/// </summary>\n[PublicApi]\npublic interface IHtmlHelper\n{\n    /// <summary>\n    /// Returns a HtmlString which Razor will output as Raw Html.\n    /// </summary>\n    /// <returns>\n    /// An HtmlString object which will be not be html-encoded when added to a page with @Html.Raw(...)\n    /// </returns>\n    IHtmlString Raw(object stringHtml);\n\n    /// <summary>\n    /// Render a razor file to the page.\n    /// This mimics the .net core API Html.Partial() in DNN\n    /// </summary>\n    /// <param name=\"relativePath\">path/file of razor, like \"../shared/_list-item.cshtml\"</param>\n    /// <param name=\"data\">TODO new v16.00</param>\n    /// <returns></returns>\n    IHtmlString Partial(string relativePath, object data = default);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Web.WebPages;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Eav.DataSource;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sxc.Code;\nglobal using ToSic.Sxc.Code.Sys;\nglobal using ToSic.Sxc.Context;\nglobal using ToSic.Sxc.Dnn.Web;\nglobal using ToSic.Sxc.Services;\nglobal using ToSic.Sxc.Web;\nglobal using ToSic.Sys.Utils;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.SystemTests\")]\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/ToSic.Sxc.Dnn.Razor.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-NetFramework.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>ToSic.Sxc</RootNamespace>\n    <AssemblyName>ToSic.Sxc.Dnn.Razor</AssemblyName>\n\n    <TargetFrameworkProfile />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <!-- ignore warning that Dnn was loaded 2x - ATM necessary for MS build? @STV -->\n    <NoWarn>$(NoWarn);MSB4011</NoWarn>\n    <!-- ignore warning that it's using a dangerous version of Dnn (v9.6.1) @2dm -->\n    <NoWarn>$(NoWarn);NU1902</NoWarn>\n\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RunPostBuildEvent>Always</RunPostBuildEvent>\n  </PropertyGroup>\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);MSB3277</NoWarn>\n    <LangVersion>preview</LangVersion>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageReference Include=\"DotNetNuke.Core\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.AspNet.Razor\" Version=\"3.2.9\" />\n    <PackageReference Include=\"Microsoft.CodeDom.Providers.DotNetCompilerPlatform\" Version=\"3.6.0\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.configuration\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Runtime.Caching\" />\n    <Reference Include=\"System.Web\" />\n    <Reference Include=\"System.Web.Razor\">\n      <HintPath>..\\..\\packages\\microsoft.aspnet.razor\\3.2.9\\lib\\net45\\System.Web.Razor.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.WebPages\">\n      <HintPath>..\\..\\..\\Dependencies\\System.Web\\System.Web.WebPages.dll</HintPath>\n      <Private>False</Private>\n      <SpecificVersion>False</SpecificVersion>\n    </Reference>\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.DataSources\\ToSic.Eav.DataSources.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Code.HotBuild\\ToSic.Sxc.Code.HotBuild.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Engines\\ToSic.Sxc.Engines.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.LightSpeed\\ToSic.Sxc.LightSpeed.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Dnn.Core\\ToSic.Sxc.Dnn.Core.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/ToSic.Sxc.Dnn.Razor.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=engines_005Crazor/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.Razor/Web/RazorComponentBase.cs",
    "content": "﻿using Custom.Razor.Sys;\nusing ToSic.Sxc.Dnn;\nusing ToSic.Sxc.Dnn.Razor;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing IHasLog = ToSic.Sys.Logging.IHasLog;\nusing ILog = ToSic.Sys.Logging.ILog;\n\nnamespace ToSic.Sxc.Web;\n\n/// <summary>\n/// The base page type for razor pages\n/// It's the foundation for RazorPage and the old SexyContent page\n/// It only contains internal wiring stuff, so not to be published\n/// </summary>\n[PrivateApi(\"internal class only!\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract partial class RazorComponentBase : WebPageBase, IRazor, IHasCodeLog, IHasLog, IDnnRazorCompatibility, ICompatibilityLevel\n{\n    #region Constructor / Setup\n\n    /// <summary>\n    /// Special helper to move all Razor logic into a separate class.\n    /// For architecture of Composition over Inheritance.\n    /// </summary>\n    [PrivateApi]\n    internal DnnRazorHelper RzrHlp => field ??= new DnnRazorHelper().Init(this);\n\n    /// <summary>\n    /// Internal access to the underlying RenderPage.\n    /// This is needed by the render helper to provide the default behavior\n    /// if we are not using Roslyn\n    /// </summary>\n    internal virtual HelperResult BaseRenderPage(string path, RenderSpecs renderSpecs)\n    {\n        var data = renderSpecs.Data;\n        var l = (this as IHasLog).Log.Fn<HelperResult>($\"{nameof(path)}: '{path}', {nameof(data)}: {data != null}; partialSpecs: {renderSpecs.PartialSpecs}\");\n\n        // Do the proper RenderPage of the base class, and also pass in the RenderSpecs\n        // because they might be used to communicate caching settings back.\n        return data == null\n            ? l.Return(base.RenderPage(path, new { }, renderSpecs), \"default render, no data\")\n            : l.Return(base.RenderPage(path, data, renderSpecs), \"default render with data\");\n    }\n\n    /// <inheritdoc />\n    [PrivateApi]\n    internal IExecutionContext ExCtx { get; private set; }\n\n    /// <inheritdoc />\n    [PrivateApi]\n    public void ConnectToRoot(IExecutionContext exCtx)\n    {\n        RzrHlp.ConnectToRoot(exCtx);\n        ExCtx = exCtx;\n    }\n\n    /// <summary>\n    /// Override the base class ConfigurePage, and additionally update internal objects so sub-pages work just like the master\n    /// </summary>\n    /// <param name=\"parentPage\"></param>\n    [PrivateApi]\n    protected override void ConfigurePage(WebPageBase parentPage)\n    {\n        base.ConfigurePage(parentPage);\n        RzrHlp.ConfigurePage(parentPage, VirtualPath);\n    }\n\n    /// <summary>\n    /// Must be set on each derived class\n    /// </summary>\n    [PrivateApi]\n    public abstract int CompatibilityLevel { get; }\n\n    #endregion\n\n    #region Secret Stuff like IHasLog or Compile Helpers\n\n    /// <summary>\n    /// EXPLICIT Log implementation (to ensure that new IHasLog.Log interface is implemented)\n    /// </summary>\n    [PrivateApi] ILog IHasLog.Log => RzrHlp.Log;\n\n    /// <inheritdoc />\n    public string Path => VirtualPath;\n\n    #endregion\n\n    #region Core Properties which should appear in docs\n\n    /// <inheritdoc />\n    public virtual ICodeLog Log => RzrHlp.CodeLog;\n\n    /// <inheritdoc />\n    public virtual IHtmlHelper Html => RzrHlp.Html;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/CacheKeyTestAccessors.cs",
    "content": "using ToSic.Sxc.Dnn.Razor.Sys;\n\nnamespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// Logic-free test accessor wrappers for <see cref=\"CacheKey\"/> to keep Find-All-References of production methods clean.\n/// </summary>\ninternal static class CacheKeyTestAccessors\n{\n    // Constructor forwarder (factory)\n    public static CacheKey NewCacheKeyTac(int appId, string? edition, string templatePath, string contentHash, string appCodeHash, string? appPath = null)\n        => new CacheKey(appId: appId, edition: edition, templatePath: templatePath, contentHash: contentHash, appCodeHash: appCodeHash, appPath: appPath);\n\n    // Static method forwarders\n    public static string NormalizePathTac(string templatePath, string edition, string? appPath = null)\n        => CacheKey.NormalizePath(templatePath: templatePath, edition: edition, appPath: appPath);\n\n    public static string GetAppFolderTac(int appId, string edition)\n        => CacheKey.GetAppFolder(appId: appId, edition: edition);\n\n    public static string ToStringTac(this CacheKey cacheKey)\n        => cacheKey.ToString();\n\n    public static string GetFilePathTac(this CacheKey cacheKey, string cacheDirectory)\n        => cacheKey.GetFilePath(cacheDirectory: cacheDirectory);\n\n    public static bool EqualsTac(this CacheKey cacheKey, CacheKey other)\n        => cacheKey.Equals(other: other);\n\n    public static int GetHashCodeTac(this CacheKey cacheKey)\n        => cacheKey.GetHashCode();\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/CacheKeyTests.cs",
    "content": "namespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// Unit tests for CacheKey value object.\n/// Tests validate cache key format, path normalization, hash truncation, and equality behavior.\n/// </summary>\npublic class CacheKeyTests\n{\n    private const int TestAppId = 42;\n    private const string TestEdition = \"live\";\n    private const string TestContentHash = \"abcdef1234567890\"; // Long hash\n    private const string TestAppCodeHash = \"xyz789abcdefghij\"; // Long hash\n\n    /// <summary>\n    /// CacheKey.ToString() format verification\n    /// Verifies filename format: {fileName}-{extension}-{contentHash}-{appCodeHash}.dll\n    /// </summary>\n    [Fact]\n    public void CacheKey_ToString_ReturnsCorrectFormat()\n    {\n        // Arrange\n        var templatePath = \"Views/Default.cshtml\";\n        var normalizedPath = CacheKeyTestAccessors.NormalizePathTac(templatePath, TestEdition);\n        var cacheKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, templatePath, TestContentHash, TestAppCodeHash);\n\n        // Act\n        var result = cacheKey.ToStringTac();\n\n        // Assert\n        Contains(normalizedPath, result);\n        EndsWith(\".dll\", result);\n\n        // Verify format: {fileName}-{extension}-{hash1}-{hash2}.dll\n        var expectedPattern = $\"{normalizedPath}\";\n        StartsWith(expectedPattern, result);\n    }\n\n    /// <summary>\n    /// Hash truncation verification\n    /// Verifies that hashes are truncated to first 6 characters.\n    /// </summary>\n    [Fact]\n    public void CacheKey_ToString_TruncatesHashesToSixCharacters()\n    {\n        // Arrange\n        var templatePath = \"Views/Test.cshtml\";\n        var cacheKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, templatePath, TestContentHash, TestAppCodeHash);\n\n        // Act\n        var result = cacheKey.ToStringTac();\n\n        // Assert\n        var expectedContentHashShort = TestContentHash.Substring(0, 6); // \"abcdef\"\n        var expectedAppCodeHashShort = TestAppCodeHash.Substring(0, 6); // \"xyz789\"\n        \n        Contains(expectedContentHashShort, result);\n        Contains(expectedAppCodeHashShort, result);\n        \n        // Verify full hash is NOT in the filename\n        DoesNotContain(TestContentHash, result);\n        DoesNotContain(TestAppCodeHash, result);\n    }\n\n    /// <summary>\n    /// CacheKey.NormalizePath() lowercase conversion\n    /// Verifies that paths are converted to lowercase.\n    /// </summary>\n    [Fact]\n    public void CacheKey_NormalizePath_ConvertsToLowercase()\n    {\n        // Arrange\n        var inputPath = \"Views/Default.cshtml\";\n\n        // Act\n        var result = CacheKeyTestAccessors.NormalizePathTac(inputPath, TestEdition);\n\n        // Assert\n        Equal(result, result.ToLowerInvariant());\n        DoesNotContain(\"V\", result); // No uppercase V\n        DoesNotContain(\"D\", result); // No uppercase D\n    }\n\n    /// <summary>\n    /// CacheKey.NormalizePath() slash-to-hyphen replacement\n    /// Verifies that forward and backslashes are replaced with hyphens.\n    /// </summary>\n    [Fact]\n    public void CacheKey_NormalizePath_ReplacesSlashesWithHyphens()\n    {\n        // Arrange\n        var inputPath1 = \"Views/Default.cshtml\";\n        var inputPath2 = \"Views\\\\Default.cshtml\";\n\n        // Act\n        var result1 = CacheKeyTestAccessors.NormalizePathTac(inputPath1, TestEdition);\n        var result2 = CacheKeyTestAccessors.NormalizePathTac(inputPath2, TestEdition);\n\n        // Assert\n        DoesNotContain(\"/\", result1);\n        DoesNotContain(\"\\\\\", result1);\n        DoesNotContain(\"/\", result2);\n        DoesNotContain(\"\\\\\", result2);\n        \n        Contains(\"-\", result1);\n        Contains(\"-\", result2);\n        \n        // Both should produce same result\n        Equal(result1, result2);\n    }\n\n    /// <summary>\n    /// CacheKey.NormalizePath() .cshtml handling\n    /// Verifies that .cshtml extension is converted to -cshtml.\n    /// </summary>\n    [Fact]\n    public void CacheKey_NormalizePath_HandlesCSHTMLExtension()\n    {\n        // Arrange\n        var inputPath = \"Views/Default.cshtml\";\n\n        // Act\n        var result = CacheKeyTestAccessors.NormalizePathTac(inputPath, TestEdition);\n\n        // Assert\n        DoesNotContain(\".cshtml\", result);\n        Contains(\"-cshtml\", result);\n    }\n\n    /// <summary>\n    /// CacheKey.NormalizePath() complete example\n    /// Verifies the documented example: \"Views/Default.cshtml\" → \"views-default-cshtml-6995bfe9\"\n    /// </summary>\n    [Fact]\n    public void CacheKey_NormalizePath_MatchesDocumentedExample()\n    {\n        // Arrange\n        var inputPath = \"Views/Default.cshtml\";\n        var expectedOutput = \"views-default-cshtml-6995bfe9\";\n\n        // Act\n        var result = CacheKeyTestAccessors.NormalizePathTac(inputPath, TestEdition);\n\n        // Assert\n        Equal(expectedOutput, result);\n    }\n\n    /// <summary>\n    /// CacheKey.NormalizePath() removes app root prefix such as \"Portals/.../2sxc/app\".\n    /// </summary>\n    [Fact]\n    public void CacheKey_NormalizePath_TrimsAppRootPrefix()\n    {\n        // Arrange\n        var inputPath = \"Portals/0/2sxc/MyApp/live/views/Home.cshtml\";\n        var expectedOutput = \"views-home-cshtml-e5954f02\";\n\n        // Act\n        var result = CacheKeyTestAccessors.NormalizePathTac(inputPath, TestEdition);\n\n        // Assert\n        Equal(expectedOutput, result);\n        DoesNotContain(\"live-\", result);\n    }\n\n    /// <summary>\n    /// CacheKey.NormalizePath() removes edition segment when it appears at the beginning of the app-scoped path.\n    /// </summary>\n    [Fact]\n    public void CacheKey_NormalizePath_TrimsEditionPrefix()\n    {\n        // Arrange\n        const string inputPath = \"bs5/textimage/text-and-image.cshtml\";\n        const string edition = \"bs5\";\n        const string expectedOutput = \"textimage-text-and-image-cshtml-8c705c9f\";\n\n        // Act\n        var result = CacheKeyTestAccessors.NormalizePathTac(inputPath, edition);\n\n        // Assert\n        Equal(expectedOutput, result);\n        DoesNotContain($\"{edition}-\", result);\n    }\n\n    /// <summary>\n    /// CacheKey.NormalizePath() uses provided app path instead of relying on hard-coded path fragments.\n    /// Ensures app root trimming works even when the app folder name matches the default marker.\n    /// </summary>\n    [Fact]\n    public void CacheKey_NormalizePath_TrimsUsingProvidedAppPath()\n    {\n        // Arrange\n        const string inputPath = \"2sxc/2sxc/views/Home.cshtml\";\n        const string appPath = \"2sxc/2sxc\";\n\n        // Act\n        var result = CacheKeyTestAccessors.NormalizePathTac(inputPath, edition: \"root\", appPath: appPath);\n\n        // Assert\n        StartsWith(\"views-home-cshtml-\", result);\n    }\n\n    /// <summary>\n    /// Verifies that CacheKey equality works correctly for identical values.\n    /// </summary>\n    [Fact]\n    public void CacheKey_Equals_ReturnsTrueForIdenticalKeys()\n    {\n        // Arrange\n        var templatePath = \"Views/Test.cshtml\";\n        var key1 = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, templatePath, TestContentHash, TestAppCodeHash);\n        var key2 = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, templatePath, TestContentHash, TestAppCodeHash);\n\n        // Act & Assert\n        Equal(key1, key2);\n        True(key1.EqualsTac(key2));\n        Equal(key1.GetHashCodeTac(), key2.GetHashCodeTac());\n    }\n\n    /// <summary>\n    /// Verifies that CacheKey equality returns false for different values.\n    /// </summary>\n    [Fact]\n    public void CacheKey_Equals_ReturnsFalseForDifferentKeys()\n    {\n        // Arrange\n        var templatePath = \"Views/Test.cshtml\";\n        var key1 = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, templatePath, TestContentHash, TestAppCodeHash);\n        var key2 = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, templatePath, \"different\", TestAppCodeHash);\n\n        // Act & Assert\n        NotEqual(key1, key2);\n        False(key1.EqualsTac(key2));\n    }\n\n    /// <summary>\n    /// Verifies that GetFilePath combines cache directory with filename correctly.\n    /// </summary>\n    [Fact]\n    public void CacheKey_GetFilePath_CombinesDirectoryAndFilename()\n    {\n        // Arrange\n        var cacheDir = @\"C:\\temp\\cache\";\n        var templatePath = \"Views/Test.cshtml\";\n        var cacheKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, templatePath, TestContentHash, TestAppCodeHash);\n\n        // Act\n        var result = cacheKey.GetFilePathTac(cacheDir);\n\n        // Assert\n        StartsWith(cacheDir, result);\n        EndsWith(\".dll\", result);\n        Contains(Path.DirectorySeparatorChar.ToString(), result);\n    }\n\n    /// <summary>\n    /// Verifies that constructor validates parameters.\n    /// </summary>\n    [Theory]\n    [InlineData(0, \"live\", \"path\", \"hash1\", \"hash2\")] // Invalid appId\n    [InlineData(-1, \"live\", \"path\", \"hash1\", \"hash2\")] // Negative appId\n    public void CacheKey_Constructor_ThrowsOnInvalidAppId(int appId, string edition, string path, string hash1, string hash2)\n    {\n        // Act & Assert\n        Throws<ArgumentException>(() => CacheKeyTestAccessors.NewCacheKeyTac(appId, edition, path, hash1, hash2));\n    }\n\n    /// <summary>\n    /// Verifies that constructor defaults null/empty edition to \"root\".\n    /// Spec: Edition parameter is nullable and defaults to \"root\" if not provided.\n    /// </summary>\n    [Theory]\n    [InlineData(null)]\n    [InlineData(\"\")]\n    [InlineData(\"   \")]\n    public void CacheKey_Constructor_DefaultsEditionToRoot(string? edition)\n    {\n        // Arrange\n        var templatePath = \"Views/Test.cshtml\";\n\n        // Act\n        var cacheKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, edition, templatePath, TestContentHash, TestAppCodeHash);\n\n        // Assert\n        Equal(\"root\", cacheKey.Edition);\n    }\n\n    /// <summary>\n    /// Verifies that constructor uses provided edition when non-empty.\n    /// </summary>\n    [Theory]\n    [InlineData(\"live\")]\n    [InlineData(\"staging\")]\n    [InlineData(\"draft\")]\n    public void CacheKey_Constructor_UsesProvidedEdition(string edition)\n    {\n        // Arrange\n        var templatePath = \"Views/Test.cshtml\";\n\n        // Act\n        var cacheKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, edition, templatePath, TestContentHash, TestAppCodeHash);\n\n        // Assert\n        Equal(edition, cacheKey.Edition);\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using ToSic.Eav.Testing;\nglobal using static Xunit.Assert;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/RazorDiskCacheTests.cs",
    "content": "using System.Collections.Concurrent;\nusing System.Reflection;\nusing ToSic.Sxc.Dnn.Razor.Sys;\n\nnamespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// Integration tests for disk cache save/load cycle, invalidation, feature flag, and concurrent compilation.\n/// Tests validate end-to-end functionality of the CSHTML disk caching feature.\n/// </summary>\npublic class RazorDiskCacheTests\n{\n    private const string TestCacheDir = \"test-cache\";\n    private const int TestAppId = 42;\n    private const string TestEdition = \"live\";\n    private const string TestTemplatePath = \"views/test-template.cshtml\";\n    private const string TestContentHash = \"abc123\";\n    private const string TestAppCodeHash = \"xyz789\";\n\n    /// <summary>\n    /// Disk cache save/load cycle test\n    /// Verifies that a compiled assembly can be saved to disk cache and loaded back successfully.\n    /// </summary>\n    [Fact]\n    public void DiskCache_SaveAndLoad_ReturnsValidAssembly()\n    {\n        // Arrange\n        var tempCacheDir = Path.Combine(Path.GetTempPath(), TestCacheDir, Guid.NewGuid().ToString());\n        Directory.CreateDirectory(tempCacheDir);\n\n        try\n        {\n            var cacheKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition,\n                CacheKeyTestAccessors.NormalizePathTac(TestTemplatePath, TestEdition), TestContentHash, TestAppCodeHash);\n            \n            var cachePath = cacheKey.GetFilePathTac(tempCacheDir);\n            Directory.CreateDirectory(Path.GetDirectoryName(cachePath)!);\n            \n            // Create a test assembly file (using current assembly as test data)\n            var testAssemblyPath = Assembly.GetExecutingAssembly().Location;\n            File.Copy(testAssemblyPath, cachePath, overwrite: true);\n\n            // Act - Load from disk cache\n            var assemblyBytes = File.ReadAllBytes(cachePath);\n            var loadedAssembly = Assembly.Load(assemblyBytes);\n\n            // Assert\n            NotNull(loadedAssembly);\n            NotNull(loadedAssembly.FullName);\n            True(File.Exists(cachePath), \"Cache file should exist\");\n        }\n        finally\n        {\n            // Cleanup\n            if (Directory.Exists(tempCacheDir))\n                Directory.Delete(tempCacheDir, recursive: true);\n        }\n    }\n\n    /// <summary>\n    /// Verifies that cache key changes when template content changes (different contentHash).\n    /// </summary>\n    [Fact]\n    public void DiskCache_ContentHashChange_GeneratesDifferentCacheKey()\n    {\n        // Arrange\n        var originalContentHash = \"hash1\";\n        var modifiedContentHash = \"hash2\";\n\n        var originalKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition,\n            CacheKeyTestAccessors.NormalizePathTac(TestTemplatePath, TestEdition), originalContentHash, TestAppCodeHash);\n        \n        // Act - Simulate file change with different content hash\n        var modifiedKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition,\n            CacheKeyTestAccessors.NormalizePathTac(TestTemplatePath, TestEdition), modifiedContentHash, TestAppCodeHash);\n\n        // Assert\n        NotEqual(originalKey.ToStringTac(), modifiedKey.ToStringTac());\n        NotEqual(originalKey, modifiedKey);\n    }\n\n    /// <summary>\n    /// Verifies that cache key changes when AppCode assembly changes (different appCodeHash).\n    /// </summary>\n    [Fact]\n    public void DiskCache_AppCodeHashChange_GeneratesDifferentCacheKey()\n    {\n        // Arrange - Use hashes with different first 6 characters\n        var originalAppCodeHash = \"aaa111000000000000000000000000000000000000000000000000000000\";\n        var modifiedAppCodeHash = \"bbb222000000000000000000000000000000000000000000000000000000\";\n\n        var originalKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition,\n            CacheKeyTestAccessors.NormalizePathTac(TestTemplatePath, TestEdition), TestContentHash, originalAppCodeHash);\n        \n        // Act - Simulate AppCode change with different hash\n        var modifiedKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition,\n            CacheKeyTestAccessors.NormalizePathTac(TestTemplatePath, TestEdition), TestContentHash, modifiedAppCodeHash);\n\n        // Assert\n        NotEqual(originalKey.ToStringTac(), modifiedKey.ToStringTac());\n        NotEqual(originalKey, modifiedKey);\n    }\n    \n    /// <summary>\n    /// Verifies that cache key generation works with null edition (defaults to \"root\").\n    /// Validates spec: Edition parameter is nullable and defaults to \"root\" if not provided.\n    /// </summary>\n    [Fact]\n    public void DiskCache_NullEdition_DefaultsToRoot()\n    {\n        // Arrange & Act - Pass null edition\n        var cacheKey = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, null,\n            CacheKeyTestAccessors.NormalizePathTac(TestTemplatePath, null), TestContentHash, TestAppCodeHash);\n        \n        var fileName = cacheKey.ToStringTac();\n\n        // Assert\n        Equal(\"root\", cacheKey.Edition);\n        // file name no longer contains edition/app, but edition on the object must default to root\n        DoesNotContain(\"root\", fileName);\n    }\n\n    /// <summary>\n    /// Concurrent compilation safety test\n    /// Verifies that multiple threads generating cache keys for the same template produce identical results.\n    /// This validates that the CacheKey value object is thread-safe and deterministic.\n    /// </summary>\n    [Fact]\n    public void DiskCache_ConcurrentCacheKeyGeneration_ProducesIdenticalResults()\n    {\n        // Arrange\n        const int threadCount = 10;\n        var cacheKeys = new ConcurrentBag<string>();\n\n        // Act - Generate cache keys concurrently\n        Parallel.For(0, threadCount, i =>\n        {\n            var key = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition,\n                CacheKeyTestAccessors.NormalizePathTac(TestTemplatePath, TestEdition), TestContentHash, TestAppCodeHash);\n            cacheKeys.Add(key.ToStringTac());\n        });\n\n        // Assert - All cache keys should be identical\n        var distinctKeys = cacheKeys.Distinct().ToList();\n        Single(distinctKeys);\n    }\n\n    /// <summary>\n    /// Validates that cache files in a directory can be identified and deleted by pattern.\n    /// This simulates the InvalidateAppCache bulk deletion scenario.\n    /// </summary>\n    [Fact]\n    public void DiskCache_BulkInvalidation_DeletesMatchingFiles()\n    {\n        // Arrange\n        var tempCacheDir = Path.Combine(Path.GetTempPath(), TestCacheDir, Guid.NewGuid().ToString());\n        Directory.CreateDirectory(tempCacheDir);\n\n        try\n        {\n            // Create multiple cache files for the same app\n            var cacheKey1 = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, \"template1\", \"hash1\", \"apphash1\");\n            var cacheKey2 = CacheKeyTestAccessors.NewCacheKeyTac(TestAppId, TestEdition, \"template2\", \"hash2\", \"apphash1\");\n            var cacheKey3 = CacheKeyTestAccessors.NewCacheKeyTac(999, TestEdition, \"template3\", \"hash3\", \"apphash1\"); // Different app\n            \n            var cachePath1 = cacheKey1.GetFilePathTac(tempCacheDir);\n            var cachePath2 = cacheKey2.GetFilePathTac(tempCacheDir);\n            var cachePath3 = cacheKey3.GetFilePathTac(tempCacheDir);\n\n            Directory.CreateDirectory(Path.GetDirectoryName(cachePath1)!);\n            Directory.CreateDirectory(Path.GetDirectoryName(cachePath2)!);\n            Directory.CreateDirectory(Path.GetDirectoryName(cachePath3)!);\n\n            File.WriteAllText(cachePath1, \"test1\");\n            File.WriteAllText(cachePath2, \"test2\");\n            File.WriteAllText(cachePath3, \"test3\");\n\n            // Act - delete all dlls for app/edition folder\n            var appEditionDir = Path.Combine(tempCacheDir, CacheKeyTestAccessors.GetAppFolderTac(TestAppId, TestEdition));\n            var filesToDelete = Directory.Exists(appEditionDir)\n                ? Directory.GetFiles(appEditionDir, \"*.dll\", SearchOption.AllDirectories)\n                : Array.Empty<string>();\n\n            foreach (var file in filesToDelete)\n                File.Delete(file);\n\n            // Assert\n            False(File.Exists(cachePath1), \"Cache file 1 should be deleted\");\n            False(File.Exists(cachePath2), \"Cache file 2 should be deleted\");\n            True(File.Exists(cachePath3), \"Cache file 3 (different app) should remain\");\n        }\n        finally\n        {\n            // Cleanup\n            if (Directory.Exists(tempCacheDir))\n                Directory.Delete(tempCacheDir, recursive: true);\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/ToSic.Eav.Configuration.Features-Compatibility/FeatureTestsBase.cs",
    "content": "﻿//using Microsoft.Extensions.DependencyInjection;\n//using Microsoft.Extensions.DependencyInjection.Extensions;\n//using ToSic.Eav.Apps.Mocks;\n//using ToSic.Eav.Data;\n//using ToSic.Eav.Data.Mocks;\n//using ToSic.Eav.Integration;\n//using ToSic.Eav.Internal.Loaders;\n\n//namespace ToSic.Sxc.ToSic.Eav.Configuration.Features_Compatibility;\n\n//public class FeatureTestsBase: TestBaseEav\n//{\n//    public FeatureTestsBase()\n//    {\n//        // Make sure that features are ready to use\n//        var sysLoader = GetService<EavSystemLoader>();\n//        sysLoader.ReloadFeatures();\n//    }\n\n//    protected override IServiceCollection SetupServices(IServiceCollection services)\n//    {\n//        base.SetupServices(services)\n//            .AddAppLoader();\n//        services.TryAddTransient<IValueConverter, MockValueConverter>();\n//        services.TryAddTransient<IZoneMapper, MockZoneMapper>();\n//        return services;\n//    }\n\n//}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/ToSic.Eav.Configuration.Features-Compatibility/FeaturesStaticTests.cs",
    "content": "﻿using ToSic.Eav.Configuration;\nusing ToSic.Eav.Testing.Scenarios;\nusing ToSic.Sxc.Dnn.StartUp;\nusing ToSic.Sys.Capabilities.Features;\nusing BuiltInFeatures = ToSic.Sys.Capabilities.Features.BuiltInFeatures;\n\n#pragma warning disable 618\n\nnamespace ToSic.Sxc.ToSic.Eav.Configuration.Features_Compatibility;\n\n// ReSharper disable once InconsistentNaming\npublic class FeaturesStaticTests : IClassFixture<DoFixtureStartup<ScenarioFullPatronsWithDb>>\n{\n    public FeaturesStaticTests(ISysFeaturesService featuresSvc)\n    {\n        new StartupDnn().SetupOldStaticFeaturesForCompatibility(featuresSvc);\n    }\n\n    [Fact]\n    //[Ignore(\"I believe the setup doesn't work yet - needs to first load the licenses to be able to test this\")]\n    public void PasteClipboardActive()\n    {\n        var x = Features.Enabled(BuiltInFeatures.PasteImageFromClipboard.Guid);\n        True(x, \"this should be enabled and non-expired\");\n    }\n\n    [Fact]\n    //[Ignore(\"I believe the setup doesn't work yet - needs to first load the licenses to be able to test this\")]\n    public void InventedFeatureGuid()\n    {\n        var inventedGuid = new Guid(\"12345678-1c8b-4286-a33b-3210ed3b2d9a\");\n        var x = Features.Enabled(inventedGuid);\n        False(x, \"this should be enabled and expired\");\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/ToSic.Eav.Configuration.Features-Compatibility/IFeaturesTests.cs",
    "content": "﻿using ToSic.Eav.Configuration;\nusing ToSic.Eav.Testing.Scenarios;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.ToSic.Eav.Configuration.Features_Compatibility;\n\n// ReSharper disable once InconsistentNaming\npublic class IFeaturesTests(IFeaturesService Features) : IClassFixture<DoFixtureStartup<ScenarioFullPatronsWithDb>>\n{\n    [Fact]\n    public void PasteClipboardActive()\n    {\n        var x = Features.Enabled(BuiltInFeatures.PasteImageFromClipboard.Guid);\n        True(x, \"this should be enabled and non-expired\");\n    }\n\n    [Fact]\n    public void InventedFeatureGuid()\n    {\n        var inventedGuid = new Guid(\"12345678-1c8b-4286-a33b-3210ed3b2d9a\");\n        var x = Features.Enabled(inventedGuid);\n        False(x, \"this should be enabled and expired\");\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/ToSic.Eav.Configuration.Features-Compatibility/Startup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav;\nusing ToSic.Eav.Run.Startup;\nusing ToSic.Sxc.Compatibility;\nusing ToSic.Sys.Capabilities.Platform;\nusing ToSic.Testing.Shared.Platforms;\n\n#pragma warning disable CA1822\n\nnamespace ToSic.Sxc.ToSic.Eav.Configuration.Features_Compatibility;\n\n/// <summary>\n/// A Startup helper for tests which need Dependency-Injection setup for EAV Core.\n/// </summary>\n/// <remarks>\n/// Use by adding this kind of attribute to your test class:\n/// `[Startup(typeof(StartupTestFullWithDb))]`\n/// </remarks>\npublic class Startup\n{\n    /// <summary>\n    /// Startup helper\n    /// </summary>\n    public virtual void ConfigureServices(IServiceCollection services) =>\n        services\n            .AddTransient<IPlatformInfo, TestPlatformPatronPerfectionist>()\n            .AddDnnCompatibility()\n\n            .AddFixtureHelpers()\n            // Apps\n            .AddEavWork()\n            .AddEavContext()\n            .AddEavAppsPersistence()\n            .AddEavApps()\n\n            // SQL Server\n            .AddRepositoryAndEfc()\n            // Import/Export as well as File Based Json loading\n            .AddEavImportExport()\n            .AddEavPersistence()\n            // DataSources\n            .AddDataSources()\n            .AddDataSourceSystem()\n            // EAV Core\n            //.AddEavDataPersistence()\n            .AddEavDataBuild()\n            .AddEavDataStack()\n            .AddEavModels()\n            .AddEavData()\n\n            // EAV Core and Downstream\n            .AddAllLibAndSys()\n\n            // Fallbacks for services which were not implemented - must come last\n            .AddEavAllFallbacks();\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/ToSic.Sxc.Dnn.SystemTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForTestCode-NetFramework.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <PropertyGroup>\n    <RootNamespace>ToSic.Sxc.Dnn</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"DotNetNuke.Web\" Version=\"9.13.9\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps.TestsHelpers\\ToSic.Eav.Apps.TestHelpers.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Testing.FullDbFixtures\\ToSic.Eav.Testing.FullDbFixtures.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Features.TestHelpers\\ToSic.Sys.Features.TestHelpers.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Dnn\\ToSic.Sxc.Dnn.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.SystemTests/VerifyTestsRun.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn;\n\npublic class VerifyTestsRun\n{\n    [Fact]\n    public void VerifyTestsRun1()\n    {\n        // This is a dummy test to verify that the tests are running correctly.\n        // It doesn't do anything, but it's here to ensure that the test framework is set up correctly.\n        True(true);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Custom/Dnn/Api12.cs",
    "content": "﻿using ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Dnn;\n\n/// <summary>\n/// This is the base class for all custom API Controllers. <br/>\n/// With this, your code receives the full context  incl. the current App, DNN, Data, etc.\n/// </summary>\n[PublicApi(\"This is the official base class for v12+\")]\n[DnnLogExceptions]\n[DefaultToNewtonsoftForHttpJson]\npublic abstract class Api12(string logSuffix) : Hybrid.Api12(logSuffix), IDynamicWebApi, IHasDnn\n{\n    protected Api12() : this(\"Dnn12\") { }\n\n    /// <inheritdoc cref=\"IHasDnn.Dnn\"/>\n    public IDnnContext Dnn => (ExCtx as IHasDnn)?.Dnn;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Custom/Hybrid/Api12.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.Compatibility;\nusing ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// This is the base class for all custom API Controllers. <br/>\n/// With this, your code receives the full context  incl. the current App, DNN, Data, etc.\n/// </summary>\n[PublicApi(\"This is the official base class for v12+\")]\n[DnnLogExceptions]\n[DefaultToNewtonsoftForHttpJson]\npublic abstract partial class Api12(string logSuffix) : DnnSxcCustomControllerBase(logSuffix), IDynamicCode12,\n    IDynamicWebApi, IHasCodeLog, ICreateInstance\n{\n    #region Setup\n\n    protected Api12() : this(\"Hyb12\") { }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => SysHlp.CodeLog;\n\n    [PrivateApi] public int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => SysHlp.GetService<TService>();\n\n    #endregion\n\n    #region Content, Presentation, Header, App, Data\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic Content => CodeApi.Content;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic Header => CodeApi.Header;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi.Data;\n\n    #endregion\n\n\n    #region Link & Edit - added to API in 2sxc 10.01; CmsContext, Resources, Settings (v12)\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi?.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi?.Edit;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi?.CmsContext;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    public dynamic Settings => CodeApi.Settings;\n\n    [PrivateApi(\"Not yet ready\")]\n    public IDevTools DevTools => CodeApi.DevTools;\n\n    #endregion\n\n\n    #region AsDynamic implementations + AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(string json, string fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public dynamic AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi?.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n\n    #region Convert-Service\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Convert\" />\n    public IConvertService Convert => field ??= CodeApi.Convert;\n\n    #endregion\n\n\n    #region CreateSource implementations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    #endregion\n\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    /// <inheritdoc cref=\"IDynamicWebApi.SaveInAdam\"/>\n    public IFile SaveInAdam(NoParamOrder npo = default, Stream stream = null, string fileName = null, string contentType = null,\n        Guid? guid = null, string field = null, string subFolder = \"\")\n        => DynHlp.SaveInAdam(stream: stream, fileName: fileName, contentType: contentType, guid: guid, field: field, subFolder: subFolder);\n\n    #endregion\n\n    #region CreateInstance\n\n    string IGetCodePath.CreateInstancePath { get; set; }\n\n    private CompileCodeHelper CompileCodeHlp => field ??= GetService<CompileCodeHelper>().Init(this);\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\"/>\n    public dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => CompileCodeHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    #endregion\n\n\n\n    #region Net Core Compatibility Shims - Copy this entire section to WebApi Files\n\n    /// <inheritdoc cref=\"IDynamicWebApi.File\"/>\n    public dynamic File(NoParamOrder npo = default,\n        bool? download = null,\n        string virtualPath = null,\n        string contentType = null,\n        string fileDownloadName = null,\n        object contents = null)\n        => Shim.File(download: download, virtualPath: virtualPath, contentType: contentType, fileDownloadName: fileDownloadName, contents: contents);\n\n    private WebApiCoreShim Shim => new(Request);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok()\"/>\n    [NonAction] public new dynamic Ok() => Shim.Ok();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok(object)\"/>\n    [NonAction] public dynamic Ok(object value) => Shim.Ok(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NoContent()\"/>\n    [NonAction]\n    public dynamic NoContent() => Shim.NoContent();\n\n    // TODO: this Shim could now be implemented after 16.02 - since we don't have the Content property any more\n    #region Content (ca. 5 overloads) can't be implemented, because it conflicts with our property \"Content\"\n\n    #endregion\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Redirect\"/>\n    [NonAction] public new dynamic Redirect(string url) => Shim.Redirect(url);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.RedirectPermanent\"/>\n    [NonAction] public dynamic RedirectPermanent(string url) => Shim.RedirectPermanent(url);\n\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int)\"/>\n    [NonAction] public dynamic StatusCode(int statusCode) => Shim.StatusCode(statusCode);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int, object)\"/>\n    [NonAction] public dynamic StatusCode(int statusCode, object value) => Shim.StatusCode(statusCode, value);\n\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized()\"/>\n    [NonAction] public dynamic Unauthorized() => Shim.Unauthorized();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized(object)\"/>\n    [NonAction] public dynamic Unauthorized(object value) => Shim.Unauthorized(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound()\"/>\n    [NonAction] public new dynamic NotFound() => Shim.NotFound();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound(object)\"/>\n    [NonAction] public dynamic NotFound(object value) => Shim.NotFound(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.BadRequest()\"/>\n    [NonAction] public new dynamic BadRequest() => Shim.BadRequest();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict()\"/>\n    [NonAction] public new dynamic Conflict() => Shim.Conflict();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict(object)\"/>\n    [NonAction] public dynamic Conflict(object error) => Shim.Conflict(error);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Accepted()\"/>\n    [NonAction] public dynamic Accepted() => Shim.Accepted();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Forbid()\"/>\n    [NonAction] public dynamic Forbid() => Shim.Forbid();\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Custom/Hybrid/Api12_Obsolete.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\npartial class Api12\n{\n    // Obsolete stuff - not supported any more in after V10 - show helpful error messages\n\n    #region Shared Code Block between RazorComponent_Obsolete and ApiController_Obsolete\n\n    #region Obsolete CreateSource\n\n    [PrivateApi]\n    [Obsolete(\"throws error with fix-instructions. Use CreateSource<type> instead.\")]\n    public IDataSource CreateSource(string typeName = \"\", IDataSource inSource = null, ILookUpEngine configurationProvider = null)\n        => RazorExceptions.ExCreateSourceString();\n\n    #endregion\n\n    #region Compatibility with Eav.Interfaces.IEntity - introduced in 10.10 - Removed in v20\n\n    //[PrivateApi]\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(ToSic.Eav.Interfaces.IEntity entity)\n    //    => RazorExceptions.ExAsDynamicInterfacesIEntity();\n\n\n    //[PrivateApi]\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(KeyValuePair<int, ToSic.Eav.Interfaces.IEntity> entityKeyValuePair)\n    //    => RazorExceptions.AsDynamicKvpInterfacesIEntity();\n\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //[PrivateApi]\n    //public IEnumerable<dynamic> AsDynamic(IEnumerable<ToSic.Eav.Interfaces.IEntity> entities)\n    //    => RazorExceptions.AsDynamicIEnumInterfacesIEntity();\n\n\n    #endregion\n\n    #region AsDynamic<int, IEntity>\n\n    [PrivateApi]\n    [Obsolete(\"throws error with fix-instructions. Use AsDynamic(IEnumerable<IEntity>...)\")]\n    public dynamic AsDynamic(KeyValuePair<int, IEntity> entityKeyValuePair) => RazorExceptions.ExAsDynamicKvp();\n\n    #region Old AsDynamic with correct warnings\n    /// <inheritdoc/>\n    [PrivateApi]\n    public IEnumerable<dynamic> AsDynamic(IDataStream stream)\n        => throw new($\"AsDynamic for lists isn't supported here. Please use AsList(...) instead.\");\n\n    /// <inheritdoc/>\n    [PrivateApi]\n    public IEnumerable<dynamic> AsDynamic(IDataSource source)\n        => throw new($\"AsDynamic for lists isn't supported here. Please use AsList(...) instead.\");\n\n\n    /// <inheritdoc/>\n    [PrivateApi]\n    public IEnumerable<dynamic> AsDynamic(IEnumerable<IEntity> entities)\n        => throw new($\"AsDynamic for lists isn't supported here. Please use AsList(...) instead.\");\n\n    #endregion\n    #endregion\n\n    #region Presentation, ListContent, ListPresentation, List\n\n    [PrivateApi]\n    [Obsolete(\"use Content.Presentation instead\")]\n    public dynamic Presentation => RazorExceptions.ExPresentation();\n\n\n    [PrivateApi]\n    [Obsolete(\"Use Header instead\")]\n    public dynamic ListContent => RazorExceptions.ExListContent();\n\n    [PrivateApi]\n    [Obsolete(\"Use Header.Presentation instead\")]\n    public dynamic ListPresentation => RazorExceptions.ExListPresentation();\n\n    [PrivateApi]\n    [Obsolete(\"This is an old way used to loop things - removed in RazorComponent\")]\n    public IEnumerable<dynamic> List => RazorExceptions.ExList();\n\n    #endregion\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Custom/Hybrid/Api14.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.Compatibility;\nusing ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Base class for v14 Dynamic WebAPI files.\n/// Will provide the <see cref=\"ServiceKit14\"/> on property `Kit`.\n/// This contains all the popular services used in v14, so that your code can be lighter. \n/// </summary>\n/// <remarks>\n/// Important: The property `Convert` which exited on Razor12 was removed. use `Kit.Convert` instead.\n/// </remarks>\n[PublicApi]\n[DnnLogExceptions]\n[DefaultToNewtonsoftForHttpJson]\npublic abstract partial class Api14(string logSuffix) : DnnSxcCustomControllerBase(logSuffix),\n    IDynamicCode14<object, ServiceKit14>, IHasCodeLog, IDynamicWebApi, IDynamicCode12, ICreateInstance\n{\n    #region Setup\n\n    protected Api14() : this(\"Hyb14\") { }\n\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc cref=\"IHasKit{TServiceKit}.Kit\" />\n    public ServiceKit14 Kit => field ??= CodeApi.ServiceKit14;\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => SysHlp.CodeLog;\n\n    [PrivateApi] public int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n    #endregion\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => SysHlp.GetService<TService>();\n\n\n    #region Content, Presentation, Header, App, Data\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic Content => CodeApi.Content;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic Header => CodeApi.Header;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi.Data;\n\n    #endregion\n\n\n    #region Link & Edit - added to API in 2sxc 10.01; CmsContext, Resources, Settings (v12)\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi?.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi?.Edit;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi?.CmsContext;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    public dynamic Settings => CodeApi.Settings;\n\n    [PrivateApi(\"Not yet ready\")]\n    public IDevTools DevTools => CodeApi.DevTools;\n\n    #endregion\n\n\n    #region AsDynamic implementations + AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(string json, string fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public dynamic AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi?.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n\n    #region CreateSource implementations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    #endregion\n\n\n    #region Convert-Service - should NOT be in v14, but was by accident!\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Convert\" />\n    public IConvertService Convert => field ??= CodeApi.Convert;\n\n    #endregion\n\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    /// <inheritdoc cref=\"IDynamicWebApi.SaveInAdam\" />\n    public IFile SaveInAdam(NoParamOrder npo = default, Stream stream = null, string fileName = null, string contentType = null,\n        Guid? guid = null, string field = null, string subFolder = \"\")\n        => DynHlp.SaveInAdam(stream: stream, fileName: fileName, contentType: contentType, guid: guid, field: field, subFolder: subFolder);\n\n    #endregion\n\n    #region CreateInstance\n\n    string IGetCodePath.CreateInstancePath { get; set; }\n\n    private CompileCodeHelper CompileCodeHlp => field ??= GetService<CompileCodeHelper>().Init(this);\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\"/>\n    public dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => CompileCodeHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    [PrivateApi(\"added in 16.05, but not sure if it should be public\")]\n    public dynamic GetCode(string path, NoParamOrder npo = default, string className = default)\n        => CompileCodeHlp.GetCode(path: path, className: className);\n\n    #endregion\n\n\n    #region Net Core Compatibility Shims - Copy this entire section to WebApi Files\n\n    /// <inheritdoc cref=\"IDynamicWebApi.File\"/>\n    public dynamic File(NoParamOrder npo = default,\n        bool? download = null,\n        string virtualPath = null,\n        string contentType = null,\n        string fileDownloadName = null,\n        object contents = null)\n        => Shim.File(download: download, virtualPath: virtualPath, contentType: contentType, fileDownloadName: fileDownloadName, contents: contents);\n\n    private WebApiCoreShim Shim => new(Request);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok()\"/>\n    [NonAction] public new dynamic Ok() => Shim.Ok();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok(object)\"/>\n    [NonAction] public dynamic Ok(object value) => Shim.Ok(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NoContent()\"/>\n    [NonAction]\n    public dynamic NoContent() => Shim.NoContent();\n\n    // TODO: this Shim could now be implemented after 16.02 - since we don't have the Content property any more\n    #region Content (ca. 5 overloads) can't be implemented, because it conflicts with our property \"Content\"\n\n    #endregion\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Redirect\"/>\n    [NonAction] public new dynamic Redirect(string url) => Shim.Redirect(url);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.RedirectPermanent\"/>\n    [NonAction] public dynamic RedirectPermanent(string url) => Shim.RedirectPermanent(url);\n\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int)\"/>\n    [NonAction] public dynamic StatusCode(int statusCode) => Shim.StatusCode(statusCode);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int, object)\"/>\n    [NonAction] public dynamic StatusCode(int statusCode, object value) => Shim.StatusCode(statusCode, value);\n\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized()\"/>\n    [NonAction] public dynamic Unauthorized() => Shim.Unauthorized();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized(object)\"/>\n    [NonAction] public dynamic Unauthorized(object value) => Shim.Unauthorized(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound()\"/>\n    [NonAction] public new dynamic NotFound() => Shim.NotFound();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound(object)\"/>\n    [NonAction] public dynamic NotFound(object value) => Shim.NotFound(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.BadRequest()\"/>\n    [NonAction] public new dynamic BadRequest() => Shim.BadRequest();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict()\"/>\n    [NonAction] public new dynamic Conflict() => Shim.Conflict();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict(object)\"/>\n    [NonAction] public dynamic Conflict(object error) => Shim.Conflict(error);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Accepted()\"/>\n    [NonAction] public dynamic Accepted() => Shim.Accepted();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Forbid()\"/>\n    [NonAction] public dynamic Forbid() => Shim.Forbid();\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Custom/Hybrid/Api14_Obsolete.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\npartial class Api14\n{\n    // Obsolete stuff - not supported anymore in after V10 - show helpful error messages\n\n    #region Shared Code Block between RazorComponent_Obsolete and ApiController_Obsolete\n\n    #region Obsolete CreateSource\n\n    [PrivateApi]\n    [Obsolete(\"throws error with fix-instructions. Use CreateSource<type> instead.\")]\n    public IDataSource CreateSource(string typeName = \"\", IDataSource inSource = null, ILookUpEngine configurationProvider = null)\n        => RazorExceptions.ExCreateSourceString();\n\n    #endregion\n\n    #region Compatibility with Eav.Interfaces.IEntity - introduced in 10.10 - Removed in v20\n\n    //[PrivateApi]\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(ToSic.Eav.Interfaces.IEntity entity)\n    //    => RazorExceptions.ExAsDynamicInterfacesIEntity();\n\n\n    //[PrivateApi]\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(KeyValuePair<int, ToSic.Eav.Interfaces.IEntity> entityKeyValuePair)\n    //    => RazorExceptions.AsDynamicKvpInterfacesIEntity();\n\n    //[Obsolete(\"throws error with fix-instructions. Cast your entities to ToSic.Eav.Data.IEntity\")]\n    //[PrivateApi]\n    //public IEnumerable<dynamic> AsDynamic(IEnumerable<ToSic.Eav.Interfaces.IEntity> entities)\n    //    => RazorExceptions.AsDynamicIEnumInterfacesIEntity();\n\n\n    #endregion\n\n    #region AsDynamic<int, IEntity>\n\n    [PrivateApi]\n    [Obsolete(\"throws error with fix-instructions. Use AsDynamic(IEnumerable<IEntity>...)\")]\n    public dynamic AsDynamic(KeyValuePair<int, IEntity> entityKeyValuePair) => RazorExceptions.ExAsDynamicKvp();\n\n    #region Old AsDynamic with correct warnings\n    /// <inheritdoc/>\n    [PrivateApi]\n    public IEnumerable<dynamic> AsDynamic(IDataStream stream)\n        => throw new($\"AsDynamic for lists isn't supported here. Please use AsList(...) instead.\");\n\n    /// <inheritdoc/>\n    [PrivateApi]\n    public IEnumerable<dynamic> AsDynamic(IDataSource source)\n        => throw new($\"AsDynamic for lists isn't supported here. Please use AsList(...) instead.\");\n\n\n    /// <inheritdoc/>\n    [PrivateApi]\n    public IEnumerable<dynamic> AsDynamic(IEnumerable<IEntity> entities)\n        => throw new($\"AsDynamic for lists isn't supported here. Please use AsList(...) instead.\");\n\n    #endregion\n    #endregion\n\n    #region Presentation, ListContent, ListPresentation, List\n\n    [PrivateApi]\n    [Obsolete(\"use Content.Presentation instead\")]\n    public dynamic Presentation => RazorExceptions.ExPresentation();\n\n\n    [PrivateApi]\n    [Obsolete(\"Use Header instead\")]\n    public dynamic ListContent => RazorExceptions.ExListContent();\n\n    [PrivateApi]\n    [Obsolete(\"Use Header.Presentation instead\")]\n    public dynamic ListPresentation => RazorExceptions.ExListPresentation();\n\n    [PrivateApi]\n    [Obsolete(\"This is an old way used to loop things - removed in RazorComponent\")]\n    public IEnumerable<dynamic> List => RazorExceptions.ExList();\n\n    #endregion\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Custom/Hybrid/ApiTyped.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Context;\nusing System.Web.Http.Results;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.Models;\nusing ToSic.Eav.WebApi.Sys;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.Compatibility;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Base class for v16 [Typed](xref:NetCode.TypedCode.Index) WebAPI files.\n/// Use it to create custom WebAPI endpoints in your App.\n/// \n/// It provides the <see cref=\"ServiceKit16\"/> on property `Kit` which contains all the popular services to create amazing stuff.\n/// </summary>\n/// <remarks>\n/// Important: This is very different from Razor12 or Razor14, as it doesn't rely on `dynamic` code.\n/// Be aware of this since the APIs are very different - see [Typed Code](xref:NetCode.TypedCode.Index).\n/// </remarks>\n[PublicApi]\n[DnnLogExceptions]\n//[DefaultToNewtonsoftForHttpJson] - // !!! v16 should now default to normal\n[JsonFormatter]\npublic abstract class ApiTyped: DnnSxcCustomControllerBase, IHasCodeLog, IDynamicWebApi, ITypedCode16, IGetCodePath\n{\n    #region Setup\n\n    /// <summary>\n    /// Main constructor.\n    /// Doesn't have parameters so it can easily be inherited.\n    /// </summary>\n    protected ApiTyped() : base(EavWebApiConstants.HistoryNameWebApi) { }\n\n    /// <summary>\n    /// Alternate constructor to use when inheriting, placing the Insights logs in an own section.\n    /// </summary>\n    /// <param name=\"insightsGroup\">Name of the section in Insights</param>\n    protected ApiTyped(string insightsGroup) : base(\"Api16\", insightsGroup) { }\n\n    internal ICodeTypedApiHelper CodeApi => field\n        ??= ExCtx.GetTypedApi();\n\n    /// <inheritdoc cref=\"IHasKit{TServiceKit}.Kit\"/>\n    public ServiceKit16 Kit => field ??= CodeApi.ServiceKit16;\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => SysHlp.CodeLog;\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel16;\n\n    #endregion\n\n    #region Link & Edit - added to API in 2sxc 10.01; CmsContext, Resources, Settings (v12)\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => SysHlp.GetService<TService>();\n\n    /// <inheritdoc cref=\"ITypedCode16.GetService{TService}(NoParamOrder, string?)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TService GetService<TService>(NoParamOrder npo = default, string typeName = default) where TService : class\n        => AppCodeGetNamedServiceHelper.GetService<TService>(owner: this, CodeHelper.Specs, typeName);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi?.Link;\n\n    [PrivateApi(\"Not yet ready\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public IDevTools DevTools => CodeHelper.DevTools;\n\n    #endregion\n\n    #region MyContext & UniqueKey\n\n    /// <inheritdoc cref=\"ITypedApi.MyContext\" />\n    public ICmsContext MyContext => CodeApi.CmsContext;\n\n    /// <inheritdoc cref=\"ITypedApi.MyPage\" />\n    public ICmsPage MyPage => CodeApi.CmsContext.Page;\n\n    /// <inheritdoc cref=\"ITypedApi.MyUser\" />\n    public ICmsUser MyUser => CodeApi.CmsContext.User;\n\n    /// <inheritdoc cref=\"ITypedApi.MyView\" />\n    public ICmsView MyView => CodeApi.CmsContext.View;\n\n    /// <inheritdoc cref=\"ITypedApi.UniqueKey\" />\n    public string UniqueKey => Kit.Key.UniqueKey;\n\n    #endregion\n\n\n    #region AsDynamic implementations + AsList - all killed in v16\n\n    ///// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    //public dynamic AsDynamic(string json, string fallback = default) => _DynCodeRoot.Cdf.AsDynamicFromJson(json, fallback);\n\n    ///// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    //public dynamic AsDynamic(IEntity entity) => _DynCodeRoot.Cdf.AsDynamic(entity);\n\n    ///// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    //public dynamic AsDynamic(object dynamicEntity) => _DynCodeRoot.Cdf.AsDynamicInternal(dynamicEntity);\n\n    ///// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    //public dynamic AsDynamic(params object[] entities) => _DynCodeRoot.Cdf.MergeDynamic(entities);\n\n    ///// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    //public IEntity AsEntity(object dynamicEntity) => _DynCodeRoot.Cdf.AsEntity(dynamicEntity);\n\n    ///// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    //public IEnumerable<dynamic> AsList(object list) => _DynCodeRoot?.Cdf.AsDynamicList(list);\n\n    #endregion\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicWebApi.SaveInAdam\"/>\n    public IFile SaveInAdam(NoParamOrder npo = default, Stream stream = null, string fileName = null, string contentType = null,\n        Guid? guid = null, string field = null, string subFolder = \"\")\n        => DynHlp.SaveInAdam(stream: stream, fileName: fileName, contentType: contentType, guid: guid, field: field, subFolder: subFolder);\n\n    #endregion\n\n    #region New App, Settings, Resources\n\n    /// <inheritdoc />\n    public IAppTyped App => CodeApi.AppTyped;\n\n    /// <inheritdoc cref=\"ITypedApi.AllResources\" />\n    public ITypedStack AllResources => CodeHelper.AllResources;\n\n    /// <inheritdoc cref=\"ITypedApi.AllSettings\" />\n    public ITypedStack AllSettings => CodeHelper.AllSettings;\n\n    #endregion\n\n\n    #region CreateInstance\n\n    private CompileCodeHelper CompileCodeHlp => field ??= GetService<CompileCodeHelper>().Init(this);\n\n    string IGetCodePath.CreateInstancePath { get; set; }\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    public dynamic GetCode(string path, NoParamOrder npo = default, string className = default)\n        => CompileCodeHlp.GetCode(path, className: className);\n\n    #endregion\n\n    #region My... Stuff\n\n    private CodeHelperTypedData CodeHelper => field\n        ??= new(helperSpecs: new(ExCtx, false, ((IGetCodePath)this).CreateInstancePath));\n\n    /// <inheritdoc />\n    public ITypedItem MyItem => CodeHelper.MyItem;\n\n    /// <inheritdoc />\n    public IEnumerable<ITypedItem> MyItems => CodeHelper.MyItems;\n\n    /// <inheritdoc />\n    public ITypedItem MyHeader => CodeHelper.MyHeader;\n\n    /// <inheritdoc />\n    public IDataSource MyData => CodeApi.Data;\n\n    #endregion\n\n\n    #region As Conversions\n\n    /// <inheritdoc cref=\"ITypedApi.AsItem\" />\n    public ITypedItem AsItem(object data, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsItem(data, new() { ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsItems\" />\n    public IEnumerable<ITypedItem> AsItems(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsItems(list, new() { ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsEntity\" />\n    public IEntity AsEntity(ICanBeEntity thing)\n        => CodeApi.Cdf.AsEntity(thing);\n\n    /// <inheritdoc cref=\"ITypedApi.AsTyped\" />\n    public ITyped AsTyped(object original, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsTyped(original, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsTypedList\" />\n    public IEnumerable<ITyped> AsTypedList(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsTypedList(list, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack\" />\n    public ITypedStack AsStack(params object[] items)\n        => CodeApi.Cdf.AsStack(items);\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack{T}\" />\n    public T AsStack<T>(params object[] items)\n        where T : class, IModelFromData, new()\n        => CodeApi.Cdf.AsStack<T>(items);\n\n    #endregion\n\n    [PrivateApi]\n    public ITypedRazorModel MyModel => throw new(\"MyModel isn't meant to work in WebApi\");\n\n\n    #region Net Core Compatibility Shims - Copy this entire section to WebApi Files\n\n    /// <inheritdoc cref=\"IDynamicWebApi.File\"/>\n    public dynamic File(NoParamOrder npo = default,\n        bool? download = null,\n        string virtualPath = null,\n        string contentType = null,\n        string fileDownloadName = null,\n        object contents = null)\n        => Shim.File(download: download, virtualPath: virtualPath, contentType: contentType, fileDownloadName: fileDownloadName, contents: contents);\n\n    private WebApiCoreShim Shim => new(Request);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok()\"/>\n    [NonAction]\n    public new OkResult Ok() => base.Ok(); // Shim.Ok();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok(object)\"/>\n    [NonAction] public HttpResponseMessage Ok(object value) => Shim.Ok(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NoContent()\"/>\n    [NonAction]\n    public HttpResponseMessage NoContent() => Shim.NoContent();\n\n    // TODO: the Content Shim could now be implemented after 16.02 - since we don't have the Content property any more\n\n    #region Content (ca. 5 overloads) can't be implemented, because it conflicts with our property \"Content\"\n\n    #endregion\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Redirect\"/>\n    [NonAction]\n    public new RedirectResult Redirect(string url) => base.Redirect(url); // Shim.Redirect(url);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.RedirectPermanent\"/>\n    [NonAction] public HttpResponseMessage RedirectPermanent(string url) => Shim.RedirectPermanent(url);\n\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int)\"/>\n    [NonAction] public HttpResponseMessage StatusCode(int statusCode) => Shim.StatusCode(statusCode);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int, object)\"/>\n    [NonAction] public HttpResponseMessage StatusCode(int statusCode, object value) => Shim.StatusCode(statusCode, value);\n\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized()\"/>\n    [NonAction] public HttpResponseMessage Unauthorized() => Shim.Unauthorized();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized(object)\"/>\n    [NonAction] public HttpResponseMessage Unauthorized(object value) => Shim.Unauthorized(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound()\"/>\n    [NonAction]\n    public new NotFoundResult NotFound() => base.NotFound();// Shim.NotFound();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound(object)\"/>\n    [NonAction] public HttpResponseMessage NotFound(object value) => Shim.NotFound(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.BadRequest()\"/>\n    [NonAction]\n    public new BadRequestResult BadRequest() => base.BadRequest(); // Shim.BadRequest();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict()\"/>\n    [NonAction]\n    public new ConflictResult Conflict() => base.Conflict(); // Shim.Conflict();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict(object)\"/>\n    [NonAction] public HttpResponseMessage Conflict(object error) => Shim.Conflict(error);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Accepted()\"/>\n    [NonAction] public HttpResponseMessage Accepted() => Shim.Accepted();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Forbid()\"/>\n    [NonAction] public HttpResponseMessage Forbid() => Shim.Forbid();\n\n    #endregion\n\n    #region As / AsList WIP v17\n\n    /// <inheritdoc />\n    public T As<T>(object source, NoParamOrder npo = default)\n        where T : class, IModelFromData\n        => CodeApi.Cdf.AsCustom<T>(source: source, npo: npo);\n\n    /// <inheritdoc />\n    public IEnumerable<T> AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData\n        => CodeApi.Cdf.AsCustomList<T>(source, npo, nullIfNull);\n\n    #endregion\n\n    #region Customize new WIP v17\n\n    /// <summary>\n    /// WIP\n    /// </summary>\n    [PrivateApi(\"Experiment v17.02+\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    protected ICodeCustomizer Customize => field ??= CodeApi.GetService<ICodeCustomizer>(reuse: true);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Custom/readme.md",
    "content": "﻿# ToSic.Sxc.Hybrid for DNN\n\nThis folder should contain the DNN implementations of the hybrid stuff. \n\n## Notes / Best Practices\n\n* We'll create subfolders for managing the code\n* but all the objects for the custom work should be in the `ToSic.Sxc.Hybrid` namespace  \n  don't use sub-namespaces because it just makes the docs harder to read / organize. \n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/ApiController.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Dnn;\n\n/// <summary>\n/// This is the base class for all custom API Controllers. <br/>\n/// With this, your code receives the full context  incl. the current App, DNN, Data, etc.\n/// </summary>\n[PublicApi(\"This was the official base class before v12. Try to move away from it, go to the latest base class on Custom.Hybrid.ApiTyped\")]\n[DnnLogExceptions]\n[Obsolete(\"This will continue to work, but you should use the Custom.Hybrid.Api14 or Custom.Dnn.Api12 instead.\")]\n[DefaultToNewtonsoftForHttpJson]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class ApiController : DnnSxcCustomControllerBase,\n    IHasDnn,\n    ICreateInstance,\n    IDynamicCode, \n    IDynamicWebApi, \n    IHasCodeLog\n{\n    internal const string ErrRecommendedNamespaces = \"To use it, use the new base class from Custom.Hybrid.Api14 or Custom.Dnn.Api12 instead.\";\n\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <remarks>\n    /// Probably obsolete, but a bit risky to just remove\n    /// We will only add it to ApiController but not to Api12, because no new code should ever use that.\n    /// </remarks>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public IBlock Block => SysHlp.GetBlockAndContext(Request);\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel9Old;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi.Data;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => SysHlp.GetService<TService>();\n\n    /// <inheritdoc cref=\"IHasDnn.Dnn\"/>\n    public IDnnContext Dnn => (ExCtx as IHasDnn)?.Dnn;\n\n    #region AsDynamic implementations\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic AsDynamic(string json, string fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n\n    #region AsList\n\n    /// <inheritdoc />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi?.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region CreateSource implementations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    #endregion\n\n    #region Content, Presentation & List\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic Content => CodeApi.Content;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic Header => CodeApi.Header;\n\n\n    #endregion\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    public dynamic File(NoParamOrder npo = default, bool? download = null, string virtualPath = null,\n        string contentType = null, string fileDownloadName = null, object contents = null) =>\n        throw new NotSupportedException(\"Not implemented. \" + ErrRecommendedNamespaces);\n\n    /// <inheritdoc cref=\"IDynamicWebApi.SaveInAdam\"/>\n    public IFile SaveInAdam(NoParamOrder npo = default, Stream stream = null, string fileName = null, string contentType = null,\n        Guid? guid = null, string field = null, string subFolder = \"\")\n        => DynHlp.SaveInAdam(stream: stream, fileName: fileName, contentType: contentType, guid: guid, field: field, subFolder: subFolder);\n\n    #endregion\n\n    #region Link & Edit - added to API in 2sxc 10.01\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi?.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi?.Edit;\n\n    #endregion\n\n    #region CmsContext\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi?.CmsContext;\n    #endregion\n\n    #region CreateInstance\n\n    string IGetCodePath.CreateInstancePath { get; set; }\n\n    private CompileCodeHelper CompileCodeHlp => field ??= GetService<CompileCodeHelper>().Init(this);\n\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\"/>\n    public dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => CompileCodeHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    #endregion\n\n    #region IHasLog\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => SysHlp.CodeLog;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Adam/AdamController.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.WebApi.PublicApi;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Adam.AdamControllerReal<int>;\n\nnamespace ToSic.Sxc.Dnn.Backend;\n\n/// <summary>\n/// Direct access to app-content items, simple manipulations etc.\n/// Should check for security at each standard call - to see if the current user may do this\n/// Then we can reduce security access level to anonymous, because each method will do the security check\n/// </summary>\n[SupportedModules(DnnSupportedModuleNames)]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]    // use view, all methods must re-check permissions\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamController() : DnnSxcControllerBase(\"Adam\"), IAdamController<int>\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpPost]\n    [HttpPut]\n    public object Upload(int appId, string contentType, Guid guid, string field, [FromUri] string subFolder = \"\", bool usePortalRoot = false) \n        => Real.Upload(new(Request, HttpContext.Current.Request), appId, contentType, guid, field, subFolder, usePortalRoot);\n\n    // Note: #AdamItemDto - as of now, we must use object because System.Io.Text.Json will otherwise not convert the object correctly :(\n\n    [HttpGet]\n    public IEnumerable</*AdamItemDto*/object> Items(int appId, string contentType, Guid guid, string field, string subfolder, bool usePortalRoot = false)\n        => Real.Items(appId, contentType, guid, field, subfolder, usePortalRoot);\n\n\n    [HttpPost]\n    public IEnumerable</*AdamItemDto*/object> Folder(int appId, string contentType, Guid guid, string field, string subfolder, string newFolder, bool usePortalRoot)\n        => Real.Folder(appId, contentType, guid, field, subfolder, newFolder, usePortalRoot);\n\n\n    [HttpGet]\n    public bool Delete(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, int id, bool usePortalRoot)\n        => Real.Delete(appId, contentType, guid, field, subfolder, isFolder, id, usePortalRoot);\n\n\n    [HttpGet]\n    public bool Rename(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, int id, string newName, bool usePortalRoot)\n        => Real.Rename(appId, contentType, guid, field, subfolder, isFolder, id, newName, usePortalRoot);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Adam/DnnAdamSecurityChecks.cs",
    "content": "﻿using DotNetNuke.Entities.Host;\nusing DotNetNuke.Security.Permissions;\nusing DotNetNuke.Services.FileSystem;\nusing ToSic.Sxc.Adam.Sys.Security;\nusing IAsset = ToSic.Eav.Apps.Assets.IAsset;\nusing IFile = ToSic.Eav.Apps.Assets.IFile;\nusing IFolder = ToSic.Eav.Apps.Assets.IFolder;\n\nnamespace ToSic.Sxc.Dnn.Backend;\n\ninternal class DnnAdamSecurityChecks(AdamSecurityChecksBase.Dependencies services)\n    : AdamSecurityChecksBase(services, DnnConstants.LogName)\n{\n    /// <summary>\n    /// Helper to check extension based on DNN settings\n    /// </summary>\n    /// <param name=\"fileName\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// mostly a copy from https://github.com/dnnsoftware/Dnn.Platform/blob/115ae75da6b152f77ad36312eb76327cdc55edd7/DNN%20Platform/Modules/Journal/FileUploadController.cs#L72\n    /// </remarks>\n    public override bool SiteAllowsExtension(string fileName)\n    {\n        var extension = Path.GetExtension(fileName);\n        return !string.IsNullOrEmpty(extension)\n               && Host.AllowedExtensionWhitelist.IsAllowedExtension(extension.ToLowerInvariant());\n    }\n\n    public override bool CanEditFolder(IAsset item)\n    {\n        var id = (item as IFolder)?.Id\n                 ?? (item as IFile)?.ParentId\n                 ?? throw new ArgumentException(\"Should be a DNN asset\", nameof(item));\n\n        if (FolderManager.Instance.GetFolder(id) is not FolderInfo folderInfo)\n            return false;\n\n        return FolderPermissionController.CanAddFolder(folderInfo) // ex: \"WRITE\" core folder permission\n            || FolderPermissionController.CanAdminFolder(folderInfo) // ex: \"WRITE\" core folder permission\n            || FolderPermissionController.CanManageFolder(folderInfo) // ex: \"WRITE\" core folder permission\n            || FolderPermissionController.CanDeleteFolder(folderInfo) // ex: \"WRITE\" core folder permission\n            || FolderPermissionController.CanCopyFolder(folderInfo); // ex: \"WRITE\" core folder permission\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/ApiExplorerController.cs",
    "content": "﻿using System.Reflection;\nusing System.Web.Compilation;\nusing System.Web.Hosting;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.WebApi.Sys.ApiExplorer;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sxc.Dnn.Compile.Sys;\nusing ToSic.Sxc.Dnn.Integration;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing RealController = ToSic.Eav.WebApi.Sys.ApiExplorer.ApiExplorerControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n[ValidateAntiForgeryToken]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ApiExplorerController() : DnnSxcControllerRoot(RealController.LogSuffix), IApiExplorerController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpGet]\n    public HttpResponseMessage Inspect(string path)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n        return Real.Inspect(path, GetCompiledAssembly);\n    }\n\n    private Assembly GetCompiledAssembly(string path)\n    {\n        var className = Path.GetFileNameWithoutExtension(path);\n        Log.A($\"Class name: {className}\");\n\n        var controllerVirtualPath =\n            Path.Combine(\n                SysHlp.GetService<DnnAppFolderUtilities>().Setup(Request).GetAppFolderVirtualPath(SysHlp.GetService<ISite>()), \n                path);\n\n        Log.A($\"Controller Virtual Path: {controllerVirtualPath}\");\n\n        if (!File.Exists(HostingEnvironment.MapPath(controllerVirtualPath)))\n            throw new($\"Error: can't find controller file: {controllerVirtualPath}\");\n\n        Assembly assembly;\n        var appJson = SysHlp.GetService<IAppJsonConfigurationService>();\n        var block = SysHlp.GetService<DnnGetBlock>().GetCmsBlock(Request);\n        var codeFileInfo = SysHlp.GetService<SourceAnalyzer>().TypeOfVirtualPath(controllerVirtualPath);\n        if ((block != null && appJson.DnnCompilerAlwaysUseRoslyn(block.AppId)) || codeFileInfo.AppCode || FileInAppCode(path))\n        {\n            Log.A(\"has AppCode\");\n            // Figure edition\n            HotBuildSpec spec = null;\n            \n            if (block != null)\n            {\n                var edition = SysHlp.GetService<PolymorphConfigReader>().UseViewEditionOrGet(block);\n                spec = new(block.AppId, edition: edition, appName: block.App.Name);\n            }\n            assembly = SysHlp.GetService<IRoslynBuildManager>().GetCompiledAssembly(codeFileInfo, className, spec)?.Assembly;\n        }\n        else\n        {\n            assembly = BuildManager.GetCompiledAssembly(controllerVirtualPath);\n        }\n\n        if (assembly == null)\n            throw new(\"Assembly not found or compiled to null (error).\");\n\n        return assembly;\n    }\n\n    [HttpGet]\n    [JsonFormatter(Casing = Casing.Camel)]\n    public AllApiFilesDto AppApiFiles(int appId) => Real.AppApiFiles(appId);\n\n    private bool FileInAppCode(string path) => path.StartsWith(\"AppCode\\\\api\\\\\", StringComparison.InvariantCultureIgnoreCase) || path.ContainsInsensitive(\"\\\\AppCode\\\\api\\\\\");\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/AppController.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.DataSources.Sys;\nusing ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing AppDto = ToSic.Eav.WebApi.Sys.Dto.AppDto;\nusing RealController = ToSic.Sxc.Backend.Admin.AppControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n// [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)] can't be used, because it forces the security\n// token, which fails in the cases where the url is called using get, which should result in a download\n// [ValidateAntiForgeryToken] because the exports are called by the browser directly (new tab) \n// we can't set this globally (only needed for imports)\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppController() : DnnSxcControllerBase(RealController.LogSuffix), IAppController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public ICollection<AppDto> List(int zoneId) => Real.List(zoneId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    public ICollection<AppDto> InheritableApps() => Real.InheritableApps();\n\n    /// <inheritdoc />\n    [HttpDelete]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public void App(int zoneId, int appId, bool fullDelete = true)\n    {\n        SysHlp.PreventServerTimeout600();\n        Real.App(zoneId, appId, fullDelete);\n    }\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public void App(int zoneId, string name, int? inheritAppId = null) => Real.App(zoneId, name, inheritAppId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public ICollection<SiteLanguageDto> Languages(int appId) => Real.Languages(appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public AppExportInfoDto Statistics(int zoneId, int appId) => Real.Statistics(zoneId, appId);\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public bool FlushCache(int zoneId, int appId) => Real.FlushCache(zoneId, appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    public HttpResponseMessage Export(int zoneId, int appId, bool includeContentGroups, bool resetAppGuid, bool assetsAdam, bool assetsSite, bool assetAdamDeleted = true)\n        => Real.Export(new(zoneId, appId, includeContentGroups, resetAppGuid, assetsAdam, assetsSite, assetAdamDeleted))\n            .ToHttpResponse();\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    public async Task<bool> SaveData(int zoneId, int appId, bool includeContentGroups, bool resetAppGuid, bool withPortalFiles = false)\n        => (await Real.SaveData(new(zoneId, appId, includeContentGroups, resetAppGuid, WithSiteFiles: withPortalFiles))).Data;\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    public Task<ImportResultDto> Reset(int zoneId, int appId, bool withPortalFiles = false)\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.Reset(zoneId, appId, PortalSettings.DefaultLanguage, withPortalFiles);\n    }\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public List<AppStackDataRaw> GetStack(int appId, string part, string key = null, Guid? view = null)\n        => Real.GetStack(appId, part, key, view);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public ImportResultDto Import(int zoneId)\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.Import(new(Request, HttpContext.Current.Request), zoneId, HttpContext.Current.Request[\"Name\"]);\n    }\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public IEnumerable<PendingAppDto> GetPendingApps(int zoneId)\n        => Real.GetPendingApps(zoneId);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public ImportResultDto InstallPendingApps(int zoneId, IEnumerable<PendingAppDto> pendingApps)\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.InstallPendingApps(zoneId, pendingApps);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/AppExtensionsController.cs",
    "content": "using System.Web;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Admin.AppExtensionsControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppExtensionsController() : DnnSxcControllerBase(RealController.LogSuffix), IAppExtensionsController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [JsonFormatter(Casing = Casing.Camel)]\n    public ExtensionsResultDto Extensions(int appId)\n        => Real.Extensions(appId);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public PreflightResultDto InstallPreflight(int appId, string editions = \"\")\n        => Real.InstallPreflight(new(Request, HttpContext.Current.Request), appId, editions);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public PreflightResultDto InstallPreflightFrom(int appId, [FromBody] string[] urls, string editions = \"\")\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.InstallPreflightFrom(urls, appId, editions);\n    }\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public bool Install(int zoneId, int appId, string editions = \"\", bool overwrite = false)\n        => Real.Install(new(Request, HttpContext.Current.Request), zoneId, appId, editions, overwrite);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public bool InstallFrom(int zoneId, int appId, [FromBody] string[] urls, string editions = \"\", bool overwrite = false)\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.InstallFrom(urls, zoneId, appId, editions, overwrite);\n    }\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [JsonFormatter(Casing = Casing.Camel)]\n    public ExtensionInspectResultDto Inspect(int appId, string name, string edition = null)\n        => Real.Inspect(appId, name, edition);\n\n    /// <inheritdoc />\n    /// Update/create endpoint using PUT with name as route segment.\n    [Route(\"api/2sxc/admin/[controller]/{name}\")]\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [JsonFormatter(Casing = Casing.Camel)]\n    public new bool Configuration(int appId, [FromUri] string name, [FromBody] ExtensionManifest configuration)\n        => Real.Configuration(appId, name, configuration);\n\n    ///// <summary>\n    ///// Alias POST endpoint for front-ends posting to /appExtensions/extensions with query parameters.\n    ///// Matches plural POST behavior to avoid 405 errors if client uses POST.\n    ///// </summary>\n    ////[ActionName(\"extensions\")]\n    //[HttpPost]\n    //[ValidateAntiForgeryToken]\n    //[SupportedModules(DnnSupportedModuleNames)]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    //[JsonFormatter(Casing = Casing.Camel)]\n    //public bool Extensions(int appId, string name, [FromBody] ExtensionManifest configuration)\n    //    => Real.Extension(appId, name, configuration);\n\n    /// <inheritdoc />\n    [HttpGet]\n    // Note: since this is a GET download, there is no ValidateAntiForgeryToken and no header with the module names\n    //[ValidateAntiForgeryToken]\n    //[SupportedModules(DnnSupportedModuleNames)]\n    [DnnAuthorize(StaticRoles = \"Administrators\")]\n    public HttpResponseMessage Download(int appId, string name)\n        => Real.Download(appId, name).ToHttpResponse();\n\n    /// <inheritdoc />\n    [HttpDelete]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [JsonFormatter(Casing = Casing.Camel)]\n    public bool Delete(int appId, string name, string edition = null, bool force = false, bool withData = false)\n        => Real.Delete(appId, name, edition, force, withData);\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/AppFilesController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Apps.Sys.EditAssets;\nusing ToSic.Sxc.Backend.Admin.AppFiles;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Admin.AppFiles.AppFilesControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// This one supplies portal-wide (or cross-portal) settings / configuration\n/// </summary>\n[SupportedModules(DnnSupportedModuleNames)]\n[DnnLogExceptions]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppFilesController() : DnnSxcControllerBase(RealController.LogSuffix), IAppFilesController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpGet]\n    public ICollection<string> All(int appId, bool global, string path = null, string mask = \"*.*\",\n        bool withSubfolders = false, bool returnFolders = false) \n        => Real.All(appId, global, path, mask, withSubfolders, returnFolders);\n\n    [HttpGet]\n    public AssetEditInfo Asset(int appId, \n        int templateId = 0, string path = null, // identifier is always one of these two\n        bool global = false)\n        => Real.Asset(appId, templateId, path, global);\n\n    [HttpPost]\n    public bool Create(\n        [FromUri] int appId,\n        [FromUri] string path,\n        [FromUri] bool global,\n        [FromUri] string templateKey)\n        => Real.Create(appId, path, global, templateKey);\n\n    [HttpPost]\n    public bool Asset(\n        [FromUri] int appId, \n        [FromBody] AssetEditInfo template,\n        [FromUri] int templateId = 0, \n        [FromUri] string path = null, // identifier is either template Id or path\n        // todo w/SPM - global never seems to be used - must check why and if we remove or add to UI\n        // TODO: NEW PARAM TEMPLATEKey SHOULD BE USED TO CREATE THE FILE\n        [FromUri] bool global = false) \n        => Real.Asset(appId: appId, template: template, templateId: templateId, path: path, global: global);\n\n    [HttpGet]\n    public TemplatesDto GetTemplates(string purpose = null, string type = null)\n        => Real.GetTemplates(purpose, type);\n\n    [HttpGet]\n    public TemplatePreviewDto Preview(int appId, string path, string templateKey, bool global = false)\n        => Real.Preview(appId, path, templateKey, global);\n\n    [HttpGet]\n    public AllFilesDto AppFiles(int appId, string path = null, string mask = null)\n        => Real.AppFiles(appId, path, mask);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/AppInternalsController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.AppInternalsControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// Proxy Class to the AppInternalsController (Web API Controller)\n/// </summary>\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppInternalsController() : DnnSxcControllerBase(RealController.LogSuffix), IAppInternalsController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc/>\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public AppInternalsDto Get(int appId)\n        => Real.Get(appId);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/AppPartsController.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Admin.AppPartsControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n// [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)] can't be used, because it forces the security\n// token, which fails in the cases where the url is called using get, which should result in a download\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppPartsController() : DnnSxcControllerRoot(RealController.LogSuffix), IAppPartsController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [ValidateAntiForgeryToken]\n    public ExportPartsOverviewDto Get(int zoneId, int appId, string scope)\n        => Real.Get(zoneId: zoneId, appId: appId, scope: scope);\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public HttpResponseMessage Export(int zoneId, int appId, string contentTypeIdsString, string entityIdsString, string templateIdsString)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n\n        return Real.Export(zoneId: zoneId, appId: appId, contentTypeIdsString: contentTypeIdsString,\n            entityIdsString: entityIdsString, templateIdsString: templateIdsString);\n    }\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [ValidateAntiForgeryToken]\n    public ImportResultDto Import(int zoneId, int appId)\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.Import(uploadInfo: new(Request, HttpContext.Current.Request), zoneId: zoneId, appId: appId);\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/CodeController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Admin.CodeControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeController() : DnnSxcControllerBase(RealController.LogSuffix)\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public IEnumerable<RealController.HelpItem> InlineHelp(string language)\n        => Real.InlineHelp(language);\n\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    public RichResult GenerateDataModels(int appId, string generator, string edition = null, int configurationId = 0)\n        => Real.GenerateDataModels(appId, edition, generator: generator, configurationId: configurationId);\n\n    // #MigrateSimpleDataToSysDataAccess\n    //[HttpGet]\n    //[JsonFormatter]\n    //[ValidateAntiForgeryToken]\n    //[SupportedModules(DnnSupportedModuleNames)]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    //public EditionsDto GetEditions(int appId)\n    //    => Real.GetEditions(appId);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/DataController.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// Web API Controller for app data bundles etc.\n/// </summary>\n/// <remarks>\n/// Because download JSON call is made in a new window, they won't contain any http-headers like module-id or security token. \n/// So we can't use the classic protection attributes to the class like:\n/// - [SupportedModules(DnnSupportedModuleNames)]\n/// - [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n/// - [ValidateAntiForgeryToken]\n/// Instead, each method must have all attributes, or do additional security checking.\n/// Security checking is possible, because the cookie still contains user information\n/// </remarks>\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DataController() : DnnSxcControllerBase(DataControllerReal.LogSuffix), IAdminDataController\n{\n    private DataControllerReal Real => SysHlp.GetService<DataControllerReal>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public HttpResponseMessage BundleExport(int appId, Guid exportConfiguration, int indentation = 0)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n        return Real.BundleExport(appId, exportConfiguration, indentation);\n    }\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [ValidateAntiForgeryToken]\n    public ImportResultDto BundleImport(int zoneId, int appId)\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.BundleImport(new(Request, HttpContext.Current.Request), zoneId, appId);\n    }\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public bool BundleSave(int appId, Guid exportConfiguration, int indentation = 0)\n        => Real.BundleSave(appId, exportConfiguration, indentation);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public bool BundleRestore(string fileName, int zoneId, int appId)\n        => Real.BundleRestore(fileName, zoneId, appId);\n\n    ///// <inheritdoc />\n    //[HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    //public IReadOnlyList<WorkEntityRecycleBin.RecycleBinItem> GetRecycleBin(int appId)\n    //    => Real.GetRecycleBin(appId);\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    public void Recycle(int appId, int transactionId)\n        => Real.Recycle(appId, transactionId);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/DialogController.cs",
    "content": "﻿using ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Admin.DialogControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// This one supplies portal-wide (or cross-portal) settings / configuration\n/// </summary>\n[SupportedModules(DnnSupportedModuleNames)]\n[DnnLogExceptions]\n// 2dm 2024-01-26 changed from \"Admin\" to \"Edit\" because it's used in the quick-dialog.\n// It needs \"Edit\" to get settings for the quick-dialog-add-inner content\n// https://github.com/2sic/2sxc/issues/3234\n// If we refactor the quick-dialog it should provide the settings directly in the main call\n// And not need this any more - then we can switch back to \"Admin\"\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DialogController() : DnnSxcControllerBase(RealController.LogSuffix), IDialogController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpGet]\n    public DialogContextStandaloneDto Settings(int appId)\n        => Real.Settings(appId);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/DnnApiInspector.cs",
    "content": "﻿using System.Reflection;\nusing ToSic.Eav.WebApi.Sys.ApiExplorer;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\ninternal class DnnApiInspector() : ServiceBase(DnnConstants.LogName), IApiInspector\n{\n    public bool IsBody(ParameterInfo paramInfo)\n        => paramInfo.CustomAttributes.Any(ca => ca.AttributeType == typeof(FromBodyAttribute));\n\n\n    public List<string> GetHttpVerbs(MethodInfo methodInfo)\n    {\n        var httpMethods = new List<string>();\n\n        var getAtt = methodInfo.GetCustomAttribute<HttpGetAttribute>();\n        if (getAtt != null)\n            httpMethods.Add(getAtt.HttpMethods[0].Method);\n\n        var postAtt = methodInfo.GetCustomAttribute<HttpPostAttribute>();\n        if (postAtt != null)\n            httpMethods.Add(postAtt.HttpMethods[0].Method);\n\n        var putAtt = methodInfo.GetCustomAttribute<HttpPutAttribute>();\n        if (putAtt != null)\n            httpMethods.Add(putAtt.HttpMethods[0].Method);\n\n        var deleteAtt = methodInfo.GetCustomAttribute<HttpDeleteAttribute>();\n        if (deleteAtt != null)\n            httpMethods.Add(deleteAtt.HttpMethods[0].Method);\n\n        var acceptVerbsAtt = methodInfo.GetCustomAttribute<AcceptVerbsAttribute>();\n        if (acceptVerbsAtt != null)\n            httpMethods.AddRange(acceptVerbsAtt.HttpMethods.Select(m => m.Method));\n\n        return httpMethods;\n    }\n\n    public ApiSecurityDto GetSecurity(MemberInfo member)\n    {\n        var dnnAuthList = member.GetCustomAttributes<DnnModuleAuthorizeAttribute>().ToList();\n\n        return new()\n        {\n            ignoreSecurity = member.GetCustomAttribute<AllowAnonymousAttribute>() != null,\n            allowAnonymous = dnnAuthList.Any(a => a.AccessLevel == SecurityAccessLevel.Anonymous),\n            requireVerificationToken = member.GetCustomAttribute<ValidateAntiForgeryTokenAttribute>() != null,\n            superUser = dnnAuthList.Any(a => a.AccessLevel == SecurityAccessLevel.Host),\n            admin = dnnAuthList.Any(a => a.AccessLevel == SecurityAccessLevel.Admin),\n            edit = dnnAuthList.Any(a => a.AccessLevel == SecurityAccessLevel.Edit),\n            view = dnnAuthList.Any(a => a.AccessLevel == SecurityAccessLevel.View),\n            // if it has any dnn authorize attributes or supported-modules it needs the context\n            requireContext = dnnAuthList.Any() || member.GetCustomAttribute<SupportedModulesAttribute>() != null,\n        };\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/EntityController.cs",
    "content": "﻿using ToSic.Eav.ImportExport.Sys.Options;\nusing ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing Guid = System.Guid;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.EntityControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// Proxy Class to the EAV EntitiesController (Web API Controller)\n/// </summary>\n/// <remarks>\n/// Because download JSON call is made in a new window, they won't contain any http-headers like module-id or security token. \n/// So we can't use the classic protection attributes to the class like:\n/// - [SupportedModules(DnnSupportedModuleNames)]\n/// - [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n/// - [ValidateAntiForgeryToken]\n/// Instead, each method must have all attributes, or do additional security checking.\n/// Security checking is possible, because the cookie still contains user information\n/// </remarks>\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EntityController() : DnnSxcControllerBase(RealController.LogSuffix), IEntityController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc/>\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public IEnumerable<Dictionary<string, object>> List(int appId, string contentType)\n        => Real.List(appId, contentType);\n\n\n    /// <inheritdoc/>\n    [HttpDelete]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public void Delete(string contentType, int appId, int? id = null, Guid? guid = null, bool force = false, int? parentId = null, string parentField = null)\n        => Real.Delete(contentType, appId, id, guid, force, parentId, parentField);\n\n\n    /// <inheritdoc/>\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public HttpResponseMessage Json(int appId, int id, string prefix, bool withMetadata)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n\n        return Real.Json(appId, id, prefix, withMetadata);\n    }\n\n\n    /// <inheritdoc/>\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public HttpResponseMessage Download(\n        int appId,\n        string language,\n        string defaultLanguage,\n        string contentType,\n        ExportSelection recordExport, \n        ExportResourceReferenceMode resourcesReferences,\n        ExportLanguageResolution languageReferences, \n        string selectedIds = null)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n\n        return Real.Download(appId, language, defaultLanguage, contentType, recordExport, resourcesReferences,\n            languageReferences, selectedIds);\n    }\n\n\n    /// <inheritdoc/>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public ContentImportResultDto XmlPreview(ContentImportArgsDto args)\n        => Real.XmlPreview(args);\n\n\n    /// <inheritdoc/>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public ContentImportResultDto XmlUpload(ContentImportArgsDto args)\n        => Real.XmlUpload(args);\n\n\n    /// <inheritdoc/>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public bool Upload(EntityImportDto args)\n        => Real.Upload(args);\n\n\n    ///// <inheritdoc/>\n    //// not final yet, so no [HttpGet]\n    //public dynamic Usage(int appId, Guid guid) => Real.Usage(appId, guid);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/FeatureController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Admin.Features;\nusing ToSic.Eav.WebApi.Sys.Licenses;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sys.Capabilities.Features;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.Features.FeatureControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// Provide information about activated features which will be managed externally. \n/// </summary>\n/// <remarks>\n/// Added in 2sxc 10\n/// </remarks>\n[SupportedModules(DnnSupportedModuleNames)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class FeatureController() : DnnSxcControllerRoot(RealController.LogSuffix), IFeatureController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public FeatureStateDto Details(string nameId)\n        => Real.Details(nameId);\n\n    /// <summary>\n    /// POST updated features JSON configuration.\n    /// </summary>\n    /// <remarks>\n    /// Added in 2sxc 13\n    /// </remarks>\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    public bool SaveNew([FromBody] List<FeatureStateChange> changes)\n        => Real.SaveNew(changes);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/FieldController.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.FieldControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// Web API Controller for Content-Type structures, fields etc.\n/// </summary>\n[SupportedModules(DnnSupportedModuleNames)]\n[ValidateAntiForgeryToken]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class FieldController() : DnnSxcControllerBase(RealController.LogSuffix), IFieldController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    #region Fields - Get, Reorder, Data-Types (for dropdown), etc.\n\n    /// <summary>\n    /// Returns the configuration for a content type\n    /// </summary>\n    [HttpGet]\n    public IEnumerable<ContentTypeFieldDto> All(int appId, string staticName) => Real.All(appId, staticName);\n\n    /// <summary>\n    /// Used to be GET ContentType/DataTypes\n    /// </summary>\n    [HttpGet]\n    public string[] DataTypes(int appId) => Real.DataTypes(appId);\n\n    /// <summary>\n    /// Used to be GET ContentType/InputTypes\n    /// </summary>\n    [HttpGet]\n    public ICollection<InputTypeInfo> InputTypes(int appId) => Real.InputTypes(appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    public Dictionary<string, string> ReservedNames() => AttributeNames.ReservedNames;\n        \n    /// <summary>\n    /// Used to be GET ContentType/AddField\n    /// </summary>\n    [HttpPost]\n    public int Add(int appId, int contentTypeId, string staticName, string type, string inputType, int index) \n        => Real.Add(appId, contentTypeId, staticName, type, inputType, index);\n\n    /// <summary>\n    /// Used to be GET ContentType/DeleteField\n    /// </summary>\n    [HttpDelete]\n    public bool Delete(int appId, int contentTypeId, int attributeId) => Real.Delete(appId, contentTypeId, attributeId);\n\n    /// <summary>\n    /// Used to be GET ContentType/Reorder\n    /// </summary>\n    [HttpPost]\n    public bool Sort(int appId, int contentTypeId, string order) => Real.Sort(appId, contentTypeId, order);\n\n\n    /// <summary>\n    /// Used to be GET ContentType/UpdateInputType\n    /// </summary>\n    [HttpPost]\n    public bool InputType(int appId, int attributeId, string inputType) => Real.InputType(appId, attributeId, inputType);\n\n\n    #endregion\n\n    /// <summary>\n    /// Used to be GET ContentType/Rename\n    /// </summary>\n    [HttpPost]\n    public void Rename(int appId, int contentTypeId, int attributeId, string newName)\n        => Real.Rename(appId, contentTypeId, attributeId, newName);\n\n\n    #region Sharing and Inheriting\n\n    [HttpGet]\n    public IEnumerable<ContentTypeFieldDto> GetSharedFields(int appId, int attributeId = default)\n        => Real.GetSharedFields(appId, attributeId);\n\n    [HttpGet]\n    public IEnumerable<ContentTypeFieldDto> GetAncestors(int appId, int attributeId)\n        => Real.GetAncestors(appId, attributeId);\n\n    [HttpGet]\n    public IEnumerable<ContentTypeFieldDto> GetDescendants(int appId, int attributeId)\n        => Real.GetDescendants(appId, attributeId);\n    \n    [HttpPost]\n    public bool Share(int appId, int attributeId, bool share, bool hide = false)\n        => Real.Share(appId, attributeId, share, hide);\n\n    [HttpPost]\n    public bool Inherit(int appId, int attributeId, Guid inheritMetadataOf)\n        => Real.Inherit(appId, attributeId, inheritMetadataOf);\n\n    [HttpPost]\n    public bool AddInheritedField(int appId, int contentTypeId, string sourceType, Guid sourceField, string name)\n        => Real.AddInheritedField(appId, contentTypeId, sourceType, sourceField, name);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/MetadataController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Admin.Metadata;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.Metadata.MetadataControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <inheritdoc cref=\"IMetadataController\" />\n[SupportedModules(DnnSupportedModuleNames)]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class MetadataController() : DnnSxcControllerBase(RealController.LogSuffix), IMetadataController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpGet]\n    public MetadataListDto Get(int appId, int targetType, string keyType, string key, string contentType = null)\n        => Real.Get(appId, targetType, keyType, key, contentType);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/QueryController.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.WebApi.Sys.Admin.Query;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Admin.Query.QueryControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// Proxy Class to the EAV PipelineDesignerController (Web API Controller)\n/// </summary>\n[SupportedModules(DnnSupportedModuleNames)]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[DnnLogExceptions]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class QueryController() : DnnSxcControllerBase(RealController.LogSuffix, RealController.LogGroup,\n    firstMessage: $\"Query: {HttpContext.Current?.Request.Url.AbsoluteUri.After(\"/query/\")}\"), IQueryController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpGet]\n    public QueryDefinitionDto Get(int appId, int? id = null) =>\n        Real.Get(appId, id);\n\n    [HttpGet]\n    public IEnumerable<DataSourceDto> DataSources(int zoneId, int appId) =>\n        Real.DataSources(new(zoneId, appId));\n\n    [HttpPost]\n    public QueryDefinitionDto Save([FromBody] QueryDefinitionDto data, int appId, int id) =>\n        Real.Save(data, appId, id);\n\n    [HttpGet]\n    public QueryRunDto RunDev(int appId, int id, int top = 0) =>\n        Real.RunDev(appId, id, top);\n\n    [HttpGet]\n    public QueryRunDto DebugStream(int appId, int id, string from, string @out, int top = 25)  =>\n        Real.DebugStream(appId, id, @from, @out, top);\n\n    [HttpGet]\n    public void Clone(int appId, int id) =>\n        Real.Clone(appId, id);\n\n    [HttpDelete]\n    public bool Delete(int appId, int id) =>\n        Real.DeleteIfUnused(appId, id);\n\n    [HttpPost]\n    public bool Import(EntityImportDto args) =>\n        Real.Import(args);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/TypeController.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Admin.TypeControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n/// <summary>\n/// Web API Controller for Content-Type structures, fields etc.\n/// </summary>\n/// <remarks>\n/// Because download JSON call is made in a new window, they won't contain any http-headers like module-id or security token. \n/// So we can't use the classic protection attributes to the class like:\n/// - [SupportedModules(DnnSupportedModuleNames)]\n/// - [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n/// - [ValidateAntiForgeryToken]\n/// Instead, each method must have all attributes, or do additional security checking.\n/// Security checking is possible, because the cookie still contains user information\n/// </remarks>\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class TypeController() : DnnSxcControllerBase(RealController.LogSuffix), ITypeController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <summary>\n    /// Get a list of all content-types.\n    /// See https://docs.2sxc.org/basics/data/content-types/index.html\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"scope\"></param>\n    /// <param name=\"withStatistics\"></param>\n    /// <returns></returns>\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public IEnumerable<ContentTypeDto> List(int appId, string scope = null, bool withStatistics = false)\n        => Real.List(appId, scope, withStatistics);\n\n\n    /// <summary>\n    /// Used to be GET Scopes.\n    /// Scopes are a way to organize content types, see https://docs.2sxc.org/basics/data/content-types/scopes.html\n    /// </summary>\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public ScopesDto Scopes(int appId)\n        => Real.Scopes(appId);\n\n\n    /// <summary>\n    /// Used to be GET ContentTypes.\n    /// See https://docs.2sxc.org/basics/data/content-types/index.html\n    /// </summary>\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public ContentTypeDto Get(int appId, string contentTypeId, string scope = null)\n        => Real.Get(appId, contentTypeId, scope);\n\n\n    /// <summary>\n    /// Delete a Content-Type\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"staticName\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// ATM it requires the DELETE verb, but this often causes problems on IIS with WebDav.\n    /// TODO: probably switch over to use Get again, even if it's not as descriptive as delete\n    /// </remarks>\n    [HttpDelete]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public bool Delete(int appId, string staticName)\n        => Real.Delete(appId, staticName);\n\n\n    /// <summary>\n    /// Save a Content-Type.\n    /// See https://docs.2sxc.org/basics/data/content-types/index.html\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"item\"></param>\n    /// <returns></returns>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    // 2019-11-15 2dm special change: item to be Dictionary<string, object> because in DNN 9.4\n    // it causes problems when a content-type has metadata, where a value then is a deeper object\n    // in future, the JS front-end should send something clearer and not the whole object\n    public bool Save(int appId, Dictionary<string, object> item)\n        => Real.Save(appId, item);\n\n\n    /// <summary>\n    /// Used to add a Ghost content-type.\n    /// See https://docs.2sxc.org/basics/data/content-types/range-app-shared.html\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"sourceNameId\"></param>\n    /// <returns></returns>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    public bool AddGhost(int appId, string sourceNameId)\n        => Real.AddGhost(appId, sourceNameId);\n\n\n    /// <summary>\n    /// Change which attribute on a Content-Type is the title. \n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"contentTypeId\"></param>\n    /// <param name=\"attributeId\"></param>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public void SetTitle(int appId, int contentTypeId, int attributeId)\n        => Real.SetTitle(appId, contentTypeId, attributeId);\n\n\n    /// <summary>\n    /// Export a Content-Type as JSON\n    /// </summary>\n    /// <remarks>\n    /// New in 2sxc 11.07\n    /// </remarks>\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public HttpResponseMessage Json(int appId, string name)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n        return Real.Json(appId, name);\n    }\n\n\n    /// <summary>\n    /// Used to be POST ImportExport/ImportContent\n    /// </summary>\n    /// <remarks>\n    /// New in 2sxc 11.07\n    /// </remarks>\n    /// <returns></returns>\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [ValidateAntiForgeryToken]\n    public ImportResultDto Import(int zoneId, int appId)\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.Import(new(Request, HttpContext.Current.Request), zoneId, appId);\n    }\n\n    /// <summary>\n    /// Json Bundle Export\n    /// </summary>\n    /// <remarks>\n    /// New in 2sxc v15.x\n    /// </remarks>\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public HttpResponseMessage JsonBundleExport(int appId, Guid exportConfiguration, int indentation = 0)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n        return Real.JsonBundleExport(appId, exportConfiguration, indentation);\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/ViewController.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.WebApi.Sys.Context;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Backend.Views;\nusing ToSic.Sxc.Dnn.Backend.Context;\nusing ToSic.Sxc.Dnn.Pages;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Admin.ViewControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ViewController() : DnnSxcControllerBase(RealController.LogSuffix), IViewController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public IEnumerable<ViewDetailsDto> All(int appId)\n        => Real.All(appId);\n\n    /// <inheritdoc />\n    [HttpGet, HttpDelete]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public bool Delete(int appId, int id)\n        => Real.Delete(appId, id);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public HttpResponseMessage Json(int appId, int viewId)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n\n        return Real.Json(appId, viewId);\n    }\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [ValidateAntiForgeryToken]\n    public ImportResultDto Import(int zoneId, int appId)\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.Import(new(Request, HttpContext.Current.Request), zoneId, appId);\n    }\n\n    /// <inheritdoc />\n    [HttpGet]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [ValidateAntiForgeryToken]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public IEnumerable<ViewDto> Usage(int appId, Guid guid)\n        => Real.UsagePreparations((views, blocks) =>\n            {\n                // create array with all 2sxc modules in this portal\n                var allMods = new DnnPages(Log).AllModulesWithContent(PortalSettings.PortalId);\n                Log.A($\"Found {allMods.Count} modules\");\n\n                return views.Select(vwb => vwb.Init(blocks, allMods));\n            })\n            .Usage(appId, guid);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Admin/ZoneController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Eav.WebApi.Sys.Zone;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.ZoneControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Admin;\n\n[SupportedModules(DnnSupportedModuleNames)]\n[DnnLogExceptions]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ZoneController() : DnnSxcControllerBase(RealController.LogSuffix), IZoneController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    public IList<SiteLanguageDto> GetLanguages()\n        => Real.GetLanguages();\n\n    /// <inheritdoc />\n    [HttpGet]\n    public void SwitchLanguage(string cultureCode, bool enable)\n        => Real.SwitchLanguage(cultureCode, enable);\n\n    /// <inheritdoc />\n    [HttpGet]\n    public SystemInfoSetDto GetSystemInfo()\n        => Real.GetSystemInfo();\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/App/AppDataController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.App;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing static ToSic.Eav.WebApi.Sys.EavWebApiConstants;\nusing RealController = ToSic.Sxc.Backend.App.AppDataControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.App;\n\n/// <inheritdoc />\n[AllowAnonymous]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppDataController() : DnnSxcControllerBase(RealController.LogSuffix), IAppDataController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    #region Get List / all of a certain content-type\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous]   // will check security internally, so assume no requirements\n    public IEnumerable<IDictionary<string, object>> GetEntities(string contentType, string appPath = default, [FromUri] IDictionary<string, string> queryParams = null)\n        => Real.GetEntities(contentType, appPath, uri: Request.RequestUri);\n\n    #endregion\n\n    #region GetOne by ID / GUID\n        \n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will check security internally, so assume no requirements\n    public IDictionary<string, object> GetOne(string contentType, string guid, string appPath = default, [FromUri] IDictionary<string, string> queryParams = null) // this will handle Guid\n        => Real.GetOne(contentType, guid, appPath, uri: Request.RequestUri);\n\n    [HttpGet]\n    [AllowAnonymous] // will check security internally, so assume no requirements\n    public IDictionary<string, object> GetOne(string contentType, int id, string appPath = default, [FromUri] IDictionary<string, string> queryParams = null) // this will handle int id\n        => Real.GetOne(contentType, id.ToString(), appPath, uri: Request.RequestUri);\n\n    #endregion\n\n    #region Create\n\n    /// <inheritdoc />\n    [HttpPost]\n    [AllowAnonymous] // will check security internally, so assume no requirements\n    public IDictionary<string, object> CreateOrUpdate(\n        [FromUri] string contentType,\n        [FromBody] Dictionary<string, object> newContentItem, \n        [FromUri] int? id = null,\n        [FromUri] string appPath = null)\n        => Real.CreateOrUpdate(contentType, newContentItem, id, appPath);\n\n    #endregion\n\n    #region Delete\n\n    /// <inheritdoc />\n    [HttpDelete]\n    [AllowAnonymous]   // will check security internally, so assume no requirements\n    public void Delete(string contentType, string guid, [FromUri] string appPath = null) // this will handle Guid\n        => Real.Delete(contentType, guid, appPath);\n\n \n    [HttpDelete]\n    [AllowAnonymous]   // will check security internally, so assume no requirements\n    public void Delete(string contentType, int id, [FromUri] string appPath = null) // this will handle int id\n        => Real.Delete(contentType, id.ToString(), appPath);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/App/AppQueryController.cs",
    "content": "﻿using ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.WebApi.Sys.Admin.App;\nusing ToSic.Eav.WebApi.Sys.Admin.Query;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.App.AppQueryControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.App;\n\n[AllowAnonymous] // All functions will check security internally, so assume no requirements\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppQueryController() : DnnSxcControllerBase(RealController.LogSuffix), IAppQueryController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    // GET is separated from POST to solve HttpResponseException that happens when\n    // 'content-type' header is missing (or in GET request) on the endpoint that has [FromBody] in signature\n\n    [HttpGet]\n    public IDictionary<string, IEnumerable<EavLightEntity>> Query(\n        [FromUri] string name,\n        [FromUri] int? appId = null,\n        [FromUri] string stream = null,\n        [FromUri] bool? includeGuid = false\n    ) => Real.Query(name, appId, stream, includeGuid);\n\n    [HttpPost]\n    public IDictionary<string, IEnumerable<EavLightEntity>> QueryPost\n    ([FromUri] string name,\n        [FromBody] QueryParametersDtoFromClient more,\n        [FromUri] int? appId = null,\n        [FromUri] string stream = null,\n        [FromUri] bool? includeGuid = false\n    ) => Real.QueryPost(name, more, appId, stream, includeGuid);\n\n    [HttpGet] \n    public IDictionary<string, IEnumerable<EavLightEntity>> PublicQuery(\n        [FromUri] string appPath,\n        [FromUri] string name,\n        [FromUri] string stream = null\n    ) => Real.PublicQuery(appPath, name, stream);\n\n    [HttpPost]\n    public IDictionary<string, IEnumerable<EavLightEntity>> PublicQueryPost(\n        [FromUri] string appPath,\n        [FromUri] string name,\n        [FromBody] QueryParametersDtoFromClient more,\n        [FromUri] string stream = null\n    ) => Real.PublicQueryPost(appPath, name, more, stream);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/App/CacheController.cs",
    "content": "using ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\n\nnamespace ToSic.Sxc.Dnn.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CacheController() : DnnSxcControllerBase(CacheControllerReal.LogSuffix)\n{\n    private CacheControllerReal Real => SysHlp.GetService<CacheControllerReal>();\n\n    // Handles the app/auto/cache/flush route, using the current block context unless an appId is supplied.\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public bool Flush([FromBody] AppCacheFlushSpecs specs, [FromUri] int? appId = null)\n        => Real.FlushAuto(appId, specs);\n\n    // Handles the named-app route app/{appPath}/cache/flush for callers outside of a block context.\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [SupportedModules(DnnSupportedModuleNames)]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public bool Flush([FromUri] string appPath, [FromBody] AppCacheFlushSpecs specs)\n        => Real.Flush(appPath, specs);\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Cms/BlockController.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys.Ui;\nusing ToSic.Sxc.Backend.Cms;\nusing ToSic.Sxc.Backend.InPage;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Cms.BlockControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Cms;\n\n[ValidateAntiForgeryToken]\n// cannot use this, as most requests now come from a lone page [SupportedModules(DnnSupportedModuleNames)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockController() : DnnSxcControllerBase(RealController.LogSuffix), IBlockController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public string Block(int parentId, string field, int index, string app = \"\", Guid? guid = null)\n        => Real.Block(parentId, field, index, app, guid);\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public void Item([FromUri] int? index = null)\n        => Real.Item(index);\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public void App(int? appId)\n        => Real.App(appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public IEnumerable<AppUiInfo> Apps(string apps = null)\n        => Real.Apps(apps);\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public IEnumerable<ContentTypeUiInfo> ContentTypes()\n        => Real.ContentTypes();\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public IEnumerable<TemplateUiInfo> Templates()\n        => Real.Templates();\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n    public Guid? Template(int templateId, bool forceCreateContentGroup)\n        => Real.Template(templateId, forceCreateContentGroup);\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public AjaxRenderDto Render([FromUri] int templateId, [FromUri] string lang, [FromUri] string edition) \n        => Real.Set(DnnConstants.SysFolderRootVirtual.Trim('~')).Render(templateId, lang, edition);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public bool Publish(string part, int index)\n        => Real.Publish(part, index);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Cms/ContentGroupController.cs",
    "content": "﻿using ToSic.Sxc.Backend.Cms;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Cms.ContentGroupControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Cms;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentGroupController() : DnnSxcControllerBase(RealController.LogSuffix), IContentGroupController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public EntityInListDto Header(Guid guid) \n        => Real.Header(guid);\n\n\n    // TODO: shouldn't be part of ContentGroupController any more, as it's generic now\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public void Replace(Guid guid, string part, int index, int entityId, bool add = false)\n        => Real.Replace(guid, part, index, entityId, add);\n\n\n    // TODO: WIP changing this from ContentGroup editing to any list editing\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public ReplacementListDto Replace(Guid guid, string part, int index)\n        => Real.Replace(guid, part, index);\n\n\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public List<EntityInListDto> ItemList(Guid guid, string part)\n        => Real.ItemList(guid, part);\n\n\n    // TODO: part should be handed in with all the relevant names! atm it's \"content\" in the content-block scenario\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public bool ItemList([FromUri] Guid guid, List<EntityInListDto> list, [FromUri] string part = null)\n        => Real.ItemList(guid, list, part);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Cms/EditController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Cms.EditControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Cms;\n\n//[SupportedModules(DnnSupportedModuleNames)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EditController() : DnnSxcControllerBase(RealController.LogSuffix), IEditController\n{\n    #region Setup / Infrastructure\n\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    #endregion\n\n    /// <inheritdoc />\n    [HttpPost]\n    [AllowAnonymous] // will check security internally, so assume no requirements\n    public async Task<EditLoadDto> Load([FromBody] List<ItemIdentifier> items, int appId) =>\n        await Real.Load(items, appId);\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    [AllowAnonymous] // will check security internally, so assume no requirements\n    public async Task<Dictionary<Guid, int>> Save([FromBody] EditSaveDto package, int appId, bool partOfPage) =>\n        await Real.Save(package, appId, partOfPage);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n    public LinkInfoDto LinkInfo(string link, int appId, string contentType = default, Guid guid = default, string field = default) =>\n        Real.LinkInfo(link, appId, contentType, guid, field);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n    public bool Publish(int id) =>\n        Real.Publish(id);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Cms/HistoryController.cs",
    "content": "﻿using ToSic.Eav.Persistence.Versions;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Cms.HistoryControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Cms;\n\n/// <summary>\n/// Controller for history of entities\n/// </summary>\n[PrivateApi]\n[SupportedModules(DnnSupportedModuleNames)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HistoryController() : DnnSxcControllerBase(RealController.LogSuffix), IHistoryController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public List<ItemHistory> Get(int appId, [FromBody] ItemIdentifier item)\n        => Real.Get(appId, item);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    public bool Restore(int appId, int changeId, [FromBody] ItemIdentifier item) \n        => Real.Restore(appId, changeId, item);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Cms/ListController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Cms.ListControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Cms;\n\n[SupportedModules(DnnSupportedModuleNames)]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ListController() : DnnSxcControllerBase(RealController.LogSuffix), IListController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    /// <summary>\n    /// used to be GET Module/ChangeOrder\n    /// </summary>\n    [HttpPost]\n    public void Move(Guid? parent, string fields, int index, int toIndex)\n        => Real.Move(parent, fields, index, toIndex);\n\n\n    /// <inheritdoc />\n    /// <summary>\n    /// Used to be Get Module/RemoveFromList\n    /// </summary>\n    [HttpDelete]\n    public void Delete(Guid? parent, string fields, int index)\n        => Real.Delete(parent, fields, index);\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Context/DnnContextDtoExtensions.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Tabs;\nusing ToSic.Eav.WebApi.Sys.Context;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Dnn.Pages;\n\nnamespace ToSic.Sxc.Dnn.Backend.Context;\n\n/// <summary>\n/// This contains constructor like initializer calls for ContextDto objects.\n/// They are DNN specific\n/// </summary>\ninternal static class DnnContextDtoExtensions\n{\n    internal static ContentBlockDto ToDto(this BlockConfiguration block, IEnumerable<ModuleWithContent> blockModules)\n        => new()\n        {\n            Id = block.Id,\n            Guid = block.Guid,\n            Modules = blockModules.Select(m => m.Module.ToDto(m.Page)),\n        };\n\n    internal static InstanceDto ToDto(this ModuleInfo module, TabInfo page)\n        => new()\n        {\n            Id = module.ModuleID,\n            ShowOnAllPages = module.AllTabs,\n            Title = module.ModuleTitle,\n            UsageId = module.TabModuleID,\n            IsDeleted = module.IsDeleted || page.IsDeleted,\n            Page = page.ToDto(),\n        };\n\n    internal static PageDto ToDto(this TabInfo page)\n        => new()\n        {\n            Id = page.TabID,\n            Url = page.FullUrl,\n            Name = page.TabName,\n            CultureCode = page.CultureCode,\n            Visible = page.IsVisible,\n            Title = page.Title,\n            Portal = new(page.PortalID),\n        };\n\n    internal static ViewDto Init(this IView view, ICollection<BlockConfiguration> blocks, List<ModuleWithContent> modules)\n        => new()\n        {\n            Id = view.Entity.EntityId,\n            Guid = view.Entity.EntityGuid,\n            Name = view.Name,\n            Path = view.Path,\n            Blocks = blocks\n                .Where(b => b.View.Guid == view.Guid)\n                .Select(blWMod => blWMod.ToDto(modules.Where(m => m.ContentGroup == blWMod.Guid))),\n        };\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Context/DnnUiContextBuilder.cs",
    "content": "﻿using DotNetNuke.Entities.Modules;\nusing DotNetNuke.Entities.Portals;\nusing System.Web;\nusing ToSic.Eav.WebApi.Sys.Context;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Sxc.Backend.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Dnn.Web;\nusing ToSic.Sxc.WebApi.Sys.ExternalLinks;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Context;\n\ninternal sealed class DnnUiContextBuilder(\n    ISxcCurrentContextService ctxService,\n    ExternalLinksService externalLinksService,\n    UiContextBuilderBase.Dependencies deps)\n    : UiContextBuilderBase(deps)\n{\n    #region Constructor / DI\n\n    private readonly PortalSettings _portal = PortalSettings.Current;\n\n    private ModuleInfo Module => (ctxService.BlockContextOrNull()?.Module as IWrapper<ModuleInfo>)?.GetContents();\n\n    #endregion\n\n    protected override ContextResourceWithApp GetSystem(Ctx flags)\n    {\n        var result = base.GetSystem(flags);\n        result.Url = VirtualPathUtility.ToAbsolute(\"~/\");\n        return result;\n    }\n\n    protected override ContextResourceWithApp GetSite(Ctx flags)\n    {\n        var result = base.GetSite(flags);\n        result.Id = _portal.PortalId;\n        result.Url = \"//\" + _portal.PortalAlias.HTTPAlias + \"/\";\n        return result;\n    }\n\n    protected override WebResourceDto GetPage() =>\n        Module == null ? null\n            : new WebResourceDto\n            {\n                Id = Module.TabID,\n                // todo: maybe page url\n                // used to be on ps.ActiveTab.FullUrl;\n                // but we can't get it from there directly\n            };\n\n    protected override ContextAppDto GetApp(Ctx flags)\n    {\n        var appDto = base.GetApp(flags);\n        // If no app is selected yet, then there is no information to return\n        if (appDto == null) return null;\n\n        try\n        {\n            var roots = DnnJsApiService.GetApiRoots();\n            appDto.Api = roots.AppApiRoot;\n        } catch { /* ignore */ }\n        return appDto;\n    }\n\n    /// <summary>\n    /// build a getting-started url which is used to correctly show the user infos like\n    /// warnings related to his dnn or 2sxc version\n    /// infos based on his languages\n    /// redirects based on the app he's looking at, etc.\n    /// </summary>\n    /// <returns></returns>\n    protected override string GetGettingStartedUrl()\n    {\n        if (AppSpecsOrNull is not { } app)\n            return \"\";\n\n        var gsUrl = externalLinksService.LinkToDestination(\n            ExternalSxcDestinations.GettingStarted,\n            Services.SiteCtx.Site,\n            Module.ModuleID,\n            app,\n            Module.DesktopModule.ModuleName == \"2sxc\");\n        return gsUrl;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Module/ModuleController.cs",
    "content": "﻿using ToSic.Sxc.Dnn.WebApi.Sys;\n\nnamespace ToSic.Sxc.Dnn.Backend.Module;\n\n// support all modules now... \n[SupportedModules(DnnSupportedModuleNames)]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ModuleController() : DnnSxcControllerRoot(\"Mod\")\n{\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public bool Delete(int tabId, int modId)\n    {\n        Log.A($\"delete mod:{modId} on tab:{tabId}\");\n        var mc = new DotNetNuke.Entities.Modules.ModuleController();\n        mc.DeleteTabModule(tabId, modId, true);\n        Log.A(\"delete completed\");\n        return true;\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Sys/InsightsController.cs",
    "content": "﻿using ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Eav.Sys.Insights.InsightsControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Sys;\n\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class InsightsController() : DnnSxcControllerRoot(RealController.LogSuffix)\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <summary>\n    /// Single-Point-Of-Entry\n    /// The insights handle all their work in the backend, incl. view-switching.\n    /// This is important for many reasons, inc. the fact that this will always be the first endpoint to implement\n    /// on any additional system. \n    /// </summary>\n    [HttpGet] // Will do security checks internally\n    public string Details(string view, int? appId = null, string key = null, int? position = null, string type = null, bool? toggle = null, string nameId = null, string filter = default)\n        => Real.Details(view, appId, key, position, type, toggle, nameId, filter);\n\n\n    #region Controll Logging of Requests on Insights for special debugging, usually disabled to not clutter the logs\n\n    /// <summary>\n    /// Enable/disable logging of access to insights\n    /// Only enable this if you have trouble developing insights, otherwise it clutters our logs\n    /// </summary>\n    internal static bool InsightsLoggingEnabled = false;\n\n    /// <summary>\n    /// Special detection for the AppApiController to skip these requests?\n    /// </summary>\n    internal const string InsightsUrlFragment = \"/sys/insights/\";\n\n    /// <summary>\n    /// Make sure that these requests don't land in the normal api-log.\n    /// Otherwise each log-access would re-number what item we're looking at\n    /// </summary>\n    protected override string HistoryLogGroup => \"web-api.insights\";\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Sys/InstallController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Install;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Dnn.Context;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Sxc.Backend.Sys.InstallControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class InstallController()\n    : DnnSxcControllerRoot(RealController.LogSuffix), IInstallController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <summary>\n    /// Make sure that these requests don't land in the normal api-log.\n    /// Otherwise, each log-access would re-number what item we're looking at\n    /// </summary>\n    protected override string HistoryLogGroup => \"web-api.install\";\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    public bool Resume()\n        => Real.Resume();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public InstallAppsDto InstallSettings(bool isContentApp) \n        => Real.InstallSettings(isContentApp, ((DnnModule)SysHlp.GetService<IModule>()).Init(Request.FindModuleInfo()));\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [ValidateAntiForgeryToken] // Now with RVT as it's post now. Previously not, because this was a GET and could not include the RVT\n    public HttpResponseMessage RemotePackage(string packageUrl, string newName = null)\n    {\n        SysHlp.PreventServerTimeout600();\n        // Make sure the Scoped ResponseMaker has this controller context\n        SysHlp.SetupResponseMaker(this);\n        return Real.RemotePackage(packageUrl, ((DnnModule)SysHlp.GetService<IModule>()).Init(ActiveModule), newName);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Sys/LicenseController.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.WebApi.Sys.Licenses;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Eav.WebApi.Sys.Licenses.LicenseControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Sys;\n\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LicenseController() : DnnSxcControllerRoot(\"License\"), ILicenseController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <summary>\n    /// Make sure that these requests don't land in the normal api-log.\n    /// Otherwise each log-access would re-number what item we're looking at\n    /// </summary>\n    protected override string HistoryLogGroup => \"web-api.license\";\n\n    /// <inheritdoc />\n    [HttpGet]\n    public IEnumerable<LicenseDto> Summary()\n        => Real.Summary();\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    public LicenseFileResultDto Upload()\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.Upload(new(Request, HttpContext.Current.Request));\n    }\n\n    /// <inheritdoc />\n    [HttpGet]\n    public LicenseFileResultDto Retrieve()\n    {\n        SysHlp.PreventServerTimeout600();\n        return Real.Retrieve();\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Backend/Sys/LogController.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Logs;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing RealController = ToSic.Eav.WebApi.Sys.Logs.LogControllerReal;\n\nnamespace ToSic.Sxc.Dnn.Backend.Sys;\n\n/// <summary>\n/// This one supplies portal-wide (or cross-portal) settings / configuration\n/// </summary>\n[SupportedModules(DnnSupportedModuleNames)]\n[DnnLogExceptions]\n[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LogController() : DnnSxcControllerRoot(RealController.LogSuffix), ILogController\n{\n    private RealController Real => SysHlp.GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    public string EnableDebug(int duration = 1)\n        => Real.EnableDebug(DnnLogging.ActivateForDuration, duration);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Integration/DnnAppFolderUtilities.cs",
    "content": "﻿using System.Net;\nusing System.Web.Http.Routing;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.WebApi.Sys.Routing;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.WebApi.Sys;\n\nnamespace ToSic.Sxc.Dnn.Integration;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DnnAppFolderUtilities(\n    Generator<AppFolderLookupForWebApi> folder,\n    Generator<DnnGetBlock> dnnGetBlock,\n    LazySvc<CodeErrorHelpService> errorHelp)\n    : ServiceBase($\"{DnnConstants.LogName}.AppFld\", connect: [errorHelp, folder, dnnGetBlock])\n{\n    private HttpRequestMessage _request;\n\n    private HttpRequestMessage Request => _request ?? throw new(\"Request not available - call Setup(...) first!\");\n\n    public DnnAppFolderUtilities Setup(HttpRequestMessage request)\n    {\n        _request = request;\n        return this;\n    }\n\n    internal string GetAppFolderVirtualPath(ISite site)\n    {\n        var l = Log.Fn<string>();\n        var appFolder = GetAppFolder(true);\n        var appFolderVirtualPath = Path.Combine(site.AppsRootPhysical, appFolder).ForwardSlash();\n        return l.Return(appFolderVirtualPath, $\"Ok, AppFolder Virtual Path: {appFolderVirtualPath}\");\n    }\n\n    internal string GetAppFolder(bool errorIfNotFound, IBlock block = null)\n    {\n        var l = Log.Fn<string>();\n        const string errPrefix = \"Api Controller Finder Error: \";\n        const string errSuffix = \"Check event-log, code and inner exception. \";\n\n        var routeData = Request.GetRouteData();\n\n        // Figure out the Path, or show error for that.\n        string appFolder;\n        try\n        {\n            appFolder = AppPathOrNull(routeData);\n\n            // only check for app folder if we don't have a context\n            if (appFolder == null)\n            {\n                l.A(\"no folder found in url, will auto-detect\");\n                appFolder = folder.New()\n                    .Init(block ?? dnnGetBlock.New().GetCmsBlock(Request))\n                    .GetAppFolder();\n            }\n\n            l.A($\"App Folder: {appFolder}\");\n        }\n        catch (Exception getBlockException)\n        {\n            const string msg = errPrefix + \"Trying to find app name, unexpected error - possibly bad/invalid headers. \" + errSuffix;\n            if (errorIfNotFound)\n                throw l.Done(DnnHttpErrors.LogAndReturnException(Request, HttpStatusCode.BadRequest, getBlockException, msg, errorHelp.Value));\n            return l.Return(null, \"not found, maybe error\");\n        }\n\n        if (string.IsNullOrWhiteSpace(appFolder) && errorIfNotFound)\n        {\n            const string msg = errPrefix + \"App name is unknown - tried to check name in url (.../app/[app-name]/...) \" +\n                               \"and tried app-detection using url-params/headers pageid/moduleid. \" + errSuffix;\n            throw l.Done(DnnHttpErrors.LogAndReturnException(Request, HttpStatusCode.BadRequest, new(msg), msg, errorHelp.Value));\n        }\n\n        return l.ReturnAsOk(appFolder);\n    }\n\n    public static string AppPathOrNull(IHttpRouteData route) => route.Values[VarNames.AppPath]?.ToString();\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Integration/DnnHttpErrors.cs",
    "content": "﻿using System.Net;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\nnamespace ToSic.Sxc.Dnn.Integration;\n\ninternal class DnnHttpErrors\n{\n    private const string ApiErrPrefix = \"2sxc Api Controller Finder Error: \";\n    private const string ApiErrGeneral = \"Error selecting / compiling an API controller. \";\n    private const string ApiErrSuffix = \"Check event-log, code and inner exception. \";\n\n    internal const string ApiErrMessage = ApiErrPrefix + ApiErrGeneral + ApiErrSuffix;\n\n    internal static HttpResponseException LogAndReturnException(\n        HttpRequestMessage request,\n        HttpStatusCode code,\n        Exception e,\n        string msg,\n        CodeErrorHelpService errorHelp)\n    {\n        var helpText = errorHelp.FindHelp(e)?.ErrorMessage + msg;\n        var exception = new Exception(helpText, e);\n        DotNetNuke.Services.Exceptions.Exceptions.LogException(exception);\n\n        var dnnUser = DotNetNuke.Entities.Users.UserController.Instance.GetCurrentUserInfo();\n        var exToShow = dnnUser?.IsSuperUser == true \n            ? exception \n            : new PublicException(ApiErrMessage + helpText);\n        return new(request.CreateErrorResponse(code, exToShow));\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Integration/DnnWebApiLogging.cs",
    "content": "﻿using System.Web;\nusing System.Web.Http.Controllers;\nusing ToSic.Eav.Web.Sys;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sys.Code.InfoSystem;\n\nnamespace ToSic.Sxc.Dnn.Integration;\n\n/// <summary>\n/// Helper class for work on the WebAPIs which may be used by multiple base classes.\n/// This is to ensure the code is not in the class, and is reusable. \n/// </summary>\n/// <param name=\"requestLogging\">Scoped request logging</param>\n/// <param name=\"firstMessage\">First message - ATM only used for queries to simplify/show what query is called.</param>\ninternal class DnnWebApiLogging(HttpRequestLoggingScoped requestLogging, string firstMessage)\n{\n    #region Timer Around Everything\n\n    /// <summary>\n    /// Add the first message with the current path.\n    /// Will not be used until disposed, to then stop the full-timer.\n    /// </summary>\n    private readonly ILogCall _timerWrapLog = requestLogging.RootLog.Fn(\n        // Note: can't log URL as the HttpContext is not ready at this time.\n        message: firstMessage ?? $\": {HttpContext.Current?.Request.Url.AbsoluteUri}\",\n        timer: true,\n        // ReSharper disable once ExplicitCallerInfoArgument\n        cName: \"Api\"\n    );\n\n    internal void OnDispose()\n        => _timerWrapLog.Done();\n\n    #endregion\n\n\n    public void OnInitialize(HttpControllerContext controllerContext)\n    {\n        controllerContext.Request.Properties.Add(EavLogKey, requestLogging.StoreEntry);\n    }\n\n    /// <summary>\n    /// Add Log Specs to the current request and also to any reported code changes later on.\n    /// </summary>\n    public void AddLogSpecs(IBlock block, IApp app, string currentPath, CodeInfosInScope codeInfos) =>\n        requestLogging.StoreEntry.TryUpdateSpecs(() =>\n        {\n            // Add app-id to entry info to ensure controllers with same name being detected by app\n            if (currentPath != default && app != default)\n                currentPath = $\"app:{app.AppId}/{currentPath}\";\n\n            var logSpecs = new SpecsForLogHistory()\n                .BuildSpecsForLogHistory(block, app, entry: currentPath, addView: false);\n\n            logSpecs[\"Url\"] = HttpContext.Current?.Request.Url.AbsoluteUri;\n\n            codeInfos.AddContext(() => logSpecs, entryPoint: currentPath);\n\n            return logSpecs;\n        });\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Integration/GetDnnBlock.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing static ToSic.Sxc.Backend.SxcWebApiConstants;\n\nnamespace ToSic.Sxc.Dnn.Integration;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DnnGetBlock(\n    Generator<BlockOfEntity> blockFromEntity,\n    Generator<IModuleAndBlockBuilder> moduleAndBlockBuilder)\n    : ServiceBase($\"{LogName}.GetBlk\", connect: [blockFromEntity, moduleAndBlockBuilder])\n{\n    internal IBlock GetCmsBlock(HttpRequestMessage request)\n    {\n        var l = Log.Fn<IBlock>(timer: true);\n        var moduleInfo = request.FindModuleInfo();\n\n        if (moduleInfo == null)\n            return l.ReturnNull(\"request ModuleInfo not found\");\n\n        var block = moduleAndBlockBuilder.New().BuildBlock(moduleInfo, null);\n\n        // check if we need an inner block\n        if (!request.Headers.Contains(HeaderContentBlockId))\n            return l.Return(block, \"normal block, no inner-content\");\n\n        // only if it's negative, do we load the inner block\n        var blockHeaderId = request.Headers.GetValues(HeaderContentBlockId).FirstOrDefault();\n        int.TryParse(blockHeaderId, out var contentBlockId);\n\n        // only if ID is negative, do we load the inner block\n        if (contentBlockId >= 0)\n            return l.Return(block, \"normal block\");\n\n        var entBlock = GetBlockOrInnerContentBlock(request, block, contentBlockId);\n        return l.Return(entBlock, $\"inner content-block {contentBlockId}\");\n    }\n\n    private IBlock GetBlockOrInnerContentBlock(HttpRequestMessage request, IBlock block, int blockId)\n    {\n        var l = Log.Fn<IBlock>($\"{nameof(blockId)}: {blockId}\");\n\n        // If we have a list of inner-blocks (WIP, I believe not implemented) do we go down the list of blocks to find the inner-most one\n        if (request.Headers.Contains(HeaderContentBlockList))\n        {\n            var blockIds = request.Headers\n                .GetValues(HeaderContentBlockList)\n                .FirstOrDefault()?\n                .CsvToArrayWithoutEmpty();\n            if (blockIds.SafeAny())\n                return l.Return(FindInnerContentParentBlock(block, blockId, blockIds), $\"from {HeaderContentBlockList}\");\n        }\n\n        var entBlock = blockFromEntity.New().GetBlockOfEntity(block, null, blockId);\n\n        return l.Return(entBlock);\n    }\n\n    private IBlock FindInnerContentParentBlock(IBlock parent, int contentBlockId, IReadOnlyCollection<string> blockIds)\n    {\n        if (blockIds == null || blockIds.Count < 2) return parent;\n\n        foreach (var ids in blockIds) // blockIds is ordered list, from first ancestor till last successor \n        {\n            var parentIds = ids.Split(':');\n            //var parentAppId = int.Parse(parentIds[0]);\n            //var parentContentBlocks = new Guid(parentIds[1]);\n            var id = int.Parse(parentIds[0]);\n            if (!int.TryParse(parentIds[1], out var cbid) || id == cbid || cbid >= 0) continue;\n            if (cbid == contentBlockId) break; // we are done, because block should be parent/ancestor of cbid\n            parent = blockFromEntity.New().GetBlockOfEntity(parent, null, cbid);\n        }\n\n        return parent;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/Integration/StartUpDnnWebApi.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Newtonsoft.Json;\nusing ToSic.Eav.WebApi.Sys.ApiExplorer;\nusing ToSic.Eav.WebApi.Sys.Context;\nusing ToSic.Sxc.Adam.Sys.Security;\nusing ToSic.Sxc.Dnn.Backend;\nusing ToSic.Sxc.Dnn.Backend.Admin;\nusing ToSic.Sxc.Dnn.WebApi.Context;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\nnamespace ToSic.Sxc.Dnn.Integration;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class StartUpDnnWebApi\n{\n    public static IServiceCollection AddDnnWebApi(this IServiceCollection services)\n    {\n        // Settings / WebApi stuff\n        services.TryAddTransient<IUiContextBuilder, DnnUiContextBuilder>();\n        services.TryAddTransient<IApiInspector, DnnApiInspector>();\n\n        // new #2160\n        services.TryAddTransient<IAdamSecurityCheckService, DnnAdamSecurityChecks>();\n\n        services.TryAddTransient<DnnGetBlock>();\n\n        services.TryAddTransient<DnnAppFolderUtilities>(); // v14.12-01\n\n        // new v15\n        services.TryAddTransient<ApiControllerDependencies>();\n\n        // new v17\n        services.TryAddTransient<AppApiControllerSelectorService>();\n\n        return services;\n    }\n\n    public static void Configure()\n    {\n        // Configure Newtonsoft Time zone handling\n        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;\n\n        // System.Text.Json supports ISO 8601-1:2019, including the RFC 3339 profile\n        GlobalConfiguration.Configuration.Formatters.Add(JsonFormatters.SystemTextJsonMediaTypeFormatter);\n\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Compatibility/ApiTempShimmed.cs",
    "content": "﻿using ToSic.Sxc.Adam;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.Compatibility;\n\n/// <summary>\n/// </summary>\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class ApiTempShimmed : DnnSxcCustomControllerBase, IDynamicWebApi, INetCoreCompatibility\n{\n\n    #region Net Core Compatibility Shims - Copy this entire section to WebApi Files\n\n    public IFile SaveInAdam(NoParamOrder npo = default, Stream stream = null, string fileName = null,\n        string contentType = null, Guid? guid = null, string field = null, string subFolder = \"\")\n    {\n        throw new NotImplementedException();\n    }\n\n    /// <inheritdoc cref=\"IDynamicWebApi.File\"/>\n    public dynamic File(NoParamOrder npo = default,\n        bool? download = null,\n        string virtualPath = null,\n        string contentType = null,\n        string fileDownloadName = null,\n        object contents = null)\n        => Shim.File(download: download, virtualPath: virtualPath, contentType: contentType, fileDownloadName: fileDownloadName, contents: contents);\n\n    private WebApiCoreShim Shim => new(Request);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok()\"/>\n    [NonAction] public new dynamic Ok() => Shim.Ok();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok(object)\"/>\n    [NonAction] public dynamic Ok(object value) => Shim.Ok(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NoContent()\"/>\n    [NonAction]\n    public dynamic NoContent() => Shim.NoContent();\n\n    // TODO: this Shim could now be implemented after 16.02 - since we don't have the Content property any more\n    #region Content (ca. 5 overloads) can't be implemented, because it conflicts with our property \"Content\"\n\n    #endregion\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Redirect\"/>\n    [NonAction] public new dynamic Redirect(string url) => Shim.Redirect(url);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.RedirectPermanent\"/>\n    [NonAction] public dynamic RedirectPermanent(string url) => Shim.RedirectPermanent(url);\n\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int)\"/>\n    [NonAction] public dynamic StatusCode(int statusCode) => Shim.StatusCode(statusCode);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int, object)\"/>\n    [NonAction] public dynamic StatusCode(int statusCode, object value) => Shim.StatusCode(statusCode, value);\n\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized()\"/>\n    [NonAction] public dynamic Unauthorized() => Shim.Unauthorized();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized(object)\"/>\n    [NonAction] public dynamic Unauthorized(object value) => Shim.Unauthorized(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound()\"/>\n    [NonAction] public new dynamic NotFound() => Shim.NotFound();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound(object)\"/>\n    [NonAction] public dynamic NotFound(object value) => Shim.NotFound(value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.BadRequest()\"/>\n    [NonAction] public new dynamic BadRequest() => Shim.BadRequest();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict()\"/>\n    [NonAction] public new dynamic Conflict() => Shim.Conflict();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict(object)\"/>\n    [NonAction] public dynamic Conflict(object error) => Shim.Conflict(error);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Accepted()\"/>\n    [NonAction] public dynamic Accepted() => Shim.Accepted();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Forbid()\"/>\n    [NonAction] public dynamic Forbid() => Shim.Forbid();\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Compatibility/INetCoreCompatibility.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn.WebApi.Sys.Compatibility;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface INetCoreCompatibility\n{\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok()\"/>\n    dynamic Ok();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Ok(object)\"/>\n    dynamic Ok(object value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NoContent()\"/>\n    dynamic NoContent();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Redirect\"/>\n    dynamic Redirect(string url);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.RedirectPermanent\"/>\n    dynamic RedirectPermanent(string url);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int)\"/>\n    dynamic StatusCode(int statusCode);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.StatusCode(int, object)\"/>\n    dynamic StatusCode(int statusCode, object value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized()\"/>\n    dynamic Unauthorized();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Unauthorized(object)\"/>\n    dynamic Unauthorized(object value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound()\"/>\n    dynamic NotFound();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.NotFound(object)\"/>\n    dynamic NotFound(object value);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.BadRequest()\"/>\n    dynamic BadRequest();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict()\"/>\n    dynamic Conflict();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Conflict(object)\"/>\n    dynamic Conflict(object error);\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Accepted()\"/>\n    dynamic Accepted();\n\n    /// <inheritdoc cref=\"WebApiCoreShim.Forbid()\"/>\n    dynamic Forbid();\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Compatibility/WebApiCoreShim.cs",
    "content": "﻿namespace ToSic.Sxc.Dnn.WebApi.Sys.Compatibility;\n\n/// <summary>\n/// This is the helper class to compose other WebApi-classes of modern custom API Controllers. <br/>\n/// It provides Commands such as `Ok()` which already exist in .net core and allows hybrid controllers to have the same commands. \n///\n/// Use `Custom.Hybrid.Api12` or `Custom.Hybrid.Api14` as your real base classes\n/// </summary>\n[PrivateApi(\"This is the .net core Shim class for v12+\")]\n[DnnLogExceptions]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal partial class WebApiCoreShim: ServiceBase\n{\n    public HttpRequestMessage Request { get; }\n    protected internal WebApiCoreShim(HttpRequestMessage request) : base(\"Dnn.ApShim\")\n    {\n        Request = request;\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Compatibility/WebApiCoreShim_File.cs",
    "content": "﻿using System.Net;\nusing System.Text;\nusing System.Web;\nusing System.Xml;\nusing ToSic.Eav.WebApi.Sys;\nusing ToSic.Sxc.Backend;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.Compatibility;\n\npartial class WebApiCoreShim\n{\n    /// <inheritdoc />\n    public dynamic File(NoParamOrder npo = default,\n        // Important: the second parameter should _not_ be a string, otherwise the signature looks the same as the built-in File(...) method\n        bool? download = null,\n        string virtualPath = null, // important: this is the virtualPath, but it should not have the same name, to not confuse the compiler with same sounding param names\n        string contentType = null,\n        string fileDownloadName = null,\n        object contents = null // can be stream, string or byte[]\n    )\n    {\n        // fileDownloadName becomes null when download != true\n\n        // Try to figure out file mime type as needed\n        if (string.IsNullOrWhiteSpace(contentType))\n            contentType = (string.IsNullOrWhiteSpace(fileDownloadName ?? virtualPath)) ? MimeTypeConstants.FallbackType : MimeMapping.GetMimeMapping(fileDownloadName ?? virtualPath);\n\n        HttpContent httpContent = new ByteArrayContent(Encoding.UTF8.GetBytes(string.Empty));\n\n        // check if this may just be a call to the built in file, which has two strings\n        // this can only be possible if only the virtualPath and contentType were set\n        if (!string.IsNullOrWhiteSpace(virtualPath))\n            httpContent = new StreamContent(new FileStream(HttpContext.Current.Server.MapPath(virtualPath), FileMode.Open, FileAccess.Read, FileShare.ReadWrite));\n\n        var encoding = Encoding.UTF8; // the default response encoding is UTF-8\n        var isValidXml = false;\n        switch (contents)\n        {\n            case XmlDocument xmlDoc:\n                var xmlStream = new MemoryStream();\n                xmlDoc.Save(xmlStream);\n                xmlStream.Position = 0;\n                httpContent = new StreamContent(xmlStream);\n                isValidXml = true;\n                encoding = CustomApiHelpers.GetEncoding(xmlDoc);\n                break;\n            case string stringBody:\n                httpContent = new ByteArrayContent(encoding.GetBytes(stringBody));\n                isValidXml = CustomApiHelpers.IsValidXml(stringBody);\n                encoding = CustomApiHelpers.GetEncoding(stringBody);\n                break;\n            case Stream streamBody:\n                httpContent = new StreamContent(streamBody);\n                isValidXml = CustomApiHelpers.IsValidXml(streamBody);\n                encoding = CustomApiHelpers.GetEncoding(streamBody);\n                break;\n            case byte[] charBody:\n                httpContent = new ByteArrayContent(charBody);\n                isValidXml = CustomApiHelpers.IsValidXml(charBody);\n                encoding = CustomApiHelpers.GetEncoding(charBody);\n                break;\n        }\n        contentType = CustomApiHelpers.XmlContentTypeFromContent(isValidXml, contentType);\n\n        var response = Request.CreateResponse(HttpStatusCode.OK);\n        response.Content = httpContent;\n        response.Content.Headers.ContentType = CustomApiHelpers.PrepareMediaTypeHeaderValue(contentType, encoding);\n        response.Content.Headers.ContentDisposition = CustomApiHelpers.PrepareContentDispositionHeaderValue(download, fileDownloadName);\n\n        return response;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Compatibility/WebApiCoreShim_Responses.cs",
    "content": "﻿using System.Net;\n\n// The commands here should help Dnn WebAPIs \n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.Compatibility;\n\npartial class WebApiCoreShim\n{\n\n    /// <summary>\n    /// Creates a .net-core like `OkResult` object that produces an empty .net-core like `StatusCodes.Status200OK` response.\n    ///\n    /// Typical use: `return Ok();`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `OkResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage Ok() => Request.CreateResponse(HttpStatusCode.OK);\n\n    /// <summary>\n    /// Creates an .net-core like `OkObjectResult` object that produces an .net-core like `StatusCodes.Status200OK` response.\n    ///\n    /// Typical use: `return Ok(objectToInclude);`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <param name=\"value\">The content value to format in the entity body.</param>\n    /// <returns>The created .net-core like `OkObjectResult` for the response.</returns>\n    [NonAction]\n    // maybe ??? low priority\n    public HttpResponseMessage Ok(object value) => Request.CreateResponse(HttpStatusCode.OK, value);\n\n    /// <summary>\n    /// Creates a .net-core like `NoContentResult` object that produces an empty\n    /// .net-core like `StatusCodes.Status204NoContent` response.\n    ///\n    /// Typical use: `return NoContent();`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `NoContentResult` object for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage NoContent() => Request.CreateResponse(HttpStatusCode.NoContent);\n\n    // TODO: this Shim could now be implemented after 16.02 - since we don't have the Content property any more\n    #region Content (ca. 5 overloads) can't be implemented, because it conflicts with our property \"Content\"\n    //public dynamic Content(string content)\n    //{\n    //    throw new NotSupportedException();\n    //}\n\n    //public dynamic Content(string content, string contentType)\n    //{\n\n    //}\n    #endregion\n\n    #region Redirect Variants\n    // Note that .net core has ca. 30 variants - we probably just need 2\n\n    /// <summary>\n    /// Creates a .net-core like `RedirectResult` object that redirects (.net-core like `StatusCodes.Status302Found`)\n    /// to the specified <paramref name=\"url\"/>.\n    ///\n    /// Typical use: `return Redirect(\"https://2sxc.org\");`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <param name=\"url\">The URL to redirect to.</param>\n    /// <returns>The created .net-core like `RedirectResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage Redirect(string url)\n    {\n        if (string.IsNullOrEmpty(url)) throw new ArgumentNullException(nameof(url));\n        var response = Request.CreateResponse(HttpStatusCode.Redirect);\n        response.Headers.Location = new(url);\n        return response;\n    }\n\n    /// <summary>\n    /// Creates a .net-core like `RedirectResult` object with .net-core like `RedirectResult.Permanent` set to true\n    /// (.net-core like `StatusCodes.Status301MovedPermanently`) using the specified <paramref name=\"url\"/>.\n    ///\n    /// Typical use: `return RedirectPermanent(\"https://2sxc.org\");`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <param name=\"url\">The URL to redirect to.</param>\n    /// <returns>The created .net-core like `RedirectResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage RedirectPermanent(string url)\n    {\n        if (string.IsNullOrEmpty(url)) throw new ArgumentNullException(nameof(url));\n        var response = Request.CreateResponse(HttpStatusCode.MovedPermanently);\n        response.Headers.Location = new(url);\n        return response;\n    }\n\n\n\n    #endregion\n\n\n\n    #region StatusCode - low priority\n    /// <summary>\n    /// Creates a .net-core like `StatusCodeResult` object by specifying a <paramref name=\"statusCode\"/>.\n    ///\n    /// Typical use: `return StatusCode(403);`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <param name=\"statusCode\">The status code to set on the response.</param>\n    /// <returns>The created .net-core like `StatusCodeResult` object for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage StatusCode(int statusCode) => Request.CreateResponse((HttpStatusCode)statusCode);\n\n    /// <summary>\n    /// Creates a .net-core like `ObjectResult` object by specifying a <paramref name=\"statusCode\"/> and <paramref name=\"value\"/>\n    ///\n    /// Typical use: `return StatusCode(304, \"not modified\");`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <param name=\"statusCode\">The status code to set on the response.</param>\n    /// <param name=\"value\">The value to set on the .net-core like `ObjectResult\"/>.</param>\n    /// <returns>The created .net-core like `ObjectResult` object for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage StatusCode(int statusCode, object value) => Request.CreateResponse((HttpStatusCode)statusCode, value);\n    #endregion\n\n\n    /// <summary>\n    /// Creates an .net-core like `UnauthorizedResult` that produces an .net-core like `StatusCodes.Status401Unauthorized` response.\n    ///\n    /// Typical use: `return Unauthorized();`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `UnauthorizedResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage Unauthorized() => Request.CreateResponse(HttpStatusCode.Unauthorized);\n\n    /// <summary>\n    /// Creates an .net-core like `UnauthorizedObjectResult` that produces a .net-core like `StatusCodes.Status401Unauthorized` response.\n    ///\n    /// Typical use: `return Unauthorized(\"we don't like this\");`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `UnauthorizedObjectResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage Unauthorized(object value) => Request.CreateResponse(HttpStatusCode.Unauthorized, value);\n\n    /// <summary>\n    /// Creates an .net-core like `NotFoundResult` that produces a .net-core like `StatusCodes.Status404NotFound` response.\n    ///\n    /// Typical use: `return NotFound();`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `NotFoundResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage NotFound() => Request.CreateResponse(HttpStatusCode.NotFound);\n\n    /// <summary>\n    /// Creates an .net-core like `NotFoundObjectResult` that produces a .net-core like `StatusCodes.Status404NotFound` response.\n    ///\n    /// Typical use: `return Unauthorized(\"try another ID\");`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `NotFoundObjectResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage NotFound(object value) => Request.CreateResponse(HttpStatusCode.NotFound, value);\n\n    /// <summary>\n    /// Creates an .net-core like `BadRequestResult` that produces a .net-core like `StatusCodes.Status400BadRequest` response.\n    ///\n    /// Typical use: `return BadRequest();`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `BadRequestResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage BadRequest() => Request.CreateResponse(HttpStatusCode.BadRequest);\n\n    ///// <summary>\n    ///// Creates an .net-core like `BadRequestObjectResult` that produces a .net-core like `StatusCodes.Status400BadRequest` response.\n    ///// </summary>\n    ///// <param name=\"error\">An error object to be returned to the client.</param>\n    ///// <returns>The created .net-core like `BadRequestObjectResult` for the response.</returns>\n    //[NonAction]\n    //public dynamic BadRequest(object error)\n    //    => throw new NotSupportedException();\n\n    ///// <summary>\n    ///// Creates an .net-core like `BadRequestObjectResult` that produces a .net-core like `StatusCodes.Status400BadRequest` response.\n    ///// </summary>\n    ///// <param name=\"modelState\">The .net-core like `ModelStateDictionary\" /> containing errors to be returned to the client.</param>\n    ///// <returns>The created .net-core like `BadRequestObjectResult` for the response.</returns>\n    //[NonAction]\n    //public dynamic BadRequest(object modelState)\n    //    => throw new NotSupportedException();\n\n    #region Conflict\n\n    /// <summary>\n    /// Creates an .net-core like `ConflictResult` that produces a .net-core like `StatusCodes.Status409Conflict` response.\n    ///\n    /// Typical use: `return Conflict();`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `ConflictResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage Conflict() => Request.CreateResponse(HttpStatusCode.Conflict);\n\n    /// <summary>\n    /// Creates an .net-core like `ConflictObjectResult` that produces a .net-core like `StatusCodes.Status409Conflict` response.\n    ///\n    /// Typical use: `return Conflict(\"the stored file is newer\");`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <param name=\"error\">Contains errors to be returned to the client.</param>\n    /// <returns>The created .net-core like `ConflictObjectResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage Conflict(object error) => Request.CreateResponse(HttpStatusCode.Conflict, error);\n\n    ///// <summary>\n    ///// Creates an .net-core like `ConflictObjectResult` that produces a .net-core like `StatusCodes.Status409Conflict` response.\n    ///// </summary>\n    ///// <param name=\"modelState\">The .net-core like `ModelStateDictionary\" /> containing errors to be returned to the client.</param>\n    ///// <returns>The created .net-core like `ConflictObjectResult` for the response.</returns>\n    //[NonAction]\n    //public dynamic Conflict(ModelStateDictionary modelState)\n    //    => new ConflictObjectResult(modelState);\n\n\n    #endregion\n\n    #region Problem, ValidationProblem - won't implement\n    #endregion\n\n    #region Created, CreatedAtAction, CreatedAtRoute - won't impelment\n    #endregion\n\n    #region Accepted\n\n    /// <summary>\n    /// Creates a .net-core like `AcceptedResult` object that produces an .net-core like `StatusCodes.Status202Accepted` response.\n    ///\n    /// Typical use: `return Accepted();`\n    /// </summary>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    /// </remarks>\n    /// <returns>The created .net-core like `AcceptedResult` for the response.</returns>\n    [NonAction]\n    public HttpResponseMessage Accepted() => Request.CreateResponse(HttpStatusCode.Accepted);\n\n    // All other accepted - don't implement\n    ///// <summary>\n    ///// Creates a .net-core like `AcceptedResult` object that produces an .net-core like `StatusCodes.Status202Accepted` response.\n    ///// </summary>\n    ///// <param name=\"value\">The optional content value to format in the entity body; may be null.</param>\n    ///// <returns>The created .net-core like `AcceptedResult` for the response.</returns>\n    //[NonAction]\n    //public dynamic Accepted(object value)\n    //    => new AcceptedResult(location: null, value: value);\n\n    ///// <summary>\n    ///// Creates a .net-core like `AcceptedResult` object that produces an .net-core like `StatusCodes.Status202Accepted` response.\n    ///// </summary>\n    ///// <param name=\"uri\">The optional URI with the location at which the status of requested content can be monitored.\n    ///// May be null.</param>\n    ///// <returns>The created .net-core like `AcceptedResult` for the response.</returns>\n    //[NonAction]\n    //public dynamic Accepted(Uri uri)\n    //{\n    //    if (uri == null)\n    //    {\n    //        throw new ArgumentNullException(nameof(uri));\n    //    }\n\n    //    return new AcceptedResult(locationUri: uri, value: null);\n    //}\n\n    ///// <summary>\n    ///// Creates a .net-core like `AcceptedResult` object that produces an .net-core like `StatusCodes.Status202Accepted` response.\n    ///// </summary>\n    ///// <param name=\"uri\">The optional URI with the location at which the status of requested content can be monitored.\n    ///// May be null.</param>\n    ///// <returns>The created .net-core like `AcceptedResult` for the response.</returns>\n    //[NonAction]\n    //public dynamic Accepted(string uri)\n    //    => new AcceptedResult(location: uri, value: null);\n\n    ///// <summary>\n    ///// Creates a .net-core like `AcceptedResult` object that produces an .net-core like `StatusCodes.Status202Accepted` response.\n    ///// </summary>\n    ///// <param name=\"uri\">The URI with the location at which the status of requested content can be monitored.</param>\n    ///// <param name=\"value\">The optional content value to format in the entity body; may be null.</param>\n    ///// <returns>The created .net-core like `AcceptedResult` for the response.</returns>\n    //[NonAction]\n    //public dynamic Accepted(string uri, object value)\n    //    => new AcceptedResult(uri, value);\n\n    ///// <summary>\n    ///// Creates a .net-core like `AcceptedResult` object that produces an .net-core like `StatusCodes.Status202Accepted` response.\n    ///// </summary>\n    ///// <param name=\"uri\">The URI with the location at which the status of requested content can be monitored.</param>\n    ///// <param name=\"value\">The optional content value to format in the entity body; may be null.</param>\n    ///// <returns>The created .net-core like `AcceptedResult` for the response.</returns>\n    //[NonAction]\n    //public dynamic Accepted(Uri uri, object value)\n    //{\n    //    if (uri == null)\n    //    {\n    //        throw new ArgumentNullException(nameof(uri));\n    //    }\n\n    //    return new AcceptedResult(locationUri: uri, value: value);\n    //}\n    #endregion\n\n    #region Challenge - only one implemented\n    ///// <summary>\n    ///// Creates a .net-core like `ChallengeResult\"/>.\n    ///// </summary>\n    ///// <returns>The created .net-core like `ChallengeResult` for the response.</returns>\n    ///// <remarks>\n    ///// The behavior of this method depends on the .net-core like `IAuthenticationService` in use.\n    ///// .net-core like `StatusCodes.Status401Unauthorized` and .net-core like `StatusCodes.Status403Forbidden\"/>\n    ///// are among likely status results.\n    ///// </remarks>\n    //[NonAction]\n    //public dynamic Challenge()\n    //    => Request.CreateResponse(HttpStatusCode.Forbidden);\n    #endregion\n\n    #region Forbid - only one implemented\n    /// <summary>\n    /// Creates a .net-core like `ForbidResult` (.net-core like `StatusCodes.Status403Forbidden` by default).\n    ///\n    /// Typical use: `return Forbid();`\n    /// </summary>\n    /// <returns>The created .net-core like `ForbidResult` for the response.</returns>\n    /// <remarks>\n    /// This is a shim to ensure that .net Framework code can be written the same way as .net core WebApis.\n    /// It returns a `dynamic` to make it easy to use, but the real .net core implementation returns a typed object.\n    ///\n    /// Some authentication schemes, such as cookies, will convert .net-core like `StatusCodes.Status403Forbidden` to\n    /// a redirect to show a login page.\n    /// </remarks>\n    [NonAction]\n    public HttpResponseMessage Forbid() => Request.CreateResponse(HttpStatusCode.Forbidden);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/ControllerBase/ApiControllerServices.cs",
    "content": "﻿using ToSic.Sxc.Dnn.Integration;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n/// <summary>\n/// Note: normally dependencies are Constructor injected.\n/// This doesn't work in DNN.\n/// But for consistency, we're building a comparable structure here.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record ApiControllerDependencies(\n    IExecutionContextFactory ExCtxFactory,\n    DnnAppFolderUtilities AppFolderUtilities,\n    LazySvc<Apps.App> AppOverrideLazy)\n    : DependenciesRecord(connect: [ExCtxFactory, AppFolderUtilities, AppOverrideLazy]);"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/ControllerBase/DnnSxcControllerBase.cs",
    "content": "﻿using System.Web.Http.Controllers;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n/// <summary>\n/// This class is the base class of 2sxc API access\n/// It will auto-detect the SxcBlock context\n/// But it will NOT provide an App or anything like that\n/// </summary>\n[DnnLogExceptions]\n[PrivateApi(\"This was only ever used as an internal base class, so it can be modified as needed - just make sure the derived types don't break\")]\n// Can't hide in Intellisense, because that would hide it for all derived classes too\n// [ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class DnnSxcControllerBase(string logSuffix, string insightsGroup = default, string firstMessage = default)\n    : DnnSxcControllerRoot(logSuffix, insightsGroup, firstMessage)\n{\n    protected override void Initialize(HttpControllerContext controllerContext)\n    {\n        base.Initialize(controllerContext);\n        DynHlp.InitializeBlockContext(controllerContext.Request);\n    }\n\n    internal DynamicApiCompileCodeHelpers DynHlp => field ??= new(this, SysHlp);\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/ControllerBase/DnnSxcControllerRoot.cs",
    "content": "﻿using System.Web.Http.Controllers;\nusing ToSic.Eav.WebApi.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n[DnnLogWebApi, ConfigureJsonOnlyResponse]\n[PrivateApi(\"This controller is never used publicly, you can rename any time you want\")]\n// Can't hide in Intellisense, because that would hide it for all derived classes too\n// [ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class DnnSxcControllerRoot : DnnApiController, IHasLog\n{\n    internal const string DnnSupportedModuleNames = \"2sxc,2sxc-app\";\n\n    protected DnnSxcControllerRoot(string logSuffix, string insightsGroup = default, string firstMessage = default)\n    {\n        Log = new Log(\"Api.\" + logSuffix);\n        // ReSharper disable once VirtualMemberCallInConstructor\n        SysHlp = new(this, insightsGroup ?? HistoryLogGroup, firstMessage);\n    }\n\n    /// <summary>\n    /// Special helper to move all Razor logic into a separate class.\n    /// For architecture of Composition over Inheritance.\n    /// </summary>\n    internal DnnWebApiHelper SysHlp { get; }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    protected override void Initialize(HttpControllerContext controllerContext)\n    {\n        var l = Log.Fn();\n        // Add the logger to the request, in case it's needed in error-reporting\n        SysHlp.WebApiLogging.OnInitialize(controllerContext);\n        base.Initialize(controllerContext);\n        l.Done();\n    }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    protected override void Dispose(bool disposing)\n    {\n        SysHlp.OnDispose();\n        base.Dispose(disposing);\n    }\n\n    /// <inheritdoc />\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public ILog Log { get; }\n\n    /// <summary>\n    /// The group name for log entries in insights.\n    /// Helps group various calls by use case. \n    /// </summary>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    protected virtual string HistoryLogGroup => EavWebApiConstants.HistoryNameWebApi;\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/ControllerBase/DnnSxcCustomControllerBase.cs",
    "content": "﻿using System.Web.Http.Controllers;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n/// <summary>\n/// This is the foundation for both the old SxcApiController and the new Dnn.ApiController.\n/// incl. the current App, DNN, Data, etc.\n/// For others, please use the SxiApiControllerBase, which doesn't have all that, and is usually then\n/// safer because it can't accidentally mix the App with a different appId in the params\n/// </summary>\n[PrivateApi(\"This is an internal base class used for the App ApiControllers. Make sure the implementations don't break\")]\n// Note: 2022-02 2dm I'm not sure if this was ever published as the official api controller, but it may have been?\n[DnnLogExceptions]\n// Can't hide in Intellisense, because that would hide it for all derived classes too\n// [ShowApiWhenReleased(ShowApiMode.Never)]\n[method: PrivateApi]\npublic abstract class DnnSxcCustomControllerBase(string logSuffix, string insightsGroup = default)\n    : DnnSxcControllerBase(logSuffix, insightsGroup)\n{\n    #region Constructor & DI / Setup\n\n    /// <summary>\n    /// Empty constructor is important for inheriting classes\n    /// </summary>\n    [PrivateApi]\n    protected DnnSxcCustomControllerBase() : this(\"DynApi\") { }\n\n    [PrivateApi]\n    protected override void Initialize(HttpControllerContext controllerContext)\n    {\n        base.Initialize(controllerContext);\n        var init = DynHlp.Initialize(controllerContext);\n        if (this is IGetCodePath thisWithPath)\n            thisWithPath.CreateInstancePath = init.Folder;\n        ExCtx = init.Root;\n    }\n\n    #endregion\n\n    #region Internal / Plumbing / Obsolete\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public IExecutionContext ExCtx { get; private set; }\n\n\n\n    /// <summary>\n    /// The name of the logger in insights. The inheriting class should provide the real name to be used.\n    /// Note: Probably almost never used, except by 2sic. Must determine if we just remove it\n    /// </summary>\n    [Obsolete(\"Deprecated in v13.03 - doesn't serve a purpose any more. Will just remain to avoid breaking public uses of this property.\")]\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    // ReSharper disable once UnassignedGetOnlyAutoProperty\n    protected virtual string HistoryLogName { get; }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/ControllerBase/DnnWebApiHelper.cs",
    "content": "﻿using System.Web;\nusing ToSic.Eav.Web.Sys;\nusing ToSic.Eav.WebApi.Sys;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Dnn.Integration;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\ninternal class DnnWebApiHelper : CodeHelperBase\n{\n    #region Constructor & Destructor\n\n    public DnnWebApiHelper(IHasLog apiController, string historyLogGroup, string firstMessage = default) : base(\"Dnn.ApiHlp\")\n    {\n        var requestLogging = GetService<Generator<HttpRequestLoggingScoped, HttpRequestLoggingScoped.Opts>>()\n                .New(new() { Segment = historyLogGroup ?? EavWebApiConstants.HistoryNameWebApi, RootName = \"Dnn.Api\" });\n        this.LinkLog(requestLogging.RootLog);\n        apiController.LinkLog(requestLogging.RootLog);\n        WebApiLogging = new(requestLogging, firstMessage: firstMessage);\n    }\n\n    public void OnDispose()\n        => WebApiLogging.OnDispose();\n\n    #endregion\n\n    #region Logging\n\n    public DnnWebApiLogging WebApiLogging { get; }\n\n    #endregion\n\n    #region Basic Service\n\n    /// <summary>\n    /// Get a service of a specified type. \n    /// </summary>\n    /// <typeparam name=\"TService\"></typeparam>\n    /// <returns></returns>\n    /// <remarks>\n    /// This will override the base functionality to ensure that any services created will be able to get the CodeContext.\n    /// </remarks>\n    public TService GetService<TService>() where TService : class\n        => ExCtxOrNull?.GetService<TService>()\n            ?? _serviceProvider.Get(DnnStaticDi.GetPageScopedServiceProvider).Build<TService>(Log);\n    // Must cache it, to be really sure we use the same ServiceProvider in the same request\n    private readonly GetOnce<IServiceProvider> _serviceProvider = new();\n\n    public void SetupResponseMaker(System.Web.Http.ApiController apiController)\n        => GetService<IResponseMaker>().Init(apiController);\n\n    #endregion\n\n    /// <summary>\n    ///  Extend Time so Web Server doesn't time out\n    /// </summary>\n    public void PreventServerTimeout600()\n        => HttpContext.Current.Server.ScriptTimeout = 600;\n\n    public IBlock GetBlockAndContext(HttpRequestMessage request) \n        => _blcCtx.Get(() => GetService<DnnGetBlock>().GetCmsBlock(request));\n    private readonly GetOnce<IBlock> _blcCtx = new();\n\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/ControllerBase/DynamicApiCompileCodeHelpers.cs",
    "content": "﻿using System.Web.Http.Controllers;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Backend.Adam;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.InfoSystem;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\ninternal class DynamicApiCompileCodeHelpers: CompileCodeHelper\n{\n\n    public DynamicApiCompileCodeHelpers(DnnApiController owner, DnnWebApiHelper sysHlp)\n    {\n        _owner = owner;\n        this.LinkLog((owner as IHasLog)?.Log);\n        _sysHlp = sysHlp;\n    }\n\n    private readonly DnnApiController _owner;\n    private readonly DnnWebApiHelper _sysHlp;\n\n    #region Init\n\n    /// <summary>\n    /// This will make sure that any services requiring the context can get it.\n    /// It must usually be called from the base class which expects to use this.\n    /// </summary>\n    /// <param name=\"request\"></param>\n    public void InitializeBlockContext(HttpRequestMessage request)\n    {\n        if (_blockContextInitialized)\n            return;\n        _blockContextInitialized = true;\n        SharedCurrentContextService = _sysHlp.GetService<ISxcCurrentContextService>();\n        SharedCurrentContextService.AttachBlock(_sysHlp.GetBlockAndContext(request));\n    }\n\n    private bool _blockContextInitialized;\n\n\n    public (IExecutionContext Root, string Folder) Initialize(HttpControllerContext controllerContext)\n    {\n        var request = controllerContext.Request;\n        InitializeBlockContext(request);\n\n        // Note that the CmsBlock is created by the BaseClass, if it's detectable. Otherwise, it's null\n        var block = _sysHlp.GetBlockAndContext(request);\n        Log.A($\"HasBlock: {block != null}\");\n\n        var services = _sysHlp.GetService<ApiControllerDependencies>().ConnectServices(Log);\n        var exCtx = services.ExCtxFactory.New(new()\n        {\n            OwnerOrNull = _owner,\n            BlockOrNull = block,\n            ParentLog = Log,\n            CompatibilityFallback = CompatibilityLevels.CompatibilityLevel10,\n        });\n\n        _sysHlp.ConnectToRoot(exCtx);\n\n        AdamCode = exCtx.GetService<AdamCode>();\n\n        // In case SxcBlock was null, there is no instance, but we may still need the app\n        var app = exCtx.GetApp();\n        if (app == null! /* Special: there are cases where it's null, even though the API doesn't show it */)\n        {\n            Log.A(\"DynCode.App is null\");\n            app = GetAppOrNullFromUrlParams(services, request);\n            if (app != null)\n                ((IExCtxAttachApp)exCtx).AttachApp(app);\n        }\n\n        var reqProperties = request.Properties;\n\n        // must run this after creating AppAndDataHelpers\n        reqProperties.Add(DnnConstants.DnnContextKey, (exCtx as IHasDnn)?.Dnn);\n\n        /*if (*/\n        reqProperties.TryGetTyped(SourceCodeConstants.SharedCodeRootPathKeyInCache, out string path);\n        /*) CreateInstancePath = path; */\n\n        // 16.02 - try to log more details about the current API call\n        var currentPath = reqProperties.TryGetTyped(SourceCodeConstants.SharedCodeRootFullPathKeyInCache, out string p2) ? p2.AfterLast(\"/\") : null;\n        _sysHlp.WebApiLogging?.AddLogSpecs(block, app, currentPath, _sysHlp.GetService<CodeInfosInScope>());\n\n\n        return (exCtx, path);\n    }\n\n\n    private IApp GetAppOrNullFromUrlParams(ApiControllerDependencies services, HttpRequestMessage request)\n    {\n        var l = Log.Fn<IApp>();\n        try\n        {\n            var routeAppPath = services.AppFolderUtilities.Setup(request).GetAppFolder(false);\n            var appReader = SharedCurrentContextService.SetAppOrNull(routeAppPath)?.AppReaderRequired;\n\n            if (appReader == default)\n                return l.ReturnNull(\"no app detected\");\n            \n            var siteCtx = SharedCurrentContextService.Site();\n            // Look up if page publishing is enabled - if module context is not available, always false\n            l.A($\"AppId: {appReader.AppId}\");\n            var app = services.AppOverrideLazy.Value;\n            app.Init(siteCtx.Site, appReader.PureIdentity(), new());\n            return l.Return(app, $\"found #{app.AppId}\");\n        }\n        catch\n        {\n            // ignore\n            return l.ReturnNull(\"exception, ignore\");\n        }\n    }\n\n    #endregion\n\n    public ISxcCurrentContextService SharedCurrentContextService;\n\n    #region Adam\n\n    public AdamCode AdamCode { get; private set; }\n\n    public Sxc.Adam.IFile SaveInAdam(NoParamOrder npo = default,\n        Stream stream = null,\n        string fileName = null,\n        string contentType = null,\n        Guid? guid = null,\n        string field = null,\n        string subFolder = \"\") =>\n        AdamCode.SaveInAdam(\n            stream: stream,\n            fileName: fileName,\n            contentType: contentType,\n            guid: guid,\n            field: field,\n            subFolder: subFolder);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/ConfigureJsonOnlyResponseAttribute.cs",
    "content": "﻿using System.Web.Http.Controllers;\nusing System.Web.Http.Filters;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\n/// <summary>\n/// Configure the WebApi controller to only use JSON responses.\n/// This should enforce JSON formatting.\n/// It's only needed in .net4x where the default is xml.\n/// </summary>\n/// <remarks>\n/// The proper way to implement per-controller configuration is to create a custom attribute that implements IControllerConfiguration and\n/// modifies the HttpControllerSettings (not the global configuration directly)\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]   // unclear if this needs to be public\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]\npublic class ConfigureJsonOnlyResponseAttribute : ActionFilterAttribute, IControllerConfiguration, IHasLog\n{\n    // For debugging\n\n    // turn on if we ever need to debug stuff again, but avoid this in production, unless really, really necessary\n#if DEBUG\n    private static readonly bool LogAnything = true;\n#else\n    private static readonly bool LogAnything = false; \n#endif\n\n    // ReSharper disable ConvertToConstant.Local\n    private static readonly bool LogDetails = false;\n    private static readonly bool TestThrowInitialize = false;\n    private static readonly bool TestThrowOnActionExecuting = false;\n    // ReSharper restore ConvertToConstant.Local\n\n    public ILog Log { get; } = LogAnything ? new Log(\"Api.JsnAttr\") : null;\n\n    private bool IsDebugEnabled()\n        => new GlobalDebugParser(LogDetails ? Log : null).IsDebugEnabled();\n\n    // Keys for per-request storage (avoid header mutation)\n    private const string DebugFlagKey = \"2sxc.DebugEnabled\";\n\n    /// <summary>\n    /// This will just run once for every controller.\n    /// </summary>\n    /// <param name=\"controllerSettings\"></param>\n    /// <param name=\"controllerDescriptor\"></param>\n    /// <remarks>\n    /// The proper way to implement per-controller configuration is to modifies the HttpControllerSettings (not the global configuration directly)\n    /// This approach creates a controller-specific configuration that is isolated from the global settings.\n    /// https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/configuring-aspnet-web-api#per-controller-configuration\n    /// </remarks>\n    public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)\n    {\n        // Create an independent log for this operation - don't use a class-level log because it would grow too much\n        // add to insights-history for analytic\n        PlaceLogInHistory(Log);\n        var l = Log.Fn($\"{nameof(controllerDescriptor)}: {controllerDescriptor.ControllerType.FullName}\");\n\n        try\n        {\n            // Debug logging during dev-builds\n            var debugEnabled = IsDebugEnabled(); // no request context here\n            if (debugEnabled)\n                DnnJsonFormattersDebug.DumpFormattersToLog(Log, \"init-before\", controllerSettings.Formatters);\n\n            // This creates a controller-specific configuration\n            var formattersManager = new DnnJsonFormattersManager(Log);\n            formattersManager.ReconfigureControllerWithBestSerializers(\n                controllerSettings.Formatters,\n                GetCustomAttributes(controllerDescriptor.ControllerType)\n            );\n\n            // Debug logging during dev-builds\n            if (debugEnabled)\n                DnnJsonFormattersDebug.DumpFormattersToLog(Log, \"init-after\", controllerSettings.Formatters);\n\n            // Test throwing an exception. Usually in debugging you will move the execution cursor to here to generate errors for specific requests\n            if (TestThrowInitialize)\n                throw new($\"Test Exception in {nameof(Initialize)}\");\n\n        }\n        catch (Exception ex)\n        {\n            // Add info - and add to system log as we want to see what actually happened\n            l.Ex(ex);\n            throw;\n        }\n        finally\n        {\n            l.Done();\n        }\n    }\n\n    /// <summary>\n    /// Dynamic Per-Request Configuration\n    /// </summary>\n    /// <param name=\"context\"></param>\n    public override void OnActionExecuting(HttpActionContext context)\n    {\n        // Log = new Log(\"Dnn.Attr\"); // new log for each run\n        PlaceLogInHistory(Log);\n        var l = Log.Fn($\"{nameof(context.Request.RequestUri)}:{context.Request?.RequestUri}\");\n\n        try\n        {\n            // Ensure we only configure once per request (probably not necessary anymore)\n            if (PerRequestConfigurationHelper.SkipOnMultipleExecutionsOnTheSameRequest(context, l))\n            {\n                l.Done(\"exit early, repeat on same request\");\n                return; \n            }\n\n            var requestProperties = context.Request?.Properties;\n\n            // Cache debug-flag per request\n            var debugEnabled = GetCachedDebugEnabled(requestProperties);\n\n            var oldFormatters = context.ControllerContext.ControllerDescriptor.Configuration.Formatters;\n            if (oldFormatters == null)\n            {\n                l.Done(\"formatters are null, unexpected\");\n                return;\n            }\n\n            if (debugEnabled)\n                DnnJsonFormattersDebug.DumpFormattersToLog(Log, \"action-before\", oldFormatters);\n\n            // Re-use manager instance per request if possible to avoid repeated allocations\n            var dnnJsonFormattersManager = new DnnJsonFormattersManager(Log);\n\n            // Get any attribute for formatting on the current action, as this can override the controller-level configuration\n            var jsonFormatterAttributeOnAction = context.ActionDescriptor\n                .GetCustomAttributes<JsonFormatterAttribute>()\n                .FirstOrDefault();\n\n            var effectiveJsonFormatterAttribute = ApplyQueryStringCasingOverride(context, jsonFormatterAttributeOnAction);\n\n            var perRequestConfiguration = PerRequestConfigurationHelper\n                .CreateAndApplyPerRequestConfiguration(context, dnnJsonFormattersManager, effectiveJsonFormatterAttribute);\n\n            // Debug logging during dev-builds\n            if (debugEnabled && perRequestConfiguration != null)\n                DnnJsonFormattersDebug.DumpFormattersToLog(Log, \"action-after\", perRequestConfiguration?.Formatters);\n\n            l.Done();\n\n            // Test throwing an exception. Usually in debugging you will move the execution cursor to here to generate errors for specific requests\n            if (TestThrowOnActionExecuting)\n                throw new($\"Test Exception in {nameof(OnActionExecuting)}\");\n        }\n        catch (Exception ex)\n        {\n            // Add info - and add to system log as we want to see what actually happened\n            l.Ex(ex);\n            throw;\n        }\n    }\n\n    // Cache debug-flag per request\n    private bool GetCachedDebugEnabled(IDictionary<string, object> requestProperties)\n    {\n        if (requestProperties?.TryGetTyped(DebugFlagKey, out bool dbgBool) == true)\n            return dbgBool;\n\n        var debugEnabled = IsDebugEnabled();\n        requestProperties?[DebugFlagKey] = debugEnabled;\n\n        return debugEnabled;\n    }\n\n    /// <summary>\n    /// Allows request-level casing override using `?$casing=camel` without touching global formatter state.\n    /// </summary>\n    private static JsonFormatterAttribute ApplyQueryStringCasingOverride(HttpActionContext context, JsonFormatterAttribute currentAttribute)\n    {\n        if (!TryGetQueryStringCasingOverride(context, out var requestedCasing))\n            return currentAttribute;\n\n        return new()\n        {\n            EntityFormat = currentAttribute?.EntityFormat ?? EntityFormat.Light,\n            Casing = requestedCasing\n        };\n    }\n\n    /// <summary>\n    /// Returns true only for supported casing overrides; unsupported values are ignored.\n    /// </summary>\n    private static bool TryGetQueryStringCasingOverride(HttpActionContext context, out Casing casing)\n        => JsonCasingOverrideHelper.TryParseCasingOverride(context?.Request?.GetQueryNameValuePairs(), out casing);\n\n\n    /// <summary>\n    /// since it's really hard to debug attribute/serialization issues, try to log this problem\n    /// </summary>\n    private void PlaceLogInHistory(ILog log)\n    {\n        if (LogAnything)\n            GetService<ILogStore>()?.Add(\"webapi-serialization\", log);\n    }\n\n    // Do NOT CACHE the ServiceProvider, as this attribute seems to be long-lived and shared between requests\n    private TService GetService<TService>() where TService : class\n        => DnnStaticDi.GetPageScopedServiceProvider().Build<TService>(Log);\n}\n\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/DnnJsonFormattersDebug.cs",
    "content": "﻿using System.Net.Http.Formatting;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\ninternal class DnnJsonFormattersDebug\n{\n\n    internal static void DumpFormattersToLog(ILog log, string phase, MediaTypeFormatterCollection formatters)\n    {\n        var l = log.Fn($\"dump:{phase}\");\n        try\n        {\n            // Intro\n            l.A($\"Dumping formatters ({formatters?.Count ?? -1}) at {phase}\");\n\n            // If nothing, exit early\n            if (formatters == null)\n            {\n                l.A(\"Formatters collection is NULL\");\n                return;\n            }\n\n            // Show each formatter\n            for (var i = 0; i < formatters.Count; i++)\n            {\n                var f = formatters[i];\n                if (f == null)\n                {\n                    l.A($\"[{i}] NULL formatter\");\n                    continue;\n                }\n                var type = f.GetType();\n                var info = $\"[{i}] {type.FullName} ({f.GetHashCode()})\";\n                // Try to unwrap common tracer pattern\n                try\n                {\n                    var innerProp = type.GetProperty(\"InnerFormatter\");\n                    if (innerProp != null)\n                        info += innerProp.GetValue(f) is MediaTypeFormatter inner\n                            ? $\" -> inner: {inner.GetType().FullName}\"\n                            : \" -> inner: null\";\n                }\n                catch { /* ignore reflection errors */ }\n                l.A(info);\n            }\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n        }\n        finally\n        {\n            l.Done();\n        }\n    }\n\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/DnnJsonFormattersManager.cs",
    "content": "﻿using System.Net.Http.Formatting;\nusing System.Web.Http.Controllers;\nusing ToSic.Sxc.WebApi.Sys.ActionFilters;\nusing static ToSic.Sxc.Dnn.WebApi.Sys.HttpJson.DnnJsonFormattersDebug;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\ninternal class DnnJsonFormattersManager(ILog parentLog): HelperBase(parentLog, \"Dnn.JFManager\")\n{\n    // For debugging\n    // ReSharper disable once ConvertToConstant.Local\n    private static readonly bool LogDetails = false;\n\n    /// <summary>\n    /// Name used in the Tracer wrapper around SystemTextJsonMediaTypeFormatter\n    /// </summary>\n    private const string SystemTextJsonMediaTypeFormatterName = \"System.Net.Http.Formatting.SystemTextJsonMediaTypeFormatter\";\n\n    private bool IsDebugEnabled()\n        => new GlobalDebugParser(LogDetails ? Log : null).IsDebugEnabled();\n\n\n    private object EnsureNoNulls(MediaTypeFormatterCollection formatters)\n    {\n        var l = Log.Fn<object>();\n        try\n        {\n            if (formatters.All(f => f != null))\n                return l.ReturnNull(\"No null formatters found\");\n\n            l.A(\"Null formatter(s) detected - will rebuild collection without nulls\");\n            var safe = formatters\n                .Where(f => f != null)\n                .ToList();\n\n            formatters.Clear();\n            formatters.AddRange(safe);\n\n            return l.ReturnNull($\"Sanitized formatters count: {formatters.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnNull(\"Exception during EnsureNoNulls\");\n        }\n    }\n\n    // This creates a controller-specific configuration\n    internal void ReconfigureControllerWithBestSerializers(MediaTypeFormatterCollection formatters, Attribute[] customAttributes)\n    {\n        var l = Log.Fn();\n\n        if (IsDebugEnabled())\n            DumpFormattersToLog(Log, \"before-controller\", formatters);\n\n        // Remove the XML formatter\n        l.A(\"Will remove the default XmlFormatter\");\n        try\n        {\n            if (formatters.XmlFormatter != null)\n                formatters.Remove(formatters.XmlFormatter);\n        }\n        catch (Exception ex)\n        {\n            l.E(\"XmlFormatter remove failed\");\n            l.Ex(ex);\n        }\n\n        // Get JsonFormatterAttribute from controller - would mark the controller to use System.Text.Json\n        var jsonFormatterAttribute = customAttributes\n            .OfType<JsonFormatterAttribute>()\n            .FirstOrDefault();\n\n        // For older apis we need to leave NewtonsoftJson (when JsonFormatterAttribute is missing on controller)\n        var keepOldNewtonsoft = customAttributes\n            .OfType<DefaultToNewtonsoftForHttpJsonAttribute>()\n            .Any();\n\n        if (keepOldNewtonsoft && jsonFormatterAttribute == null)\n        {\n            if (IsDebugEnabled())\n                DumpFormattersToLog(Log, \"after-controller-skip\", formatters);\n\n            l.Done($\"Has {nameof(DefaultToNewtonsoftForHttpJsonAttribute)} and no custom {nameof(JsonFormatterAttribute)} will leave serializers intact.\");\n\n            return;\n        }\n\n        // For newer apis we need to use System.Text.Json, but generated per request\n        // because of DI dependencies for EavJsonConvertors in new generated JsonOptions\n\n        // Remove default JsonMediaTypeFormatter (Newtonsoft) with a single rebuild pass\n        try\n        {\n            var keep = formatters\n                .Where(f => f is not JsonMediaTypeFormatter)\n                .ToList();\n            formatters.Clear();\n            formatters.AddRange(keep);\n        }\n        catch (Exception ex)\n        {\n            l.E(\"Newtonsoft remove (rebuild) failed\");\n            l.Ex(ex);\n        }\n\n        // Add SystemTextJsonMediaTypeFormatter with JsonSerializerOptions based on JsonFormatterAttribute from controller\n        ReplaceJsonFormatterWithNewInstance(formatters, jsonFormatterAttribute);\n\n        EnsureNoNulls(formatters);\n\n        if (IsDebugEnabled())\n            DumpFormattersToLog(Log, \"after-controller\", formatters);\n\n        l.Done();\n    }\n\n    internal void ReconfigureActionWithContextAwareSerializer(\n        HttpControllerDescriptor controllerDescriptor,\n        MediaTypeFormatterCollection formatters,\n        JsonFormatterAttribute jsonFormatterAttributeOnAction)\n    {\n        var l = Log.Fn();\n\n        // Get JsonFormatterAttribute from action **Method**\n        l.A(jsonFormatterAttributeOnAction == null\n            ? $\"{nameof(JsonFormatterAttribute)} is missing on action method.\" // note: before 20.09 it returned here\n            : $\"Method has custom {nameof(JsonFormatterAttribute)}\");\n\n        // For older apis we need to leave (when JsonFormatterAttribute is missing on action method)\n        var controllerHasDefaultToOld = Attribute.GetCustomAttributes(controllerDescriptor.ControllerType)\n            .OfType<DefaultToNewtonsoftForHttpJsonAttribute>()\n            .Any();\n        if (controllerHasDefaultToOld)\n        {\n            l.Done($\"Controller has {nameof(DefaultToNewtonsoftForHttpJsonAttribute)}, will exit leaving old serializers.\");\n            return;\n        }\n\n        if (formatters == null)\n        {\n            l.Done(\"Formatters collection is null - nothing to reconfigure\");\n            return;\n        }\n\n        l.A($\"Found {formatters.Count} formatters\");\n\n        if (IsDebugEnabled())\n            DumpFormattersToLog(Log, \"before-action\", formatters);\n\n        ReplaceJsonFormatterWithNewInstance(formatters, jsonFormatterAttributeOnAction);\n\n        EnsureNoNulls(formatters);\n\n        if (IsDebugEnabled())\n            DumpFormattersToLog(Log, \"after-action\", formatters);\n\n        l.Done();\n    }\n\n\n    internal void ReplaceJsonFormatterWithNewInstance(MediaTypeFormatterCollection formatters, JsonFormatterAttribute jsonFormatterAttributeOnAction)\n    {\n        var l = Log.Fn();\n\n        // 2025-11-08 2dm - creating a list to avoid multiple enumeration of formatters\n        // since I sometimes observed a single error after restart \"Collection was modified; enumeration operation may not execute.\"\n        // Defensive: copy once to avoid collection-modified exceptions\n        var formattersListCopy = formatters.ToList();\n\n        // Collect formatters to remove (STJ and tracer-like) in one pass\n        var toKeep = new List<MediaTypeFormatter>(formattersListCopy.Count);\n        var removedForCasingMedia = new List<MediaTypeFormatter>(); // all removed items\n        var removedStj = new List<SystemTextJsonMediaTypeFormatter>(); // only STJ for casing helper\n        foreach (var f in formattersListCopy)\n        {\n            if (f is SystemTextJsonMediaTypeFormatter stj)\n            {\n                removedForCasingMedia.Add(stj);\n                removedStj.Add(stj);\n                continue;\n            }\n            \n            // Tracers seem to be wrapped formatters which can also do trace-logging.\n            // We noticed that these are prepared\n\n            // Detect tracer by ToString match\n            if (f != null && f.ToString() == SystemTextJsonMediaTypeFormatterName)\n            {\n                removedForCasingMedia.Add(f);\n                // Try to unwrap actual inner STJ if present\n                try\n                {\n                    var innerProp = f.GetType().GetProperty(\"InnerFormatter\");\n                    if (innerProp?.GetValue(f) is SystemTextJsonMediaTypeFormatter inner)\n                    {\n                        removedForCasingMedia.Add(inner);\n                        removedStj.Add(inner);\n                    }\n                }\n                catch (Exception ex)\n                {\n                    l.E(\"Failed to unwrap tracer\");\n                    l.Ex(ex);\n                }\n                continue;\n            }\n\n            toKeep.Add(f);\n        }\n\n        // If no STJ present after removal, add new one configured by factory\n        var hasStj = toKeep.Any(x => x is SystemTextJsonMediaTypeFormatter);\n        if (!hasStj)\n        {\n            l.A($\"Will add {nameof(SystemTextJsonMediaTypeFormatter)} since none were found\");\n            MediaTypeFormatter newFactory = null;\n            try\n            {\n                newFactory = JsonConverterFactoryHelpers.CreateNewFormatterFactory(\n                    // Get the service provider from the current request scope using DnnStaticDi helper\n                    // This ensures all services (including EavJsonConverterFactory and its dependencies) use the current request's culture\n                    DnnStaticDi.GetPageScopedServiceProvider(),\n                    jsonFormatterAttributeOnAction,\n                    () => JsonFormatterCasingHelpersForDnn.ExtractCasingFromFormatters(removedStj),\n                    jsonSerializerOptions => new SystemTextJsonMediaTypeFormatter { JsonSerializerOptions = jsonSerializerOptions }\n                );\n            }\n            catch (Exception ex)\n            {\n                l.E(\"CreateNewFormatterFactory threw\");\n                l.Ex(ex);\n            }\n\n            if (newFactory != null)\n                toKeep.Insert(0, newFactory);\n            else\n                l.A(\"CreateNewFormatterFactory returned NULL - will not insert\");\n        }\n        else\n        {\n            l.A($\"It has a {nameof(SystemTextJsonMediaTypeFormatter)}, so won't add.\");\n        }\n\n        // Rebuild collection once to avoid multiple Remove calls\n        try\n        {\n            formatters.Clear();\n            foreach (var f in toKeep)\n                formatters.Add(f);\n        }\n        catch (Exception ex)\n        {\n            l.E(\"Rebuild formatters failed\");\n            l.Ex(ex);\n        }\n\n        l.Done();\n    }\n\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/GlobalDebugParser.cs",
    "content": "using System.Diagnostics;\nusing System.Web;\nusing DotNetNuke.Entities.Controllers;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\n// Helper for parsing debug decision from querystring and host-setting (no headers, no empty values).\ninternal class GlobalDebugParser(ILog parentLog) : HelperBase(parentLog, \"Dnn.DbRqPr\")\n{\n    private const string Debug = \"debug\";\n\n    // HostSetting key (DNN Host / SuperUser scope) - avoids web.config edits/restarts\n    private const string HostSettingForceDebugKey = \"Sxc:ForceDebug\";\n\n    // Global state cached in-memory for fast checks (not user-bound)\n    private static bool? _globalDebug;\n    private static readonly object GlobalLock = new();\n\n    // Determines whether tracing is enabled for the given HttpContext.\n    // Precedence: explicit query toggle -> cached host-setting -> default(false)\n    internal bool IsDebugEnabled()\n    {\n        var l = Log.Fn<bool>(\"parse debug state\");\n        try\n        {\n#if DEBUG\n            if (Debugger.IsAttached)\n            {\n                l.A(\"Debugger attached -> debug = true\");\n                return l.ReturnTrue(\"attached\");\n            }\n#endif\n            var ctx = HttpContext.Current; // may be null outside request scope\n\n            // 1) Query string explicit toggle (requires value true/false; no empty value supported)\n            try\n            {\n                if (ctx?.Request != null)\n                {\n                    var req = ctx.Request;\n                    var hasKey = req.QueryString.AllKeys?.Contains(Debug) == true;\n                    if (hasKey)\n                    {\n                        var qVal = req.QueryString[Debug];\n                        l.A($\"query:'{qVal}'\");\n\n                        if (qVal != null)\n                        {\n                            if (IsTruthy(qVal))\n                            {\n                                SetGlobalDebug(true, out var persistedOk);\n                                l.A($\"explicit query toggle on; host-setting-persist={(persistedOk ? \"ok\" : \"fail\")}\");\n                                return l.ReturnTrue(\"explicit-on\");\n                            }\n\n                            if (IsFalsey(qVal))\n                            {\n                                SetGlobalDebug(false, out var persistedOk);\n                                l.A($\"explicit query toggle off; host-setting-persist={(persistedOk ? \"ok\" : \"fail\")}\");\n                                return l.ReturnFalse(\"explicit-off\");\n                            }\n\n                            l.A(\"query value invalid -> ignore\");\n                        }\n                    }\n                }\n            }\n            catch (Exception ex)\n            {\n                l.Ex(ex);\n            }\n\n            // 2) Fallback to global cached host-setting\n            try\n            {\n                var forced = GetGlobalDebug();\n                if (forced.HasValue)\n                {\n                    l.A($\"global forced = {forced.Value}\");\n                    return l.Return(forced.Value, forced.Value ? \"global-on\" : \"global-off\");\n                }\n            }\n            catch (Exception ex)\n            {\n                l.Ex(ex);\n            }\n\n            l.A(\"default = false\");\n            return l.ReturnFalse(\"default-off\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnFalse(\"error\");\n        }\n    }\n\n    // Retrieve forced debug from cache or HostSettings\n    private static bool? GetGlobalDebug()\n    {\n        if (_globalDebug.HasValue)\n            return _globalDebug.Value;\n\n        lock (GlobalLock)\n        {\n            if (_globalDebug.HasValue)\n                return _globalDebug.Value;\n\n            try\n            {\n                var raw = HostController.Instance.GetString(HostSettingForceDebugKey, null);\n                if (raw == null)\n                {\n                    _globalDebug = null; // unset\n                }\n                else if (IsTruthy(raw))\n                {\n                    _globalDebug = true;\n                }\n                else if (IsFalsey(raw))\n                {\n                    _globalDebug = false;\n                }\n                else\n                {\n                    _globalDebug = null; // unknown -> ignore\n                }\n            }\n            catch\n            {\n                _globalDebug = null;\n            }\n            return _globalDebug;\n        }\n    }\n\n    // Set global forced debug & persist in HostSettings; returns persistence success\n    private static void SetGlobalDebug(bool enable, out bool persistedOk)\n    {\n        lock (GlobalLock)\n        {\n            _globalDebug = enable;\n            persistedOk = TryPersistHostSetting(enable);\n        }\n    }\n\n    private static bool TryPersistHostSetting(bool enable)\n    {\n        try\n        {\n            var value = enable ? \"true\" : \"false\";\n            HostController.Instance.Update(HostSettingForceDebugKey, value, clearCache: true);\n            return true;\n        }\n        catch\n        {\n            return false; // keep in-memory state\n        }\n    }\n\n    private static bool IsTruthy(string value)\n    {\n        if (value == null) return false;\n        var v = value.Trim().ToLowerInvariant();\n        return v.Length == 0 || v is \"true\" or \"1\" or \"yes\" or \"on\";\n    }\n\n    private static bool IsFalsey(string value)\n    {\n        if (value == null) return false;\n        var v = value.Trim().ToLowerInvariant();\n        return v is \"false\" or \"0\" or \"no\" or \"off\";\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/JsonFormatterCasingHelpersForDnn.cs",
    "content": "﻿using System.Net.Http.Formatting;\nusing System.Text.Json;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\ninternal class JsonFormatterCasingHelpersForDnn\n{\n    internal static Casing ExtractCasingFromFormatters(List<SystemTextJsonMediaTypeFormatter> formatters)\n    {\n        if (formatters is not { Count: > 0 })\n            return Casing.Unspecified;\n\n        foreach (var formatter in formatters)\n        {\n            var options = formatter.JsonSerializerOptions;\n            if (options?.PropertyNamingPolicy != null)\n                return GetCasing(options);\n        }\n\n        return Casing.Unspecified;\n    }\n\n    /// <summary>\n    /// Get the casing configuration from JsonSerializerOptions.\n    /// Analyzes both PropertyNamingPolicy and DictionaryKeyPolicy to determine the casing.\n    /// </summary>\n    /// <param name=\"options\">The JsonSerializerOptions to analyze</param>\n    /// <returns>The detected Casing configuration</returns>\n    internal static Casing GetCasing(JsonSerializerOptions options)\n    {\n        if (options == null! /* paranoid */)\n            return Casing.Unspecified;\n\n        var isCamelCase = options.PropertyNamingPolicy == JsonNamingPolicy.CamelCase;\n        var isDictionaryCamelCase = options.DictionaryKeyPolicy == JsonNamingPolicy.CamelCase;\n\n        // If both are camelCase, return the simple Camel flag\n        if (isCamelCase && isDictionaryCamelCase)\n            return Casing.Camel;\n\n        // If both preserve original casing\n        if (!isCamelCase && !isDictionaryCamelCase)\n            return Casing.Preserve;\n\n        // Mixed scenarios - use granular flags\n        var result = Casing.Unspecified;\n\n        if (isCamelCase)\n            result |= Casing.Camel;\n        else\n            result |= Casing.Preserve;\n\n        if (isDictionaryCamelCase)\n            result |= Casing.DictionaryCamel;\n        else\n            result |= Casing.DictionaryPreserve;\n\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/JsonFormatters.cs",
    "content": "﻿using System.Net.Http.Formatting;\nusing ToSic.Eav.Serialization.Sys.Json;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\ninternal class JsonFormatters\n{\n    public static SystemTextJsonMediaTypeFormatter SystemTextJsonMediaTypeFormatter =>\n        field ??= new()\n        {\n            JsonSerializerOptions = JsonOptions.UnsafeJsonWithoutEncodingHtml\n        };\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/PerRequestConfigurationHelper.cs",
    "content": "﻿using System.Reflection;\nusing System.Web.Http.Controllers;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\n/// <summary>\n/// Helper to change the formatters of an API call for this request only.\n/// We need it, because every request could have different cultures etc. which is provided through DI.\n/// Making it any other way could have side effects on later / other requests.\n/// </summary>\ninternal class PerRequestConfigurationHelper\n{\n\n    /// <summary>\n    /// Ensure we only configure once per request.\n    /// </summary>\n    /// <param name=\"context\"></param>\n    /// <param name=\"l\"></param>\n    /// <returns>`false` if not yet configured, `true` if already configured.</returns>\n    internal static bool SkipOnMultipleExecutionsOnTheSameRequest(HttpActionContext context, ILogCall l)\n    {\n        const string markerKey = \"2sxc.JsonFormatter.Configured\";\n\n        // Use Request.Properties to mark rather than mutating headers (faster & avoids client-side confusion)\n        var props = context.Request?.Properties;\n        if (props == null)\n            return false;\n\n        // If it was already configured, we would get a count,\n        // so we can increase it and log that this is happening - but skip the actual configuration again.\n        if (props.TryGetTyped(markerKey, out int cnt))\n        {\n            cnt++;\n            props[markerKey] = cnt;\n            l.A($\"Formatter configuration already ran for this request - skipping (count:{cnt})\");\n            return true;\n        }\n\n        // First time, mark it as configured and continue with the configuration.\n        props[markerKey] = 1;\n        return false;\n    }\n\n    internal static HttpConfiguration CreateAndApplyPerRequestConfiguration(\n        HttpActionContext context,\n        DnnJsonFormattersManager manager,\n        JsonFormatterAttribute jsonFormatterAttributeOnCurrentAction)\n    {\n        var configOriginal = context.ControllerContext.Configuration\n                             ?? throw new InvalidOperationException(\"Controller configuration is not available.\");\n\n        // Create a copy of the previous configuration\n        var settingsCopy = new HttpControllerSettings(configOriginal);\n\n\n        manager.ReconfigureActionWithContextAwareSerializer(\n            context.ControllerContext.ControllerDescriptor,\n            settingsCopy.Formatters,    // this list will be updated, side effect!\n            jsonFormatterAttributeOnCurrentAction\n        );\n\n        var perRequestConfiguration = ApplyControllerSettings(settingsCopy, configOriginal);\n\n        var updated = ApplyPerRequestConfiguration(context, perRequestConfiguration);\n        return updated;\n    }\n\n    private static HttpConfiguration ApplyPerRequestConfiguration(HttpActionContext context, HttpConfiguration configuration)\n    {\n        // Note: null should not be possible, will probably cause problems upstream\n        if (configuration == null)\n            return null;\n        context.ControllerContext.Configuration = configuration;\n        context.Request?.SetConfiguration(configuration);\n        return configuration;\n    }\n\n    /// <summary>\n    /// This gives access to the internal static method `HttpConfiguration.ApplyControllerSettings`\n    /// which is used by Web API to create a controller-specific configuration based on the global configuration and controller settings.\n    ///\n    /// We need it to spin up per-request clones of the controller configuration without touching shared state\n    /// </summary>\n    /// <remarks>\n    /// We will use this method to create a per-request configuration that we can modify without affecting the global configuration or other requests.\n    /// The underlying method is retrieved through reflection, but we'll cache the delegate for performance, so we only pay the reflection cost once.\n    ///\n    /// The method we wrap is:\n    /// internal static HttpConfiguration ApplyControllerSettings(HttpControllerSettings settings, HttpConfiguration configuration)\n    /// {\n    ///   if (!settings.IsFormatterCollectionInitialized && !settings.IsParameterBindingRuleCollectionInitialized && !settings.IsServiceCollectionInitialized)\n    ///     return configuration;\n    ///   HttpConfiguration httpConfiguration = new HttpConfiguration(configuration, settings);\n    ///   httpConfiguration.Initializer(httpConfiguration);\n    ///   return httpConfiguration;\n    /// }\n    /// </remarks>\n    private static readonly Func<HttpControllerSettings, HttpConfiguration, /* out */ HttpConfiguration> ApplyControllerSettings\n        = typeof(HttpConfiguration).GetDelegateToMethod<Func<HttpControllerSettings, HttpConfiguration, /* out */ HttpConfiguration>>(\n            methodName: \"ApplyControllerSettings\",\n            bindingAttr: BindingFlags.NonPublic | BindingFlags.Static\n        );\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/System.Text.Json.Formatter.cs",
    "content": "﻿// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n// https://github.com/aspnet/AspLabs/blob/main/src/AspNetCoreWebAPI/src/System.Text.Json.Formatter/SystemTextJsonMediaTypeFormatter.cs\n\n// 2024-01-10 2dm NOTES\n// It seems to be identical with the code from the source, so I assume that it patches capabilities\n// which were added by a newer .net but missing in Dnn\n// Also not sure when we can remove this\n\nusing System.Net.Http.Headers;\nusing System.Text;\nusing System.Text.Json;\n\n// ReSharper disable once CheckNamespace\nnamespace System.Net.Http.Formatting;\n\n/// <summary>\n/// <see cref=\"MediaTypeFormatter\"/> class to handle Json.\n/// </summary>\ninternal class SystemTextJsonMediaTypeFormatter : MediaTypeFormatter\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"JsonMediaTypeFormatter\"/> class.\n    /// </summary>\n    public SystemTextJsonMediaTypeFormatter()\n    {\n        // Set default supported media types\n        SupportedMediaTypes.Add(new(\"application/json\"));\n        SupportedMediaTypes.Add(new(\"text/json\"));\n\n        // Set default supported character encodings\n        SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true));\n        SupportedEncodings.Add(new UnicodeEncoding(bigEndian: false, byteOrderMark: true, throwOnInvalidBytes: true));\n    }\n\n    /// <summary>\n    /// Gets or sets the <see cref=\"JsonSerializerOptions\" /> used to format data. Configured using <see cref=\"JsonSerializerDefaults.Web\" />.\n    /// </summary>\n    public JsonSerializerOptions JsonSerializerOptions = new(JsonSerializerDefaults.Web);\n\n    public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)\n        => ReadFromStreamAsync(type, readStream, content, formatterLogger, default);\n\n    public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger, CancellationToken cancellationToken)\n    {\n        if (type == null)\n        {\n            throw new ArgumentNullException(\"type\");\n        }\n\n        if (readStream == null)\n        {\n            throw new ArgumentNullException(\"readStream\");\n        }\n\n        HttpContentHeaders contentHeaders = content == null ? null : content.Headers;\n\n        // If content length is 0 then return default value for this type\n        if (contentHeaders != null && contentHeaders.ContentLength == 0)\n        {\n            return GetDefaultValueForType(type);\n        }\n\n        // Get the character encoding for the content\n        // Never non-null since SelectCharacterEncoding() throws in error / not found scenarios\n        Encoding effectiveEncoding = SelectCharacterEncoding(contentHeaders);\n\n        Stream transcodingStream = null;\n        if (effectiveEncoding.CodePage != Encoding.UTF8.CodePage)\n        {\n#if NET5_0_OR_GREATER\n                transcodingStream = Encoding.CreateTranscodingStream(readStream, Encoding.UTF8, effectiveEncoding, leaveOpen: true);\n#else\n            throw new NotSupportedException(\"Using non-UTF8 encoding is not supported.\");\n#endif\n        }\n\n        try\n        {\n            var result = await JsonSerializer.DeserializeAsync(transcodingStream ?? readStream, type, JsonSerializerOptions, cancellationToken);\n            return result;\n        }\n        finally\n        {\n#if NET5_0_OR_GREATER\n                await (transcodingStream?.DisposeAsync() ?? default);\n#else\n            transcodingStream?.Dispose();\n#endif\n        }\n    }\n\n    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)\n        => WriteToStreamAsync(type, value, writeStream, content, transportContext, default);\n\n    public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\n    {\n        if (type == null)\n        {\n            throw new ArgumentNullException(\"type\");\n        }\n\n        if (writeStream == null)\n        {\n            throw new ArgumentNullException(\"writeStream\");\n        }\n\n        Encoding effectiveEncoding = SelectCharacterEncoding(content == null ? null : content.Headers);\n        Stream transcodingStream = null;\n        if (effectiveEncoding.CodePage != Encoding.UTF8.CodePage)\n        {\n#if NET5_0_OR_GREATER\n                transcodingStream = Encoding.CreateTranscodingStream(writeStream, Encoding.UTF8, effectiveEncoding, leaveOpen: true);\n#else\n            throw new NotSupportedException(\"Using non-UTF8 encoding is not supported.\");\n#endif\n        }\n\n        try\n        {\n            await JsonSerializer.SerializeAsync(transcodingStream ?? writeStream, value, type, JsonSerializerOptions, cancellationToken);\n        }\n        finally\n        {\n#if NET5_0_OR_GREATER\n                await (transcodingStream?.DisposeAsync() ?? default);\n#else\n            transcodingStream?.Dispose();\n#endif\n        }\n    }\n\n    public override bool CanReadType(Type type) => true;\n\n    public override bool CanWriteType(Type type) => true;\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/TypeReflectionExtensions.cs",
    "content": "﻿using System.Reflection;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\ninternal static class TypeReflectionExtensions\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <typeparam name=\"TFunc\">Signature of the method</typeparam>\n    /// <param name=\"type\"></param>\n    /// <param name=\"methodName\">name of the method</param>\n    /// <param name=\"bindingAttr\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"InvalidOperationException\"></exception>\n    internal static TFunc GetDelegateToMethod<TFunc>(this Type type, string methodName, BindingFlags bindingAttr) where TFunc : Delegate\n    {\n        // Find the internal static method using reflection - it's internal and static, so we need to specify those binding flags\n        var method = type.GetMethod(methodName, bindingAttr);\n\n        // Make sure we found it - this should always be the case\n        if (method == null)\n            throw new InvalidOperationException($\"Unable to locate {type.Name}.{methodName}\");\n\n        // Create a delegate for the method - this will allow us to call it efficiently without reflection after the initial lookup\n        var delegateToInternalMethod = method.CreateDelegate(typeof(TFunc));\n\n        return (TFunc)delegateToInternalMethod;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/HttpJson/UseOldNewtonsoftForHttpJsonAttribute.cs",
    "content": "﻿using System.Net.Http.Formatting;\nusing System.Web.Http.Controllers;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\n\n/// <summary>\n/// Mark all base classes for custom WebApi controllers which should use the old Newtonsoft.\n/// Important because it otherwise breaks existing code which may be using Newtonsoft objects - specifically old Mobius WebApi controllers.\n/// https://github.com/2sic/2sxc/issues/2917\n/// Should only be applied to the base classes up to Api14, but not on newer classes\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]   // unclear if this needs to be public\npublic class DefaultToNewtonsoftForHttpJsonAttribute : Attribute\n{\n    /// <summary>\n    /// For older apis we need to leave NewtonsoftJson as the serializer.\n    /// </summary>\n    /// <param name=\"controllerSettings\"></param>\n    /// <param name=\"controllerDescriptor\"></param>\n    public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)\n        => SetDefaultNewtonsoftJsonFormatter(controllerSettings);\n\n    private void SetDefaultNewtonsoftJsonFormatter(HttpControllerSettings controllerSettings)\n    {\n        // Remove System.Text.Json JsonMediaTypeFormatter\n        var formatters = controllerSettings.Formatters\n            .OfType<SystemTextJsonMediaTypeFormatter>()\n            .ToList();\n        foreach (var f in formatters)\n            controllerSettings.Formatters.Remove(f);\n\n        // Bring back original JsonFormatter\n        if (!controllerSettings.Formatters.OfType<JsonMediaTypeFormatter>().Any())\n            controllerSettings.Formatters.Insert(0, controllerSettings.Formatters.JsonFormatter);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Logging/DnnLogExceptions.cs",
    "content": "﻿using System.Net;\nusing System.Web.Http.Filters;\nusing ToSic.Sxc.Dnn.Run;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DnnLogExceptions : ExceptionFilterAttribute\n{\n    public override void OnException(HttpActionExecutedContext context)\n    {\n        var exception = context.Exception;\n        DotNetNuke.Services.Exceptions.Exceptions.LogException(exception);\n\n        // try to access log created so far\n        try\n        {\n            LogStoreEntry logEntry = null;\n            if (context.Request?.Properties.TryGetTyped(EavLogKey, out LogStoreEntry logEntryObj) ?? false)\n                logEntry = logEntryObj;\n\n            if (logEntry != null)\n            {\n                // must to ContainsKey checks, otherwise we get too many errors which is a problem while debugging\n                // var log = logEntry.Log; // context.Request.Properties[DnnConstants.EavLogKey] as ILog;\n                var dnnContext = context.Request.Properties.TryGetValue(DnnContextKey, out var ctxObj)\n                    ? ctxObj as IDnnContext\n                    : null;\n                DnnLogging.LogToDnn(\"2sxc-Api\", \"Auto-Log Exception\", logEntry.Log, dnnContext, force: true);\n            }\n            else\n                DnnLogging.LogToDnn(\"2sxc-Api\",\n                    \"exception, but no additional internal log to add, EavLog doesn't exist\", force: true);\n        }\n        catch\n        {\n            DnnLogging.TryToReportLoggingFailure(\"SxcWebApiExceptionHandling\");\n        }\n\n        // special manual exception maker, because otherwise IIS at runtime removes all messages\n        // without this, debug-infos like what entity is causing the problem will not be shown to the client\n        context.Response = context.Request.CreateErrorResponse(HttpStatusCode.BadRequest,\n            \"Bad Request\",\n            context.Exception);\n        var httpError = (HttpError)((ObjectContent<HttpError>)context.Response.Content).Value;\n        if (!httpError.ContainsKey(\"ExceptionType\"))\n            httpError.Add(\"ExceptionType\", exception.GetType().FullName);\n        if (!httpError.ContainsKey(\"ExceptionMessage\"))\n            httpError.Add(\"ExceptionMessage\", exception.Message);\n    }\n\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Logging/DnnLogWebApi.cs",
    "content": "﻿using System.Web.Http.Filters;\nusing ToSic.Sxc.Dnn.Run;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DnnLogWebApi : ActionFilterAttribute\n{\n    public override bool AllowMultiple => false;\n\n    private const string AlreadyLogged = \"LogDetailsAlreadyHappened\";\n\n    public override void OnActionExecuted(HttpActionExecutedContext actionContext)\n    {\n        base.OnActionExecuted(actionContext);\n\n        try\n        {\n            var reqProps = actionContext.Request.Properties;\n\n            // check if already logged, and set property to prevent double-logging\n            if (reqProps.ContainsKey(AlreadyLogged))\n                return;\n            reqProps.Add(AlreadyLogged, true);\n\n            // check if we have any logging details for this request\n            if (!reqProps.TryGetTyped(EavLogKey, out LogStoreEntry logStoreEntry))\n                return;\n\n            // check if we have additional context information (portal, module, etc.)\n            reqProps.TryGetValue(DnnContextKey, out var dnnContext);\n\n            DnnLogging.LogToDnn(\"2sxc-Api\", \n                actionContext.Request.RequestUri.PathAndQuery,\n                logStoreEntry.Log, \n                dnnContext as IDnnContext);\n        }\n        catch\n        {\n            DnnLogging.TryToReportLoggingFailure(\"WebApiLogDetails\");\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Providers/ModifiedTabAndModuleInfoProvider.cs",
    "content": "﻿// This is a copy of the StandardTabAndModuleInfoProvider from DNN 7.4.2\n// It's modified to work with the PageId instead of TabId\n// Note that it will be added to a ConcurrentQueue<ITabAndModuleInfoProvider>\n// So it's not meant to replace the existing one, but add another mechanism of finding it\n// I hope/assume it will be used if the other one fails.\n\nusing System.Web;\nusing DotNetNuke.Common.Utilities;\nusing DotNetNuke.Entities.Modules;\nusing ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys.Providers;\n\ninternal sealed class ModifiedTabAndModuleInfoProvider : ITabAndModuleInfoProvider\n{\n    private const string ModuleIdKey = ContextConstants.ModuleIdKey; // changed 2dm 2021-10-07\n    private const string TabIdKey = ContextConstants.PageIdKey; // changed by 2dm 2020-11-20\n\n    public bool TryFindTabId(HttpRequestMessage request, out int tabId)\n    {\n        tabId = FindInt(request, TabIdKey);\n        return tabId > Null.NullInteger;\n    }\n\n    public bool TryFindModuleId(HttpRequestMessage request, out int moduleId)\n    {\n        moduleId = FindInt(request, ModuleIdKey);\n        return moduleId > Null.NullInteger;\n    }\n\n    public bool TryFindModuleInfo(HttpRequestMessage request, out ModuleInfo moduleInfo)\n    {\n        moduleInfo = null;\n\n        if (TryFindTabId(request, out var tabId) && TryFindModuleId(request, out var moduleId))\n            moduleInfo = ModuleController.Instance.GetModule(moduleId, tabId, false);\n\n        return moduleInfo != null;\n    }\n\n    private static int FindInt(HttpRequestMessage requestMessage, string key)\n    {\n        string value = null;\n        if (requestMessage.Headers.TryGetValues(key, out var values))\n        {\n            value = values.FirstOrDefault();\n        }\n\n        if (string.IsNullOrEmpty(value) && requestMessage.RequestUri != null)\n        {\n            var queryString = HttpUtility.ParseQueryString(requestMessage.RequestUri.Query);\n            value = queryString[key];\n        }\n\n        return int.TryParse(value, out var id) ? id : Null.NullInteger;\n    }\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Routing/AppApiControllerSelector.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing System.Web.Http.Controllers;\nusing System.Web.Http.Dispatcher;\nusing ToSic.Sxc.Dnn.Backend.Sys;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n/// <inheritdoc />\n/// <summary>\n/// This controller will check if it's responsible (based on url)\n/// ...and if yes, compile / run the app-specific api controllers\n/// ...otherwise hand processing back to next api controller up-stream\n/// </summary>\ninternal class AppApiControllerSelector(HttpConfiguration configuration) : IHttpControllerSelector\n{\n    public IHttpControllerSelector PreviousSelector { get; set; }\n\n    public IDictionary<string, HttpControllerDescriptor> GetControllerMapping() => PreviousSelector.GetControllerMapping();\n\n    private static readonly string[] AllowedRoutes = [\n        \"desktopmodules/2sxc/api/app-api/\", // old routes, dnn 7/8 & dnn 9\n        \"api/2sxc/app-api/\"\n    ]; \n\n    // new in 2sxc 9.34 #1651 - added \"([^/]+\\/)?\" to allow an optional edition parameter\n    private static readonly string[] RegExRoutes =\n    [\n        @\"desktopmodules\\/2sxc\\/api\\/app\\/[^/]+\\/([^/]+\\/)?api\",\n        @\"api\\/2sxc\\/app\\/[^/]+\\/([^/]+\\/)?api\"\n    ];\n\n    /// <summary>\n    /// Verify if this request is one which should be handled by this system\n    /// </summary>\n    /// <param name=\"request\"></param>\n    /// <returns>true if we want to handle it</returns>\n    private static bool IsSxcOrEavRequest(HttpRequestMessage request)\n    {\n        var routeData = request.GetRouteData();\n        var routeTemplateLower = routeData.Route.RouteTemplate.ToLowerInvariant();\n        var simpleMatch = AllowedRoutes.Any(routeTemplateLower.Contains);\n        if (simpleMatch)\n            return true;\n\n        var rexMatch = RegExRoutes.Any(a => new Regex(a, RegexOptions.None).IsMatch(routeTemplateLower));\n        return rexMatch;\n\n    }\n\n    public HttpControllerDescriptor SelectController(HttpRequestMessage request)\n    {\n        // Do this once and early, to be really sure we always use the same one\n        var sp = DnnStaticDi.GetPageScopedServiceProvider();\n\n        // Log this lookup and add to history for insights\n        var uriToLog = request?.RequestUri?.AbsoluteUri;\n        var log = new Log(\"Sxc.Http\", null, uriToLog);\n        AddToInsightsHistory(sp, uriToLog, log);\n\n        var l = log.Fn<HttpControllerDescriptor>();\n\n        if (!IsSxcOrEavRequest(request))\n            return l.Return(PreviousSelector.SelectController(request), $\"not 2sxc request, use upstream ${nameof(HttpControllerDescriptor)}\");\n\n        // 2024-03-21 New: offload all the work to a separate class, to use more normal DI for most of the code\n        var appControllerSelectorSvc = sp.Build<AppApiControllerSelectorService>(log);\n        try\n        {\n            var newDescriptor = appControllerSelectorSvc.SelectController(configuration, request);\n            return l.Return(newDescriptor, $\"found descriptor for '{newDescriptor?.ControllerName}'. Will hand that over to .net\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            throw;\n        }\n    }\n\n\n\n    private static void AddToInsightsHistory(IServiceProvider sp, string urlOrNull, ILog log)\n    {\n        // Note: This should never error, but it's too important risk breaking just for logging\n        try\n        {\n            var addToHistory = true;\n            if (InsightsController.InsightsLoggingEnabled)\n                addToHistory = urlOrNull?.Contains(InsightsController.InsightsUrlFragment) ?? true;\n            \n            if (addToHistory) sp.Build<ILogStore>().Add(\"http-request\", log);\n        }\n        catch { /* ignore */ }\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Routing/AppApiControllerSelectorService.cs",
    "content": "﻿using System.Net;\nusing System.Reflection;\nusing System.Web.Compilation;\nusing System.Web.Hosting;\nusing System.Web.Http.Controllers;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.Routing;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Dnn.Compile;\nusing ToSic.Sxc.Dnn.Compile.Sys;\nusing ToSic.Sxc.Dnn.Context;\nusing ToSic.Sxc.Dnn.Integration;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n/// <summary>\n/// Special service to handle the selection of the correct API controller.\n///\n/// It's in a separate class, so DI etc. works properly\n/// </summary>\ninternal partial class AppApiControllerSelectorService(\n    DnnAppFolderUtilities folderUtilities,\n    ISite site,\n    LazySvc<IRoslynBuildManager> roslynLazy,\n    LazySvc<DnnGetBlock> getBlockLazy,\n    LazySvc<SourceAnalyzer> analyzerLazy,\n    LazySvc<CodeErrorHelpService> codeErrorSvc,\n    LazySvc<AssemblyCacheManager> assemblyCacheManager,\n    LazySvc<AppCodeLoader> appCodeLoader,\n    LazySvc<ISxcCurrentContextService> sxcContextResolver,\n    MemoryCacheService memoryCacheService,\n    LazySvc<IAppJsonConfigurationService> appJson)\n    : ServiceBase(\"Dnn.ApiSSv\", connect: [folderUtilities, site, roslynLazy, getBlockLazy, analyzerLazy, codeErrorSvc, assemblyCacheManager, appCodeLoader, sxcContextResolver, memoryCacheService, appJson])\n{\n    #region Setup / Init\n\n    private void Setup(HttpConfiguration configuration, HttpRequestMessage request)\n    {\n        _configuration = configuration;\n        _request = request;\n    }\n\n    private HttpRequestMessage Request => _request ?? throw new(\"Request not available - call Setup(...) first!\");\n    private HttpRequestMessage _request;\n\n    private HttpConfiguration Configuration => _configuration ?? throw new(\"Configuration not available - call Setup(...) first!\");\n    private HttpConfiguration _configuration;\n\n    #endregion\n\n\n    public HttpControllerDescriptor SelectController(HttpConfiguration configuration, HttpRequestMessage request)\n    {\n        Setup(configuration, request);\n\n        var l = Log.Fn<HttpControllerDescriptor>();\n\n        var routeData = request.GetRouteData();\n\n        var controllerTypeName = routeData.Values[VarNames.Controller] + EavConstants.ApiControllerSuffix;\n        l.A($\"Controller: {controllerTypeName}\");\n\n        // Now Handle the 2sxc app-api queries\n\n        try\n        {\n            // new for 2sxc 9.34 #1651\n            var edition = VarNames.GetEdition(routeData.Values);\n            l.A($\"Edition: {edition}\");\n\n\n            // Try to get block - will only work, if the request has all headers\n            var block = getBlockLazy.Value.GetCmsBlock(request);\n            l.A($\"has block: {block != null}\");\n\n            // Figure out the Path, or show error for that\n            var appFolder = folderUtilities.Setup(request).GetAppFolder(true, block);\n            l.A($\"AppFolder: {appFolder}\");\n\n            // Specs for HotBuild - may not be available, but should be retrieved from the block or App-Path\n            HotBuildSpec spec;\n            if (block != null)\n            {\n                // TODO: HAD TO trim last slash, because it was added in the get-call, but causes trouble here\n                // must ensure it's improved and done the same way in Oqtane!!!\n                spec = new(block.AppId, edition: edition.TrimLastSlash(), block.AppOrNull?.Name);\n                l.A($\"{nameof(spec)} from Block: {spec}\");\n            }\n            else\n            {\n                // find AppId based on path - otherwise we don't have a proper spec, and things fail\n                var appSpecs = sxcContextResolver.Value.SetAppOrNull(appFolder)?.AppReaderRequired.Specs ?? throw new(\"App not found\");\n                spec = new(appSpecs.AppId, edition: edition.TrimLastSlash(), appSpecs.Name);\n                l.A($\"{nameof(spec)} from App based on path: {spec}\");\n            }\n\n            // First check local app (in this site), then global\n            var descriptor = Get(appFolder, edition, controllerTypeName, false, spec);\n            if (descriptor != null)\n                return l.ReturnAsOk(descriptor);\n\n            l.A(\"path not found, will check on shared location\");\n            descriptor = Get(appFolder, edition, controllerTypeName, true, spec);\n            if (descriptor != null)\n                return l.ReturnAsOk(descriptor);\n        }\n        catch (Exception e)\n        {\n            throw l.Done(DnnHttpErrors.LogAndReturnException(request, HttpStatusCode.InternalServerError, e, DnnHttpErrors.ApiErrMessage, codeErrorSvc.Value));\n        }\n\n        // If we got to here we didn't find it.\n        // But we want to throw the exception here, otherwise it's re-wrapped.\n        l.A(\"Path / Controller not found in shared, error will be thrown in a moment\");\n        var msgFinal = $\"2sxc Api Controller Finder: Controller {controllerTypeName} not found in app and paths.\";\n        throw l.Done(DnnHttpErrors.LogAndReturnException(request, HttpStatusCode.NotFound, new(), msgFinal, codeErrorSvc.Value));\n    }\n\n    private (HttpControllerDescriptorWithPaths descriptor, IEnumerable<string> cacheKeys, IList<string> filePaths) BuildDescriptorIfExists(string appFolder, string edition, string controllerTypeName, bool shared, HotBuildSpec spec)\n    {\n        var l = Log.Fn<(HttpControllerDescriptorWithPaths descriptor, IEnumerable<string> cacheKeys, IList<string> filePaths)>(\n            $\"{nameof(appFolder)}:'{appFolder}'; {nameof(edition)}:'{edition}'; {nameof(controllerTypeName)}:'{controllerTypeName}'; {nameof(shared)}:{shared}; {spec}\",\n            timer: true\n        );\n        // 0. Prepare folders which will be used\n        var controllerFolder = GetControllerFolder(appFolder, edition, shared);\n\n        // 1. Check AppCode Dll\n        if (spec != null)\n        {\n            var appCodeAssemblyResult = appCodeLoader.Value.GetAppCode(spec).AssemblyResult;\n\n            // If assembly found, check if this controller exists in that dll - if yes, return it\n            var type = appCodeAssemblyResult?.Assembly?.FindControllerTypeByName(controllerTypeName);\n            if (type != null)\n            {\n                // cache dependency on existing cache item with AppCode assembly \n                var appCodeDescriptor = new HttpControllerDescriptor(Configuration, type.Name, type);\n                var fakeFolder = controllerFolder.Replace(\"/api/\", \"/AppCode/\");\n                return l.Return((descriptor: new(appCodeDescriptor, fakeFolder, fakeFolder + \"AppCode-auto-compiled.dll\"),\n                                cacheKeys: [appCodeAssemblyResult.CacheDependencyId],\n                                filePaths: null), \n                        \"Api controller from AppCode\");\n            }\n        }\n\n        // 2. Normal Api, compiled on the fly\n        var controllerPath = GetControllerPath(appFolder, edition, shared, controllerTypeName);\n        l.A($\"Controller Folder: '{controllerFolder}' Path: '{controllerPath}'\");\n\n        // note: this may look like something you could optimize/cache the result, but that's a bad idea\n        // because when the file changes, the type-object will be different, so please don't optimize :)\n        var (descriptor, cacheDependencyKeys) = BuildDescriptorOrThrow(controllerPath, controllerTypeName, spec);\n        var hasCacheKeys = cacheDependencyKeys?.Count > 0;\n        return l.Return((descriptor: new(descriptor, controllerFolder, controllerPath), \n                        cacheKeys: hasCacheKeys ? cacheDependencyKeys : null, // cache dependency on existing cache item;\n                        filePaths: hasCacheKeys ? null: [HostingEnvironment.MapPath(controllerPath)]), // cache dependency on existing api file\n            $\"normal Api controller from '{controllerPath}'\"); \n    }\n\n    private string GetControllerFolder(string appFolder, string edition, bool shared)\n        => Path.Combine(shared ? site.SharedAppsRootRelative() : site.AppsRootPhysical, appFolder, edition + \"api/\").ForwardSlash();\n\n    private string GetControllerPath(string appFolder, string edition, bool shared, string controllerTypeName)\n        => Path.Combine(GetControllerFolder(appFolder, edition, shared), $\"{controllerTypeName}.cs\");\n\n    private (HttpControllerDescriptor HttpControllerDescriptor, List<string> CacheDependecyKeys) BuildDescriptorOrThrow(string fullPath, string typeName, HotBuildSpec spec)\n    {\n        var l = Log.Fn<(HttpControllerDescriptor, List<string>)>($\"{nameof(fullPath)}:'{fullPath}'; {nameof(typeName)}:'{typeName}'; {spec}\", timer: true);\n        Assembly assembly;\n        List<string> cacheDependencyKeys = null;\n        var codeFileInfo = analyzerLazy.Value.TypeOfVirtualPath(fullPath);\n        var alwaysUseRoslyn = appJson.Value.DnnCompilerAlwaysUseRoslyn(spec.AppId);\n        if (alwaysUseRoslyn || codeFileInfo.AppCode)\n        {\n            l.A(\"AppCode - use Roslyn\");\n            var result = roslynLazy.Value.GetCompiledAssembly(codeFileInfo, typeName, spec);\n            assembly = result?.Assembly;\n\n            // build list of cache dependencies keys\n            if (!string.IsNullOrEmpty(result?.CacheDependencyId))\n            {\n                cacheDependencyKeys = [result.CacheDependencyId];\n                if (alwaysUseRoslyn) \n                    cacheDependencyKeys.Add(appJson.Value.AppJsonCacheKey(spec.AppId));\n            }\n            l.A($\"cache dependency keys: {cacheDependencyKeys?.Count ?? 0}\");\n        }\n        else\n        {\n            l.A(\"no AppCode - use BuildManager\");\n            assembly = BuildManager.GetCompiledAssembly(fullPath);\n        }\n\n        if (assembly == null)\n            throw l.Ex(new Exception(\"Assembly not found or compiled to null (error).\"));\n\n        l.A($\"FindControllerTypeByName: '{typeName}'\");\n        var type = assembly.FindControllerTypeByName(typeName)\n            ?? throw l.Ex(new Exception($\"Type '{typeName}' not found in assembly. Could be a compile error or name mismatch.\"));\n\n        l.A($\"Type found: '{type.Name}'\");\n        return l.Return((new (Configuration, type.Name, type), cacheDependencyKeys));\n    }\n\n    ///// <summary>\n    ///// help with path resolution for compilers running inside the created controller\n    ///// </summary>\n    //private void SetPathForCompilersInsideController(string appFolder, string edition, string controllerTypeName, bool shared)\n    //{\n    //    var controllerPath = GetControllerPath(appFolder, edition, shared, controllerTypeName);\n    //    if (!File.Exists(HostingEnvironment.MapPath(controllerPath))) return;\n    //    var controllerFolder = GetControllerFolder(appFolder, edition, shared);\n    //    PreservePathForGetCodeInController(controllerFolder, controllerPath);\n    //}\n\n    private void PreservePathForGetCodeInController(string controllerFolder, string controllerPath)\n    {\n        if (Request == null) return;\n        Request.Properties.Add(SourceCodeConstants.SharedCodeRootPathKeyInCache, controllerFolder);\n        Request.Properties.Add(SourceCodeConstants.SharedCodeRootFullPathKeyInCache, controllerPath);\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Routing/AppApiControllerSelectorService_Cache.cs",
    "content": "﻿using System.Web.Http.Controllers;\nusing ToSic.Sxc.Code.Sys.HotBuild;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\ninternal partial class AppApiControllerSelectorService\n{\n    private static string CacheKey(string appFolder, string controllerTypeName, bool shared, HotBuildSpec spec)\n        => $\"AppApiCtrl:Descriptor:{appFolder}:{controllerTypeName}:{shared}:{spec.CacheKey()}\";\n\n    private HttpControllerDescriptor Get(string appFolder, string editionPath, string controllerTypeName,\n        bool shared, HotBuildSpec spec)\n    {\n\n        var descriptorCacheKey = CacheKey(appFolder, controllerTypeName, shared, spec);\n        if (memoryCacheService.TryGet<HttpControllerDescriptorWithPaths>(descriptorCacheKey, out var dataWithPaths))\n        {\n            PreservePathForGetCodeInController(dataWithPaths.Folder, dataWithPaths.FullPath);\n            return dataWithPaths.Descriptor;\n        }\n\n        Log.A($\"Descriptor not found in cache, will try to build it ({nameof(descriptorCacheKey)}:'{descriptorCacheKey}')\");\n\n        var (data, cacheKeys, filePaths) = BuildDescriptorIfExists(appFolder, editionPath, controllerTypeName, shared, spec);\n\n        memoryCacheService.Set(key: descriptorCacheKey, value: data, func: p => p\n            .SetSlidingExpiration(new TimeSpan(1, 0, 0))\n            .WatchCacheKeys(cacheKeys)\n            .WatchFiles(filePaths)\n        );\n\n        PreservePathForGetCodeInController(data.Folder, data.FullPath);\n\n        return data.Descriptor;\n    }\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Routing/HttpControllerDescriptorWithPaths.cs",
    "content": "﻿using System.Web.Http.Controllers;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\ninternal class HttpControllerDescriptorWithPaths(HttpControllerDescriptor descriptor, string folder, string fullPath)\n{\n    public HttpControllerDescriptor Descriptor { get; } = descriptor;\n\n    /// <summary>\n    /// The folder in which the controller is located.\n    /// For controllers inside AppCode, the folder is the AppCode folder.\n    /// </summary>\n    public string Folder { get; } = folder;\n\n    /// <summary>\n    /// The exact path to the controller file.\n    /// Note that I'm not sure what it's actually used for.\n    /// </summary>\n    public string FullPath { get; } = fullPath;\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Routing/RouteMapper.cs",
    "content": "﻿using System.Web.Http.Dispatcher;\nusing ToSic.Eav.WebApi.Sys.Routing;\nusing ToSic.Sxc.Dnn.Backend;\nusing ToSic.Sxc.Dnn.Backend.Admin;\nusing ToSic.Sxc.Dnn.Backend.App;\nusing ToSic.Sxc.Dnn.Backend.Cms;\nusing ToSic.Sxc.Dnn.Backend.Module;\nusing ToSic.Sxc.Dnn.Backend.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.Providers;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\n// ReSharper disable once UnusedMember.Global\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class RouteMapper : IServiceRouteMapper\n{\n    // DNN Module Name used in the route\n    const string Mod2Sxc = \"2sxc\";\n\n    // Route Concept\n    // starting with eav means it's a rather low-level admin function, always needs an AppId\n    // eav\n    // eav-???\n    // starting with app means that it's a app-specific action, more for the JS developers working with content\n    // app-content  will do basic content-actions like get one, edit, update, delete\n    // app-query    will try to request a query\n    // app-api      will call custom c# web-apis of a specific app\n\n    private static readonly string[] StdNsWebApi = [typeof(AppDataController).Namespace];\n    private static readonly string[] AdamNamespaces = [typeof(AdamController).Namespace];\n    private IMapRoute _mapRouteManager;\n\n    private static readonly object AppContentDefaults = new\n    {\n        controller = ControllerNames.AppContent,\n        id = RouteParameter.Optional\n    };\n\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public void RegisterRoutes(IMapRoute mapRouteManager)\n    {\n        _mapRouteManager = mapRouteManager;\n\n        // #DropOldPre8Routes\n        //// old API routes before 08.10\n        //RegisterOldRoutesBefore0810();\n\n\n        #region new API routes after 08.10\n\n        // ADAM routes\n        AddWithDefaults(\"adam-auto\", $\"{AppRoots.AppAutoContent}/{ValueTokens.SetTypeGuidField}\", ControllerNames.Adam, AdamNamespaces);\n        AddWithDefaults(\"adam2-auto\", $\"{AppRoots.AppAutoContent}/{ValueTokens.SetTypeGuidFieldAction}\", ControllerNames.Adam, AdamNamespaces);\n        AddWithDefaults(\"adam3-auto\", $\"{AppRoots.AppAutoData}/{ValueTokens.SetTypeGuidField}\", ControllerNames.Adam, AdamNamespaces); // new, v13\n        AddWithDefaults(\"adam4-auto\", $\"{AppRoots.AppAutoData}/{ValueTokens.SetTypeGuidFieldAction}\", ControllerNames.Adam, AdamNamespaces); // new, v13\n\n        // App Content routes - for GET/DELETE/PUT entities using REST\n        // 1. Type and null or int-id\n        // 2. Type and guid-id\n        var idNullOrNumConstraints = ConstraintForIdEmptyOrNumber();\n        foreach (var part in Roots.Content)\n        {\n            AddWithConstraints($\"2sxc-{part.Name}\",      $\"{part.Path}/{ValueTokens.SetTypeAndId}\", AppContentDefaults, idNullOrNumConstraints, StdNsWebApi);\n            AddWithDefaults($\"2sxc-guid-{part.Name}\", $\"{part.Path}/{ValueTokens.SetTypeAndGuid}\",  ControllerNames.AppContent, StdNsWebApi);\n        }\n\n        // App-API routes - for the custom code API calls of an app\n        foreach (var part in Roots.AppAutoNamedInclEditions)\n            AddBasic($\"app-api{part.Name}\", $\"{part.Path}/{RouteParts.RouteApiControllerAction}\", StdNsWebApi); // new, v08.10+\n\n\n        // App-Query routes - to access designed queries\n        // new routes, v08.10+\n        foreach (var part in Roots.QueryRoots)\n        {\n            AddWithDefaults($\"2sxc-auto-{part.Name}\",        $\"{part.Path}/{ValueTokens.Name}\", ControllerNames.AppQuery, StdNsWebApi);\n            AddWithDefaults($\"2sxc-auto-slash{part.Name}\",   $\"{part.Path}/{ValueTokens.Name}/\", ControllerNames.AppQuery, StdNsWebApi);\n            AddWithDefaults($\"2sxc-auto-stream{part.Name}\",  $\"{part.Path}/{ValueTokens.Name}/{ValueTokens.Stream}\", ControllerNames.AppQuery, StdNsWebApi);\n        }\n        #endregion\n\n\n        #region New routes in 2sxc 11.06+ which should replace most previous internal routes\n\n        // /Sys/ Part 1: Special update v13 - all the insights-commands go through \"Details?view=xyz\n        // It's important that this comes first, otherwise the second /sys/ will capture this as well\n        _mapRouteManager.MapHttpRoute(Mod2Sxc, \"2sxc-sys-new\", $\"{Areas.Sys}/Insights/{{View}}\",\n            new\n            {\n                controller = \"Insights\",\n                action = nameof(InsightsController.Details)\n            }, [typeof(InsightsController).Namespace]);\n\n        // /Sys/ Part 2: All others\n        AddBasic(\"2sxc-sys\", $\"{Areas.Sys}/{ValueTokens.SetControllerAction}\", [typeof(InstallController).Namespace]);\n        AddBasic(\"2sxc-cms\", $\"{Areas.Cms}/{ValueTokens.SetControllerAction}\", [typeof(BlockController).Namespace]);\n        AddBasic(\"2sic-admin\", $\"{Areas.Admin}/{ValueTokens.SetControllerAction}\", [typeof(MetadataController).Namespace]);\n        // Specific admin route to support folder segment for AppController.Extensions\n        AddBasic($\"2sxc-admin-app-extensions-{ValueTokens.Name}\", url: $\"{Areas.Admin}/{ValueTokens.SetControllerAction}/{ValueTokens.Name}\", namespaces: [typeof(AppController).Namespace]);\n\n        #endregion\n\n        // v21 - app cache/Lightspeed\n        AddBasic(\"2sxc-app-cache-auto\", $\"{AppRoots.AppAuto}/{ValueTokens.SetControllerAction}\", [typeof(CacheController).Namespace]);\n        AddBasic(\"2sxc-app-cache-name\", $\"{AppRoots.AppNamed}/{ValueTokens.SetControllerAction}\", [typeof(CacheController).Namespace]);\n\n        // DNN: System calls to dnn - this is just for module delete\n        AddBasic(\"dnn\", $\"dnn/{ValueTokens.SetControllerAction}\", [typeof(ModuleController).Namespace]);\n\n\n        // Add custom service locator into the chain of service-locators\n        // this is needed to enable custom API controller lookup for the app-api\n        var config = GlobalConfiguration.Configuration;\n        var previousSelector = config.Services.GetService(typeof(IHttpControllerSelector)) as IHttpControllerSelector;\n        config.Services.Replace(typeof(IHttpControllerSelector), new AppApiControllerSelector(config) { PreviousSelector = previousSelector });\n\n        // Attempt to add another Module Resolver to the list which will work with the header PageId instead of TabId\n        GlobalConfiguration.Configuration.AddTabAndModuleInfoProvider(new ModifiedTabAndModuleInfoProvider());\n    }\n\n    // #DropOldPre8Routes\n    //private void RegisterOldRoutesBefore0810()\n    //{\n    //    // ADAM routes\n    //    var oldContentRoot = \"app-content\";\n    //    AddWD(\"adam-old-81\", $\"{oldContentRoot}/{ValueTokens.SetTypeGuidField}\", ControllerNames.Adam, AdamNamespace);\n    //    AddWD(\"adam\", $\"{oldContentRoot}/{ValueTokens.SetTypeGuidFieldAction}\", ControllerNames.Adam, AdamNamespace);\n\n    //    // App Content routes - for GET/DELETE/PUT entities using REST\n    //    // 1. Type and null or int-id\n    //    // 2. Type and guid-id\n    //    var idNullOrNumber = ConstraintForIdEmptyOrNumber();\n    //    AddWC(\"app-content\", $\"{oldContentRoot}/{ValueTokens.SetTypeAndId}\", AppContentDefs, idNullOrNumber, StdNsWebApi);\n    //    AddWD(\"app-content-guid\", $\"{oldContentRoot}/{ValueTokens.SetTypeAndGuid}\", ControllerNames.AppContent, StdNsWebApi);\n\n    //    // App-API routes - for the custom code API calls of an app\n    //    // these are the old routes, before 2sxc v08.10\n    //    AddWD(Mod2Sxc, \"app-api-old-81\", $\"app-api/{ValueTokens.SetControllerAction}\", StdNsWebApi);\n\n    //    // App-Query routes - to access designed queries\n    //    // these are the old routes, before 2sxc v08.10\n    //    const string rootQueryPre0810 = \"app-query\";\n    //    AddWD(\"app-query-old-81\", $\"{rootQueryPre0810}/{ValueTokens.Name}\", ControllerNames.AppQuery, StdNsWebApi);\n    //}\n\n    /// <summary>\n    /// Generate a constraint which only matches an ID parameter which is either empty or contains only digits.\n    /// </summary>\n    /// <returns></returns>\n    private static object ConstraintForIdEmptyOrNumber() => new { id = @\"^\\d*$\" };\n\n    #region \"Add\" shorthands\n\n    /// <summary>\n    /// Add just with namespaces\n    /// </summary>\n    void AddBasic(string name, string url, string[] namespaces)\n        => _mapRouteManager.MapHttpRoute(Mod2Sxc, name, url, namespaces);\n\n    /// <summary>\n    /// Add WD - \"With Defaults\"\n    /// </summary>\n    void AddWithDefaults(string name, string url, string controllerName, string[] namespaces)\n    {\n        var objDefaults = new { controller = controllerName };\n        _mapRouteManager.MapHttpRoute(Mod2Sxc, name, url, objDefaults, namespaces);\n    }\n\n    /// <summary>\n    /// Add WC - \"With Constraints\"\n    /// </summary>\n    void AddWithConstraints(string name, string url, object defaults, object constraints, string[] namespaces)\n        => _mapRouteManager.MapHttpRoute(Mod2Sxc, name, url, defaults, constraints, namespaces);\n\n    #endregion\n\n}\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Dnn/WebApi/Sys/Routing/RouteParts.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Routing;\n\nnamespace ToSic.Sxc.Dnn.WebApi.Sys;\n\ninternal class Roots\n{\n    public static RootId[] QueryRoots =\n    [\n        new(\"qry-auto\", $\"{AppRoots.AppAuto}/{AppParts.Query}\"), \n        new(\"qry-name\", $\"{AppRoots.AppNamed}/{AppParts.Query}\")\n    ];\n    public static RootId[] AppAutoAndNamed =\n    [\n        new(\"app-auto\", AppRoots.AppAuto), \n        new(\"app-name\",  AppRoots.AppNamed)\n    ];\n    public static RootId[] Content =\n    [\n        new(\"cont-auto\", AppRoots.AppAutoContent), \n        new(\"cont-name\", AppRoots.AppNamedContent),\n        new(\"data-auto\", AppRoots.AppAutoData), // new, v13\n        new(\"data-name\", AppRoots.AppNamedData) // new, v13\n    ];\n\n    public static RootId[] AppAutoNamedInclEditions = AppAutoAndNamed\n        .Concat(AppAutoAndNamed.Select(rid => new RootId($\"{rid.Name}-edition\", $\"{rid.Path}/{ValueTokens.Edition}\")))\n        .ToArray();\n}\n\ninternal struct RootId(string name, string path)\n{\n    public string Name = name;\n    public string Path = path;\n}\n\n\ninternal class RouteParts\n{\n    public const string RouteApiControllerAction = $\"api/{ValueTokens.SetControllerAction}\";\n}\n\ninternal class ControllerNames\n{\n    public const string Adam = \"Adam\";\n    public const string AppContent = \"AppData\";\n    public const string AppQuery = \"AppQuery\";\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Net.Http;\nglobal using System.Web.Http;\nglobal using DotNetNuke.Security;\nglobal using DotNetNuke.Web.Api;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Wrappers;\nglobal using ToSic.Sxc.WebApi;\nglobal using ToSic.Sys.Utils;\nglobal using static ToSic.Sxc.Dnn.DnnConstants;"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Obsolete/SexyContent/WebApi/SxcApiController.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeApiService;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Compatibility.Sxc;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Dnn.Run;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Dnn.Code;\nusing ToSic.Sxc.Dnn.WebApi.Sys;\nusing ToSic.Sxc.Dnn.WebApi.Sys.HttpJson;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing IApp = ToSic.Sxc.Apps.IApp;\nusing IFolder = ToSic.Sxc.Adam.IFolder;\n\n// ReSharper disable InheritdocInvalidUsage\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.SexyContent.WebApi;\n\n/// <inheritdoc cref=\"DnnSxcCustomControllerBase\" />\n/// <summary>\n/// This is the base class for API Controllers which need the full context\n/// incl. the current App, DNN, Data, etc.\n/// For others, please use the SxiApiControllerBase, which doesn't have all that, and is usually then\n/// safer because it can't accidentally mix the App with a different appId in the params\n/// </summary>\n[DnnLogExceptions]\n[Obsolete(\"This will continue to work, but you should use the Custom.Hybrid.Api14 or Custom.Dnn.Api12 instead.\")]\n[PrivateApi(\"This was the official base class a long time ago, Name & APIs must remain stable\")]\n[DefaultToNewtonsoftForHttpJson]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract partial class SxcApiController() :\n    DnnSxcCustomControllerBase(\"OldApi\"),\n    IDynamicCode,\n    IHasDnn,\n    ICreateInstance,\n    IDynamicWebApi,\n    // #RemovedV20 #IAppAndDataHelpers\n    //IDynamicCodeBeforeV10\n    //#pragma warning disable 618\n    //    IAppAndDataHelpers,\n    //#pragma warning restore 618\n    IHasCodeLog\n{\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => SysHlp.GetService<TService>();\n\n    /// <inheritdoc cref=\"IHasDnn.Dnn\"/>\n    public IDnnContext Dnn => (ExCtx as IHasDnn)?.Dnn;\n\n    [Obsolete]\n    [PrivateApi]\n    public SxcHelper Sxc => field\n        ??= new(CodeApi?.Block?.Context?.Permissions.IsContentAdmin ?? false, SysHlp.GetService<IConvertToEavLight> ());\n\n    /// <summary>\n    /// Old API - probably never used, but we shouldn't remove it as we could break some existing code out there\n    /// </summary>\n    [PrivateApi]\n    public IBlock Block => SysHlp.GetBlockAndContext(Request);\n\n    [PrivateApi] public int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel9Old;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => /*(IBlockDataSource)*/CodeApi.Data;\n\n    // Explicit implementation of expected interface, but it should not work in the normal code\n    // as the old code sometimes expects Data.Cache.GetContentType\n    /// <inheritdoc />\n    IDataSource IDynamicCode.Data => CodeApi.Data;\n\n\n    #region AsDynamic implementations\n\n    /// <inheritdoc />\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc />\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc />\n    [PublicApi(\"Careful - still Experimental in 12.02\")]\n    public dynamic AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc />\n    [PrivateApi(\"old api, only available in old API controller\")]\n    public dynamic AsDynamic(KeyValuePair<int, IEntity> entityKeyValuePair) => CodeApi.Cdf.CodeAsDyn(entityKeyValuePair.Value);\n\n    /// <inheritdoc />\n    public IEnumerable<dynamic> AsDynamic(IDataStream stream) => CodeApi.Cdf.CodeAsDynList(stream.List);\n\n    /// <inheritdoc />\n    public IEntity AsEntity(object dynamicEntity) =>  CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    /// <inheritdoc />\n    public IEnumerable<dynamic> AsDynamic(IEnumerable<IEntity> entities) =>  CodeApi.Cdf.CodeAsDynList(entities);\n    #endregion\n\n    #region Compatibility with Eav.Interfaces.IEntity - introduced in 10.10 - Removed in v20\n\n    //[PrivateApi]\n    //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(Eav.Interfaces.IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity as IEntity);\n\n\n    //[PrivateApi]\n    //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public dynamic AsDynamic(KeyValuePair<int, Eav.Interfaces.IEntity> entityKeyValuePair) => CodeApi.Cdf.CodeAsDyn(entityKeyValuePair.Value as IEntity);\n\n    //[PrivateApi]\n    //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n    //public IEnumerable<dynamic> AsDynamic(IEnumerable<Eav.Interfaces.IEntity> entities) => CodeApi.Cdf.CodeAsDynList(entities.Cast<IEntity>());\n    #endregion\n\n\n    #region CreateSource implementations\n    [Obsolete]\n    [PrivateApi]\n    public IDataSource CreateSource(string typeName = \"\", IDataSource inSource = null, ILookUpEngine configurationProvider = null)\n        => new CodeApiServiceObsolete(ExCtx).CreateSource(typeName, inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource \n        => CodeApi.CreateSource<T>(source);\n\n    #endregion\n\n    #region Content, Presentation & List\n    /// <summary>\n    /// content item of the current view\n    /// </summary>\n    public dynamic Content => CodeApi.Content;\n\n    /// <summary>\n    /// presentation item of the content-item. \n    /// </summary>\n    [Obsolete(\"please use Content.Presentation instead\")]\n    public dynamic Presentation => CodeApi.Content?.Presentation;\n\n    public dynamic Header => CodeApi.Header;\n\n    [Obsolete(\"use Header instead\")]\n    public dynamic ListContent => CodeApi.Header;\n\n    /// <summary>\n    /// presentation item of the content-item. \n    /// </summary>\n    [Obsolete(\"please use Header.Presentation instead\")]\n    public dynamic ListPresentation => CodeApi.Header?.Presentation;\n\n    // #RemovedV20 #Element\n    //[Obsolete(\"This is an old way used to loop things. Use Data[\\\"Default\\\"] instead. Will be removed in 2sxc v10\")]\n    //public List<Element> List => new CodeApiServiceObsolete(ExCtx).ElementList;\n\n    #endregion\n\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    /// <inheritdoc cref=\"IDynamicWebApi.SaveInAdam\"/>\n    public IFile SaveInAdam(NoParamOrder npo = default, Stream stream = null, string fileName = null, string contentType = null,\n        Guid? guid = null, string field = null, string subFolder = \"\")\n        => DynHlp.SaveInAdam(stream: stream, fileName: fileName, contentType: contentType, guid: guid, field: field, subFolder: subFolder);\n\n    #endregion\n\n    #region CreateInstance\n\n    string IGetCodePath.CreateInstancePath { get; set; }\n\n    private CompileCodeHelper CompileCodeHlp => field ??= GetService<CompileCodeHelper>().Init(this);\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\"/>\n    public dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => CompileCodeHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    #endregion\n\n    #region Link & Edit - added in 2sxc 10.01\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi?.Link!;\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi?.Edit!;\n\n    #endregion\n\n    #region CmsContext, Resources and Settings\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    ///// <inheritdoc />\n    //public dynamic Resources => _DynCodeRoot.Resources;\n\n    ///// <inheritdoc />\n    //public dynamic Settings => _DynCodeRoot.Settings;\n\n    #endregion\n\n    #region IHasLog\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => SysHlp.CodeLog;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/Obsolete/SexyContent/WebApi/SxcApiController_NotImplemented.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Wrappers;\nusing ApiController = ToSic.Sxc.Dnn.ApiController;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.SexyContent.WebApi;\n\npartial class SxcApiController\n{\n\n    #region new AsDynamic - not supported\n\n    [PrivateApi]\n    public dynamic AsDynamic(string json, string fallback = WrapperConstants.EmptyJson)\n        => throw new($\"The AsDynamic(string) is a new feature in 2sxc 10.20. {ApiController.ErrRecommendedNamespaces}\");\n\n\n    #endregion\n\n    #region AsList - only in newer APIs\n\n    [PrivateApi]\n    public IEnumerable<dynamic> AsList(object list)\n        => throw new($\"AsList is a new feature in 2sxc 10.20. {ApiController.ErrRecommendedNamespaces}\");\n\n    #endregion\n\n    [PrivateApi]\n    public dynamic File(NoParamOrder npo = default, bool? download = null,\n        string virtualPath = null, string contentType = null, string fileDownloadName = null, object contents = null) =>\n        throw new NotSupportedException($\"This method is not available in the old {nameof(SxcApiController)}. {ApiController.ErrRecommendedNamespaces}\");\n\n\n}"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/ToSic.Sxc.Dnn.WebApi.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-NetFramework.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>ToSic.Sxc</RootNamespace>\n    <AssemblyName>ToSic.Sxc.Dnn.WebApi</AssemblyName>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <!-- ignore warning that Dnn was loaded 2x - ATM necessary for MS build? @STV -->\n    <NoWarn>$(NoWarn);MSB4011</NoWarn>\n    <!-- ignore warning that it's using a dangerous version of Dnn (v9.6.1) @2dm -->\n    <NoWarn>$(NoWarn);NU1902</NoWarn>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);MSB3277</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"DotNetNuke.Core\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.Web\" Version=\"9.11.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"DotNetNuke.Web.Mvc\" Version=\"9.11.0\" />\n    <PackageReference Include=\"Microsoft.AspNet.WebApi.WebHost\" Version=\"5.2.9\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.AspNet.WebPages\" Version=\"3.2.9\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"9.0.0\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"System.Threading.Tasks.Extensions\" Version=\"4.5.4\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Runtime.Caching\" />\n    <Reference Include=\"System.Web\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"ToSic.Razor\">\n      <HintPath>..\\..\\..\\Dependencies\\RazorBlade\\Release\\net472\\ToSic.Razor.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.DataSources\\ToSic.Eav.DataSources.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Utils\\ToSic.Sys.Utils.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Dnn.Core\\ToSic.Sxc.Dnn.Core.csproj\" />\n\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Custom\\readme.md\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Src/Dnn/ToSic.Sxc.Dnn.WebApi/ToSic.Sxc.Dnn.WebApi.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=autodetectcontext/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cbackend_005Cadam/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cwebapi_005Cadam/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cwebapi_005Cinternal_005Ccontrollerbase/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cwebapi_005Cinternal_005Clogging/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cwebapi_005Cinternal_005Crouting/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cwebapi_005Crouting/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cwebapi_005Csys_005Ccontrollerbase/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cwebapi_005Csys_005Clogging/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=dnn_005Cwebapi_005Csys_005Crouting/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sxc_005Cwebapi_005Ccms_005Ceditui/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sxc_005Cwebapi_005Chelpers/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sxc_005Cwebapi_005Crouting/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sxc_005Cwebapi_005Csystem_005Cinsights/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=webapi_005Ccms_005Ceditui/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=webapi_005Chelpers/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=webapi_005Crouting/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=webapi_005Csystem_005Cinsights/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Integration/BasicEav01/.gitignore",
    "content": "sys-2sxc"
  },
  {
    "path": "Src/Integration/BasicEav01/BasicEav01.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net9.0</TargetFramework>\n    <CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory>\n    <RootNamespace>IntegrationSamples.BasicEav01</RootNamespace>\n    <Configurations>Debug;Release;DebugOqtane;DebugDnn</Configurations>\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\" Version=\"9.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n  </ItemGroup>\n\n  <Target Name=\"PostBuild\" AfterTargets=\"PostBuildEvent\">\n    <Exec Command=\"@Echo Configuration='$(Configuration)'&#xD;&#xA;@Echo StartWith ='$(Configuration.StartsWith('Debug'))'&#xD;&#xA;@Echo Platform ='$(Platform)'&#xD;&#xA;@Echo ProjectDir '$(ProjectDir)'&#xD;&#xA;@SET BuildTarget=$(ProjectDir)sys-2sxc&#xD;&#xA;@Echo BuildTarget '%25BuildTarget%25'&#xD;&#xA;&#xD;&#xA;@REM Copy the data folders&#xD;&#xA;robocopy /mir &quot;$(ProjectDir)..\\..\\Data\\.data\\ &quot; &quot;%25BuildTarget%25\\.data\\ &quot;&#xD;&#xA;\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Context/IntUser.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace IntegrationSamples.BasicEav01.Context\n{\n    /// <summary>\n    /// #2sxcIntegration\n    /// Dummy user, which always says it's a superuser\n    /// </summary>\n    public class IntUser: IUser\n    {\n        public int Id => 0;\n        public string IdentityToken => \"impl-user:0\";\n        public Guid? Guid => System.Guid.Empty;\n        public List<int> Roles => new List<int>();\n        public bool IsSystemAdmin => true;\n        [Obsolete(\"deprecated in v14.09 2022-10, will be removed ca. v16 #remove16\")]\n        public bool IsSuperUser => true;\n        [Obsolete(\"deprecated in v14.09 2022-10, will be removed ca. v16 #remove16\")]\n        public bool IsAdmin => IsSiteAdmin;\n\n        public bool IsSiteAdmin => true;\n        public bool IsContentAdmin => true;\n        public bool IsDesigner => true;\n        public bool IsAnonymous => false;\n\n        public string Username => \"unknown\";\n\n        public string Name => Username;\n\n        public string Email => \"unknown@unknown.org\";\n\n    }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Controllers/InsightsController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\n\nnamespace IntegrationSamples.BasicEav01.Controllers\n{\n    [Route(\"api/sxc/\" + Areas.Sys + \"/[controller]\")]\n    [ApiController]\n    public class InsightsController : ControllerBase\n    {\n        /// <summary>\n        /// Constructor which will retrieve the Insights backend for use here\n        /// </summary>\n        public InsightsController(InsightsControllerReal insights) => _insights = insights;\n        private readonly InsightsControllerReal _insights;\n\n        /// <summary>\n        /// The main call on this controller, will return all kinds of views with information\n        /// </summary>\n        [HttpGet(\"{view}\")]\n        public ContentResult Details(\n            [FromRoute] string view,\n            [FromQuery] int? appId = null,\n            [FromQuery] string key = null,\n            [FromQuery] int? position = null,\n            [FromQuery] string type = null,\n            [FromQuery] bool? toggle = null,\n            [FromQuery] string nameId = null\n        ) => Content(_insights.Details(view, appId, key, position, type, toggle, nameId), \"text/html\");\n    }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/IntegrationConstants.cs",
    "content": "﻿\n\n// #2sxcIntegration\n\nnamespace IntegrationSamples.BasicEav01\n{\n    /// <summary>\n    /// This contains constant parameters for the integration demo to work.\n    /// You will probably adjust these to match your needs\n    /// </summary>\n    public class IntegrationConstants\n    {\n        /// <summary>\n        /// In the demo setup this is the blog app on the PC of 2dm\n        /// </summary>\n        public const int ZoneId = 2;\n        public const int AppId = 78;\n\n        public static IAppIdentity AppIdentity = new AppIdentity(ZoneId, AppId);\n    }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/Error.cshtml",
    "content": "﻿@page\n@model ErrorModel\n@{\n    ViewData[\"Title\"] = \"Error\";\n}\n\n<h1 class=\"text-danger\">Error.</h1>\n<h2 class=\"text-danger\">An error occurred while processing your request.</h2>\n\n@if (Model.ShowRequestId)\n{\n    <p>\n        <strong>Request ID:</strong> <code>@Model.RequestId</code>\n    </p>\n}\n\n<h3>Development Mode</h3>\n<p>\n    Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.\n</p>\n<p>\n    <strong>The Development environment shouldn't be enabled for deployed applications.</strong>\n    It can result in displaying sensitive information from exceptions to end users.\n    For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>\n    and restarting the app.\n</p>\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/Error.cshtml.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.Extensions.Logging;\n\nnamespace IntegrationSamples.BasicEav01.Pages\n{\n    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]\n    public class ErrorModel : PageModel\n    {\n        public string RequestId { get; set; }\n\n        public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);\n\n        private readonly ILogger<ErrorModel> _logger;\n\n        public ErrorModel(ILogger<ErrorModel> logger)\n        {\n            _logger = logger;\n        }\n\n        public void OnGet()\n        {\n            RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/Index.cshtml",
    "content": "﻿@page\n@using Microsoft.Extensions.Configuration\n@model IndexModel\n@inject IConfiguration Configuration;\n@{\n    ViewData[\"Title\"] = \"2sxc Integration - Read-Only Implementation\";\n}\n\n<div class=\"text-center\">\n  <h1 class=\"display-4\">2sxc Integration - Read-Only Implementation</h1>\n</div>\n<div>\n    <p>\n        This should be the most basic integration possible, where we only read 2sxc data, but do nothing else.\n    </p>\n  \n    <h2>Basics</h2>\n    <p>\n        The following projects / solutions were added. If doing this from an external system, make sure you have the right DLLs.\n    </p>\n    <ol>\n        <li>Eav with all EAV parts (Core, Repository, WebApi etc.)</li>\n    </ol>\n\n    <h2>DB Connection</h2>\n    <p>\n        In this demo the DB Connection String is in <code>appsettings.json</code> - it will be loaded by the Startup.cs \n    </p>\n    <ol>\n        <li>\n            ATM it's set to: <code>@Configuration.GetConnectionString(\"SiteSqlServer\")</code>\n        </li>\n    </ol>\n\n    <h2>App Identity</h2>\n    <p>\n        In this demo we are using a fixed app identity. It is <code>@IntegrationConstants.ZoneId / @IntegrationConstants.AppId</code>\n    </p>\n    \n    <h2>Functionality</h2>\n    <p>\n        This is a super-basic demo. ATM it has only these features\n    </p>\n    <ol>\n        <li>You can read the data from an App out of an existing DB</li>\n        <li>Insights works, so you can see logs of what happens internally and also see what objects were used in the <code>Unknown</code> implementation.</li>\n    </ol>\n</div>"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/Index.cshtml.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.Extensions.Logging;\n\nnamespace IntegrationSamples.BasicEav01.Pages\n{\n    public class IndexModel : PageModel\n    {\n        private readonly ILogger<IndexModel> _logger;\n\n        public IndexModel(ILogger<IndexModel> logger)\n        {\n            _logger = logger;\n        }\n\n        public void OnGet()\n        {\n\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/Shared/_Layout.cshtml",
    "content": "﻿<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>@ViewData[\"Title\"] - ReadOnlyWeb</title>\n    <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css\" integrity=\"sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2\" crossorigin=\"anonymous\">\n    <link rel=\"stylesheet\" href=\"~/css/site.css\" />\n</head>\n<body>\n  <header>\n    <nav class=\"navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3\">\n      <div class=\"container\">\n        <a class=\"navbar-brand\" asp-area=\"\" asp-page=\"/Index\">Integration #1 - ReadOnly</a>\n        <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\".navbar-collapse\" aria-controls=\"navbarSupportedContent\"\n                aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n          <span class=\"navbar-toggler-icon\"></span>\n        </button>\n        <div class=\"navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse\">\n          <ul class=\"navbar-nav flex-grow-1\">\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Index\">Home</a>\n            </li>\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/ShowEavData\">Show EAV Data</a>\n            </li>\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" href=\"/api/sxc/sys/Insights/Help\" target=\"_blank\">Show Insights</a>\n            </li>\n          </ul>\n        </div>\n      </div>\n    </nav>\n  </header>\n  <div class=\"container\">\n    <main role=\"main\" class=\"pb-3\">\n      @RenderBody()\n    </main>\n  </div>\n\n  <footer class=\"border-top footer text-muted\">\n    <div class=\"container\">\n      &copy; 2020 - ReadOnlyWeb - <a asp-area=\"\" asp-page=\"/Privacy\">Privacy</a>\n    </div>\n  </footer>\n\n  <script src=\"https://code.jquery.com/jquery-3.5.1.slim.min.js\" integrity=\"sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj\" crossorigin=\"anonymous\"></script>\n  <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js\" integrity=\"sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx\" crossorigin=\"anonymous\"></script>\n\n  @RenderSection(\"Scripts\", required: false)\n</body>\n</html>\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/Shared/_ValidationScriptsPartial.cshtml",
    "content": "﻿<script src=\"https://cdn.jsdelivr.net/npm/jquery-validation@1.19.2/dist/jquery.validate.min.js\" integrity=\"sha256-+BEKmIvQ6IsL8sHcvidtDrNOdZO3C9LtFPtF2H0dOHI=\" crossorigin=\"anonymous\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/jquery-validation-unobtrusive@3.2.11/dist/jquery.validate.unobtrusive.min.js\" integrity=\"sha256-9GycpJnliUjJDVDqP0UEu/bsm9U+3dnQUH8+3W10vkY=\" crossorigin=\"anonymous\"></script>"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/ShowEavData.cshtml",
    "content": "﻿@page\n@inject IAppStateCacheService AppStateCacheService\n@{\n    ViewData[\"Title\"] = \"First Read Data from EAV\";\n\n    // #2sxcIntegration\n    var appIdentity = IntegrationConstants.AppIdentity;\n    var appState = AppStateCacheService.Get(appIdentity);\n    var firstItem = appState.List.FirstOrDefault();\n}\n\n<h1>@ViewData[\"Title\"]</h1>\n\n<p>\n  Here you should see data from EAV\n</p>\n\n<div>\n  Reading data from EAV Zone/App: @appIdentity.ZoneId / @appIdentity.AppId\n</div>\n\n<ol>\n  <li>State Object: @appState</li>\n  <li>List Object: @appState.List</li>\n  <li>List Count: @appState.List.Count</li>\n  <li>First: @firstItem</li>\n  <li>Title of first item: @firstItem?.GetBestTitle()</li>\n  <li>FirstItem modified: @firstItem?.Modified</li>\n</ol>\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/_ViewImports.cshtml",
    "content": "@namespace IntegrationSamples.BasicEav01.Pages\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Pages/_ViewStart.cshtml",
    "content": "﻿@{\n    Layout = \"_Layout\";\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Program.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Hosting;\n\nnamespace IntegrationSamples.BasicEav01\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Properties/launchSettings.json",
    "content": "﻿{\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,\n    \"anonymousAuthentication\": true,\n    \"iisExpress\": {\n      \"applicationUrl\": \"http://localhost:65487\",\n      \"sslPort\": 44384\n    }\n  },\n  \"profiles\": {\n    \"IIS Express\": {\n      \"commandName\": \"IISExpress\",\n      \"launchBrowser\": true,\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES\": \"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\"\n      }\n    },\n    \"BasicEav01\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"https://localhost:5001;http://localhost:5000\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES\": \"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/Startup.cs",
    "content": "using System.IO;\nusing IntegrationSamples.BasicEav01.Context;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Hosting;\n\nnamespace IntegrationSamples.BasicEav01\n{\n    public class Startup\n    {\n        /// <summary>\n        /// This method gets called first by the runtime. Use it to get configuration values. \n        /// </summary>\n        public Startup(IConfiguration configuration)\n        {\n            _connStringFromConfig = configuration.GetConnectionString(\"SiteSqlServer\");\n        }\n        private readonly string _connStringFromConfig;\n\n\n        /// <summary>\n        /// This method gets called second by the runtime. Use this method to add services to the container.\n        /// </summary>\n        public void ConfigureServices(IServiceCollection services)\n        {\n            // #2sxcIntegration\n            // Register our Always-Super-User (to allow Insights to be used)\n            services.TryAddTransient<IUser, IntUser>();\n            // Enable all of EAV\n            services.AddEav();\n\n            // RazorPages - standard .net core MVC feature\n            services.AddRazorPages();\n        }\n\n\n        /// <summary>\n        /// This method gets called third by the runtime. Use this method to configure the HTTP request pipeline.\n        /// </summary>\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            // ----- Start EAV stuff #2sxcIntegration -----\n            var serviceProvider = app.ApplicationServices;\n            \n            // Set Connection String\n            serviceProvider.GetRequiredService<IDbConfiguration>().ConnectionString = _connStringFromConfig;\n\n            // Set global path where it will find the .data folder\n            var globalConfig = serviceProvider.GetRequiredService<IGlobalConfiguration>();\n            globalConfig.GlobalFolder = Path.Combine(env.ContentRootPath, \"sys-2sxc\");\n\n            // Trigger start where the data etc. will be loaded & initialized\n            serviceProvider.GetRequiredService<SystemLoader>().StartUp();\n            // ----- End EAV stuff #2sxcIntegration -----\n\n\n            // Standard Stuff\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n            else\n            {\n                app.UseExceptionHandler(\"/Error\");\n                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.\n                app.UseHsts();\n            }\n\n            app.UseHttpsRedirection();\n            app.UseStaticFiles();\n            app.UseRouting();\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapRazorPages();\n\n                // #2sxcIntegration - enable insights controllers\n                endpoints.MapControllers();\n            });\n\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n\n  \"//1\":  \"#2sxcIntegration: Added this to point to the right DB\",\n  \"ConnectionStrings\": {\n    \"SiteSqlServer\": \"Data Source=localhost;Initial Catalog=2sxc-dnn742;Integrated Security=True\"\n  }\n}\n"
  },
  {
    "path": "Src/Integration/BasicEav01/wwwroot/css/site.css",
    "content": "﻿/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\nfor details on configuring this project to bundle and minify static web assets. */\n\na.navbar-brand {\n  white-space: normal;\n  text-align: center;\n  word-break: break-all;\n}\n\n/* Provide sufficient contrast against white background */\na {\n  color: #0366d6;\n}\n\n.btn-primary {\n  color: #fff;\n  background-color: #1b6ec2;\n  border-color: #1861ac;\n}\n\n.nav-pills .nav-link.active, .nav-pills .show > .nav-link {\n  color: #fff;\n  background-color: #1b6ec2;\n  border-color: #1861ac;\n}\n\n/* Sticky footer styles\n-------------------------------------------------- */\nhtml {\n  font-size: 14px;\n}\n@media (min-width: 768px) {\n  html {\n    font-size: 16px;\n  }\n}\n\n.border-top {\n  border-top: 1px solid #e5e5e5;\n}\n.border-bottom {\n  border-bottom: 1px solid #e5e5e5;\n}\n\n.box-shadow {\n  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);\n}\n\nbutton.accept-policy {\n  font-size: 1rem;\n  line-height: inherit;\n}\n\n/* Sticky footer styles\n-------------------------------------------------- */\nhtml {\n  position: relative;\n  min-height: 100%;\n}\n\nbody {\n  /* Margin bottom by footer height */\n  margin-bottom: 60px;\n}\n.footer {\n  position: absolute;\n  bottom: 0;\n  width: 100%;\n  white-space: nowrap;\n  line-height: 60px; /* Vertically center the text there */\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/.gitignore",
    "content": "﻿\n# don't include the js / data files which should always come from elsewhere\n\n/wwwroot/system\n/sys-2sxc/"
  },
  {
    "path": "Src/Integration/SxcEdit01/Context/IntSite.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context;\n\nnamespace IntegrationSamples.SxcEdit01.Context\n{\n    public class IntSite : ISite\n    {\n        public ISite Init(int siteId, ILog parentLog)\n        {\n            Id = siteId;\n            return this;\n        }\n\n        public int Id { get; set; }= 1;\n\n        public string Name => \"Demo Integration Site\";\n\n        public string AppsRootPhysical => \"todo apps root phys not set\";\n\n        public string AppsRootPhysicalFull => \"todo apps root physical full not set\";\n\n        public string AppAssetsLinkTemplate => \"todo apps root link not set/\" + AppConstants.AppFolderPlaceholder;\n\n        /// <summary>\n        /// #2sxcIntegration\n        /// This is important to set, for ADAM uploads to find out where they go.\n        /// It's the path relative to the project folder, not the URL\n        /// </summary>\n        public string ContentPath => \"wwwroot\";\n\n        public string Url => \"https://\" + UrlRoot;\n\n        public string UrlRoot => \"some-domain/en-us\";\n\n        public int ZoneId => Id;\n\n        public string CurrentCultureCode => \"\";\n\n        public string DefaultCultureCode => \"\";\n\n\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Context/IntUser.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace IntegrationSamples.SxcEdit01.Context\n{\n    /// <summary>\n    /// #2sxcIntegration\n    /// Dummy user, which always says it's a superuser\n    /// </summary>\n    public class IntUser: IUser\n    {\n        public int Id => 0;\n        public string IdentityToken => \"impl-user:0\";\n        public Guid? Guid => System.Guid.Empty;\n        public List<int> Roles => new List<int>();\n\n        public bool IsSystemAdmin => true;\n        [Obsolete(\"deprecated in v14.09 2022-10, will be removed ca. v16 #remove16\")]\n        public bool IsSuperUser => true;\n        [Obsolete(\"deprecated in v14.09 2022-10, will be removed ca. v16 #remove16\")]\n        public bool IsAdmin => IsSiteAdmin;\n\n        public bool IsSiteAdmin => true;\n        public bool IsContentAdmin => true;\n        public bool IsDesigner => true;\n        public bool IsAnonymous => false;\n\n        public string Username => \"unknown\";\n        public string Name => Username;\n\n        public string Email => \"unknown@unknown.org\";\n\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Controllers/AdamController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Eav.WebApi.PublicApi;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\n\n// #todo: security checks on APIs still completely missing\n\nnamespace IntegrationSamples.SxcEdit01.Controllers\n{\n    /// <summary>\n    /// Direct access to app-content items, simple manipulations etc.\n    /// Should check for security at each standard call - to see if the current user may do this\n    /// Then we can reduce security access level to anonymous, because each method will do the security check\n    /// </summary>\n    [ApiController]\n    [Route(IntegrationConstants.DefaultRouteRoot + AppRoots.AppAutoData + \"/\" + ValueTokens.SetTypeGuidField)]\n    public class AdamController : IntControllerBase<AdamControllerReal<string>>, IAdamController<string>\n    {\n        // IMPORTANT: Uses the Proxy/Real concept - see https://r.2sxc.org/proxy-controllers\n\n        public AdamController() : base(\"Adam\") { }\n\n        [HttpPost]\n        [HttpPut]\n        public UploadResultDto Upload(int appId, string contentType, Guid guid, string field, string subFolder = \"\", bool usePortalRoot = false)\n            => Real.Upload(new HttpUploadedFile(Request), appId, contentType, guid, field, subFolder, usePortalRoot);\n\n        [HttpGet(\"items\")]\n        public IEnumerable<AdamItemDto> Items(int appId, string contentType, Guid guid, string field, string subfolder, bool usePortalRoot = false)\n            => Real.Items(appId, contentType, guid, field, subfolder, usePortalRoot);\n\n        [HttpPost(\"folder\")]\n        public IEnumerable<AdamItemDto> Folder(int appId, string contentType, Guid guid, string field, string subfolder, string newFolder, bool usePortalRoot)\n            => Real.Folder(appId, contentType, guid, field, subfolder, newFolder, usePortalRoot);\n\n        [HttpGet(\"delete\")]\n        public bool Delete(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, string id, bool usePortalRoot)\n            => Real.Delete(appId, contentType, guid, field, subfolder, isFolder, id, usePortalRoot);\n\n        [HttpGet(\"rename\")]\n        public bool Rename(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, string id, string newName, bool usePortalRoot)\n            => Real.Rename(appId, contentType, guid, field, subfolder, isFolder, id, newName, usePortalRoot);\n\n    }\n}"
  },
  {
    "path": "Src/Integration/SxcEdit01/Controllers/DialogController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\n\nnamespace IntegrationSamples.SxcEdit01.Controllers\n{\n    [Route(IntegrationConstants.DefaultRouteRoot + AreaRoutes.Admin)]\n    [ApiController]\n    public class DialogController : IntControllerBase<DialogControllerReal>, IDialogController\n    {\n        // IMPORTANT: Uses the Proxy/Real concept - see https://r.2sxc.org/proxy-controllers\n\n        public DialogController() :base(DialogControllerReal.LogSuffix) { }\n\n        [HttpGet]\n        public DialogContextStandaloneDto Settings(int appId) => Real.Settings(appId);\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Controllers/EditController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Eav.WebApi.Sys.Dto;\nusing ToSic.Eav.WebApi.Sys.Routing;\nusing ToSic.Sxc.Backend.Cms;\n\nnamespace IntegrationSamples.SxcEdit01.Controllers\n{\n    //[AutoValidateAntiforgeryToken]\n    [Route(IntegrationConstants.DefaultRouteRoot + AreaRoutes.Cms)]\n    [ApiController]\n    public class EditController: IntControllerBase<EditControllerReal>, IEditController\n    {\n        // IMPORTANT: Uses the Proxy/Real concept - see https://r.2sxc.org/proxy-controllers\n\n        public EditController() : base(EditControllerReal.LogSuffix) { }\n\n\n        [HttpPost]\n        [AllowAnonymous] // Anonymous is ok, security check happens internally\n        public async Task<EditLoadDto> Load([FromBody] List<ItemIdentifier> items, int appId)\n            => await Real.Load(items, appId);\n\n        [HttpPost]\n        // todo #mvcSec [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n        public async Task<Dictionary<Guid, int>> Save([FromBody] EditSaveDto package, int appId, bool partOfPage)\n            => await Real.Save(package, appId, partOfPage);\n\n        /// <inheritdoc />\n        [HttpGet]\n        //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n        public LinkInfoDto LinkInfo(string link, int appId, string contentType = default, Guid guid = default, string field = default)\n            => Real.LinkInfo(link, appId, contentType, guid, field);\n\n        /// <inheritdoc />\n        [HttpPost]\n        //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n        public bool Publish(int id)\n            => Real.Publish(id);\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Controllers/HistoryController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing System.Collections.Generic;\nusing ToSic.Eav.Persistence.Versions;\nusing ToSic.Sxc.Backend.Cms;\n\nnamespace IntegrationSamples.SxcEdit01.Controllers\n{\n    // Release routes\n    [Route(IntegrationConstants.DefaultRouteRoot + AreaRoutes.Cms)]\n\n    //[ValidateAntiForgeryToken]\n    public class HistoryController : IntControllerBase<HistoryControllerReal>, IHistoryController\n    {\n        public HistoryController(): base(HistoryControllerReal.LogSuffix) { }\n\n        /// <inheritdoc />\n        [HttpPost]\n        public List<ItemHistory> Get(int appId, [FromBody] ItemIdentifier item) \n            => Real.Get(appId, item);\n\n        /// <inheritdoc />\n        [HttpPost]\n        public bool Restore(int appId, int transactionId, [FromBody] ItemIdentifier item) =>\n            Real.Restore(appId, transactionId, item);\n    }\n}"
  },
  {
    "path": "Src/Integration/SxcEdit01/Controllers/InsightsController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\n\nnamespace IntegrationSamples.SxcEdit01.Controllers\n{\n    [Route(IntegrationConstants.DefaultRouteRoot + Areas.Sys + \"/[controller]\")]\n    [ApiController]\n    public class InsightsController : IntControllerBase<InsightsControllerReal>\n    {\n        // IMPORTANT: Uses the Proxy/Real concept - see https://r.2sxc.org/proxy-controllers\n\n        public InsightsController(): base(InsightsControllerReal.LogSuffix) {}\n\n        /// <summary>\n        /// The main call on this controller, will return all kinds of views with information\n        /// </summary>\n        [HttpGet(\"{view}\")]\n        public ContentResult Details(\n            [FromRoute] string view,\n            [FromQuery] int? appId = null,\n            [FromQuery] string key = null,\n            [FromQuery] int? position = null,\n            [FromQuery] string type = null,\n            [FromQuery] bool? toggle = null,\n            [FromQuery] string nameId = null\n        ) => Content(Real.Details(view, appId, key, position, type, toggle, nameId), \"text/html\");\n    }\n}"
  },
  {
    "path": "Src/Integration/SxcEdit01/Controllers/IntControllerBase.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing ToSic.Sxc.WebApi.Sys;\n\nnamespace IntegrationSamples.SxcEdit01.Controllers\n{\n    /// <summary>\n    /// This kind of base controller is recommended for all 2sxc/eav implementations. It solves various problems:\n    ///\n    /// 1. Ensures logging and also times the request for better insights\n    /// 2. Provides a `GetService` command for all API Controllers\n    /// 3. Provides the `Real` controller which was specified\n    /// 4. Standardizes the response ni case of a empty response so it properly reports HTTP 204\n    /// </summary>\n    /// <typeparam name=\"TRealController\"></typeparam>\n    public abstract class IntControllerBase<TRealController> : Controller, IHasLog where TRealController : class, IHasLog\n    {\n        // IMPORTANT: Uses the Proxy/Real concept - see https://r.2sxc.org/proxy-controllers\n\n        /// <summary>\n        /// Constructor initializes the log, and makes sure that the helper is ready for timing and other features\n        /// </summary>\n        /// <param name=\"logName\"></param>\n        protected IntControllerBase(string logName)\n        {\n            Log = new Log(IntegrationConstants.LogPrefix + logName, null, GetType().Name);\n            _helper = new NetCoreControllersHelper(this);\n        }\n\n        /// <summary>\n        /// The helper to assist in timing and common operations of WebApi Controllers\n        /// </summary>\n        private readonly NetCoreControllersHelper _helper;\n\n        /// <inheritdoc />\n        public ILog Log { get; }\n\n        /// <summary>\n        /// The group name for log entries in insights.\n        /// Helps group various calls by use case. \n        /// </summary>\n        protected virtual string HistoryLogGroup => EavWebApiConstants.HistoryNameWebApi;\n\n        /// <summary>\n        /// Initializer - Prepare the ServiceProvider and start the timer\n        /// </summary>\n        /// <param name=\"context\"></param>\n        [NonAction]\n        public override void OnActionExecuting(ActionExecutingContext context)\n        {\n            base.OnActionExecuting(context);\n            _helper.OnActionExecuting(context, HistoryLogGroup);\n        }\n\n        /// <summary>\n        /// Make sure we stop the timer and do some minor fixes\n        /// </summary>\n        /// <param name=\"context\"></param>\n        [NonAction]\n        public override void OnActionExecuted(ActionExecutedContext context)\n        {\n            base.OnActionExecuted(context);\n            _helper.OnActionExecuted(context);\n        }\n\n        /// <summary>\n        /// The RealController which is the full backend of this controller.\n        /// Note that it's not available at construction time, because the ServiceProvider isn't ready till later.\n        /// </summary>\n        protected TRealController Real => _real ??= _helper.Real<TRealController>();\n        private TRealController _real;\n\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Controllers/PongController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\n\nnamespace IntegrationSamples.SxcEdit01.Controllers\n{\n    [Route(\"api/[controller]/[action]\")]\n    [ApiController]\n    public class PongController : IntControllerBase<DummyControllerReal>\n    {\n        public PongController() : base(\"Pong\") { }\n\n        [HttpGet]\n        public string Pong() => \"pong\";\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using ToSic.Sys.Logging;"
  },
  {
    "path": "Src/Integration/SxcEdit01/IntegrationConstants.cs",
    "content": "﻿using ToSic.Eav.Apps;\n\nnamespace IntegrationSamples.SxcEdit01\n{\n    // #2sxcIntegration\n\n    public class IntegrationConstants\n    {\n        public const string LogPrefix = \"Int\";\n\n        // WebAPI Constants\n        public const string DefaultRouteRoot = \"api/sxc/\";\n\n        /// <summary>\n        /// In the demo setup this is the blog app on the PC of 2dm\n        /// </summary>\n        public const int ZoneId = 145;\n        public const int AppId = 1369;\n        public static IAppIdentity AppIdentity = new AppIdentity(ZoneId, AppId);\n\n        //public const int PageId = 4427;         // probably not needed TODO: VERIFY\n        //public const int ModuleId = 9771;       // probably not needed TODO: VERIFY\n\n        // An entity in the test-db - yours will be different\n        public const int ItemWithImagesId = 128280;\n        public const string ImagesField = \"ImageLibrary\";\n\n        #region Parameters used in the page to load the scripts and init the $2sxc JS APIs - see _Layout.cshtml\n\n        // URLs of JS to load\n        public const string UrlTo2sxcJs = EnvUiRoot + \"js/2sxc.api.min.js\";\n        public const string UrlTo2sxcInPageJs = EnvUiRoot + \"dist/inpage/inpage.min.js\";\n\n        // Environment settings for the JS to use\n        //public const int EnvPageId = 2742;\n        public const string EnvApiRoot = \"/\" + DefaultRouteRoot;    // the api base path\n        public const string EnvUiRoot = \"/system/sxc/\";             // the path above the `js` and `dist` which contains everything\n        public const string EnvRvt = \"...\";                         // This sample doesn't use RequestVerificationTokens\n\n        #endregion\n\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Pages/Edit.cshtml",
    "content": "﻿@page\n@using ToSic.Eav.Apps.Sys.State\n@using ToSic.Eav.Data\n@using ToSic.Eav.Data.Sys.Entities\n@using ToSic.Eav.Metadata\n@using ToSic.Sxc.Services\n@using ToSic.Sys.DI\n@inject IAppStateCacheService AppStateCacheService\n@inject IServiceProvider ServiceProvider;\n@{\n  ViewData[\"Title\"] = \"Edit 2sxc data\";\n\n  // Adjust these values to your testing environment\n  var appIdentity = IntegrationConstants.AppIdentity;\n  var appState = AppStateCacheService.Get(appIdentity);\n  var firstItem = appState.List.First();\n}\n<h1>@ViewData[\"Title\"]</h1>\n\n<script language=\"javascript\">\n    // Important note\n    // This requires that the JS is loaded on the page. In this sample it's done in the _Layout.cshtml\n    // It also requires some environment properties to be set - which is also done in _Layout.cshtml\n    function getSxc() {\n        return $2sxc({ zoneId: @appIdentity.ZoneId, appId: @appIdentity.AppId });\n    }\n</script>\n<p>\n  Try using the $2sxc js api for @appIdentity.ZoneId/@appIdentity.AppId - first item @firstItem.EntityId <br />\n</p>\n\n<ol>\n  <li>Check api works - <a href=\"/api/pong/pong\" target=\"_blank\">Test</a></li>\n  <li><a href=\"/api/sxc/sys/insights/help\" target=\"_blank\">Insights</a></li>\n  <li><a href=\"/api/sxc/Dialog/Settings?appId=@appIdentity.AppId\" target=\"_blank\">Call Dialog/Settings?appId=@appIdentity.AppId</a></li>\n  <li><a href=\"#\" onclick=\"getSxc().manage.run('app')\">Click to open app-dialog</a></li>\n  <li><a href=\"#\" onclick=\"getSxc().manage.run('edit', { entityId: @firstItem.EntityId })\">Click to open edit dialog</a></li>\n</ol>\n\n<hr />\n<h2>ADAM Images / Files</h2>\n<ol>\n    <!-- TODO: check if it should be CMS.run -->\n    <li><a href=\"#\" onclick=\"getSxc().manage.run('edit', { entityId: @IntegrationConstants.ItemWithImagesId })\">Edit something with images!</a></li>\n</ol>\n@{\n    // Create a log-object (optional) which is used to track what the code does\n    // could also just be null\n    var log = new LogAdapter(new Log(\"My.Log\"));\n\n    // Get the App execution context since our code here doesn't have it\n    var dynCodeSvc = ServiceProvider.Build<IDynamicCodeService>();\n    var dynCode = dynCodeSvc.OfApp(appIdentity);\n\n    var entityWithAdam = dynCode.App.Data.List.GetOne(IntegrationConstants.ItemWithImagesId);\n    var folder2 = dynCode.AsAdam(entityWithAdam, IntegrationConstants.ImagesField);\n}\n<h3>Files in @dynCode.AsDynamic(entityWithAdam).EntityTitle </h3>\n<ol>\n  @foreach (var img in folder2.Files)\n  {\n    <li>@img.Url</li>\n  }\n</ol>\n\n<hr />\n<h2>Metadata</h2>\n@{\n  var targetType = (int)TargetTypes.CmsItem; // 10;\n  var myItemId = 1234;\n  var md = appState.GetMetadata(targetType, myItemId);\n}\nFound Metadata: @md.Count()\n<ol>\n  @foreach (var m in md)\n  {\n    <li onclick=\"getSxc().manage.run('edit', { entityId: @m.EntityId })\">@m.Type.Name: @m.GetBestTitle()</li>\n  }\n</ol>\n\n\n<script>\n    function openMetadata(targetId) {\n        console.log('test1');\n        // TODO: CHECK Target property - was this public API? how can we prevent breaks?\n        const forRef = { Number: targetId, TargetType: @targetType, Singleton: true };\n        getSxc().manage.run('edit', {\n            items: [\n                { ContentTypeName: 'MetadataGps', For: forRef, Operations: \"singleton\", Prefill: { Color: \"super-pink\" } },\n                { ContentTypeName: 'MetadataCar', For: forRef, Sfx: \"singleton\" }\n            ]\n        });\n    }\n</script>\n\nwip\n<p>\n  <a href=\"#\" onclick=\"openMetadata('@myItemId')\">Edit Test for @myItemId</a>\n</p>\n\n<p>\n  @{\n    var tempId = 2742;\n  }\n  <a href=\"#\" onclick=\"openMetadata(@tempId)\">Edit Test for @tempId</a>\n</p>\n\n<hr />\n<p>\n  <!-- Note to myself: key seems to have a bug, if it's not a string-->\n  <a href=\"#\" onclick=\"getSxc().manage.run('edit', {\n    items: [\n        { ContentTypeName: 'MetadataGps', EntityId: 0, Metadata: { targetType: 10, keyType: 'number', key: @myItemId } },\n        { ContentTypeName: 'MetadataCar', EntityId: 0, For: { targetType: 10, Number: @myItemId } }\n    ]\n})\">Edit Test</a>\n</p>\n\nkind of works...\n<p>\n  <a href=\"#\" onclick=\"getSxc().manage.run('edit', { metadata: { targetType: @targetType, keyType: 'number', key: @myItemId }, contentType: 'MetadataGps', entityId: 0 })\">Edit Metadata</a>\n</p>"
  },
  {
    "path": "Src/Integration/SxcEdit01/Pages/Error.cshtml",
    "content": "﻿@page\n@model ErrorModel\n@{\n    ViewData[\"Title\"] = \"Error\";\n}\n\n<h1 class=\"text-danger\">Error.</h1>\n<h2 class=\"text-danger\">An error occurred while processing your request.</h2>\n\n@if (Model.ShowRequestId)\n{\n    <p>\n        <strong>Request ID:</strong> <code>@Model.RequestId</code>\n    </p>\n}\n\n<h3>Development Mode</h3>\n<p>\n    Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.\n</p>\n<p>\n    <strong>The Development environment shouldn't be enabled for deployed applications.</strong>\n    It can result in displaying sensitive information from exceptions to end users.\n    For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>\n    and restarting the app.\n</p>\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Pages/Error.cshtml.cs",
    "content": "using System.Diagnostics;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.Extensions.Logging;\n\nnamespace IntegrationSamples.SxcEdit01.Pages\n{\n    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]\n    public class ErrorModel : PageModel\n    {\n        public string RequestId { get; set; }\n\n        public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);\n\n        private readonly ILogger<ErrorModel> _logger;\n\n        public ErrorModel(ILogger<ErrorModel> logger)\n        {\n            _logger = logger;\n        }\n\n        public void OnGet()\n        {\n            RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Pages/Index.cshtml",
    "content": "﻿@page\n@{\n    ViewData[\"Title\"] = \"2sxc Integration - Edit Implementation\";\n}\n\n<div class=\"text-center\">\n  <h1 class=\"display-4\">2sxc Integration - Edit Entities Implementation</h1>\n</div>\n\n<p>\n  This should be the most basic integration possible, where we only read 2sxc data, but do nothing else.\n</p>\n\n<h2>Basics</h2>\n<p>\n  The following projects / solutions were added. If doing this from an external system, make sure you have the right DLLs.\n</p>\n<ol>\n  <li>Eav</li>\n  <li>Eav.Core</li>\n  <li>Sxc.WebApi</li>\n</ol>\n\n<h2>Packages</h2>\n<ol>\n  <li>MVC.Newtonsoft 3.1.4</li>\n</ol>\n\n<h2>MVC specific stuff</h2>\n<ol>\n  <li>See code, basically have to add routing and add controllers with Newtonsoft</li>\n</ol>\n\n<h2>DB Connection</h2>\n<ol>\n  <li>Add DB Connection String to appsettings.json</li>\n  <li>Create StartupEavAndSxc and add the ConfigureConnectionString - then call it from the normal Startup.cs</li>\n</ol>\n\n<h2>JS In-Page integration</h2>\n<ol>\n  <li>Add scripts js / inpage and include in page</li>\n  <li>add $2sxc.env.load</li>\n  <li>Add a link which runs a JS to open the edit dialog</li>\n</ol>\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Pages/Shared/_Layout.cshtml",
    "content": "﻿<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  <title>@ViewData[\"Title\"] - Edit</title>\n  <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css\" integrity=\"sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2\" crossorigin=\"anonymous\">\n  <link rel=\"stylesheet\" href=\"~/css/site.css\" />\n\n\n</head>\n<body>\n  <header>\n    <nav class=\"navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3\">\n      <div class=\"container\">\n        <a class=\"navbar-brand\" asp-area=\"\" asp-page=\"/Index\">Integration #2 - Edit</a>\n        <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\".navbar-collapse\" aria-controls=\"navbarSupportedContent\"\n                aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n          <span class=\"navbar-toggler-icon\"></span>\n        </button>\n        <div class=\"navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse\">\n          <ul class=\"navbar-nav flex-grow-1\">\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Index\">Home</a>\n            </li>\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Edit\">Edit</a>\n            </li>\n          <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" href=\"/api/sxc/sys/Insights/Help\" target=\"_blank\">Show Insights</a>\n          </li>\n          </ul>\n        </div>\n      </div>\n    </nav>\n  </header>\n  <div class=\"container\">\n    <main role=\"main\" class=\"pb-3\">\n      @RenderBody()\n    </main>\n  </div>\n\n  <footer class=\"border-top footer text-muted\">\n    <div class=\"container\">\n      &copy; 2022 - Edit Integration Sample - <a asp-area=\"\" asp-page=\"/Privacy\">Privacy</a>\n    </div>\n  </footer>\n\n  <script src=\"https://code.jquery.com/jquery-3.5.1.slim.min.js\" integrity=\"sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj\" crossorigin=\"anonymous\"></script>\n  <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js\" integrity=\"sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx\" crossorigin=\"anonymous\"></script>\n  \n<!-- #2sxcIntegration -->\n<script src=\"@IntegrationConstants.UrlTo2sxcJs\"></script>\n<script src=\"@IntegrationConstants.UrlTo2sxcInPageJs\"></script>\n<script language=\"javascript\">\n  $2sxc.env.load({\n    // optional pageId: 0,\n    rvt: '@IntegrationConstants.EnvRvt',\n    api: '@IntegrationConstants.EnvApiRoot',\n    uiRoot: `@IntegrationConstants.EnvUiRoot`, \n  });\n</script>\n\n@RenderSection(\"Scripts\", required: false)\n</body>\n</html>\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Pages/Shared/_ValidationScriptsPartial.cshtml",
    "content": "﻿<script src=\"https://cdn.jsdelivr.net/npm/jquery-validation@1.19.2/dist/jquery.validate.min.js\" integrity=\"sha256-+BEKmIvQ6IsL8sHcvidtDrNOdZO3C9LtFPtF2H0dOHI=\" crossorigin=\"anonymous\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/jquery-validation-unobtrusive@3.2.11/dist/jquery.validate.unobtrusive.min.js\" integrity=\"sha256-9GycpJnliUjJDVDqP0UEu/bsm9U+3dnQUH8+3W10vkY=\" crossorigin=\"anonymous\"></script>"
  },
  {
    "path": "Src/Integration/SxcEdit01/Pages/_ViewImports.cshtml",
    "content": "@namespace IntegrationSamples.SxcEdit01.Pages\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Pages/_ViewStart.cshtml",
    "content": "﻿@{\n    Layout = \"_Layout\";\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Program.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Hosting;\n\nnamespace IntegrationSamples.SxcEdit01\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Properties/launchSettings.json",
    "content": "﻿{\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,\n    \"anonymousAuthentication\": true,\n    \"iisExpress\": {\n      \"applicationUrl\": \"http://localhost:65487\",\n      \"sslPort\": 44384\n    }\n  },\n  \"profiles\": {\n    \"IIS Express\": {\n      \"commandName\": \"IISExpress\",\n      \"launchBrowser\": true,\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES\": \"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\"\n      }\n    },\n    \"SxcEdit01\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"https://localhost:5001;http://localhost:5000\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES\": \"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/Startup.cs",
    "content": "using System.IO;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing ToSic.Sxc.Backend;\nusing ToSic.Sxc.Run.Startup;\nusing ToSic.Sys.Configuration;\n\nnamespace IntegrationSamples.SxcEdit01\n{\n    public class Startup\n    {\n        /// <summary>\n        /// This method gets called first by the runtime. Use it to get configuration values. \n        /// </summary>\n        public Startup(IConfiguration configuration)\n        {\n            _connStringFromConfig = configuration.GetConnectionString(\"SiteSqlServer\");\n        }\n        private readonly string _connStringFromConfig;\n\n        /// <summary>\n        /// This method gets called second by the runtime. Use this method to add services to the container.\n        /// </summary>\n        public void ConfigureServices(IServiceCollection services)\n        {\n            services.AddRazorPages();\n\n            // #2sxcIntegration\n            services\n                .AddMvcRazor()\n                .AddControllersAndConfigureJson()\n                .AddImplementations()\n                .AddAdamWebApi<string, string>()\n                .AddSxcWebApi()\n                .AddSxcCore()\n                .AddEav();\n        }\n\n\n        /// <summary>\n        /// This method gets called third by the runtime. Use this method to configure the HTTP request pipeline.\n        /// </summary>\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            // ----- Start EAV stuff #2sxcIntegration -----\n            var serviceProvider = app.ApplicationServices;\n\n            // Set Connection String\n            serviceProvider.GetRequiredService<IDbConfiguration>().ConnectionString = _connStringFromConfig;\n\n            // Set global path where it will find the .data folder\n            var globalConfig = serviceProvider.GetRequiredService<IGlobalConfiguration>();\n            globalConfig.GlobalFolder = Path.Combine(env.ContentRootPath, \"sys-2sxc\");\n\n            // Trigger start where the data etc. will be loaded & initialized\n            serviceProvider.GetRequiredService<SystemLoader>().StartUp();\n            // ----- End EAV stuff #2sxcIntegration -----\n\n            if (env.IsDevelopment())\n                app.UseDeveloperExceptionPage();\n            else\n            {\n                app.UseExceptionHandler(\"/Error\");\n                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.\n                app.UseHsts();\n            }\n\n            app.UseHttpsRedirection();\n            app.UseStaticFiles();\n            app.UseRouting();\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapRazorPages();\n\n                // #2sxcIntegration - enable controllers\n                endpoints.MapControllers();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/StartupEavAndSxc.cs",
    "content": "﻿using IntegrationSamples.SxcEdit01.Context;\nusing Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.AspNetCore.Mvc.Routing;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Context;\n\nnamespace IntegrationSamples.SxcEdit01\n{\n    /// <summary>\n    /// #2sxcIntegration\n    /// This static class contains the important bits to connect the EAV with the Dependency Injection of this test site\n    /// </summary>\n    public static class StartupEavAndSxc\n    {\n        internal static IServiceCollection AddImplementations(this IServiceCollection services)\n        {\n            // Context\n            services.TryAddTransient<ISite, IntSite>();\n            services.TryAddTransient<IUser, IntUser>();\n\n            // ADAM\n            services.TryAddTransient<AdamManager, AdamManager<string, string>>();\n            services.TryAddTransient<IAdamPaths, AdamPathsWwwroot>();\n\n            return services;\n        }\n\n        internal static IServiceCollection AddMvcRazor(this IServiceCollection services)\n        {\n            // enable use of HttpContext\n            services.AddHttpContextAccessor();\n\n            // enable use of UrlHelper for AbsolutePath\n            // used by LinkPath - but this is only for older .net\n            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();\n            services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();\n            services.AddScoped(it => it.GetService<IUrlHelperFactory>()\n                .GetUrlHelper(it.GetService<IActionContextAccessor>().ActionContext));\n\n            return services;\n        }\n\n        internal static IServiceCollection AddControllersAndConfigureJson(this IServiceCollection services)\n        {\n            services.AddControllers(options => { options.AllowEmptyInputInBodyModelBinding = true; })\n                // This is needed to preserve compatibility with previous api usage\n                // Set the JSON serializer options\n                .AddJsonOptions(options => options.JsonSerializerOptions.SetUnsafeJsonSerializerOptions());\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/SxcEdit01.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net9.0</TargetFramework>\n    <CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory>\n    <RootNamespace>IntegrationSamples.SxcEdit01</RootNamespace>\n    <Configurations>Debug;Release;DebugOqtane;DebugDnn</Configurations>\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"wwwroot\\system\\**\" />\n    <Content Remove=\"wwwroot\\system\\**\" />\n    <EmbeddedResource Remove=\"wwwroot\\system\\**\" />\n    <None Remove=\"wwwroot\\system\\**\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.NewtonsoftJson\" Version=\"9.0.0\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\" Version=\"9.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"StartUp\\\" />\n  </ItemGroup>\n\n  <Target Name=\"PostBuild\" AfterTargets=\"PostBuildEvent\">\n    <Exec Command=\"@Echo Configuration='$(Configuration)'&#xD;&#xA;@Echo StartWith ='$(Configuration.StartsWith('Debug'))'&#xD;&#xA;@Echo Platform ='$(Platform)'&#xD;&#xA;@Echo ProjectDir '$(ProjectDir)'&#xD;&#xA;@SET BuildTarget=$(ProjectDir)sys-2sxc&#xD;&#xA;@Echo BuildTarget '%25BuildTarget%25'&#xD;&#xA;&#xD;&#xA;@REM Copy the data folders&#xD;&#xA;robocopy /mir &quot;$(ProjectDir)..\\..\\Data\\.data\\ &quot; &quot;%25BuildTarget%25\\.data\\ &quot;&#xD;&#xA;robocopy /mir &quot;$(ProjectDir)..\\..\\Data\\.databeta\\ &quot; &quot;%25BuildTarget%25\\.databeta\\ &quot;&#xD;&#xA;robocopy /mir &quot;$(ProjectDir)..\\..\\Data\\.data-custom\\ &quot; &quot;%25BuildTarget%25\\.data-custom\\ &quot;&#xD;&#xA;&#xD;&#xA;@Set BuildTarget=$(ProjectDir)\\wwwroot\\system\\sxc&#xD;&#xA;Echo Will copy js &amp; css to %25BuildTarget%25&#xD;&#xA;&#xD;&#xA;@REM Copy 2sxc JS stuff&#xD;&#xA;robocopy /mir &quot;$(Source)\\js\\ &quot; &quot;%25BuildTarget%25\\js\\ &quot;&#xD;&#xA;robocopy /mir &quot;$(Source)\\dist\\ &quot; &quot;%25BuildTarget%25\\dist\\ &quot;&#xD;&#xA;robocopy /mir &quot;$(Source)\\system\\ &quot; &quot;%25BuildTarget%25\\system\\ &quot;&#xD;&#xA;\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n\n  \"//1\":  \"#2sxcIntegration: Added this to point to the right DB\",\n  \"ConnectionStrings\": {\n    \"SiteSqlServer\": \"Data Source=localhost;Initial Catalog=2sxc-dnn742;Integrated Security=True\"\n  }\n}\n"
  },
  {
    "path": "Src/Integration/SxcEdit01/wwwroot/css/site.css",
    "content": "﻿/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\nfor details on configuring this project to bundle and minify static web assets. */\n\na.navbar-brand {\n  white-space: normal;\n  text-align: center;\n  word-break: break-all;\n}\n\n/* Provide sufficient contrast against white background */\na {\n  color: #0366d6;\n}\n\n.btn-primary {\n  color: #fff;\n  background-color: #1b6ec2;\n  border-color: #1861ac;\n}\n\n.nav-pills .nav-link.active, .nav-pills .show > .nav-link {\n  color: #fff;\n  background-color: #1b6ec2;\n  border-color: #1861ac;\n}\n\n/* Sticky footer styles\n-------------------------------------------------- */\nhtml {\n  font-size: 14px;\n}\n@media (min-width: 768px) {\n  html {\n    font-size: 16px;\n  }\n}\n\n.border-top {\n  border-top: 1px solid #e5e5e5;\n}\n.border-bottom {\n  border-bottom: 1px solid #e5e5e5;\n}\n\n.box-shadow {\n  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);\n}\n\nbutton.accept-policy {\n  font-size: 1rem;\n  line-height: inherit;\n}\n\n/* Sticky footer styles\n-------------------------------------------------- */\nhtml {\n  position: relative;\n  min-height: 100%;\n}\n\nbody {\n  /* Margin bottom by footer height */\n  margin-bottom: 60px;\n}\n.footer {\n  position: absolute;\n  bottom: 0;\n  width: 100%;\n  white-space: nowrap;\n  line-height: 60px; /* Vertically center the text there */\n}\n"
  },
  {
    "path": "Src/Mvc/.gitignore",
    "content": "﻿################################################################################\n# This .gitignore file was automatically created by Microsoft(R) Visual Studio.\n################################################################################\n\n/Website/bin\n/Website/obj\nToSic.Sxc.Mvc/bin\nToSic.Sxc.Mvc/obj\nWebsite/wwwroot/System/Sxc/**"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Dev/InstanceId.cs",
    "content": "﻿using System;\n\nnamespace ToSic.Sxc.Mvc.Dev\n{\n    public class InstanceId\n    {\n        public InstanceId(int t, int p, int a, int c, Guid b)\n        {\n            Zone = t;\n            Page = p;\n            App = a;\n            Container = c;\n            Block = b;\n        }\n\n        public int Zone;\n        public int Page;\n        public int App;\n        public int Container;\n        public Guid Block;\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Dev/TestIds.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace ToSic.Sxc.Mvc.Dev\n{\n    public class TestIds\n    {\n        // Global, valid for all\n        public const int PrimaryZone = 2;\n        public const string DefaultLanguage = \"en-us\";\n        public const string DefaultLanguageText = \"MVC English!\";\n        public const int PrimaryApp = 2;\n\n        public static InstanceId Blog = new InstanceId(2, 680, 78, 3002, new Guid(\"9cbcee9d-49d5-4fe0-8e74-1e20f74a5916\"));\n\n        public static InstanceId ContentOnHome = new InstanceId(2, 56, 2, 6935, new Guid(\"f8ae3d07-5805-4650-a46d-a047e113ab53\"));\n\n        // Token app here: http://2sexycontent.2dm.2sic/features/Tokens\n        public static InstanceId Token = new InstanceId(128, 4062, 1262,9170, new Guid(\"584b7398-8517-4bdf-b05d-71d64b935f4f\"));\n\n        public static List<InstanceId> FakeDb = new List<InstanceId>\n        {\n            Blog,\n            ContentOnHome,\n            Token,\n        };\n\n        public static InstanceId FindInstance(int containerId) => FakeDb.FirstOrDefault(i => i.Container == containerId);\n    }\n}\n\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Factory.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Lib.Logging;\nusing ToSic.Eav.Run;\nusing ToSic.Lib.Documentation;\nusing ToSic.Sxc.LookUp;\nusing App = ToSic.Sxc.Apps.App;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.Mvc\n{\n    public class Factory\n    {\n        [InternalApi_DoNotUse_MayChangeWithoutNotice]\n        public static IApp App(\n            int zoneId,\n            int appId,\n            ISite site,\n            bool showDrafts,\n            ILog parentLog)\n        {\n            var log = new Log(\"Mvc.Factry\", parentLog);\n            log.A($\"Create App(z:{zoneId}, a:{appId}, tenantObj:{site != null}, showDrafts: {showDrafts}, parentLog: {parentLog != null})\");\n            var app = Eav.Factory.StaticBuild<App>();\n            if (site != null) app.PreInit(site);\n\n            // debugging\n            var appIdentity = new AppIdentity(zoneId, appId);\n            var configDelegate = Eav.Factory.StaticBuild<AppConfigDelegate>().Init(parentLog).Build(showDrafts);\n\n            var appStuff = app.Init(appIdentity, configDelegate, parentLog);\n\n            return appStuff;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// This is needed for our code to access internal-properties\n[assembly: InternalsVisibleTo(\"Website\")]\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Run/MvcFileSystem.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing ToSic.Lib.Logging;\nusing ToSic.Eav.Run;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Mvc.Web;\n\nnamespace ToSic.Sxc.Mvc.Run\n{\n    public class MvcFileSystem: HasLog, IAdamFileSystem<string, string>\n    {\n        private readonly IServerPaths _serverPaths;\n\n        #region Constructor / DI / Init\n\n        public MvcFileSystem(IServerPaths serverPaths) : base(\"Dnn.FilSys\") => _serverPaths = serverPaths;\n\n        public IAdamFileSystem<string, string> Init(AdamManager<string, string> adamContext, ILog parentLog)\n        {\n            Log.LinkTo(parentLog);\n            AdamContext = adamContext;\n            return this;\n        }\n\n\n        protected AdamManager<string, string> AdamContext;\n\n        #endregion\n        // #todo MVC\n        public int MaxUploadKb() => 25000;\n\n        public File<string, string> GetFile(string fileId)\n        {\n            var dir = AdjustPathToSiteRoot(fileId);\n            return FileToAdam(dir);\n        }\n\n        public List<File<string, string>> GetFiles(IFolder folder)\n        {\n            var dir = Directory.GetFiles(AdjustPathToSiteRoot(folder.Path));\n            return dir.Select(FileToAdam).ToList();\n        }\n\n        public void Rename(IFile file, string newName) => throw new NotImplementedException();\n\n        public void Delete(IFile file) => throw new NotImplementedException();\n\n        public File<string, string> Add(IFolder parent, Stream body, string fileName, bool ensureUniqueName) => throw new NotImplementedException();\n\n        public void AddFolder(string path)\n        {\n            path = PathOnDrive(path);\n            Directory.CreateDirectory(path);\n        }\n\n        public bool FolderExists(string path)\n        {\n            var serverPath = PathOnDrive(path);\n            var exists = Directory.Exists(serverPath);\n            return exists;\n        }\n\n        private string PathOnDrive(string path)\n        {\n            if (path.Contains(\"..\")) throw new ArgumentException(\"path may not contain ..\", nameof(path));\n            // check if it already has the root path attached, otherwise add\n            path = path.StartsWith(AdamContext.Site.ContentPath) ? path : Path.Combine(AdamContext.Site.ContentPath, path);\n            path = path.Replace(\"//\", \"/\").Replace(\"\\\\\\\\\", \"\\\\\");\n            return _serverPaths.FullContentPath(path);\n        }\n\n        public Folder<string, string> GetFolder(string folderId) => AdamFolder(AdjustPathToSiteRoot(folderId));\n\n        public List<Folder<string, string>> GetFolders(IFolder folder)\n        {\n            var dir = Directory.GetDirectories(AdjustPathToSiteRoot(folder.Path));\n            return dir.Select(AdamFolder).ToList();\n        }\n\n        private static string AdjustPathToSiteRoot(string path)\n        {\n            return path.StartsWith(\"adam\", StringComparison.CurrentCultureIgnoreCase)\n                ? Path.Combine(MvcConstants.WwwRoot, path)\n                : path;\n        }\n\n        public void Rename(IFolder folder, string newName) => throw new NotImplementedException();\n\n        public void Delete(IFolder folder) => throw new NotImplementedException();\n\n        public Folder<string, string> Get(string path) => AdamFolder(path);\n\n        #region DnnToAdam\n        private Folder<string, string> AdamFolder(string path)\n        {\n            var f = new DirectoryInfo(PathOnDrive(path));\n\n            return new Folder<string, string>(AdamContext)\n            {\n                Path = path,\n                SysId = path,\n                ParentSysId = FindParentPath(path),\n                Name = f.Name,\n                Created = f.CreationTime,\n                Modified = f.LastWriteTime,\n\n                Url = AdamContext.Site.ContentPath + path,\n            };\n        }\n\n        private static string FindParentPath(string path)\n        {\n            var cleanedPath = path.TrimEnd('/').TrimEnd('\\\\');\n            var prevSlashF = cleanedPath.LastIndexOf('/');\n            var prevSlashB = cleanedPath.LastIndexOf('\\\\');\n            var lastSlash = prevSlashB > prevSlashF ? prevSlashB : prevSlashF;\n            var parentPath = lastSlash == -1 ? \"\" : cleanedPath.Substring(0, lastSlash);\n            return parentPath;\n        }\n\n\n        private File<string, string> FileToAdam(string path)\n        {\n            var f = new FileInfo(PathOnDrive(path));\n            var directoryName = f.Directory.Name;\n            return new File<string, string>(AdamContext)\n            {\n                FullName = f.Name,\n                Extension = f.Extension,\n                Size = Convert.ToInt32(f.Length),\n                SysId = path,\n                Folder = directoryName,\n                ParentSysId = path.Replace(f.Name, \"\", StringComparison.InvariantCultureIgnoreCase), // \"todo mvc\",// Constants.NullId,\n\n                Path = path,\n\n                Created = f.CreationTime,\n                Modified = f.LastWriteTime,\n                Name = Path.GetFileNameWithoutExtension(f.Name),\n                Url = AdamContext.Site.ContentPath + directoryName + f.Name\n            };\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Run/MvcGlobalFolderRepository.cs",
    "content": "﻿//using System.Collections.Generic;\n//using ToSic.Eav.Repositories;\n//using ToSic.Eav.Run;\n\n//namespace ToSic.Sxc.Mvc.Run\n//{\n//    public class MvcGlobalFolderRepository: FolderBasedRepository\n//    {\n//        #region Constructor and DI\n\n//        public MvcGlobalFolderRepository(IServerPaths serverPaths) => _serverPaths = serverPaths;\n\n//        private readonly IServerPaths _serverPaths;\n\n//        #endregion\n\n//        public override List<string> RootPaths => new List<string>\n//        {\n//            // todo: fix, as FullSystemPath should now come from Configuration\n//            //_serverPaths.FullSystemPath(\"wwwroot/System/Sxc/.data\"),\n//        };\n//    }\n//}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Run/MvcModule.cs",
    "content": "﻿using System;\nusing ToSic.Eav.Apps.Run;\nusing ToSic.Lib.Logging;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Mvc.Dev;\n\nnamespace ToSic.Sxc.Mvc.Run\n{\n    public class MvcModule: IModule\n    {\n        public MvcModule() {}\n\n        public MvcModule Init(int? tenantId = null, int? id = null, int? appId = null, Guid? block = null)\n        {\n            TenantId = tenantId ?? TestIds.Blog.Zone;\n            Id = id ?? TestIds.Blog.Container;\n            AppId = appId ?? TestIds.Blog.App;\n            Block = block ?? TestIds.Blog.Block;\n            return this;\n        }\n\n        // Temp implementation, don't support im MVC\n        public IModule Init(int id, ILog parentLog) => throw new System.NotImplementedException();\n\n        /// <inheritdoc />\n        public int Id { get; set; }\n\n        public bool IsContent { get; }\n\n        /// <inheritdoc />\n        public int TenantId { get; set; }\n\n        /// <inheritdoc />\n        public bool IsPrimary => BlockIdentifier.AppId == TestIds.PrimaryApp;\n\n        public IBlockIdentifier BlockIdentifier \n            => _blockIdentifier ??= new BlockIdentifier(TenantId, AppId, Block, Guid.Empty);\n\n        private IBlockIdentifier _blockIdentifier;\n\n        // special while testing\n        public int AppId;\n\n        public Guid Block;\n    }\n\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Run/MvcPermissionCheck.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing ToSic.Eav.Apps.Security;\nusing ToSic.Eav.Security;\n\nnamespace ToSic.Sxc.Mvc.Run\n{\n    public class MvcPermissionCheck: AppPermissionCheck\n    {\n        public MvcPermissionCheck(): base(\"Mvc\") { }\n\n        // todo: #permissions\n        protected override bool EnvironmentAllows(List<Grants> grants) => true;\n\n        protected override bool VerifyConditionOfEnvironment(string condition)\n        {\n            if (condition.Equals(\"SecurityAccessLevel.Anonymous\", StringComparison.CurrentCultureIgnoreCase))\n                return true;\n            return false;\n        }\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Run/MvcSite.cs",
    "content": "﻿using System.IO;\nusing Microsoft.AspNetCore.Http;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Run;\nusing ToSic.Lib.Documentation;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Mvc.Dev;\nusing ToSic.Sxc.Mvc.Web;\n\n// #todo: not really multi-tenant, incl. url \n\nnamespace ToSic.Sxc.Mvc.Run\n{\n    /// <summary>\n    /// This is a Mvc implementation of a Tenant-object. \n    /// </summary>\n    [InternalApi_DoNotUse_MayChangeWithoutNotice(\"this is just fyi\")]\n    public sealed class MvcSite : Site<object>, ICmsSite\n    {\n        /// <summary>\n        /// Constructor for DI\n        /// </summary>\n        /// <param name=\"httpContextAccessor\"></param>\n        public MvcSite(IHttpContextAccessor httpContextAccessor)\n        {\n            UnwrappedContents = null;\n            HttpContext = httpContextAccessor.HttpContext;\n        }\n\n\n        private HttpContext HttpContext { get; }\n\n        public override ISite Init(int siteId)\n        {\n            _siteId = siteId;\n            return this;\n        }\n\n        /// <inheritdoc />\n        public override string DefaultCultureCode => TestIds.DefaultLanguage;\n\n        /// <inheritdoc />\n        public override string CurrentCultureCode => TestIds.DefaultLanguage;\n\n\n        /// <inheritdoc />\n        public override int Id => _siteId;\n\n        private int _siteId;\n\n        // https://localhost:44361\n        public override string Url => HttpContext?.Request.Host.ToString();\n\n        /// <inheritdoc />\n        public override string Name => \"Dummy Site Name\";\n\n        [PrivateApi]\n        public override string AppsRootPhysical => AppsRootPartial();\n\n        private string AppsRootPartial()\n        {\n            return Path.Combine(MvcConstants.WwwRoot, Settings.AppsRootFolder);\n        }\n\n        public override string AppsRootPhysicalFull => Eav.Factory.Resolve<IServerPaths>().FullAppPath(AppsRootPartial());\n\n\n        /// <inheritdoc />\n        public override string ContentPath => MvcConstants.WwwRoot;\n\n        public override int ZoneId => _siteId;\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Run/MvcUser.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Mvc.Run\n{\n    public class MvcUser: IUser, ICmsUser\n    {\n        public int Id => 1;\n        public new string IdentityToken => \"mvcuser:1\";\n        public Guid? Guid => System.Guid.Empty;\n        public List<int> Roles => new List<int>();\n        public bool IsSuperUser => true;\n        public bool IsAdmin => true;\n        public bool IsDesigner => true;\n        public bool IsAnonymous => false;\n\n        #region New Permission properties for v12\n\n        /// <inheritdoc />\n        // This is a hopefully clearer implementation of what the user can do\n        public bool IsSiteAdmin => IsAdmin;\n\n        /// <inheritdoc />\n        // This is a hopefully clearer implementation of what the user can do\n        public bool IsSiteDeveloper => IsDesigner;\n\n        /// <inheritdoc />\n        // This is a hopefully clearer implementation of what the user can do\n        public bool IsSystemAdmin => IsSuperUser;\n\n        #endregion\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Run/MvcZoneMapper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing ToSic.Eav.Apps.Run;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Plumbing;\nusing ToSic.Eav.Run;\n\nnamespace ToSic.Sxc.Mvc.Run\n{\n    public class MvcZoneMapper : ZoneMapperBase\n    {\n        /// <inheritdoc />\n        public MvcZoneMapper(IServiceProvider serviceProvider) : base(\"Mvc.ZoneMp\")\n        {\n            _serviceProvider = serviceProvider;\n        }\n\n        private readonly IServiceProvider _serviceProvider;\n\n        public override int GetZoneId(int tenantId) => tenantId;\n\n        \n        public override ISite SiteOfZone(int zoneId) => _serviceProvider.Build<ISite>().Init(zoneId);\n\n\n        public override List<TempTempCulture> CulturesWithState(int tenantId, int zoneId)\n        {\n            return new List<TempTempCulture>\n            {\n                new TempTempCulture(\"en-us\", \"English USA\", true)\n            };\n        }\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/StartUpMvc.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Apps.Security;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Run;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Mvc.Run;\nusing ToSic.Sxc.Mvc.Web;\nusing ToSic.Sxc.Mvc.WebApi.Adam;\nusing ToSic.Sxc.Mvc.WebApi.Context;\nusing ToSic.Sxc.Web.JsContext;\nusing ToSic.Sxc.WebApi.Adam;\n\nnamespace ToSic.Sxc.Mvc\n{\n    public static class StartUpMvc\n    {\n        public static IServiceCollection AddSxcMvc(this IServiceCollection services)\n        {\n            services.AddTransient<ISite, MvcSite>();\n            services.AddTransient<IZoneCultureResolver, MvcSite>();\n            services.AddTransient<IModule, MvcModule>();\n            services.AddTransient<IZoneMapper, MvcZoneMapper>();\n            services.AddTransient<AppPermissionCheck, MvcPermissionCheck>();\n            //services.AddTransient<DynamicCodeRoot, MvcDynamicCode>();\n            services.AddTransient<MvcContextBuilder>();\n\n            // MVC Specific stuff\n            services.AddScoped<MvcPageProperties>();\n\n            // Add SxcEngineTest\n            services.AddTransient<SxcMvc>();\n            services.AddTransient<IAdamFileSystem<string, string>, MvcFileSystem>();\n            // Still pending...\n            //sc.AddTransient<XmlExporter, DnnXmlExporter>();\n            //sc.AddTransient<IAppFileSystemLoader, DnnAppFileSystemLoader>();\n            //sc.AddTransient<IAppRepositoryLoader, DnnAppFileSystemLoader>();\n\n            // v16\n            services.AddScoped<JsApiCache>();\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/StartupNotImplemented.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.Mvc\n{\n    /// <summary>\n    /// Register types which are necessary for the system to boot, but are not used in a basic\n    /// headless setup\n    /// </summary>\n    public static class StartupNotImplemented\n    {\n        public static IServiceCollection AddNotImplemented(this IServiceCollection services)\n        {\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/SxcMvc.cs",
    "content": "﻿using System;\nusing Microsoft.AspNetCore.Html;\nusing Microsoft.AspNetCore.Http;\nusing ToSic.Eav.Context;\nusing ToSic.Lib.Logging;\nusing ToSic.Eav.Plumbing;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Mvc.Dev;\nusing ToSic.Sxc.Mvc.Run;\nusing ToSic.Sxc.Mvc.Web;\n\n\nnamespace ToSic.Sxc.Mvc\n{\n    public class SxcMvc: HasLog\n    {\n        #region Constructor and DI\n        \n        public SxcMvc(IHttpContextAccessor httpContextAccessor, MvcPageProperties pageProperties) : base(\"Mvc.View\")\n        {\n            PageProperties = pageProperties;\n            _httpContext = httpContextAccessor.HttpContext;\n            // add log to history!\n            History.Add(\"sxc-mvc-view\", Log);\n        }\n\n        private readonly HttpContext _httpContext;\n        public MvcPageProperties PageProperties;\n\n        #endregion\n\n        public HtmlString Render(InstanceId id)\n        {\n            var blockBuilder = CreateBlock(id.Zone, id.Page, id.Container, id.App, id.Block, Log);\n            \n            var result = blockBuilder.BlockBuilder.Render();\n\n            // todo: set parameters for loading scripts etc.\n            //PageProperties.Headers += \"hello!!!\";\n            return new HtmlString(result);\n        }\n\n        //public DynamicCodeRoot CreateDynCode(InstanceId id, ILog log) =>\n        //    new MvcDynamicCode().Init(CreateBlock(id.Zone, id.Page, id.Container, id.App, id.Block, log), log);\n\n\n        public IBlock CreateBlock(int zoneId, int pageId, int containerId, int appId, Guid blockGuid, ILog log)\n        {\n            var context = CreateContext(zoneId, pageId, containerId, appId, blockGuid);\n            var block = _httpContext.RequestServices.Build<BlockFromModule>().Init(context, log);\n            return block;\n        }\n\n        private IContextOfBlock CreateContext(int zoneId, int pageId, int containerId, int appId, Guid blockGuid)\n            => CreateContext(_httpContext.RequestServices, zoneId, appId, containerId, appId, blockGuid);\n\n        public static IContextOfBlock CreateContext(IServiceProvider sp, int zoneId, int pageId, int containerId, int appId, Guid blockGuid)\n        {\n\n            var ctx = sp.Build<IContextOfBlock>();\n            ctx.Init(null);\n            ctx.Site.Init(zoneId);\n            ctx.Page.Init(pageId);\n            ((MvcModule) ctx.Module).Init(tenantId: zoneId, id: containerId, appId: appId, block: blockGuid);\n            return ctx;\n\n            //var publishing = sp.Build<IPagePublishingResolver>();\n            //return new ContextOfBlock(\n            //    sp,\n            //    sp.Build<ISite>().Init(zoneId),\n            //    //new SxcPage(pageId, null, http.RequestServices.Build<IHttp>().QueryStringKeyValuePairs()),\n            //    //new MvcContainer(tenantId: zoneId, id: containerId, appId: appId, block: blockGuid),\n            //    new MvcUser()\n            //    //publishing.GetPublishingState(containerId)\n            //).Init(\n            //    sp.Build<SxcPage>().Init(pageId),\n            //    new MvcContainer(tenantId: zoneId, id: containerId, appId: appId, block: blockGuid),\n            //    publishing.GetPublishingState(containerId)\n            //);\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/ToSic.Sxc.Mvc.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.1</TargetFramework>\n    <Configurations>Debug;Release;DebugOqtane;DebugDnn</Configurations>\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"Code\\**\" />\n    <Compile Remove=\"Engines\\**\" />\n    <EmbeddedResource Remove=\"Code\\**\" />\n    <EmbeddedResource Remove=\"Engines\\**\" />\n    <None Remove=\"Code\\**\" />\n    <None Remove=\"Engines\\**\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Reference Include=\"ToSic.Razor\">\n      <HintPath>..\\..\\..\\Dependencies\\RazorBlade\\Release\\netstandard2.0\\ToSic.Razor.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"NotImplemented\\\" />\n    <Folder Include=\"TestStuff\\\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Web/MvcConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Mvc.Web\n{\n    public class MvcConstants\n    {\n        public const string SiteRoot = \"/\";\n        public const string UiRoot = \"/system/sxc/\";\n\n        public const string WwwRoot = \"wwwroot/\";\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/Web/MvcPageProperties.cs",
    "content": "﻿using System.Text;\nusing Microsoft.AspNetCore.Html;\nusing ToSic.Lib.Logging;\nusing ToSic.Sxc.Edit;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Web.JsContext;\n\nnamespace ToSic.Sxc.Mvc.Web\n{\n    public class MvcPageProperties: HasLog\n    {\n        private readonly JsApiCache _jsApiCache;\n\n        #region Constructor and DI\n\n        public MvcPageProperties(JsApiCache jsApiCache) : base(\"Mvc.PgProp\")\n        {\n            _jsApiCache = jsApiCache;\n        }\n\n        #endregion\n\n        public bool AddContextMeta = true;\n\n        public bool AddJsCore = true;\n        //public bool AddJsAdvanced = true;\n        public bool AddCmsJs = true;\n        public bool AddCmsCss = true;\n\n        public string Headers = \"\";\n\n\n        public HtmlString FinalHeaders()\n        {\n            var headers = new StringBuilder();\n            headers.AppendLine(\"<!-- 2sxc headers -->\");\n            if (AddContextMeta) headers.AppendLine(ContextHeader());\n            if(AddJsCore) headers.AppendLine(Tag.Script().Src($\"{MvcConstants.UiRoot}{InpageCms.CoreJs}\").ToString());\n            if(AddCmsJs) headers.AppendLine(Tag.Script().Src($\"{MvcConstants.UiRoot}{InpageCms.EditJs}\").ToString());\n            if(AddCmsCss) headers.AppendLine(Tag.Link().Href($\"{MvcConstants.UiRoot}{InpageCms.EditCss}\").Rel(\"stylesheet\").ToString());\n            headers.AppendLine($\"<meta />{Headers}<!-- end -->\");\n            return new HtmlString(headers.ToString());\n        }\n\n        public HtmlString FinalFooter()\n        {\n            return new HtmlString(\"<!-- footer from PageManager - should later contain the scripts etc.\");\n        }\n\n\n        public string ContextHeader()\n        {\n            var wrapLog = Log.Fn<string>();\n\n            var pageId = 0;\n            var siteRoot = MvcConstants.SiteRoot;\n            var apiRoot = siteRoot + WebApi.WebApiConstants.WebApiRoot + \"/\";\n            var jsApiJson = _jsApiCache.JsApiJson(\n                platform: \"MVC\", \n                pageId: pageId, \n                siteRoot: () => siteRoot, \n                apiRoot: () => apiRoot, \n                appApiRoot: () => apiRoot,\n                uiRoot: () => \"TODO\",\n                rvtHeader: \"TODO\",\n                rvt: AntiForgeryToken,\n                dialogQuery: MvcConstants.UiRoot);\n            var json = InpageCms.JsApiJson(jsApiJson);\n\n            var meta = Tag.Meta().Name(InpageCms.MetaName).Content(json).ToString();\n\n            return wrapLog.ReturnAndLog(meta);\n        }\n\n        private string AntiForgeryToken()\n        {\n            return \"anti forgery token todo\";\n        }\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/Adam/AdamController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Lib.Logging;\nusing ToSic.Eav.WebApi.Adam;\nusing ToSic.Eav.WebApi.Dto;\nusing ToSic.Eav.WebApi.Errors;\nusing ToSic.Eav.WebApi.PublicApi;\nusing ToSic.Sxc.WebApi.Adam;\nusing ToSic.Sxc.WebApi.PublicApi;\n\n// #todo: security checks on APIs still completely missing\n// #todo: upload not implemented yet\n\nnamespace ToSic.Sxc.Mvc.WebApi.Adam\n{\n    /// <summary>\n    /// Direct access to app-content items, simple manipulations etc.\n    /// Should check for security at each standard call - to see if the current user may do this\n    /// Then we can reduce security access level to anonymous, because each method will do the security check\n    /// </summary>\n    [ApiController]\n    [Route(WebApiConstants.WebApiRoot + \"/app-content/{contentType}/{guid}/{field}/\")]\n    public class AdamController : SxcStatefulControllerBase, IAdamController<int>\n    {\n        private readonly AdamTransUpload<int, int> _adamUpload;\n        private readonly AdamTransGetItems<string, string> _adamItems;\n        private readonly AdamTransFolder<string, string> _adamFolders;\n        private readonly AdamTransDelete<string, string> _adamDelete;\n        private readonly AdamTransRename<string, string> _adamRename;\n\n        #region Constructor / DI\n\n        protected override string HistoryLogName => \"Api.Adam\";\n\n        public AdamController(AdamTransUpload<int, int> adamUpload, \n            AdamTransGetItems<string, string> adamItems, \n            AdamTransFolder<string, string> adamFolders,\n            AdamTransDelete<string, string> adamDelete,\n         AdamTransRename<string, string> adamRename)\n        {\n            _adamUpload = adamUpload;\n            _adamItems = adamItems;\n            _adamFolders = adamFolders;\n            _adamDelete = adamDelete;\n            _adamRename = adamRename;\n        }\n\n        #endregion\n        [HttpPost]\n        [HttpPut]\n        public UploadResultDto Upload(int appId, string contentType, Guid guid, string field, string subFolder = \"\", bool usePortalRoot = false)\n        {\n            // wrap all of it in try/catch, to reformat error in better way for js to tell the user\n            try\n            {\n                // Check if the request contains multipart/form-data.\n                if (Request.Form.Files.Count < 1) // ..Content.IsMimeMultipartContent())\n                    return new UploadResultDto\n                    {\n                        Success = false,\n                        Error = \"doesn't look like a file-upload\"\n                    };\n\n                var filesCollection = Request.Form.Files;\n                if (filesCollection.Count <= 0)\n                {\n                    Log.A(\"Error, no files\");\n                    return new UploadResultDto { Success = false, Error = \"No file was uploaded.\" };\n                }\n\n                var originalFile = filesCollection[0];\n                var stream = originalFile.OpenReadStream();\n                var fileName = originalFile.FileName;\n                var uploader = _adamUpload.Init(appId, contentType, guid, field, usePortalRoot, Log);\n                return uploader.UploadOne(stream, subFolder, fileName);\n            }\n            catch (HttpExceptionAbstraction he)\n            {\n                return new UploadResultDto { Success = false, Error = he.Message };\n            }\n            catch (Exception e)\n            {\n                return new UploadResultDto { Success = false, Error = e.Message };\n            }\n        }\n\n\n        #region adam-file manager\n\n        // test method to provide a public API for accessing adam items easily\n        //[HttpGet]\n        //public IEnumerable<AdamItemDto> ItemsWithAppIdFromContext(string contentType, Guid guid, string field, string folder = \"\")\n        //{\n        //    // if app-path specified, use that app, otherwise use from context\n        //    var appId = GetBlock().AppId;\n        //    return Items(appId, contentType, guid, field, folder);\n        //}\n\n        [HttpGet(\"items\")]\n        public IEnumerable<AdamItemDto> Items(int appId, string contentType, Guid guid, string field, string subfolder, bool usePortalRoot = false)\n        {\n            var callLog = Log.Fn<IEnumerable<AdamItemDto>>($\"adam items a:{appId}, i:{guid}, field:{field}, subfolder:{subfolder}, useRoot:{usePortalRoot}\");\n            var results = _adamItems\n                .Init(appId, contentType, guid, field, usePortalRoot, Log)\n                .ItemsInField(subfolder);\n            return callLog.ReturnAsOk(results);\n        }\n\n        [HttpPost(\"folder\")]\n        public IEnumerable<AdamItemDto> Folder(int appId, string contentType, Guid guid, string field, string subfolder, string newFolder, bool usePortalRoot) \n            => _adamFolders\n                .Init(appId, contentType, guid, field, usePortalRoot, Log)\n                .Folder(subfolder, newFolder);\n\n        [HttpGet(\"delete\")]\n        public bool Delete(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, int id, bool usePortalRoot) \n            => _adamDelete\n                .Init(appId, contentType, guid, field, usePortalRoot, Log)\n                .Delete(subfolder, isFolder, id.ToString(), id.ToString());\n\n        [HttpGet(\"rename\")]\n        public bool Rename(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, int id, string newName, bool usePortalRoot) \n            => _adamRename\n                .Init(appId, contentType, guid, field, usePortalRoot, Log)\n                .Rename(subfolder, isFolder, id.ToString(), id.ToString(), newName);\n\n        #endregion\n\n    }\n}"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/App/AppDataController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.WebApi.App;\nusing ToSic.Sxc.WebApi.App;\n\n\n// TODO: #MissingFeature not yet implemented create/update/delete\n// TODO: #MissingFeature not yet implemented GetContext using current context\n\nnamespace ToSic.Sxc.Mvc.WebApi.App\n{\n    [ApiController]\n    [Route(WebApiConstants.WebApiRoot + \"/app/{appPath}/content/\")]\n    public class AppDataController: SxcStatefulControllerBase, IAppDataController\n    {\n        #region DI / Constructor\n        protected override string HistoryLogName => WebApiConstants.MvcApiLogPrefix + \"AppCnt\";\n        \n        #endregion\n\n        #region Get List / all of a certain content-type\n        /// <summary>\n        /// Get all Entities of specified Type\n        /// </summary>\n        [HttpGet(\"{contentType}\")]\n        [AllowAnonymous]   // will check security internally, so assume no requirements\n        public IEnumerable<Dictionary<string, object>> GetEntities(string contentType, string appPath = null)\n            => Eav.Factory.Resolve<AppContent>().Init(appPath, Log).GetItems(contentType, appPath);\n\n        #endregion\n\n\n        #region GetOne by ID / GUID\n\n        [HttpGet(\"{contentType}/{id}\")]\n        [AllowAnonymous] // will check security internally, so assume no requirements\n        public Dictionary<string, object> GetOne(string contentType, string id, string appPath = null)\n        {\n            if(int.TryParse(id, out var intId))\n                return GetAndSerializeOneAfterSecurityChecks(contentType,\n                    entityApi => entityApi.GetOrThrow(contentType, intId), appPath);\n\n            if (Guid.TryParse(id, out var guid))\n                return GetAndSerializeOneAfterSecurityChecks(contentType,\n                    entityApi => entityApi.GetOrThrow(contentType, guid), appPath);\n\n            throw new Exception(\"id neither int/guid, can't process\");\n        }\n\n\n        /// <summary>\n        /// Preprocess security / context, then get the item based on an passed in method, \n        /// ...then process/finish\n        /// </summary>\n        /// <param name=\"contentType\"></param>\n        /// <param name=\"getOne\"></param>\n        /// <param name=\"appPath\"></param>\n        /// <returns></returns>\n        private Dictionary<string, object> GetAndSerializeOneAfterSecurityChecks(string contentType, Func<IEnumerable<IEntity>, IEntity> getOne, string appPath) \n            => Eav.Factory.Resolve<AppContent>().Init(appPath, Log).GetOne(contentType, getOne, appPath);\n\n        #endregion\n\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/App/AppQueryController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing System.Collections.Generic;\nusing ToSic.Eav.Plumbing;\nusing ToSic.Eav.WebApi.Admin.App;\n\n// TODO: #MissingFeature\n// 1. Query from context / header\n// 2. GetContext using current context\n// 3. Verify that additional query params would affect query results\n\nnamespace ToSic.Sxc.Mvc.WebApi.App\n{\n    [Route(WebApiConstants.WebApiRoot + \"/app/{appPath}/query/\")]\n    [ApiController]\n    public class AppQueryController : SxcStatefulControllerBase, IAppQueryController\n    {\n        #region DI / Constructor\n        protected override string HistoryLogName => \"App.AppQry\";\n\n        #endregion\n\n\n        [HttpGet(\"{name}\")]\n        [HttpPost(\"{name}\")]\n        public Dictionary<string, IEnumerable<Dictionary<string, object>>> Query(\n            string name,\n            AppQueryParameters more,\n            bool includeGuid = false,\n            string stream = null,\n            int? appId = null\n        ) => HttpContext.RequestServices.Build<AppQuery>().Init(Log).Query(appId, name, includeGuid, stream, more);\n\n        [HttpGet(\"{name}\")]\n        [HttpPost(\"{name}\")]\n        public Dictionary<string, IEnumerable<Dictionary<string, object>>> PublicQuery(\n            string appPath,\n            string name,\n            AppQueryParameters more,\n            [FromQuery] string stream = null\n        ) => HttpContext.RequestServices.Build<AppQuery>().Init(Log).PublicQuery(appPath, name, stream, more);\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/Cms/EditController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Eav.WebApi.Dto;\nusing ToSic.Eav.WebApi.Formats;\nusing ToSic.Eav.WebApi.PublicApi;\nusing ToSic.Sxc.Mvc.WebApi.Context;\nusing ToSic.Sxc.WebApi.Cms;\n\nnamespace ToSic.Sxc.Mvc.WebApi.Cms\n{\n    [Route(WebApiConstants.WebApiRoot + \"/cms/edit/[action]\")]\n    [ApiController]\n    public class EditController: SxcStatefulControllerBase, IEditController\n    {\n        #region DI\n        protected override string HistoryLogName => WebApiConstants.MvcApiLogPrefix + \"UiCntr\";\n\n        public EditController(MvcContextBuilder contextBuilder, \n            Lazy<EntityPickerBackend> entityBackend, \n            Lazy<EditLoadBackend> loadBackend,\n            Lazy<EditSaveBackend> saveBackendLazy,\n            Lazy<HyperlinkBackend<int, int>> linkBackendLazy)\n        {\n            _contextBuilder = contextBuilder;\n            _entityBackend = entityBackend;\n            _loadBackend = loadBackend;\n            _saveBackendLazy = saveBackendLazy;\n            _linkBackendLazy = linkBackendLazy;\n        }\n\n        private readonly MvcContextBuilder _contextBuilder;\n        private readonly Lazy<EntityPickerBackend> _entityBackend;\n        private readonly Lazy<EditLoadBackend> _loadBackend;\n        private readonly Lazy<EditSaveBackend> _saveBackendLazy;\n        private readonly Lazy<HyperlinkBackend<int, int>> _linkBackendLazy;\n        private EntityPickerBackend EntityBackend => _entityBackend.Value;\n\n        #endregion\n\n\n        [HttpGet]\n        [AllowAnonymous]   // will check security internally, so assume no requirements\n        public string Ping() => \"test ping\";\n\n        [HttpPost]\n        [AllowAnonymous]   // will check security internally, so assume no requirements\n        public EditDto Load([FromBody] List<ItemIdentifier> items, int appId)\n        {\n            var context = GetContext();\n            var block = GetBlock();\n            var result = _loadBackend.Value\n                .Init(Log)\n                .Load(appId, items);\n            return result;\n        }\n\n        [HttpPost]\n        // todo #mvcSec [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n        public Dictionary<Guid, int> Save([FromBody] EditDto package, int appId, bool partOfPage)\n            => _saveBackendLazy.Value.Init(appId, Log).Save(package, partOfPage);\n\n        [HttpGet]\n        [HttpPost]\n        [AllowAnonymous] // security check happens internally\n        public IEnumerable<EntityForPickerDto> EntityPicker(int appId, [FromBody] string[] items, string contentTypeName = null)\n            => EntityBackend.Init(Log).GetAvailableEntities(appId, items, contentTypeName);\n\n        // 2021-04-13 2dm should be unused now\n        ///// <inheritdoc />\n        //[HttpGet]\n        //// [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n        //public string LookupLink(string link, int appId, string contentType = default, Guid guid = default, string field = default)\n        //    => _linkBackendLazy.Value.Init(Log).ResolveHyperlink(appId, link, contentType, guid, field);\n\n        /// <inheritdoc />\n        [HttpGet]\n        //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n        public LinkInfoDto LinkInfo(string link, int appId, string contentType = default, Guid guid = default, string field = default)\n            => _linkBackendLazy.Value.Init(Log).LookupHyperlink(appId, link, contentType, guid, field);\n\n        /// <inheritdoc />\n        [HttpPost]\n        //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n        public bool Publish(int id)\n            => false /*Real.Publish(id)*/; // TODO\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/Context/MvcContextBuilder.cs",
    "content": "﻿using System.Collections.Generic;\nusing ToSic.Eav.Apps.Run;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.WebApi.Dto;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Mvc.Dev;\nusing ToSic.Sxc.Run;\n\nusing ToSic.Sxc.WebApi.Context;\n\nnamespace ToSic.Sxc.Mvc.WebApi.Context\n{\n    public class MvcContextBuilder: UiContextBuilderBase\n    {\n        public MvcContextBuilder(ILinkPaths linkPaths, Dependencies deps) : base(deps)\n        {\n            _linkPaths = linkPaths;\n        }\n\n        internal MvcContextBuilder Init(IBlock block)\n        {\n            _context = block.Context;\n            SetZoneAndApp(block.ZoneId, block.App);\n            return this;\n        }\n\n        private readonly ILinkPaths _linkPaths;\n        private IContextOfBlock _context;\n\n\n        protected override LanguageDto GetLanguage()\n        {\n            return new LanguageDto\n            {\n                Current = TestIds.DefaultLanguage,\n                Primary = TestIds.DefaultLanguage,\n                All = new Dictionary<string, string>\n                {\n                    {TestIds.DefaultLanguage, TestIds.DefaultLanguageText}\n                }\n            };\n        }\n\n        protected override WebResourceDto GetSystem() =>\n            new WebResourceDto\n            {\n                Url = _linkPaths.ToAbsolute(\"~/\")\n            };\n\n        protected override WebResourceDto GetSite() =>\n            new WebResourceDto\n            {\n                Id = _context.Site.Id,\n                Url = \"//\" + _context.Site.Url,\n            };\n\n        protected override WebResourceDto GetPage() =>\n            new WebResourceDto\n            {\n                Id = _context.Page.Id,\n            };\n\n        protected override EnableDto GetEnable()\n        {\n            return new EnableDto\n            {\n                AppPermissions = true,\n                CodeEditor = true,\n                Query = true\n            };\n        }\n\n        protected override string GetGettingStartedUrl() => \"#todo-not-yet-implemented-getting-started\";\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/SxcStatefullControllerBase.cs",
    "content": "﻿using System;\nusing Microsoft.Extensions.Primitives;\nusing ToSic.Eav.Apps;\nusing ToSic.Lib.Logging;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Plumbing;\nusing ToSic.Lib.DI;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Mvc.Dev;\n\n\nnamespace ToSic.Sxc.Mvc.WebApi\n{\n    public abstract class SxcStatefulControllerBase: SxcStatelessControllerBase\n    {\n        protected IContextOfSite GetSiteContext()\n        {\n            return HttpContext.RequestServices.Build<IContextOfSite>();\n        }\n\n\n        protected IContextOfApp GetAppContext(int appId)\n        {\n            // First get a normal basic context which is initialized with site, etc.\n            var appContext = HttpContext.RequestServices.Build<IContextOfApp>();\n            appContext.Init(Log);\n            appContext.ResetApp(appId);\n            return appContext;\n        }\n\n        protected IContextOfBlock GetContext()\n        {\n            //var publishing = HttpContext.RequestServices.Build<IPagePublishingResolver>();\n\n            // in case the initial request didn't yet find a block builder, we need to create it now\n            //var site = HttpContext.RequestServices.Build<ISite>().Init(TestIds.PrimaryZone);\n            var ctx = HttpContext.RequestServices.Build<IContextOfBlock>();\n            ctx.Init(Log);\n            ctx.Site.Init(TestIds.PrimaryZone);\n            //ctx.Init(new PageNull(), new ContainerNull());\n            //var context = // BlockBuilder?.Context ??\n            //    new ContextOfBlock(HttpContext.RequestServices, site, new MvcUser())\n            //        .Init(new PageNull(), new ContainerNull(), new BlockPublishingState());\n            return ctx;\n        }\n\n        protected IBlock GetBlock(bool allowNoContextFound = true)\n        {\n            var wrapLog = Log.Fn<IBlock>(parameters: $\"request:..., {nameof(allowNoContextFound)}: {allowNoContextFound}\");\n\n            var containerId = GetTypedHeader(Sxc.WebApi.WebApiConstants.HeaderInstanceId, -1);\n            var contentblockId = GetTypedHeader(Sxc.WebApi.WebApiConstants.HeaderContentBlockId, 0); // this can be negative, so use 0\n            var pageId = GetTypedHeader(Sxc.WebApi.WebApiConstants.HeaderPageId, -1);\n            var instance = TestIds.FindInstance(containerId);\n\n            if (containerId == -1 || pageId == -1 || instance == null)\n            {\n                if (allowNoContextFound) return wrapLog.ReturnNull(\"not found\");\n                throw new Exception(\"No context found, cannot continue\");\n            }\n\n            var ctx = SxcMvc.CreateContext(HttpContext.RequestServices, instance.Zone, pageId, containerId, instance.App,\n                instance.Block);\n            IBlock block = HttpContext.RequestServices.Build<BlockFromModule>().Init(ctx, Log);\n\n            // only if it's negative, do we load the inner block\n            if (contentblockId > 0) return wrapLog.Return(block, \"found\");\n\n            Log.A($\"Inner Content: {contentblockId}\");\n            block = HttpContext.RequestServices.Build<BlockFromEntity>().Init(block, contentblockId, Log);\n\n            return wrapLog.Return(block, \"found\");\n        }\n\n        private T GetTypedHeader<T>(string headerName, T fallback)\n        {\n            var valueString = Request.Headers[headerName];\n            if (valueString == StringValues.Empty) return fallback;\n\n            try\n            {\n                return (T) Convert.ChangeType(valueString.ToString(), typeof(T));\n            }\n            catch\n            {\n                return fallback;\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/SxcStatelessControllerBase.cs",
    "content": "﻿using System;\nusing Microsoft.AspNetCore.Http.Extensions;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Lib.Logging;\nusing ToSic.Sxc.Blocks;\n\nnamespace ToSic.Sxc.Mvc.WebApi\n{\n    public abstract class SxcStatelessControllerBase : ControllerBase, IHasLog\n    {\n        protected SxcStatelessControllerBase()\n        {\n            // ReSharper disable once VirtualMemberCallInConstructor\n            // todo: redesign so it works - in .net core the HttpContext isn't ready in the constructor\n            Log = new Log(HistoryLogName, null, $\"Path: {HttpContext?.Request.GetDisplayUrl()}\");\n            //TimerWrapLog = Log.Call(message: \"timer\", useTimer: true);\n            GetService<LogHistory>().Add(HistoryLogGroup, Log);\n            // register for dispose / stopping the timer at the end\n            _logWrapper = new LogWrapper(Log);\n            // todo: get this to work\n            // ControllerContext.HttpContext.Response.RegisterForDispose(_logWrapper);\n        }\n\n        #region Dummy Content-Block, as still stateless\n\n        protected IBlock NoBlock => null;\n\n        #endregion\n\n        /// <inheritdoc />\n        public ILog Log { get; }\n\n        private readonly LogWrapper _logWrapper;\n\n        /// <summary>\n        /// The group name for log entries in insights.\n        /// Helps group various calls by use case. \n        /// </summary>\n        protected virtual string HistoryLogGroup { get; } = \"web-api\";\n\n        /// <summary>\n        /// The name of the logger in insights.\n        /// The inheriting class should provide the real name to be used.\n        /// </summary>\n        protected abstract string HistoryLogName { get; }\n\n        //protected void Dispose(bool disposing)\n        //{\n        //    TimerWrapLog(null);\n        //    base.Dispose(disposing);\n        //}\n\n    }\n\n    internal class LogWrapper: IDisposable\n    {\n        private readonly LogCall _timerWrapLog;\n\n        internal LogWrapper(ILog log) => _timerWrapLog = log.Fn(message: \"timer\", startTimer: true);\n        public void Dispose() => _timerWrapLog.Done();\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/System/InsightsController.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Sxc.Web.WebApi.System;\n\nnamespace ToSic.Sxc.Mvc.WebApi.System\n{\n    [Route(WebApiConstants.WebApiDefaultRoute)]\n    [ApiController]\n    public class InsightsController : SxcStatelessControllerBase\n    {\n        private readonly Lazy<Insights> _lazyInsights;\n\n        #region Logging aspects\n\n         protected override string HistoryLogName => \"Api.Debug\";\n\n        /// <summary>\n        /// Make sure that these requests don't land in the normal api-log.\n        /// Otherwise each log-access would re-number what item we're looking at\n        /// </summary>\n        protected override string HistoryLogGroup { get; } = \"web-api.insights\";\n       \n        #endregion\n\n        /// <summary>\n        /// Enable/disable logging of access to insights\n        /// Only enable this if you have trouble developing insights, otherwise it clutters our logs\n        /// </summary>\n        internal const bool InsightsLoggingEnabled = false;\n\n        //internal const string InsightsUrlFragment = \"/sys/insights/\";\n\n\n        #region Construction and Security\n\n        public InsightsController(Lazy<Insights> lazyInsights)\n        {\n            _lazyInsights = lazyInsights;\n        }\n\n        protected Insights Insights => _insights ??= _lazyInsights.Value.Init(Log, ThrowIfNotSuperuser, msg => new Exception(msg));\n        private Insights _insights;\n\n\n        private void ThrowIfNotSuperuser()\n        {\n            // todo: security relevant before final release\n            //if (!PortalSettings.UserInfo.IsSuperUser)\n            //    throw Http.PermissionDenied(\"requires Superuser permissions\");\n        }\n\n        #endregion\n\n        private ContentResult Wrap(string contents) => base.Content(contents, \"text/html\");\n\n\n        #region Help and Basics\n\n        [HttpGet]\n        public ContentResult Help() => Wrap(Insights.Help());\n\n        [HttpGet]\n        public ContentResult IsAlive() => Wrap(Insights.IsAlive().ToString());\n\n        #endregion\n\n        #region App\n        [HttpGet]\n        public ContentResult LoadLog(int? appId = null) => Wrap(Insights.LoadLog(appId));\n\n        [HttpGet]\n        public ContentResult Cache() => Wrap(Insights.Cache());\n\n        [HttpGet]\n        public ContentResult Stats(int? appId = null) => Wrap(Insights.Stats(appId));\n        #endregion\n\n        #region Logs\n\n        /// <summary>\n        /// Logs is different from the WebForms implementation, because route detection isn't as rigid in .net core\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <param name=\"position\"></param>\n        /// <param name=\"pause\"></param>\n        /// <returns></returns>\n        [HttpGet]\n        public ContentResult Logs([FromQuery]string key, [FromQuery] int? position, [FromQuery] bool? pause)\n        {\n            // pause command, in this case it's the only parameter\n            if (pause != null) return Wrap(Insights.Logs(pause.Value));\n\n            if (key == null) return Wrap(Insights.Logs());\n            if (position == null) return Wrap(Insights.Logs(key));\n            return Wrap(Insights.Logs(key, position.Value));\n        }\n\n        [HttpGet]\n        public ContentResult LogsFlush(string key) => Wrap(Insights.LogsFlush(key));\n        #endregion\n\n        #region AppActions\n\n        [HttpGet]\n        public ContentResult Purge(int? appId = null) => Wrap(Insights.Purge(appId));\n\n        #endregion\n\n        #region Attributes\n\n        [HttpGet]\n        public ContentResult Attributes(int appId, string type = null) => Wrap(Insights.Attributes(appId, type));\n\n        [HttpGet]\n        public ContentResult AttributeMetadata(int? appId = null, string type = null, string attribute = null) =>\n            Wrap(Insights.AttributeMetadata(appId, type, attribute));\n\n        [HttpGet]\n        public ContentResult AttributePermissions(int? appId = null, string type = null, string attribute = null) =>\n            Wrap(Insights.AttributePermissions(appId, type, attribute));\n\n        #endregion\n\n\n        #region Entities\n\n        [HttpGet]\n        public ContentResult Entities(int? appId = null, string type = null) => Wrap(Insights.Entities(appId, type));\n\n        [HttpGet]\n        public ContentResult EntityMetadata(int? appId = null, int? entity = null) => Wrap(Insights.EntityMetadata(appId, entity));\n\n        [HttpGet]\n        public ContentResult EntityPermissions(int? appId = null, int? entity = null) =>\n            Wrap(Insights.EntityPermissions(appId, entity));\n\n        [HttpGet]\n        public ContentResult Entity(int? appId = null, string entity = null) => Wrap(Insights.Entity(appId, entity));\n        #endregion\n\n\n        #region Types\n\n        [HttpGet]\n        public ContentResult Types(int? appId = null, bool detailed = false) => Wrap(Insights.Types(appId, detailed));\n\n        [HttpGet]\n        public ContentResult GlobalTypes() => Wrap(Insights.GlobalTypes());\n\n        [HttpGet]\n        public ContentResult GlobalTypesLog() => Wrap(Insights.GlobalTypesLog());\n\n        [HttpGet]\n        public ContentResult TypeMetadata(int? appId = null, string type = null) => Wrap(Insights.TypeMetadata(appId, type));\n\n        [HttpGet]\n        public ContentResult TypePermissions(int? appId = null, string type = null) => Wrap(Insights.TypePermissions(appId, type));\n        #endregion\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/ToSic.Sxc.Mvc/WebApi/WebApiConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Mvc.WebApi\n{\n    public class WebApiConstants: ToSic.Sxc.WebApi.WebApiConstants\n    {\n        public const string WebApiRoot = \"api/sxc\";\n        public const string WebApiDefaultRoute = WebApiRoot + \"/[controller]/[action]\";\n\n        public const string MvcApiLogPrefix = \"MAP.\";\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Exp/PageBaseLoadingBlogOnly.cs",
    "content": "﻿using ToSic.Lib.Logging;\nusing ToSic.Eav.Plumbing;\nusing ToSic.Lib.DI;\n\nnamespace ToSic.Sxc.Mvc.RazorPages.Exp\n{\n    public abstract partial class PageBaseLoadingBlogOnly: Microsoft.AspNetCore.Mvc.RazorPages.Page, IHasLog\n    {\n        public TService GetService<TService>() => HttpContext.RequestServices.Build<TService>();\n\n        #region Constructor / DI\n        protected PageBaseLoadingBlogOnly()\n        {\n            Log = new Log(\"Mvc.Page\");\n        }\n        public ILog Log { get; }\n        #endregion\n\n\n        public string Hi() => \"hi\";\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Exp/PageBaseLoadingBlogOnly_Block.cs",
    "content": "﻿using ToSic.Eav.Plumbing;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Mvc.Dev;\n\n\nnamespace ToSic.Sxc.Mvc.RazorPages.Exp\n{\n    public partial class PageBaseLoadingBlogOnly\n    {\n        #region DynCode \n\n        public Sxc.Code.IDynamicCodeRoot _DynCodeRoot => _dynCode ??= HttpContext.RequestServices.Build<Code.DynamicCodeRoot>().Init(Block, Log);\n        private Sxc.Code.IDynamicCodeRoot _dynCode;\n        #endregion\n        public IBlock Block \n        {\n            get\n            {\n                if (_blockLoaded) return _block;\n                _blockLoaded = true;\n\n                var ctx = GetService<IContextOfBlock>();\n                ctx.Init(Log);\n                ctx.Site.Init(TestIds.PrimaryZone);\n                ctx.Site.Init(0);\n\n                //var context = new ContextOfBlock(\n                //    ServiceProvider,\n                //    ServiceProvider.Build<ISite>().Init(TestIds.PrimaryZone),\n                //    new MvcUser()\n                //).Init(\n                //    ServiceProvider.Build<SxcPage>().Init(0),\n                //    new MvcContainer(),\n                //    new BlockPublishingState()\n                //    );\n                _block = GetService<BlockFromModule>().Init(ctx, Log);\n                return _block;\n            }\n        }\n        private IBlock _block;\n        private bool _blockLoaded;\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Exp/PageBaseLoadingBlogOnly_CreateInstance.cs",
    "content": "﻿using System;\n\nnamespace ToSic.Sxc.Mvc.RazorPages.Exp\n{\n    public partial class PageBaseLoadingBlogOnly\n    {\n        public string CreateInstancePath { get; set; }\n\n        /// <summary>\n        /// Creates instances of the shared pages with the given relative path\n        /// </summary>\n        /// <returns></returns>\n        public dynamic CreateInstance(string virtualPath,\n            string dontRelyOnParameterOrder = Eav.Constants.RandomProtectionParameter,\n            string name = null,\n            string relativePath = null,\n            bool throwOnError = true)\n        {\n            throw new NotImplementedException();\n            //var path = NormalizePath(virtualPath);\n            //VerifyFileExists(path);\n            //return path.EndsWith(CodeCompiler.CsFileExtension)\n            //    ? DynCode.CreateInstance(path, dontRelyOnParameterOrder, name, null, throwOnError)\n            //    : CreateInstanceCshtml(path);\n        }\n\n        protected dynamic CreateInstanceCshtml(string path)\n        {\n            throw new NotImplementedException();\n            //var webPage = (RazorComponentBase)CreateInstanceFromVirtualPath(path);\n            //webPage.ConfigurePage(this);\n            //return webPage;\n        }\n\n        protected static void VerifyFileExists(string path)\n        {\n            throw new NotImplementedException();\n            //if (!File.Exists(HostingEnvironment.MapPath(path)))\n            //    throw new FileNotFoundException(\"The shared file does not exist.\", path);\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Exp/PageBaseLoadingBlogOnly_IDynamicCode.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.DataSources;\nusing ToSic.Eav.LookUp;\nusing ToSic.Lib.Documentation;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.DataSources;\n\nusing ToSic.Sxc.Web;\n\nnamespace ToSic.Sxc.Mvc.RazorPages.Exp\n{\n    public partial class PageBaseLoadingBlogOnly: IDynamicCode\n    {\n\n        #region Content, Header, etc. and List\n        /// <inheritdoc/>\n        public new dynamic Content => _DynCodeRoot.Content;\n\n        /// <inheritdoc />\n        public dynamic Header => _DynCodeRoot.Header;\n\n        #endregion\n\n\n        #region Link, Edit, App, Data\n\n        /// <inheritdoc />\n        public ILinkHelper Link => _DynCodeRoot.Link;\n\n        /// <inheritdoc />\n        public IInPageEditingSystem Edit => _DynCodeRoot.Edit;\n\n        [PrivateApi] public int CompatibilityLevel => _DynCodeRoot.CompatibilityLevel;\n\n        /// <inheritdoc />\n        public IApp App => _DynCodeRoot.App;\n\n        /// <inheritdoc />\n        public IBlockDataSource Data => _DynCodeRoot.Data;\n\n        #endregion\n\n        #region AsDynamic in many variations\n\n        /// <inheritdoc/>\n        public dynamic AsDynamic(string json, string fallback = DynamicJacket.EmptyJson) => _DynCodeRoot.AsDynamic(json, fallback);\n\n        /// <inheritdoc/>\n        public dynamic AsDynamic(IEntity entity) => _DynCodeRoot.AsDynamic(entity);\n\n        /// <inheritdoc/>\n        public dynamic AsDynamic(object dynamicEntity) => _DynCodeRoot.AsDynamic(dynamicEntity);\n\n\n        #endregion\n\n        #region AsEntity\n        /// <inheritdoc/>\n        public IEntity AsEntity(object dynamicEntity) => _DynCodeRoot.AsEntity(dynamicEntity);\n        #endregion\n\n        #region AsList\n\n        /// <inheritdoc />\n        public IEnumerable<dynamic> AsList(object list) => _DynCodeRoot?.AsList(list);\n\n        public T CreateSource<T>(IDataStream inStream) where T : IDataSource\n        {\n            throw new NotImplementedException();\n        }\n\n        public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = null) where T : IDataSource\n        {\n            throw new NotImplementedException();\n        }\n\n\n        #endregion\n\n\n\n        #region Adam \n\n        /// <inheritdoc />\n        public IFolder AsAdam(IDynamicEntity entity, string fieldName) => _DynCodeRoot.AsAdam(entity, fieldName);\n\n\n        /// <inheritdoc />\n        public IFolder AsAdam(IEntity entity, string fieldName) => _DynCodeRoot.AsAdam(entity, fieldName);\n\n        #endregion\n\n        #region RunContext - new in 11.08 or similar, not implemented in old base classes\n\n        public ICmsContext CmsContext => _DynCodeRoot.CmsContext;\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Exp/SxcTestPageViewParams.cs",
    "content": "﻿using System;\nusing Microsoft.AspNetCore.Mvc.Razor.Internal;\nusing ToSic.Custom;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Mvc.Dev;\n\nnamespace ToSic.Sxc.Mvc.RazorPages.Exp\n{\n    public abstract class SxcTestPageViewParams<TModel>: Razor12<TModel>\n    {\n        [RazorInject]\n        public SxcMvc SxcMvc { get; set; }\n\n        protected SxcTestPageViewParams(/*SxcMvc sxcMvc*/)\n        {\n            Log.Rename(\"Mvc.SxcRzr\");\n            //_sxcMvc = sxcMvc;\n        }\n\n        #region Properties to identify the block\n\n        public int Id => _id ?? (_id = GetNumberFromViewData(\"Id\")).Value;\n        private int? _id;\n\n        public int PageId => _pageId ?? (_pageId = GetNumberFromViewData(\"PageId\")).Value;\n        private int? _pageId;\n\n        public int AppId => _appId ?? (_appId = GetNumberFromViewData(\"AppId\")).Value;\n        private int? _appId;\n\n        public Guid BlockGuid => _blockGuid ?? (_blockGuid = GetGuidFromViewData(\"Block\")).Value;\n        private Guid? _blockGuid;\n\n        private int GetNumberFromViewData(string name)\n        {\n            object idObj = null;\n            ViewData?.TryGetValue(name, out idObj);\n            int.TryParse(idObj?.ToString(), out var tempId);\n            return tempId;\n        }\n        private Guid GetGuidFromViewData(string name)\n        {\n            object idObj = null;\n            ViewData?.TryGetValue(name, out idObj);\n            Guid.TryParse(idObj?.ToString(), out var tempId);\n            return tempId;\n        }\n\n        #endregion\n\n\n        //public override IBlock Block \n        //{\n        //    get\n        //    {\n        //        if (_block != null) return _block;\n        //        _block = SxcMvc.CreateBlock(TestIds.PrimaryZone, PageId, Id, AppId, BlockGuid, Log);\n        //        return _block;\n        //    }\n        //}\n\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Components/First.cshtml",
    "content": "﻿@{\n    ViewData[\"Title\"] = \"FirstViewComponent\";\n}\n\n<h1>FirstViewComponent</h1>\n\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Engine/Blog.cshtml",
    "content": "﻿@page\n@using ToSic.Sxc.Mvc\n@using ToSic.Sxc.Mvc.Dev\n@inject SxcMvc SxcEngine\n@model Website.Pages.EngineBlogModel\n@{\n    ViewData[\"Title\"] = \"EngineBlog\";\n}\n\n<h1>Engine calling Blog Instance</h1>\n\nRender: @SxcEngine.Render(TestIds.Blog)\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Engine/Blog.cshtml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace Website.Pages\n{\n    public class EngineBlogModel : PageModel\n    {\n        public void OnGet()\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Engine/TokenApp.cshtml",
    "content": "﻿@page\n@using ToSic.Sxc.Mvc\n@using ToSic.Sxc.Mvc.Dev\n@model Website.Pages.TokenModel\n@inject SxcMvc SxcEngine\n@{\n    ViewData[\"Title\"] = \"Token\";\n}\n\n<h1>Engine Token App test</h1>\n\nRender: @SxcEngine.Render(TestIds.Token)\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Engine/TokenApp.cshtml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace Website.Pages\n{\n    public class TokenModel : PageModel\n    {\n        public void OnGet()\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Error.cshtml",
    "content": "﻿@page\n@model ErrorModel\n@{\n    ViewData[\"Title\"] = \"Error\";\n}\n\n<h1 class=\"text-danger\">Error.</h1>\n<h2 class=\"text-danger\">An error occurred while processing your request.</h2>\n\n@if (Model.ShowRequestId)\n{\n    <p>\n        <strong>Request ID:</strong> <code>@Model.RequestId</code>\n    </p>\n}\n\n<h3>Development Mode</h3>\n<p>\n    Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.\n</p>\n<p>\n    <strong>The Development environment shouldn't be enabled for deployed applications.</strong>\n    It can result in displaying sensitive information from exceptions to end users.\n    For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>\n    and restarting the app.\n</p>\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Error.cshtml.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.Extensions.Logging;\n\nnamespace Website.Pages\n{\n    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]\n    public class ErrorModel : PageModel\n    {\n        public string RequestId { get; set; }\n\n        public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);\n\n        private readonly ILogger<ErrorModel> _logger;\n\n        public ErrorModel(ILogger<ErrorModel> logger)\n        {\n            _logger = logger;\n        }\n\n        public void OnGet()\n        {\n            RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/Eav/EavCore.cshtml",
    "content": "﻿@page\n@using ToSic.Eav.Persistence.Efc.Models\n@using ToSic.Eav.Plumbing\n@model Website.Pages.EavCoreModel\n@{\n    ViewData[\"Title\"] = \"Eav.Core\";\n}\n\n<h1>Eav.Core and Basic \"the DLLs are Here\"</h1>\n\n<ol>\n    <li>\n        An EAV Constant: @ToSic.Eav.Constants.ContentAppName\n    </li>\n    <li>\n        A DataSource Object: @(HttpContext.RequestServices.Build<ToSic.Eav.DataSources.DataSourceFactory>().GetType().AssemblyQualifiedName)\n    </li>\n    <li>\n        Repository type Code: @(ToSic.Eav.Repositories.RepositoryTypes.Code)\n    </li>\n    <li>\n        2sxc constant: @(ToSic.Sxc.Settings.PortalHostDirectory)\n    </li>\n    <li>\n        App Cache: @(ToSic.Eav.Factory.Resolve<ToSic.Eav.Caching.IAppsCache>().GetType().Name)\n    </li>\n    <li>\n        EavDbContext (transient...?) : @(ToSic.Eav.Factory.Resolve<EavDbContext>().GetType().Namespace)\n    </li>\n</ol>\n<h2>State of App 4 (Blog)</h2>\n\n<ol>\n    <li>\n        Timestamp : @(ToSic.Eav.Apps.State.Get(4).CacheTimestamp)\n    </li>\n    <li>\n        Items in it : @(ToSic.Eav.Apps.State.Get(4).List.Count)\n    </li>\n    <li>\n        First Item: Guid @(Model.EntityInBlog.EntityGuid) <br/>\n        Title: @Model.EntityInBlog.GetBestTitle() <br/>\n        Query AllQueries: @ToSic.Eav.Apps.State.Get(4)  can't work yet, this object doesn't have queries!\n    </li>\n    <li>\n        Blog DS = @Model.BlogRoot().List.Count()\n    </li>\n    <li>\n        blog tags: @Model.BlogTags().List.Count() <br/>\n        first: @Model.BlogTags().List.FirstOrDefault()?.GetBestTitle()\n    </li>\n    <li>\n        App: @Model.BlogApp.AppGuid <br/>\n        Folder: @Model.BlogApp.Folder <br/>\n        Data: @Model.BlogApp.Data.List.Count() <br/>\n        Query: @*@Model.BlogApp.Query[\"AllQueries\"].List.Count()*@ not working at TONCIP51 (probabliy old blog app)\n    </li>\n</ol>\n\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/Eav/EavCore.cshtml.cs",
    "content": "﻿using System.Linq;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.DataSources;\nusing ToSic.Eav.LookUp;\nusing ToSic.Eav.Plumbing;\nusing ToSic.Eav.Run;\nusing ToSic.Sxc.Mvc.Dev;\nusing ToSic.Sxc.Mvc.Run;\n\nnamespace Website.Pages\n{\n    public class EavCoreModel : PageModel\n    {\n        public DataSourceFactory DataSourceFactory { get; }\n        protected const int ZoneId = 2;\n        protected const int AppId = 4;\n\n        public EavCoreModel(DataSourceFactory dataSourceFactory)\n        {\n            DataSourceFactory = dataSourceFactory;\n        }\n\n\n        public void OnGet()\n        {\n            EntityInBlog = State.Get(AppId).List.First();\n        }\n\n        public IEntity EntityInBlog;\n\n        private ILookUpEngine ConfigProvider => new LookUpEngine(null);\n\n        public IDataSource BlogRoot()\n        {\n            return DataSourceFactory.GetDataSource<IAppRoot>(new AppIdentity(ZoneId, AppId), null, ConfigProvider);\n        }\n\n        public IDataSource BlogTags()\n        {\n            var dsBlog = BlogRoot();\n            var dsFilter = DataSourceFactory.GetDataSource<EntityTypeFilter>(dsBlog, dsBlog);\n            dsFilter.TypeName = \"Tag\";\n            return dsFilter;\n        }\n\n        public IApp BlogApp => _blogApp ??= ToSic.Sxc.Mvc.Factory.App(ZoneId, AppId, DataSourceFactory.ServiceProvider.Build<ISite>().Init(TestIds.PrimaryZone), false, null);\n        private IApp _blogApp;\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/Eav/EavDi.cshtml",
    "content": "﻿@page\n@model Website.Pages.EavDiModel\n@{\n    ViewData[\"Title\"] = \"EavDi\";\n}\n\n<h1>Eav Dependency Injections</h1>\n\n\n<h2>MapPath and more</h2>\n<ol>\n    <li>\n        MapPath(2sxc): @Model.ServerPaths.FullAppPath(\"2sxc\");\n    </li>\n    <li>\n        ToAbsolute(2sxc): @Model.LinkPaths.ToAbsolute(\"2sxc\"); <br />\n        ToAbsolute(\"~/2sxc\"): @Model.LinkPaths.ToAbsolute(\"~/2sxc\") <br />\n        ToAbsolute(\"/2sxc\"): @Model.LinkPaths.ToAbsolute(\"/2sxc\")\n    </li>\n    <li>\n        Combine: @Model.LinkPaths.ToAbsolute(\"~/Portals/0\", \"2sxc\") <br/>\n        Combine: @Model.LinkPaths.ToAbsolute(\"/Portals/0/\", \"2sxc\") <br/>\n    </li>\n</ol>\n\n<h2>Inherits</h2>\n<ol>\n    <li>\n        Current Type: @GetType().FullName\n    </li>\n    <li>\n        Current Type: @GetType().BaseType.FullName\n    </li>\n</ol>"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/Eav/EavDi.cshtml.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Run;\nusing ToSic.Sxc.Run;\nusing ToSic.Sxc.Web;\n\nnamespace Website.Pages\n{\n    public class EavDiModel : PageModel\n    {\n        public EavDiModel(ISite site, IHttpContextAccessor httpC, IHttp http, IServerPaths serverPaths, ILinkPaths linkPaths)\n        {\n            // itenant should exist\n            var x = site.Id;\n            var y = httpC.HttpContext.Request.Body;\n            Http = http;\n            ServerPaths = serverPaths;\n            LinkPaths = linkPaths;\n        }\n\n        public IHttp Http;\n        public readonly IServerPaths ServerPaths;\n        public readonly ILinkPaths LinkPaths;\n\n\n        public void OnGet()\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/PreconfiguredBase/Blog.cshtml",
    "content": "﻿@page\n@inherits ToSic.Sxc.Mvc.RazorPages.Exp.PageBaseLoadingBlogOnly\n@model Website.Pages.SxcBlockModel\n@{\n    ViewData[\"Title\"] = \"SxcBlock\";\n}\n\n<h1>This initial page inherits the Class which only knows the blog instance</h1>\n<div>\n    testing... \n</div>\n\n<h2>Details</h2>\n\n<ol>\n    <li>\n        App: @App (AppId: @Block.App.AppId) <br/>\n        Items: @App.Data (@App.Data.List.Count())<br/>\n    </li>\n    <li>\n        AsDynamic entity: @AsDynamic(App.Data.List.First()).EntityTitle\n    </li>\n    <li>\n        AsDynamic Json: @AsDynamic(\"{\\\"test\\\": 25}\").test\n    </li>\n    <li>\n        Get data BlogPost: @App.Data[\"BlogPost\"].List.Count()\n        @{\n            var last = AsList(App.Data[\"BlogPost\"]).Last();\n        }\n        First: @last.Title (image is @last.Image) <br/>\n        Body: @last.Body \n        <div>\n            @Html.Raw(last.Body)\n        </div>\n    </li>\n</ol>\n\n<h2>Content</h2>\n\nContent is null: \"@(Content == null)\" @Content \"@Content.EntityTitle\"\n\n<h3>Data</h3>\n<ol>\n    <li>Data: @Data</li>\n    <li>Out Streams: (@Data.Out.Count) @String.Join(',', Data.Out.Keys)</li>\n    <li>Out Default: (@Data.List.Count())</li>\n</ol>\n\n<h3>Items List </h3>\n<ol>\n    @foreach (var item in AsList(Data))\n    {\n        <li>@item.EntityTitle</li>\n    }\n</ol>\n\n<hr/>\n\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/PreconfiguredBase/Blog.cshtml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace Website.Pages\n{\n    public class SxcBlockModel : PageModel\n    {\n        public void OnGet()\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/RenderPartial/Contact.cshtml",
    "content": "﻿@page\n@model Website.Pages.ContactModel\n\n<h1>Contact / Send Mail</h1>\n\nFrom https://www.learnrazorpages.com/advanced/render-partial-to-string <br/>\n\n<em>Note: won't send a real mail, just show it</em>\n\n<h2>The render inside this</h2>\n@Html.Raw(Model.InnerRender)\n\n<hr/>\n\n@if (TempData[\"PostResult\"] == null)\n{\n    <h2>The Form</h2>\n    <form method=\"post\">\n        <label asp-for=\"ContactForm.Name\"></label>\n        <div class=\"form-group\">\n            <input asp-for=\"ContactForm.Name\">\n        </div>\n        <label asp-for=\"ContactForm.Email\"></label>\n        <div class=\"form-group\">\n            <input asp-for=\"ContactForm.Email\">\n        </div>\n        <label asp-for=\"ContactForm.Subject\"></label>\n        <div class=\"form-group\">\n            <input asp-for=\"ContactForm.Subject\">\n        </div>\n        <label asp-for=\"ContactForm.Message\"></label>\n        <div class=\"form-group\">\n            <textarea asp-for=\"ContactForm.Message\"></textarea>\n        </div>\n        <label asp-for=\"ContactForm.Priority\"></label>\n        <div class=\"form-group\">\n            <select asp-for=\"ContactForm.Priority\" asp-items=\"Html.GetEnumSelectList<Priority>()\">\n                <option value=\"\">Set Priority</option>\n            </select>\n        </div>\n        <div class=\"form-group\">\n            <button class=\"btn btn-sm btn-primary\">Submit </button>\n        </div>\n    </form>\n}\nelse\n{\n    <h2>Result</h2>\n    <p>@Html.Raw(TempData[\"PostResult\"]))</p>\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/RenderPartial/Contact.cshtml.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing System.Threading.Tasks;\nusing RazorPartialToString.Services;\nusing ToSic.Sxc.Razor;\n\nnamespace Website.Pages\n{\n    public class ContactModel : PageModel\n    {\n        private readonly IRazorRenderer _renderer;\n        public ContactModel(IRazorRenderer renderer)\n        {\n            _renderer = renderer;\n        }\n        [BindProperty]\n        public ContactForm ContactForm { get; set; }\n        [TempData]\n        public string PostResult { get; set; }\n\n        public async Task OnGetAsync()\n        {\n            InnerRender = await _renderer.RenderToStringAsync(\"RenderPartial/_RenderPartialMail\",\n                new ContactForm\n                {\n                    Email = \"something@somewhere\",\n                    Message = \"Hello message!\",\n                    Name = \"The Dude\",\n                    Priority = Priority.Medium,\n                    Subject = \"This is the subject\"\n                });\n        }\n\n        public async Task<IActionResult> OnPostAsync()\n        {\n            var body = await _renderer.RenderToStringAsync(\"RenderPartial/_RenderPartialMail\", ContactForm);\n            PostResult = body; // \"Check your specified pickup directory\";\n            return RedirectToPage();\n        }\n\n\n        public string InnerRender;\n    }\n    public class ContactForm\n    {\n        public string Email { get; set; }\n        public string Message { get; set; }\n        public string Name { get; set; }\n        public string Subject { get; set; }\n        public Priority Priority { get; set; }\n    }\n    public enum Priority\n    {\n        Low, Medium, High\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/RenderPartial/Render2.cshtml",
    "content": "﻿@page\n@model Website.Pages.RenderPartial.Render2Model\n\n<h1>Render V2</h1>\n\nFrom https://www.learnrazorpages.com/advanced/render-partial-to-string <br/>\n\n<em>Note: won't send a real mail, just show it</em>\n\n<h2>The render inside this</h2>\n@Html.Raw(Model.InnerRender)\n\n<hr/>\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/RenderPartial/Render2.cshtml.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Custom.Hybrid;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Mvc;\nusing ToSic.Sxc.Mvc.Web;\nusing ToSic.Sxc.Razor;\nusing ToSic.Sxc.Razor.Internal;\n\nnamespace Website.Pages.RenderPartial\n{\n    public class Render2Model : PageModel\n    {\n        private readonly IRazorRenderer _renderer;\n        private readonly SxcMvc _sxcMvc;\n        public Render2Model(IRazorRenderer renderer, SxcMvc sxcMvc)\n        {\n            _renderer = renderer;\n            _sxcMvc = sxcMvc;\n        }\n\n        public async Task OnGetAsync()\n        {\n            DynamicCodeRoot dynCode = null;// _sxcMvc.CreateDynCode(TestIds.Blog, null);\n\n            var path = $\"/{MvcConstants.WwwRoot}2sxc/Blog App/_1 Main blog view.cshtml\";\n\n            InnerRender = await _renderer.RenderToStringAsync(\n                path,\n                new ContactForm\n                {\n                    Email = \"something@somewhere\",\n                    Message = \"Hello message!\",\n                    Name = \"The Dude\",\n                    Priority = Priority.Medium,\n                    Subject = \"This is the subject\"\n                }, rzv =>\n                {\n                    if (rzv.RazorPage is IRazor12 asSxc)\n                    {\n                        asSxc._DynCodeRoot = dynCode;\n                        //asSxc.VirtualPath = path;\n                        //asSxc.Purpose = Purpose.WebView;\n                    }\n                });\n        }\n\n\n        public string InnerRender;\n    }\n\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/SpecialBase/CallWwwRunContent.cshtml",
    "content": "﻿@page\n@using ToSic.Sxc.Mvc.Dev\n@model Website.Pages.DynamicRazorModel\n@{\n    ViewData[\"Title\"] = \"DynamicRazor\";\n}\n\n<h1>Dynamic Razor Data</h1>\n\n@Html.Partial(\"../../../wwwroot/2sxc/Content/RunContent.cshtml\", new ViewDataDictionary(ViewData)\n{\n    { \"Id\", TestIds.ContentOnHome.Container },\n    { \"PageId\", TestIds.ContentOnHome.Page },\n    { \"AppId\", TestIds.ContentOnHome.App },\n    { \"Block\", TestIds.ContentOnHome.Block }\n})\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/SpecialBase/CallWwwRunContent.cshtml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace Website.Pages\n{\n    public class DynamicRazorModel : PageModel\n    {\n        public void OnGet()\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/SpecialBase/CallingPartialWithViewParamsBase.cshtml",
    "content": "﻿@page\n@using ToSic.Sxc.Mvc.Dev\n@model Website.Pages.BlogModel\n\n<h1>Directly call Partial view in wwwroot/blog/_list and pass in data</h1>\n\n@Html.Partial(\"../../../wwwroot/2sxc/Blog App/_List.cshtml\", new ViewDataDictionary(ViewData)\n{\n    { \"Id\", TestIds.Blog.Container },\n    { \"PageId\", TestIds.Blog.Page},\n    { \"AppId\", TestIds.Blog.App},\n    { \"Block\", TestIds.Blog.Block}\n})\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/SpecialBase/CallingPartialWithViewParamsBase.cshtml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace Website.Pages\n{\n    public class BlogModel : PageModel\n    {\n        public void OnGet()\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/UsePartials/CallPartialViewWithViewParams.cshtml",
    "content": "﻿@page\n@using ToSic.Sxc.Mvc.Dev\n@model Website.Pages.ComponentsModel\n@{\n    ViewData[\"Title\"] = \"Components\";\n}\n\n<h1>Components</h1>\n\ntodo\n\n<h2>First</h2>\n\ntodo\n\n<h2>Second</h2>\n\n<h2>Third (works but not exciting)</h2>\n@await Component.InvokeAsync(\"Third\")\n\nawait Component.InvokeAsync()\n\n<h2>\n    Partials\n</h2>\n@Html.Partial(\"Partial/Partial1.cshtml\")\n\n<h2>Component with Params</h2>\n@await Component.InvokeAsync(\"ComponentWithParams\", new { pageId = TestIds.Blog.Page, instanceId = TestIds.Blog.Container })\n\n\n<h2>Direct call of my component inheriting from SxcRazorPage</h2>\n\n\n@Html.Partial(\"Partial/SxcRazorPageWithParamsInView\", new ViewDataDictionary(ViewData)\n{\n    { \"AppIdentity\", TestIds.Blog.Container },\n    { \"PageId\", TestIds.Blog.Page },\n    { \"AppId\", TestIds.Blog.App },\n    { \"Block\", TestIds.Blog.Block }\n})\n\n<h2>Now a simple content</h2>\n@Html.Partial(\"Partial/SxcRazorPageWithParamsInView\", new ViewDataDictionary(ViewData)\n{\n    { \"Id\", TestIds.ContentOnHome.Container },\n    { \"PageId\", TestIds.ContentOnHome.Page },\n    { \"AppId\", TestIds.ContentOnHome.App },\n    { \"Block\", TestIds.ContentOnHome.Block }\n})"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/UsePartials/CallPartialViewWithViewParams.cshtml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace Website.Pages\n{\n    public class ComponentsModel : PageModel\n    {\n        public void OnGet()\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/UsePartials/Partial/Partial1.cshtml",
    "content": "﻿@page\n@inherits ToSic.Sxc.Mvc.RazorPages.Exp.PageBaseLoadingBlogOnly\n@model Website.Pages.ComponentsModel\n\n<hr />\n<h3>Partial1</h3>\nMy Type: @GetType().Name\n<br />\nBase Type: @GetType().BaseType.Name (@GetType().BaseType.FullName)\n\nApp: @App.Name\n<hr />"
  },
  {
    "path": "Src/Mvc/Website/Pages/Exp/UsePartials/Partial/SxcRazorPageWithParamsInView.cshtml",
    "content": "﻿@inherits ToSic.Sxc.Mvc.RazorPages.Exp.SxcTestPageViewParams<TModel>\n@{\n    ViewData[\"Title\"] = \"Default\";\n}\n\n<h1>SxcRazorPage as Partial - showing app/content data</h1>\n\n<ol>\n    <li>\n        Id: @ViewData[\"AppIdentity\"] / @Id <br />\n        Page: @PageId\n    </li>\n    <li>\n        App: @App.Name\n    </li>\n</ol>\n\n<h4>Type info</h4>\n\n@GetType().FullName\n\n<h2>Details</h2>\n\n<ol>\n    <li>\n        App: @App (AppId: @App.AppId) <br />\n        Items: @App.Data (@App.Data.List.Count())<br />\n    </li>\n    <li>\n        AsDynamic entity: @AsDynamic(App.Data.List.First()).EntityTitle\n    </li>\n    <li>\n        AsDynamic Json: @AsDynamic(\"{\\\"test\\\": 25}\").test\n    </li>\n    @if (App.Data.Out.ContainsKey(\"BlogPost\"))\n    {\n        <li>\n            Get data BlogPost: @App.Data[\"BlogPost\"].List.Count()\n            @{\n                var last = AsList(App.Data[\"BlogPost\"]).Last();\n            }\n            First: @last.Title (image is @last.Image) <br/>\n            Body: @last.Body\n            <div>\n                @Html.Raw(last.Body)\n            </div>\n        </li>\n    }\n</ol>\n\n<h2>Content</h2>\n\nContent is null: \"@(Content == null)\" @Content \"@Content.EntityTitle\"\n\n<h3>Data</h3>\n<ol>\n    <li>Data: @Data</li>\n    <li>Out Streams: (@Data.Out.Count) @String.Join(',', Data.Out.Keys)</li>\n    <li>Out Default: (@Data.List.Count())</li>\n</ol>\n\n<h3>Items List </h3>\n<ol>\n    @foreach (var item in AsList(Data))\n    {\n        <li>@item.EntityTitle</li>\n    }\n</ol>\n\n<hr />"
  },
  {
    "path": "Src/Mvc/Website/Pages/Index.cshtml",
    "content": "﻿@page\n@using ToSic.Sxc.Mvc.WebApi\n@model IndexModel\n@{\n    ViewData[\"Title\"] = \"Home page\";\n    //ViewData[\"SxcPageHeaders\"] = \"<!-- test -->\";\n}\n\n<div class=\"text-center\">\n    <h1 class=\"display-4\">Welcome</h1>\n    <p>Learn about <a href=\"https://docs.microsoft.com/aspnet/core\">building Web apps with ASP.NET Core</a>.</p>\n</div>\n\n<hr />\n\n<h2>\n    Test API Insights\n</h2>\n\n<ol>\n    <li>\n        <a href=\"/@WebApiConstants.WebApiRoot/insights/help\">Insights Help</a>\n    </li>\n</ol>\n\n<h2>\n    Content / Query API\n</h2>\n<ol>\n    <li>\n        Tags\n        <a href=\"/@WebApiConstants.WebApiRoot/app/Blog%20App/content/Tag\">List</a> or\n        <a href=\"/@WebApiConstants.WebApiRoot/app/Blog%20App/content/Tag/6628\">One (#6628)</a>\n    </li>\n    <li>\n        BlogPost\n        <a href=\"/@WebApiConstants.WebApiRoot/app/Blog%20App/content/BlogPost\">List</a> or\n        <a href=\"/@WebApiConstants.WebApiRoot/app/Blog%20App/content/BlogPost/1057\">One with AppIdentity (#1057)</a> or\n        <a href=\"/@WebApiConstants.WebApiRoot/app/Blog%20App/content/BlogPost/d5fce6dd-c16a-4374-aaff-dc223e45b540\">One with guAppIdentity (#d5fce6dd-c16a-4374-aaff-dc223e45b540)</a>\n    </li>\n  <li>\n    Tags Query\n    <a href=\"/@WebApiConstants.WebApiRoot/app/Blog%20App/query/Tags\">List</a> or\n\n  </li>\n  <li>\n    Routing Table <a href=\"/route-debugger\">Routing debug table</a>\n  </li>\n</ol>\n\n\n<hr/>\n<h2>Other stuff</h2>\n@Model.Hello\n\nchanged"
  },
  {
    "path": "Src/Mvc/Website/Pages/Index.cshtml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.Extensions.Logging;\n\nnamespace Website.Pages\n{\n    public class IndexModel : PageModel\n    {\n        private readonly ILogger<IndexModel> _logger;\n\n        public IndexModel(ILogger<IndexModel> logger)\n        {\n            _logger = logger;\n        }\n\n        public void OnGet()\n        {\n\n        }\n\n        public string Hello => \"hello daniel\";\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Shared/Components/ComponentWithParams/Default.cshtml",
    "content": "﻿inherits ToSic.Sxc.Mvc.RazorPages.Page\n@inherits ToSic.Sxc.Mvc.RazorPages.Exp.SxcTestPageViewParams<TModel>\n@{\n    ViewData[\"Title\"] = \"Default\";\n}\n\n<h4>ComponentWith Params</h4>\n\n<ol>\n    foreach (var name in Model)\n    {\n        <li>name</li>\n    }\n</ol>\n\n<h4>Type info</h4>\n\n@GetType().FullName"
  },
  {
    "path": "Src/Mvc/Website/Pages/Shared/Components/Second/Default.cshtml",
    "content": "﻿@page\n@model Website.Pages.Shared.Components.Second.DefaultModel\n@{\n    ViewData[\"Title\"] = \"Default\";\n}\n\n<h1>Second component</h1>\n\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Shared/Components/Second/Default.cshtml.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace Website.Pages.Shared.Components.Second\n{\n    public class DefaultModel : PageModel\n    {\n        public void OnGet()\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/Shared/Components/Third/Default.cshtml",
    "content": "﻿@model List<string>\n@{\n    ViewData[\"Title\"] = \"Default\";\n}\n\n<h1>Third component</h1>\n\n<ol>\n@foreach (var name in Model)\n{\n    <li>@name</li>\n}\n</ol>"
  },
  {
    "path": "Src/Mvc/Website/Pages/Shared/RenderPartial/_RenderPartialMail.cshtml",
    "content": "﻿@model ContactForm\n@{\n    Layout = null;\n}\n<!DOCTYPE html>\n<html>\n<head>\n    <title>Contact Email Partial #1</title>\n    <style>\n        body{font-family:Calibri, sans-serif;font-size: 11pt;color: #555;}\n        blockquote{border-left: 8px solid #cceeaa;font-size: 12pt;margin:0;padding: 30px 60px;}\n    </style>\n</head>\n<body>\n<h1>Contact Form</h1>\n<p>@Model.Name sent a message via the contact form at @DateTime.Now as follows:</p>\n<blockquote>@Model.Message</blockquote>\n<p>@Model.Name is using the email address @Model.Email and considers the message to \n    be @Model.Priority.ToString() priority.</p>\n</body>\n</html>"
  },
  {
    "path": "Src/Mvc/Website/Pages/Shared/RenderPartial2/_RenderPartial2.cshtml",
    "content": "﻿@inherits ToSic.Custom.Razor12<ContactForm>\n@model ContactForm\n@{\n    Layout = null;\n}\n<h1>Render Partial 2</h1>\n<p>@Model.Name sent a message via the contact form at @DateTime.Now as follows:</p>\n<blockquote>@Model.Message</blockquote>\n<p>\n    @Model.Name is using the email address @Model.Email and considers the message to\n    be @Model.Priority.ToString() priority.\n</p>\n\nTest call for debugging the parent class...\n<hr/>\n\nApp: @App.Name"
  },
  {
    "path": "Src/Mvc/Website/Pages/Shared/_Layout.cshtml",
    "content": "﻿<!DOCTYPE html>\n@using ToSic.Sxc.Mvc.Web\n@inject MvcPageProperties PageProperties\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"wAppIdentityth=device-wAppIdentityth, initial-scale=1.0\" />\n  <title>@ViewData[\"Title\"] - Website</title>\n  <link rel=\"stylesheet\" href=\"~/lib/bootstrap/dist/css/bootstrap.min.css\" />\n  <link rel=\"stylesheet\" href=\"~/css/site.css\" />\n  @* For now - include jquery on the top*@\n  <script src=\"~/lib/jquery/dist/jquery.min.js\"></script>\n\n  @* DynamicHeaders from the page *@\n  @PageProperties.FinalHeaders()\n</head>\n<body>\n  <header>\n    <nav class=\"navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3\">\n      <div class=\"container\">\n        <a class=\"navbar-brand\" asp-area=\"\" asp-page=\"/Index\">Website</a>\n        <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\".navbar-collapse\" aria-controls=\"navbarSupportedContent\"\n                aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n          <span class=\"navbar-toggler-icon\"></span>\n        </button>\n        <div class=\"navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse\">\n          <ul class=\"navbar-nav flex-grow-1\">\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Index\">Home</a>\n            </li>\n            <li class=\"nav-item dropdown\">\n              <a class=\"nav-link dropdown-toggle\" href=\"#\" id=\"navbarDropdown\" role=\"button\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n                Basic Experiments\n              </a>\n              <div class=\"dropdown-menu\" aria-labelledby=\"navbarDropdown\">\n                <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Exp/Eav/EavDi\">Test basic Eav DI and Map-Path</a>\n                <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Exp/Eav/EavCore\">Use EAV to access an app state</a>\n                <div class=\"dropdown-divider\"></div>\n                <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Exp/UsePartials/CallPartialViewWithViewParams\">Call Partial View with ViewParams</a>\n                <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Exp/RenderPartial/Contact\">Render Partial - Contact Form</a>\n                <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Exp/RenderPartial/Render2\">Model-Inner-Render of wwwwroot-file</a>\n                <div class=\"dropdown-divider\"></div>\n                <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Exp/PreconfiguredBase/Blog\">Page which has a base class loading blog</a>\n                <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Exp/SpecialBase/CallingPartialWithViewParamsBase\">Calling wwwroot component with ViewParams</a>\n                <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Exp/SpecialBase/CallWwwRunContent\">Call RunContent on wwwroot</a>\n                <div class=\"dropdown-divider\"></div>\n\n                <a class=\"dropdown-item\" href=\"#\">Action</a>\n                <a class=\"dropdown-item\" href=\"#\">Another action</a>\n                <div class=\"dropdown-divider\"></div>\n                <a class=\"dropdown-item\" href=\"#\">Something else here</a>\n              </div>\n            </li>\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Standalone/Standalone\">Standalone</a>\n            </li>\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Engine/TokenApp\">Engine-Token</a>\n            </li>\n            <li class=\"nav-item\">\n              <a class=\"nav-link text-dark\" asp-area=\"\" asp-page=\"/Engine/Blog\">Engine-Blog</a>\n            </li>\n          </ul>\n        </div>\n      </div>\n    </nav>\n  </header>\n  <div class=\"container\">\n    <main role=\"main\" class=\"pb-3\">\n      @RenderBody()\n    </main>\n  </div>\n\n  <footer class=\"border-top footer text-muted\">\n    <div class=\"container\">\n      &copy; 2020 - Website - <a asp-area=\"\" asp-page=\"/Privacy\">Privacy</a>\n    </div>\n  </footer>\n\n  <script src=\"~/lib/bootstrap/dist/js/bootstrap.bundle.min.js\"></script>\n  <script src=\"~/js/site.js\" asp-append-version=\"true\"></script>\n\n  @RenderSection(\"Scripts\", required: false)\n\n  @* Dynamic Footer from the page *@\n  @PageProperties.FinalFooter()\n</body>\n</html>\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Shared/_ValidationScriptsPartial.cshtml",
    "content": "﻿<script src=\"~/lib/jquery-validation/dist/jquery.validate.min.js\"></script>\n<script src=\"~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js\"></script>\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Standalone/Standalone.cshtml",
    "content": "﻿@page\n@using ToSic.Eav.Plumbing\n@{\n  ViewData[\"Title\"] = \"Eav.Core\";\n}\n\n<h1>Standalone to open dialogs</h1>\n\n<script src=\"/system/sxc/js/2sxc.api.min.js\"></script>\n<script src=\"/system/sxc/dist/inpage/inpage.min.js\"></script>\n\nThings which must work:\n<ol>\n  <li>Scripts added</li>\n  <li>Page Context?</li>\n</ol>\n\n<ol>\n  <li>\n    An EAV Constant: @ToSic.Eav.Constants.ContentAppName\n  </li>\n  <li>\n    A DataSource Object: @(HttpContext.RequestServices.Build<ToSic.Eav.DataSources.DataSourceFactory>().GetType().AssemblyQualifiedName)\n  </li>\n  <li>\n    Repository type Code: @(ToSic.Eav.Repositories.RepositoryTypes.Code)\n  </li>\n  <li>\n    2sxc constant: @(ToSic.Sxc.Settings.PortalHostDirectory)\n  </li>\n  <li>\n    App Cache: @(ToSic.Eav.Factory.Resolve<ToSic.Eav.Caching.IAppsCache>().GetType().Name)\n  </li>\n</ol>\n<h2>State of App 4 (Blog)</h2>\n\n<ol>\n  <li>\n    Timestamp : @(ToSic.Eav.Apps.State.Get(4).CacheTimestamp)\n  </li>\n  <li>\n    Items in it : @(ToSic.Eav.Apps.State.Get(4).List.Count)\n  </li>\n  <li>\n    Query AllQueries: @ToSic.Eav.Apps.State.Get(4)  can't work yet, this object doesn't have queries!\n  </li>\n\n</ol>\n\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/Standalone/Standalone.cshtml.cs",
    "content": "﻿using System.Linq;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.DataSources;\nusing ToSic.Eav.LookUp;\nusing ToSic.Eav.Plumbing;\nusing ToSic.Eav.Run;\nusing ToSic.Sxc.Mvc.Dev;\nusing ToSic.Sxc.Mvc.Run;\n\nnamespace Website.Pages\n{\n\n}"
  },
  {
    "path": "Src/Mvc/Website/Pages/_ViewImports.cshtml",
    "content": "@using Website\n@namespace Website.Pages\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n"
  },
  {
    "path": "Src/Mvc/Website/Pages/_ViewStart.cshtml",
    "content": "﻿@{\n    Layout = \"_Layout\";\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Program.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Hosting;\n\nnamespace Website\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Properties/launchSettings.json",
    "content": "﻿{\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,\n    \"anonymousAuthentication\": true,\n    \"iisExpress\": {\n      \"applicationUrl\": \"http://localhost:50363\",\n      \"sslPort\": 44361\n    }\n  },\n  \"profiles\": {\n    \"IIS Express\": {\n      \"commandName\": \"IISExpress\",\n      \"launchBrowser\": true,\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES\": \"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\"\n      }\n    },\n    \"Website\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"applicationUrl\": \"https://localhost:5001;http://localhost:5000\",\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\",\n        \"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES\": \"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/RazorPartialToString/IRazorPartialToStringRenderer.cs",
    "content": "﻿using System.Threading.Tasks;\nnamespace RazorPartialToString.Services\n{\n    public interface IRazorPartialToStringRenderer\n    {\n        Task<string> RenderPartialToStringAsync<TModel>(string partialName, TModel model);\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/RazorPartialToString/RazorPartialToStringRenderer.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Abstractions;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\nusing Microsoft.AspNetCore.Mvc.Razor;\nusing Microsoft.AspNetCore.Mvc.Rendering;\nusing Microsoft.AspNetCore.Mvc.ViewEngines;\nusing Microsoft.AspNetCore.Mvc.ViewFeatures;\nusing Microsoft.AspNetCore.Routing;\n\nnamespace RazorPartialToString.Services\n{\n    public class RazorPartialToStringRenderer : IRazorPartialToStringRenderer\n    {\n        private IRazorViewEngine _viewEngine;\n        private ITempDataProvider _tempDataProvider;\n        private IServiceProvider _serviceProvider;\n        public RazorPartialToStringRenderer(\n            IRazorViewEngine viewEngine,\n            ITempDataProvider tempDataProvider,\n            IServiceProvider serviceProvider)\n        {\n            _viewEngine = viewEngine;\n            _tempDataProvider = tempDataProvider;\n            _serviceProvider = serviceProvider;\n        }\n        public async Task<string> RenderPartialToStringAsync<TModel>(string partialName, TModel model)\n        {\n            var actionContext = GetActionContext();\n            var partial = FindView(actionContext, partialName);\n            using (var output = new StringWriter())\n            {\n                var viewContext = new ViewContext(\n                    actionContext,\n                    partial,\n                    new ViewDataDictionary<TModel>(\n                        metadataProvider: new EmptyModelMetadataProvider(),\n                        modelState: new ModelStateDictionary())\n                    {\n                        Model = model\n                    },\n                    new TempDataDictionary(\n                        actionContext.HttpContext,\n                        _tempDataProvider),\n                    output,\n                    new HtmlHelperOptions()\n                );\n                await partial.RenderAsync(viewContext);\n                return output.ToString();\n            }\n        }\n        private IView FindView(ActionContext actionContext, string partialName)\n        {\n            var getPartialResult = _viewEngine.GetView(null, partialName, false);\n            if (getPartialResult.Success)\n            {\n                return getPartialResult.View;\n            }\n            var findPartialResult = _viewEngine.FindView(actionContext, partialName, false);\n            if (findPartialResult.Success)\n            {\n                return findPartialResult.View;\n            }\n            var searchedLocations = getPartialResult.SearchedLocations.Concat(findPartialResult.SearchedLocations);\n            var errorMessage = string.Join(\n                Environment.NewLine,\n                new[] { $\"Unable to find partial '{partialName}'. The following locations were searched:\" }.Concat(searchedLocations)); ;\n            throw new InvalidOperationException(errorMessage);\n        }\n        private ActionContext GetActionContext()\n        {\n            var httpContext = new DefaultHttpContext\n            {\n                RequestServices = _serviceProvider\n            };\n            return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());\n        }\n    }\n}"
  },
  {
    "path": "Src/Mvc/Website/Startup.cs",
    "content": "using System.IO;\nusing System.Text.Json;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Mvc.ApplicationParts;\nusing Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.AspNetCore.Mvc.Routing;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.FileProviders;\nusing Microsoft.Extensions.Hosting;\nusing RazorPartialToString.Services;\nusing ToSic.Eav.Serialization;\nusing ToSic.Sxc.Mvc;\n\nnamespace Website\n{\n    public class Startup\n    {\n        public Startup(IConfiguration configuration, IWebHostEnvironment environment)\n        {\n            Configuration = configuration;\n            HostEnvironment = environment;\n        }\n\n\n        public IConfiguration Configuration { get; }\n        public IWebHostEnvironment HostEnvironment { get; }\n\n        // This method gets called by the runtime. Use this method to add services to the container.\n        public void ConfigureServices(IServiceCollection services)\n        {\n            // Add razor pages dynamic compilation WIP\n            services.AddRazorPages()\n                // experiment\n                // https://github.com/aspnet/samples/blob/master/samples/aspnetcore/mvc/runtimecompilation/MyApp/Startup.cs#L26\n                .AddRazorRuntimeCompilation(options =>\n                {\n                    var configuredPath = Configuration[\"SxcRoot\"];\n                    var libraryPath = Path.GetFullPath(Path.Combine(HostEnvironment.ContentRootPath, configuredPath));\n                    options.FileProviders.Add(new PhysicalFileProvider(libraryPath));\n                });\n\n            // enable use of HttpContext\n            services.AddHttpContextAccessor();\n\n            // enable webapi - include all controllers in the Sxc.Mvc assembly\n            services.AddControllers(options => { options.AllowEmptyInputInBodyModelBinding = true; })\n                // This is needed to preserve compatibility with previous api usage\n                // Set the JSON serializer options\n                .AddJsonOptions(options => options.JsonSerializerOptions.SetUnsafeJsonSerializerOptions())\n                .PartManager.ApplicationParts.Add(new AssemblyPart(typeof(SxcMvc).Assembly));\n\n            // enable use of UrlHelper for AbsolutePath\n            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();\n            services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();\n            services.AddScoped(it => it.GetService<IUrlHelperFactory>()\n                .GetUrlHelper(it.GetService<IActionContextAccessor>().ActionContext));\n\n            // Try to get partial to string rendering\n            services.AddTransient<IRazorPartialToStringRenderer, RazorPartialToStringRenderer>();\n            //services.AddTransient<IRenderRazor, RenderRazor>();\n\n            StartupEavAndSxc.ConfigureIoC(services, Configuration);\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n                app.UseRouteDebugger();\n            }\n            else\n            {\n                app.UseExceptionHandler(\"/Error\");\n                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.\n                app.UseHsts();\n            }\n\n            app.UseHttpsRedirection();\n            var defFiles = new DefaultFilesOptions();\n            defFiles.DefaultFileNames.Clear();\n            defFiles.DefaultFileNames.Add(\"index.html\");\n            app.UseDefaultFiles(defFiles);\n            app.UseStaticFiles();\n\n            app.UseRouting();\n\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapRazorPages();\n                endpoints.MapControllers();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/StartupEavAndSxc.cs",
    "content": "﻿using Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav;\nusing ToSic.Eav.Configuration;\nusing ToSic.Eav.Plumbing;\nusing ToSic.Sxc;\nusing ToSic.Sxc.Mvc;\nusing ToSic.Sxc.Razor;\nusing ToSic.Sxc.WebApi;\n\nnamespace Website\n{\n    public class StartupEavAndSxc\n    {\n        internal static void ConfigureIoC(IServiceCollection services, IConfiguration configuration)\n        {\n            ToSic.Eav.Factory.UseExistingServices(services);\n            ToSic.Eav.Factory.ActivateNetCoreDi(services2 =>\n            {\n                services2\n                    .AddSxcMvc()\n                    .AddNotImplemented()\n                    .AddSxcRazor()\n\n                    // probably the basics needed to read data\n                    .AddAdamWebApi<string, string>()\n                    .AddSxcWebApi()\n                    .AddSxcCore()\n                    .AddEav();\n            });\n\n            var connectionString = configuration.GetConnectionString(\"SiteSqlServer\");\n            services.BuildServiceProvider().Build<IDbConfiguration>().ConnectionString = connectionString;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/Website.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net9.0</TargetFramework>\n    <CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory>\n    <RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>\n    <AnalysisLevel>none</AnalysisLevel>\n    <Configurations>Debug;Release;DebugOqtane;DebugDnn</Configurations>\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"wwwroot\\System\\Sxc\\**\" />\n    <Content Remove=\"wwwroot\\System\\Sxc\\**\" />\n    <EmbeddedResource Remove=\"wwwroot\\System\\Sxc\\**\" />\n    <None Remove=\"wwwroot\\System\\Sxc\\**\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Include=\"RazorPartialToString\\IRazorPartialToStringRenderer.cs\" />\n    <Content Include=\"RazorPartialToString\\RazorPartialToStringRenderer.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Edi.RouteDebugger\" Version=\"1.3.2\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.NewtonsoftJson\" Version=\"9.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"9.0.0\" />\n    <PackageReference Include=\"Microsoft.VisualStudio.Web.CodeGeneration.Design\" Version=\"9.0.0\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Common\" Version=\"4.14.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.DataSources\\ToSic.Eav.DataSources.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\" />\n    <ProjectReference Include=\"..\\..\\Razor\\ToSic.Sxc.Razor\\ToSic.Sxc.Razor.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Mvc\\ToSic.Sxc.Mvc.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"Engine\\\" />\n    <Folder Include=\"wwwroot\\adam\\\" />\n    <Folder Include=\"wwwroot\\System\\\" />\n  </ItemGroup>\n\n  <Target Name=\"PostBuild\" AfterTargets=\"PostBuildEvent\">\n    <Exec Command=\"@set BuildTarget=$(ProjectDir)wwwroot\\System\\Sxc&#xD;&#xA;&#xD;&#xA;@REM Copy the data folders&#xD;&#xA;robocopy /mir $(ProjectDir)..\\..\\Data\\.data\\ %25BuildTarget%25\\.data\\&#xD;&#xA;robocopy /mir $(ProjectDir)..\\..\\Data\\.databeta\\ %25BuildTarget%25\\.databeta\\&#xD;&#xA;robocopy /mir $(ProjectDir)..\\..\\Data\\.data-custom\\ %25BuildTarget%25\\.data-custom\\&#xD;&#xA;&#xD;&#xA;@REM Copy 2sxc JS stuff&#xD;&#xA;robocopy /mir $(Source)\\js\\ %25BuildTarget%25\\js\\&#xD;&#xA;robocopy /mir $(Source)\\dist\\ %25BuildTarget%25\\dist\\&#xD;&#xA;robocopy /mir $(Source)\\system\\ %25BuildTarget%25\\system\\&#xD;&#xA;&#xD;&#xA;@echo Copied all files to this Website target: '%25BuildTarget%25'\" />\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "Src/Mvc/Website/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n\n  \"ConnectionStrings\": {\n    \"SiteSqlServer\": \"Data Source=localhost;Initial Catalog=2sxc-dnn742;Integrated Security=True\"\n  } \n}\n"
  },
  {
    "path": "Src/Mvc/Website/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"SxcRoot\": \"wwwroot/2sxc\"\n}\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/Blog App/_1 Main blog view.cshtml",
    "content": "﻿@inherits ToSic.Custom.Razor12<TModel>\n\n<h1>Main Blog List file</h1>\n\nMy type: @GetType().FullName\n\nThe App being shown: @App.Name\n<br />\n\nContent Title: @Content.Title\n\n\n<h2>Details</h2>\n\n<ol>\n    <li>\n        App: @App (AppId: @App.AppId) <br />\n        Items: @App.Data (@App.Data.List.Count())<br />\n    </li>\n    <li>\n        AsDynamic entity: @AsDynamic(App.Data.List.First()).EntityTitle\n    </li>\n    <li>\n        AsDynamic Json: @AsDynamic(\"{\\\"test\\\": 25}\").test\n    </li>\n    @if (App.Data.Out.ContainsKey(\"BlogPost\"))\n    {\n        <li>\n            Get data BlogPost: @App.Data[\"BlogPost\"].List.Count()\n            @{\n                var last = AsList(App.Data[\"BlogPost\"]).Last();\n            }\n            First: @last.Title (image is @last.Image) <br />\n            Body: @last.Body\n            <div>\n                @Html.Raw(last.Body)\n            </div>\n        </li>\n    }\n</ol>\n\n<h2>Content</h2>\n\nContent is null: \"@(Content == null)\" @Content \"@Content.EntityTitle\"\n\n<h3>Data</h3>\n<ol>\n    <li>Data: @Data</li>\n    <li>Out Streams: (@Data.Out.Count) @String.Join(',', Data.Out.Keys)</li>\n    <li>Out Default: (@Data.List.Count())</li>\n</ol>\n\n<h3>Blog Items List </h3>\n<ol>\n    @foreach (var item in AsList(Data))\n    {\n        <li @Edit.TagToolbar(item)>\n            <a href=\"?post=@item.UrlKey\">@item.EntityTitle</a>\n            \n        </li>\n    }\n</ol>\n\n<hr />"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/Blog App/_List.cshtml",
    "content": "﻿@inherits ToSic.Sxc.Mvc.RazorPages.Exp.SxcTestPageViewParams<TModel>\n\n<h1>Blog List file</h1>\n\nMy type: @GetType().FullName\n\nThe App being shown: @App.Name\n<br />\n\nContent Title: @Content.Title\n\n\n<h2>Details</h2>\n\n<ol>\n    <li>\n        App: @App (AppId: @App.AppId) <br />\n        Items: @App.Data (@App.Data.List.Count())<br />\n    </li>\n    <li>\n        AsDynamic entity: @AsDynamic(App.Data.List.First()).EntityTitle\n    </li>\n    <li>\n        AsDynamic Json: @AsDynamic(\"{\\\"test\\\": 25}\").test\n    </li>\n    @if (App.Data.Out.ContainsKey(\"BlogPost\"))\n    {\n        <li>\n            Get data BlogPost: @App.Data[\"BlogPost\"].List.Count()\n            @{\n                var last = AsList(App.Data[\"BlogPost\"]).Last();\n            }\n            First: @last.Title (image is @last.Image) <br />\n            Body: @last.Body\n            <div>\n                @Html.Raw(last.Body)\n            </div>\n        </li>\n    }\n</ol>\n\n<h2>Content</h2>\n\nContent is null: \"@(Content == null)\" @Content \"@Content.EntityTitle\"\n\n<h3>Data</h3>\n<ol>\n    <li>Data: @Data</li>\n    <li>Out Streams: (@Data.Out.Count) @String.Join(',', Data.Out.Keys)</li>\n    <li>Out Default: (@Data.List.Count())</li>\n</ol>\n\n<h3>Items List </h3>\n<ol>\n    @foreach (var item in AsList(Data))\n    {\n        <li>\n            <a href=\"?post=@item.UrlKey\">@item.EntityTitle</a>\n            \n        </li>\n    }\n</ol>\n\n<hr />"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/Blog App/_Post Details.cshtml",
    "content": "﻿@inherits ToSic.Custom.Razor12<TModel>\n@{\n    ViewData[\"Title\"] = \"Default\";\n}\n\n<h1>Post Details - should have same name as in real blog app</h1>\n\nMy type: @GetType().FullName\n\nThe App being shown: @App.Name\n<br />\n\nContent Title: @Content.Title\n\n\n<h2>Details</h2>\n\n<ol>\n    <li>\n        App: @App (AppId: @App.AppId) <br />\n        Items: @App.Data (@App.Data.List.Count())<br />\n    </li>\n    <li>\n        AsDynamic entity: @AsDynamic(App.Data.List.First()).EntityTitle\n    </li>\n    <li>\n        AsDynamic Json: @AsDynamic(\"{\\\"test\\\": 25}\").test\n    </li>\n    @if (App.Data.Out.ContainsKey(\"BlogPost\"))\n    {\n        <li>\n            Get data BlogPost: @App.Data[\"BlogPost\"].List.Count()\n            @{\n                var last = AsList(App.Data[\"BlogPost\"]).Last();\n            }\n            First: @last.Title (image is @last.Image) <br />\n            Body: @last.Body\n            <div>\n                @Html.Raw(last.Body)\n            </div>\n        </li>\n    }\n</ol>\n\n<h2>Content</h2>\n\nContent is null: \"@(Content == null)\" @Content \"@Content.EntityTitle\"\n\n<h3>Data</h3>\n<ol>\n    <li>Data: @Data</li>\n    <li>Out Streams: (@Data.Out.Count) @String.Join(',', Data.Out.Keys)</li>\n    <li>Out Default: (@Data.List.Count())</li>\n</ol>\n\n<hr />"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/Content/Helpers.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Website.wwwroot._2sxc.Content\n{\n    public class Helpers\n    {\n        public string Hello() => \"hello from Helpers\";\n    }\n}\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/Content/RunContent.cshtml",
    "content": "﻿@inherits ToSic.Sxc.Mvc.RazorPages.Exp.SxcTestPageViewParams<TModel>\n@{\n    ViewData[\"Title\"] = \"Default\";\n}\n\n<h1>Dynamically compiled razor file</h1>\n\nMy type: @GetType().FullName\n\nThe App being shown: @App.Name <br/>\n\nContent Title: @Content.Title\n\n@Html.Partial(\"_InnerPart.cshtml\")\n\n\n\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/Content/_InnerPart.cshtml",
    "content": "﻿@inherits ToSic.Custom.Razor12<TModel>\n@{\n    ViewData[\"Title\"] = \"Default\";\n}\n\n<h2>Inner Part - loaded with Partial</h2>\n\nMy type: @GetType().FullName <br/>\n\nMy Path: @this.Path <br/>\nCreateInstance Path: @this.CreateInstancePath\n\n<hr/>"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/Tokens/Details.html",
    "content": "<h1>Details of [Content:EntityTitle] [Content:Toolbar]</h1>\n<div>\n    [Content:Body]\n</div>"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/Tokens/List.html",
    "content": "<p>\n    You successfully created your own template.\n    Start editing it by hovering the \"Manage\" button and opening the \"Edit Template\" dialog.\n</p>\n\n\n<ol>\n<repeat repeat=\"Item in Data:Default\">\n    <li>\n        [Item:Title] [Item:Toolbar] <br>\n        <a href=\"?details=[Item:UrlKey]\">Details...</a>\n    </li>\n</repeat>\n\n[Employee:Repeater:Alternator4]\n\n</ol>"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/2sxc/readme.md",
    "content": "﻿# 2sxc Directory\n\nThis is a directory for 2sxc apps.\n\nATM it's still empty"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/css/site.css",
    "content": "﻿/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\nfor details on configuring this project to bundle and minify static web assets. */\n\na.navbar-brand {\n  white-space: normal;\n  text-align: center;\n  word-break: break-all;\n}\n\n/* Provide sufficient contrast against white background */\na {\n  color: #0366d6;\n}\n\n.btn-primary {\n  color: #fff;\n  background-color: #1b6ec2;\n  border-color: #1861ac;\n}\n\n.nav-pills .nav-link.active, .nav-pills .show > .nav-link {\n  color: #fff;\n  background-color: #1b6ec2;\n  border-color: #1861ac;\n}\n\n/* Sticky footer styles\n-------------------------------------------------- */\nhtml {\n  font-size: 14px;\n}\n@media (min-width: 768px) {\n  html {\n    font-size: 16px;\n  }\n}\n\n.border-top {\n  border-top: 1px solid #e5e5e5;\n}\n.border-bottom {\n  border-bottom: 1px solid #e5e5e5;\n}\n\n.box-shadow {\n  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);\n}\n\nbutton.accept-policy {\n  font-size: 1rem;\n  line-height: inherit;\n}\n\n/* Sticky footer styles\n-------------------------------------------------- */\nhtml {\n  position: relative;\n  min-height: 100%;\n}\n\nbody {\n  /* Margin bottom by footer height */\n  margin-bottom: 60px;\n}\n.footer {\n  position: absolute;\n  bottom: 0;\n  width: 100%;\n  white-space: nowrap;\n  line-height: 60px; /* Vertically center the text there */\n}\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/js/site.js",
    "content": "﻿// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\n// for details on configuring this project to bundle and minify static web assets.\n\n// Write your Javascript code.\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/bootstrap/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2011-2018 Twitter, Inc.\nCopyright (c) 2011-2018 The Bootstrap Authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css",
    "content": "/*!\n * Bootstrap Grid v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\nhtml {\n  box-sizing: border-box;\n  -ms-overflow-style: scrollbar;\n}\n\n*,\n*::before,\n*::after {\n  box-sizing: inherit;\n}\n\n.container {\n  width: 100%;\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n\n@media (min-width: 576px) {\n  .container {\n    max-width: 540px;\n  }\n}\n\n@media (min-width: 768px) {\n  .container {\n    max-width: 720px;\n  }\n}\n\n@media (min-width: 992px) {\n  .container {\n    max-width: 960px;\n  }\n}\n\n@media (min-width: 1200px) {\n  .container {\n    max-width: 1140px;\n  }\n}\n\n.container-fluid {\n  width: 100%;\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n\n.row {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  margin-right: -15px;\n  margin-left: -15px;\n}\n\n.no-gutters {\n  margin-right: 0;\n  margin-left: 0;\n}\n\n.no-gutters > .col,\n.no-gutters > [class*=\"col-\"] {\n  padding-right: 0;\n  padding-left: 0;\n}\n\n.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,\n.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,\n.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,\n.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,\n.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,\n.col-xl-auto {\n  position: relative;\n  width: 100%;\n  padding-right: 15px;\n  padding-left: 15px;\n}\n\n.col {\n  -ms-flex-preferred-size: 0;\n  flex-basis: 0;\n  -ms-flex-positive: 1;\n  flex-grow: 1;\n  max-width: 100%;\n}\n\n.col-auto {\n  -ms-flex: 0 0 auto;\n  flex: 0 0 auto;\n  width: auto;\n  max-width: 100%;\n}\n\n.col-1 {\n  -ms-flex: 0 0 8.333333%;\n  flex: 0 0 8.333333%;\n  max-width: 8.333333%;\n}\n\n.col-2 {\n  -ms-flex: 0 0 16.666667%;\n  flex: 0 0 16.666667%;\n  max-width: 16.666667%;\n}\n\n.col-3 {\n  -ms-flex: 0 0 25%;\n  flex: 0 0 25%;\n  max-width: 25%;\n}\n\n.col-4 {\n  -ms-flex: 0 0 33.333333%;\n  flex: 0 0 33.333333%;\n  max-width: 33.333333%;\n}\n\n.col-5 {\n  -ms-flex: 0 0 41.666667%;\n  flex: 0 0 41.666667%;\n  max-width: 41.666667%;\n}\n\n.col-6 {\n  -ms-flex: 0 0 50%;\n  flex: 0 0 50%;\n  max-width: 50%;\n}\n\n.col-7 {\n  -ms-flex: 0 0 58.333333%;\n  flex: 0 0 58.333333%;\n  max-width: 58.333333%;\n}\n\n.col-8 {\n  -ms-flex: 0 0 66.666667%;\n  flex: 0 0 66.666667%;\n  max-width: 66.666667%;\n}\n\n.col-9 {\n  -ms-flex: 0 0 75%;\n  flex: 0 0 75%;\n  max-width: 75%;\n}\n\n.col-10 {\n  -ms-flex: 0 0 83.333333%;\n  flex: 0 0 83.333333%;\n  max-width: 83.333333%;\n}\n\n.col-11 {\n  -ms-flex: 0 0 91.666667%;\n  flex: 0 0 91.666667%;\n  max-width: 91.666667%;\n}\n\n.col-12 {\n  -ms-flex: 0 0 100%;\n  flex: 0 0 100%;\n  max-width: 100%;\n}\n\n.order-first {\n  -ms-flex-order: -1;\n  order: -1;\n}\n\n.order-last {\n  -ms-flex-order: 13;\n  order: 13;\n}\n\n.order-0 {\n  -ms-flex-order: 0;\n  order: 0;\n}\n\n.order-1 {\n  -ms-flex-order: 1;\n  order: 1;\n}\n\n.order-2 {\n  -ms-flex-order: 2;\n  order: 2;\n}\n\n.order-3 {\n  -ms-flex-order: 3;\n  order: 3;\n}\n\n.order-4 {\n  -ms-flex-order: 4;\n  order: 4;\n}\n\n.order-5 {\n  -ms-flex-order: 5;\n  order: 5;\n}\n\n.order-6 {\n  -ms-flex-order: 6;\n  order: 6;\n}\n\n.order-7 {\n  -ms-flex-order: 7;\n  order: 7;\n}\n\n.order-8 {\n  -ms-flex-order: 8;\n  order: 8;\n}\n\n.order-9 {\n  -ms-flex-order: 9;\n  order: 9;\n}\n\n.order-10 {\n  -ms-flex-order: 10;\n  order: 10;\n}\n\n.order-11 {\n  -ms-flex-order: 11;\n  order: 11;\n}\n\n.order-12 {\n  -ms-flex-order: 12;\n  order: 12;\n}\n\n.offset-1 {\n  margin-left: 8.333333%;\n}\n\n.offset-2 {\n  margin-left: 16.666667%;\n}\n\n.offset-3 {\n  margin-left: 25%;\n}\n\n.offset-4 {\n  margin-left: 33.333333%;\n}\n\n.offset-5 {\n  margin-left: 41.666667%;\n}\n\n.offset-6 {\n  margin-left: 50%;\n}\n\n.offset-7 {\n  margin-left: 58.333333%;\n}\n\n.offset-8 {\n  margin-left: 66.666667%;\n}\n\n.offset-9 {\n  margin-left: 75%;\n}\n\n.offset-10 {\n  margin-left: 83.333333%;\n}\n\n.offset-11 {\n  margin-left: 91.666667%;\n}\n\n@media (min-width: 576px) {\n  .col-sm {\n    -ms-flex-preferred-size: 0;\n    flex-basis: 0;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n    max-width: 100%;\n  }\n  .col-sm-auto {\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    width: auto;\n    max-width: 100%;\n  }\n  .col-sm-1 {\n    -ms-flex: 0 0 8.333333%;\n    flex: 0 0 8.333333%;\n    max-width: 8.333333%;\n  }\n  .col-sm-2 {\n    -ms-flex: 0 0 16.666667%;\n    flex: 0 0 16.666667%;\n    max-width: 16.666667%;\n  }\n  .col-sm-3 {\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-sm-4 {\n    -ms-flex: 0 0 33.333333%;\n    flex: 0 0 33.333333%;\n    max-width: 33.333333%;\n  }\n  .col-sm-5 {\n    -ms-flex: 0 0 41.666667%;\n    flex: 0 0 41.666667%;\n    max-width: 41.666667%;\n  }\n  .col-sm-6 {\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-sm-7 {\n    -ms-flex: 0 0 58.333333%;\n    flex: 0 0 58.333333%;\n    max-width: 58.333333%;\n  }\n  .col-sm-8 {\n    -ms-flex: 0 0 66.666667%;\n    flex: 0 0 66.666667%;\n    max-width: 66.666667%;\n  }\n  .col-sm-9 {\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-sm-10 {\n    -ms-flex: 0 0 83.333333%;\n    flex: 0 0 83.333333%;\n    max-width: 83.333333%;\n  }\n  .col-sm-11 {\n    -ms-flex: 0 0 91.666667%;\n    flex: 0 0 91.666667%;\n    max-width: 91.666667%;\n  }\n  .col-sm-12 {\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .order-sm-first {\n    -ms-flex-order: -1;\n    order: -1;\n  }\n  .order-sm-last {\n    -ms-flex-order: 13;\n    order: 13;\n  }\n  .order-sm-0 {\n    -ms-flex-order: 0;\n    order: 0;\n  }\n  .order-sm-1 {\n    -ms-flex-order: 1;\n    order: 1;\n  }\n  .order-sm-2 {\n    -ms-flex-order: 2;\n    order: 2;\n  }\n  .order-sm-3 {\n    -ms-flex-order: 3;\n    order: 3;\n  }\n  .order-sm-4 {\n    -ms-flex-order: 4;\n    order: 4;\n  }\n  .order-sm-5 {\n    -ms-flex-order: 5;\n    order: 5;\n  }\n  .order-sm-6 {\n    -ms-flex-order: 6;\n    order: 6;\n  }\n  .order-sm-7 {\n    -ms-flex-order: 7;\n    order: 7;\n  }\n  .order-sm-8 {\n    -ms-flex-order: 8;\n    order: 8;\n  }\n  .order-sm-9 {\n    -ms-flex-order: 9;\n    order: 9;\n  }\n  .order-sm-10 {\n    -ms-flex-order: 10;\n    order: 10;\n  }\n  .order-sm-11 {\n    -ms-flex-order: 11;\n    order: 11;\n  }\n  .order-sm-12 {\n    -ms-flex-order: 12;\n    order: 12;\n  }\n  .offset-sm-0 {\n    margin-left: 0;\n  }\n  .offset-sm-1 {\n    margin-left: 8.333333%;\n  }\n  .offset-sm-2 {\n    margin-left: 16.666667%;\n  }\n  .offset-sm-3 {\n    margin-left: 25%;\n  }\n  .offset-sm-4 {\n    margin-left: 33.333333%;\n  }\n  .offset-sm-5 {\n    margin-left: 41.666667%;\n  }\n  .offset-sm-6 {\n    margin-left: 50%;\n  }\n  .offset-sm-7 {\n    margin-left: 58.333333%;\n  }\n  .offset-sm-8 {\n    margin-left: 66.666667%;\n  }\n  .offset-sm-9 {\n    margin-left: 75%;\n  }\n  .offset-sm-10 {\n    margin-left: 83.333333%;\n  }\n  .offset-sm-11 {\n    margin-left: 91.666667%;\n  }\n}\n\n@media (min-width: 768px) {\n  .col-md {\n    -ms-flex-preferred-size: 0;\n    flex-basis: 0;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n    max-width: 100%;\n  }\n  .col-md-auto {\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    width: auto;\n    max-width: 100%;\n  }\n  .col-md-1 {\n    -ms-flex: 0 0 8.333333%;\n    flex: 0 0 8.333333%;\n    max-width: 8.333333%;\n  }\n  .col-md-2 {\n    -ms-flex: 0 0 16.666667%;\n    flex: 0 0 16.666667%;\n    max-width: 16.666667%;\n  }\n  .col-md-3 {\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-md-4 {\n    -ms-flex: 0 0 33.333333%;\n    flex: 0 0 33.333333%;\n    max-width: 33.333333%;\n  }\n  .col-md-5 {\n    -ms-flex: 0 0 41.666667%;\n    flex: 0 0 41.666667%;\n    max-width: 41.666667%;\n  }\n  .col-md-6 {\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-md-7 {\n    -ms-flex: 0 0 58.333333%;\n    flex: 0 0 58.333333%;\n    max-width: 58.333333%;\n  }\n  .col-md-8 {\n    -ms-flex: 0 0 66.666667%;\n    flex: 0 0 66.666667%;\n    max-width: 66.666667%;\n  }\n  .col-md-9 {\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-md-10 {\n    -ms-flex: 0 0 83.333333%;\n    flex: 0 0 83.333333%;\n    max-width: 83.333333%;\n  }\n  .col-md-11 {\n    -ms-flex: 0 0 91.666667%;\n    flex: 0 0 91.666667%;\n    max-width: 91.666667%;\n  }\n  .col-md-12 {\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .order-md-first {\n    -ms-flex-order: -1;\n    order: -1;\n  }\n  .order-md-last {\n    -ms-flex-order: 13;\n    order: 13;\n  }\n  .order-md-0 {\n    -ms-flex-order: 0;\n    order: 0;\n  }\n  .order-md-1 {\n    -ms-flex-order: 1;\n    order: 1;\n  }\n  .order-md-2 {\n    -ms-flex-order: 2;\n    order: 2;\n  }\n  .order-md-3 {\n    -ms-flex-order: 3;\n    order: 3;\n  }\n  .order-md-4 {\n    -ms-flex-order: 4;\n    order: 4;\n  }\n  .order-md-5 {\n    -ms-flex-order: 5;\n    order: 5;\n  }\n  .order-md-6 {\n    -ms-flex-order: 6;\n    order: 6;\n  }\n  .order-md-7 {\n    -ms-flex-order: 7;\n    order: 7;\n  }\n  .order-md-8 {\n    -ms-flex-order: 8;\n    order: 8;\n  }\n  .order-md-9 {\n    -ms-flex-order: 9;\n    order: 9;\n  }\n  .order-md-10 {\n    -ms-flex-order: 10;\n    order: 10;\n  }\n  .order-md-11 {\n    -ms-flex-order: 11;\n    order: 11;\n  }\n  .order-md-12 {\n    -ms-flex-order: 12;\n    order: 12;\n  }\n  .offset-md-0 {\n    margin-left: 0;\n  }\n  .offset-md-1 {\n    margin-left: 8.333333%;\n  }\n  .offset-md-2 {\n    margin-left: 16.666667%;\n  }\n  .offset-md-3 {\n    margin-left: 25%;\n  }\n  .offset-md-4 {\n    margin-left: 33.333333%;\n  }\n  .offset-md-5 {\n    margin-left: 41.666667%;\n  }\n  .offset-md-6 {\n    margin-left: 50%;\n  }\n  .offset-md-7 {\n    margin-left: 58.333333%;\n  }\n  .offset-md-8 {\n    margin-left: 66.666667%;\n  }\n  .offset-md-9 {\n    margin-left: 75%;\n  }\n  .offset-md-10 {\n    margin-left: 83.333333%;\n  }\n  .offset-md-11 {\n    margin-left: 91.666667%;\n  }\n}\n\n@media (min-width: 992px) {\n  .col-lg {\n    -ms-flex-preferred-size: 0;\n    flex-basis: 0;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n    max-width: 100%;\n  }\n  .col-lg-auto {\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    width: auto;\n    max-width: 100%;\n  }\n  .col-lg-1 {\n    -ms-flex: 0 0 8.333333%;\n    flex: 0 0 8.333333%;\n    max-width: 8.333333%;\n  }\n  .col-lg-2 {\n    -ms-flex: 0 0 16.666667%;\n    flex: 0 0 16.666667%;\n    max-width: 16.666667%;\n  }\n  .col-lg-3 {\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-lg-4 {\n    -ms-flex: 0 0 33.333333%;\n    flex: 0 0 33.333333%;\n    max-width: 33.333333%;\n  }\n  .col-lg-5 {\n    -ms-flex: 0 0 41.666667%;\n    flex: 0 0 41.666667%;\n    max-width: 41.666667%;\n  }\n  .col-lg-6 {\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-lg-7 {\n    -ms-flex: 0 0 58.333333%;\n    flex: 0 0 58.333333%;\n    max-width: 58.333333%;\n  }\n  .col-lg-8 {\n    -ms-flex: 0 0 66.666667%;\n    flex: 0 0 66.666667%;\n    max-width: 66.666667%;\n  }\n  .col-lg-9 {\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-lg-10 {\n    -ms-flex: 0 0 83.333333%;\n    flex: 0 0 83.333333%;\n    max-width: 83.333333%;\n  }\n  .col-lg-11 {\n    -ms-flex: 0 0 91.666667%;\n    flex: 0 0 91.666667%;\n    max-width: 91.666667%;\n  }\n  .col-lg-12 {\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .order-lg-first {\n    -ms-flex-order: -1;\n    order: -1;\n  }\n  .order-lg-last {\n    -ms-flex-order: 13;\n    order: 13;\n  }\n  .order-lg-0 {\n    -ms-flex-order: 0;\n    order: 0;\n  }\n  .order-lg-1 {\n    -ms-flex-order: 1;\n    order: 1;\n  }\n  .order-lg-2 {\n    -ms-flex-order: 2;\n    order: 2;\n  }\n  .order-lg-3 {\n    -ms-flex-order: 3;\n    order: 3;\n  }\n  .order-lg-4 {\n    -ms-flex-order: 4;\n    order: 4;\n  }\n  .order-lg-5 {\n    -ms-flex-order: 5;\n    order: 5;\n  }\n  .order-lg-6 {\n    -ms-flex-order: 6;\n    order: 6;\n  }\n  .order-lg-7 {\n    -ms-flex-order: 7;\n    order: 7;\n  }\n  .order-lg-8 {\n    -ms-flex-order: 8;\n    order: 8;\n  }\n  .order-lg-9 {\n    -ms-flex-order: 9;\n    order: 9;\n  }\n  .order-lg-10 {\n    -ms-flex-order: 10;\n    order: 10;\n  }\n  .order-lg-11 {\n    -ms-flex-order: 11;\n    order: 11;\n  }\n  .order-lg-12 {\n    -ms-flex-order: 12;\n    order: 12;\n  }\n  .offset-lg-0 {\n    margin-left: 0;\n  }\n  .offset-lg-1 {\n    margin-left: 8.333333%;\n  }\n  .offset-lg-2 {\n    margin-left: 16.666667%;\n  }\n  .offset-lg-3 {\n    margin-left: 25%;\n  }\n  .offset-lg-4 {\n    margin-left: 33.333333%;\n  }\n  .offset-lg-5 {\n    margin-left: 41.666667%;\n  }\n  .offset-lg-6 {\n    margin-left: 50%;\n  }\n  .offset-lg-7 {\n    margin-left: 58.333333%;\n  }\n  .offset-lg-8 {\n    margin-left: 66.666667%;\n  }\n  .offset-lg-9 {\n    margin-left: 75%;\n  }\n  .offset-lg-10 {\n    margin-left: 83.333333%;\n  }\n  .offset-lg-11 {\n    margin-left: 91.666667%;\n  }\n}\n\n@media (min-width: 1200px) {\n  .col-xl {\n    -ms-flex-preferred-size: 0;\n    flex-basis: 0;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n    max-width: 100%;\n  }\n  .col-xl-auto {\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    width: auto;\n    max-width: 100%;\n  }\n  .col-xl-1 {\n    -ms-flex: 0 0 8.333333%;\n    flex: 0 0 8.333333%;\n    max-width: 8.333333%;\n  }\n  .col-xl-2 {\n    -ms-flex: 0 0 16.666667%;\n    flex: 0 0 16.666667%;\n    max-width: 16.666667%;\n  }\n  .col-xl-3 {\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-xl-4 {\n    -ms-flex: 0 0 33.333333%;\n    flex: 0 0 33.333333%;\n    max-width: 33.333333%;\n  }\n  .col-xl-5 {\n    -ms-flex: 0 0 41.666667%;\n    flex: 0 0 41.666667%;\n    max-width: 41.666667%;\n  }\n  .col-xl-6 {\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-xl-7 {\n    -ms-flex: 0 0 58.333333%;\n    flex: 0 0 58.333333%;\n    max-width: 58.333333%;\n  }\n  .col-xl-8 {\n    -ms-flex: 0 0 66.666667%;\n    flex: 0 0 66.666667%;\n    max-width: 66.666667%;\n  }\n  .col-xl-9 {\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-xl-10 {\n    -ms-flex: 0 0 83.333333%;\n    flex: 0 0 83.333333%;\n    max-width: 83.333333%;\n  }\n  .col-xl-11 {\n    -ms-flex: 0 0 91.666667%;\n    flex: 0 0 91.666667%;\n    max-width: 91.666667%;\n  }\n  .col-xl-12 {\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .order-xl-first {\n    -ms-flex-order: -1;\n    order: -1;\n  }\n  .order-xl-last {\n    -ms-flex-order: 13;\n    order: 13;\n  }\n  .order-xl-0 {\n    -ms-flex-order: 0;\n    order: 0;\n  }\n  .order-xl-1 {\n    -ms-flex-order: 1;\n    order: 1;\n  }\n  .order-xl-2 {\n    -ms-flex-order: 2;\n    order: 2;\n  }\n  .order-xl-3 {\n    -ms-flex-order: 3;\n    order: 3;\n  }\n  .order-xl-4 {\n    -ms-flex-order: 4;\n    order: 4;\n  }\n  .order-xl-5 {\n    -ms-flex-order: 5;\n    order: 5;\n  }\n  .order-xl-6 {\n    -ms-flex-order: 6;\n    order: 6;\n  }\n  .order-xl-7 {\n    -ms-flex-order: 7;\n    order: 7;\n  }\n  .order-xl-8 {\n    -ms-flex-order: 8;\n    order: 8;\n  }\n  .order-xl-9 {\n    -ms-flex-order: 9;\n    order: 9;\n  }\n  .order-xl-10 {\n    -ms-flex-order: 10;\n    order: 10;\n  }\n  .order-xl-11 {\n    -ms-flex-order: 11;\n    order: 11;\n  }\n  .order-xl-12 {\n    -ms-flex-order: 12;\n    order: 12;\n  }\n  .offset-xl-0 {\n    margin-left: 0;\n  }\n  .offset-xl-1 {\n    margin-left: 8.333333%;\n  }\n  .offset-xl-2 {\n    margin-left: 16.666667%;\n  }\n  .offset-xl-3 {\n    margin-left: 25%;\n  }\n  .offset-xl-4 {\n    margin-left: 33.333333%;\n  }\n  .offset-xl-5 {\n    margin-left: 41.666667%;\n  }\n  .offset-xl-6 {\n    margin-left: 50%;\n  }\n  .offset-xl-7 {\n    margin-left: 58.333333%;\n  }\n  .offset-xl-8 {\n    margin-left: 66.666667%;\n  }\n  .offset-xl-9 {\n    margin-left: 75%;\n  }\n  .offset-xl-10 {\n    margin-left: 83.333333%;\n  }\n  .offset-xl-11 {\n    margin-left: 91.666667%;\n  }\n}\n\n.d-none {\n  display: none !important;\n}\n\n.d-inline {\n  display: inline !important;\n}\n\n.d-inline-block {\n  display: inline-block !important;\n}\n\n.d-block {\n  display: block !important;\n}\n\n.d-table {\n  display: table !important;\n}\n\n.d-table-row {\n  display: table-row !important;\n}\n\n.d-table-cell {\n  display: table-cell !important;\n}\n\n.d-flex {\n  display: -ms-flexbox !important;\n  display: flex !important;\n}\n\n.d-inline-flex {\n  display: -ms-inline-flexbox !important;\n  display: inline-flex !important;\n}\n\n@media (min-width: 576px) {\n  .d-sm-none {\n    display: none !important;\n  }\n  .d-sm-inline {\n    display: inline !important;\n  }\n  .d-sm-inline-block {\n    display: inline-block !important;\n  }\n  .d-sm-block {\n    display: block !important;\n  }\n  .d-sm-table {\n    display: table !important;\n  }\n  .d-sm-table-row {\n    display: table-row !important;\n  }\n  .d-sm-table-cell {\n    display: table-cell !important;\n  }\n  .d-sm-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-sm-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n@media (min-width: 768px) {\n  .d-md-none {\n    display: none !important;\n  }\n  .d-md-inline {\n    display: inline !important;\n  }\n  .d-md-inline-block {\n    display: inline-block !important;\n  }\n  .d-md-block {\n    display: block !important;\n  }\n  .d-md-table {\n    display: table !important;\n  }\n  .d-md-table-row {\n    display: table-row !important;\n  }\n  .d-md-table-cell {\n    display: table-cell !important;\n  }\n  .d-md-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-md-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n@media (min-width: 992px) {\n  .d-lg-none {\n    display: none !important;\n  }\n  .d-lg-inline {\n    display: inline !important;\n  }\n  .d-lg-inline-block {\n    display: inline-block !important;\n  }\n  .d-lg-block {\n    display: block !important;\n  }\n  .d-lg-table {\n    display: table !important;\n  }\n  .d-lg-table-row {\n    display: table-row !important;\n  }\n  .d-lg-table-cell {\n    display: table-cell !important;\n  }\n  .d-lg-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-lg-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .d-xl-none {\n    display: none !important;\n  }\n  .d-xl-inline {\n    display: inline !important;\n  }\n  .d-xl-inline-block {\n    display: inline-block !important;\n  }\n  .d-xl-block {\n    display: block !important;\n  }\n  .d-xl-table {\n    display: table !important;\n  }\n  .d-xl-table-row {\n    display: table-row !important;\n  }\n  .d-xl-table-cell {\n    display: table-cell !important;\n  }\n  .d-xl-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-xl-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n@media print {\n  .d-print-none {\n    display: none !important;\n  }\n  .d-print-inline {\n    display: inline !important;\n  }\n  .d-print-inline-block {\n    display: inline-block !important;\n  }\n  .d-print-block {\n    display: block !important;\n  }\n  .d-print-table {\n    display: table !important;\n  }\n  .d-print-table-row {\n    display: table-row !important;\n  }\n  .d-print-table-cell {\n    display: table-cell !important;\n  }\n  .d-print-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-print-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n.flex-row {\n  -ms-flex-direction: row !important;\n  flex-direction: row !important;\n}\n\n.flex-column {\n  -ms-flex-direction: column !important;\n  flex-direction: column !important;\n}\n\n.flex-row-reverse {\n  -ms-flex-direction: row-reverse !important;\n  flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n  -ms-flex-direction: column-reverse !important;\n  flex-direction: column-reverse !important;\n}\n\n.flex-wrap {\n  -ms-flex-wrap: wrap !important;\n  flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n  -ms-flex-wrap: nowrap !important;\n  flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n  -ms-flex-wrap: wrap-reverse !important;\n  flex-wrap: wrap-reverse !important;\n}\n\n.flex-fill {\n  -ms-flex: 1 1 auto !important;\n  flex: 1 1 auto !important;\n}\n\n.flex-grow-0 {\n  -ms-flex-positive: 0 !important;\n  flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n  -ms-flex-positive: 1 !important;\n  flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n  -ms-flex-negative: 0 !important;\n  flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n  -ms-flex-negative: 1 !important;\n  flex-shrink: 1 !important;\n}\n\n.justify-content-start {\n  -ms-flex-pack: start !important;\n  justify-content: flex-start !important;\n}\n\n.justify-content-end {\n  -ms-flex-pack: end !important;\n  justify-content: flex-end !important;\n}\n\n.justify-content-center {\n  -ms-flex-pack: center !important;\n  justify-content: center !important;\n}\n\n.justify-content-between {\n  -ms-flex-pack: justify !important;\n  justify-content: space-between !important;\n}\n\n.justify-content-around {\n  -ms-flex-pack: distribute !important;\n  justify-content: space-around !important;\n}\n\n.align-items-start {\n  -ms-flex-align: start !important;\n  align-items: flex-start !important;\n}\n\n.align-items-end {\n  -ms-flex-align: end !important;\n  align-items: flex-end !important;\n}\n\n.align-items-center {\n  -ms-flex-align: center !important;\n  align-items: center !important;\n}\n\n.align-items-baseline {\n  -ms-flex-align: baseline !important;\n  align-items: baseline !important;\n}\n\n.align-items-stretch {\n  -ms-flex-align: stretch !important;\n  align-items: stretch !important;\n}\n\n.align-content-start {\n  -ms-flex-line-pack: start !important;\n  align-content: flex-start !important;\n}\n\n.align-content-end {\n  -ms-flex-line-pack: end !important;\n  align-content: flex-end !important;\n}\n\n.align-content-center {\n  -ms-flex-line-pack: center !important;\n  align-content: center !important;\n}\n\n.align-content-between {\n  -ms-flex-line-pack: justify !important;\n  align-content: space-between !important;\n}\n\n.align-content-around {\n  -ms-flex-line-pack: distribute !important;\n  align-content: space-around !important;\n}\n\n.align-content-stretch {\n  -ms-flex-line-pack: stretch !important;\n  align-content: stretch !important;\n}\n\n.align-self-auto {\n  -ms-flex-item-align: auto !important;\n  align-self: auto !important;\n}\n\n.align-self-start {\n  -ms-flex-item-align: start !important;\n  align-self: flex-start !important;\n}\n\n.align-self-end {\n  -ms-flex-item-align: end !important;\n  align-self: flex-end !important;\n}\n\n.align-self-center {\n  -ms-flex-item-align: center !important;\n  align-self: center !important;\n}\n\n.align-self-baseline {\n  -ms-flex-item-align: baseline !important;\n  align-self: baseline !important;\n}\n\n.align-self-stretch {\n  -ms-flex-item-align: stretch !important;\n  align-self: stretch !important;\n}\n\n@media (min-width: 576px) {\n  .flex-sm-row {\n    -ms-flex-direction: row !important;\n    flex-direction: row !important;\n  }\n  .flex-sm-column {\n    -ms-flex-direction: column !important;\n    flex-direction: column !important;\n  }\n  .flex-sm-row-reverse {\n    -ms-flex-direction: row-reverse !important;\n    flex-direction: row-reverse !important;\n  }\n  .flex-sm-column-reverse {\n    -ms-flex-direction: column-reverse !important;\n    flex-direction: column-reverse !important;\n  }\n  .flex-sm-wrap {\n    -ms-flex-wrap: wrap !important;\n    flex-wrap: wrap !important;\n  }\n  .flex-sm-nowrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n  }\n  .flex-sm-wrap-reverse {\n    -ms-flex-wrap: wrap-reverse !important;\n    flex-wrap: wrap-reverse !important;\n  }\n  .flex-sm-fill {\n    -ms-flex: 1 1 auto !important;\n    flex: 1 1 auto !important;\n  }\n  .flex-sm-grow-0 {\n    -ms-flex-positive: 0 !important;\n    flex-grow: 0 !important;\n  }\n  .flex-sm-grow-1 {\n    -ms-flex-positive: 1 !important;\n    flex-grow: 1 !important;\n  }\n  .flex-sm-shrink-0 {\n    -ms-flex-negative: 0 !important;\n    flex-shrink: 0 !important;\n  }\n  .flex-sm-shrink-1 {\n    -ms-flex-negative: 1 !important;\n    flex-shrink: 1 !important;\n  }\n  .justify-content-sm-start {\n    -ms-flex-pack: start !important;\n    justify-content: flex-start !important;\n  }\n  .justify-content-sm-end {\n    -ms-flex-pack: end !important;\n    justify-content: flex-end !important;\n  }\n  .justify-content-sm-center {\n    -ms-flex-pack: center !important;\n    justify-content: center !important;\n  }\n  .justify-content-sm-between {\n    -ms-flex-pack: justify !important;\n    justify-content: space-between !important;\n  }\n  .justify-content-sm-around {\n    -ms-flex-pack: distribute !important;\n    justify-content: space-around !important;\n  }\n  .align-items-sm-start {\n    -ms-flex-align: start !important;\n    align-items: flex-start !important;\n  }\n  .align-items-sm-end {\n    -ms-flex-align: end !important;\n    align-items: flex-end !important;\n  }\n  .align-items-sm-center {\n    -ms-flex-align: center !important;\n    align-items: center !important;\n  }\n  .align-items-sm-baseline {\n    -ms-flex-align: baseline !important;\n    align-items: baseline !important;\n  }\n  .align-items-sm-stretch {\n    -ms-flex-align: stretch !important;\n    align-items: stretch !important;\n  }\n  .align-content-sm-start {\n    -ms-flex-line-pack: start !important;\n    align-content: flex-start !important;\n  }\n  .align-content-sm-end {\n    -ms-flex-line-pack: end !important;\n    align-content: flex-end !important;\n  }\n  .align-content-sm-center {\n    -ms-flex-line-pack: center !important;\n    align-content: center !important;\n  }\n  .align-content-sm-between {\n    -ms-flex-line-pack: justify !important;\n    align-content: space-between !important;\n  }\n  .align-content-sm-around {\n    -ms-flex-line-pack: distribute !important;\n    align-content: space-around !important;\n  }\n  .align-content-sm-stretch {\n    -ms-flex-line-pack: stretch !important;\n    align-content: stretch !important;\n  }\n  .align-self-sm-auto {\n    -ms-flex-item-align: auto !important;\n    align-self: auto !important;\n  }\n  .align-self-sm-start {\n    -ms-flex-item-align: start !important;\n    align-self: flex-start !important;\n  }\n  .align-self-sm-end {\n    -ms-flex-item-align: end !important;\n    align-self: flex-end !important;\n  }\n  .align-self-sm-center {\n    -ms-flex-item-align: center !important;\n    align-self: center !important;\n  }\n  .align-self-sm-baseline {\n    -ms-flex-item-align: baseline !important;\n    align-self: baseline !important;\n  }\n  .align-self-sm-stretch {\n    -ms-flex-item-align: stretch !important;\n    align-self: stretch !important;\n  }\n}\n\n@media (min-width: 768px) {\n  .flex-md-row {\n    -ms-flex-direction: row !important;\n    flex-direction: row !important;\n  }\n  .flex-md-column {\n    -ms-flex-direction: column !important;\n    flex-direction: column !important;\n  }\n  .flex-md-row-reverse {\n    -ms-flex-direction: row-reverse !important;\n    flex-direction: row-reverse !important;\n  }\n  .flex-md-column-reverse {\n    -ms-flex-direction: column-reverse !important;\n    flex-direction: column-reverse !important;\n  }\n  .flex-md-wrap {\n    -ms-flex-wrap: wrap !important;\n    flex-wrap: wrap !important;\n  }\n  .flex-md-nowrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n  }\n  .flex-md-wrap-reverse {\n    -ms-flex-wrap: wrap-reverse !important;\n    flex-wrap: wrap-reverse !important;\n  }\n  .flex-md-fill {\n    -ms-flex: 1 1 auto !important;\n    flex: 1 1 auto !important;\n  }\n  .flex-md-grow-0 {\n    -ms-flex-positive: 0 !important;\n    flex-grow: 0 !important;\n  }\n  .flex-md-grow-1 {\n    -ms-flex-positive: 1 !important;\n    flex-grow: 1 !important;\n  }\n  .flex-md-shrink-0 {\n    -ms-flex-negative: 0 !important;\n    flex-shrink: 0 !important;\n  }\n  .flex-md-shrink-1 {\n    -ms-flex-negative: 1 !important;\n    flex-shrink: 1 !important;\n  }\n  .justify-content-md-start {\n    -ms-flex-pack: start !important;\n    justify-content: flex-start !important;\n  }\n  .justify-content-md-end {\n    -ms-flex-pack: end !important;\n    justify-content: flex-end !important;\n  }\n  .justify-content-md-center {\n    -ms-flex-pack: center !important;\n    justify-content: center !important;\n  }\n  .justify-content-md-between {\n    -ms-flex-pack: justify !important;\n    justify-content: space-between !important;\n  }\n  .justify-content-md-around {\n    -ms-flex-pack: distribute !important;\n    justify-content: space-around !important;\n  }\n  .align-items-md-start {\n    -ms-flex-align: start !important;\n    align-items: flex-start !important;\n  }\n  .align-items-md-end {\n    -ms-flex-align: end !important;\n    align-items: flex-end !important;\n  }\n  .align-items-md-center {\n    -ms-flex-align: center !important;\n    align-items: center !important;\n  }\n  .align-items-md-baseline {\n    -ms-flex-align: baseline !important;\n    align-items: baseline !important;\n  }\n  .align-items-md-stretch {\n    -ms-flex-align: stretch !important;\n    align-items: stretch !important;\n  }\n  .align-content-md-start {\n    -ms-flex-line-pack: start !important;\n    align-content: flex-start !important;\n  }\n  .align-content-md-end {\n    -ms-flex-line-pack: end !important;\n    align-content: flex-end !important;\n  }\n  .align-content-md-center {\n    -ms-flex-line-pack: center !important;\n    align-content: center !important;\n  }\n  .align-content-md-between {\n    -ms-flex-line-pack: justify !important;\n    align-content: space-between !important;\n  }\n  .align-content-md-around {\n    -ms-flex-line-pack: distribute !important;\n    align-content: space-around !important;\n  }\n  .align-content-md-stretch {\n    -ms-flex-line-pack: stretch !important;\n    align-content: stretch !important;\n  }\n  .align-self-md-auto {\n    -ms-flex-item-align: auto !important;\n    align-self: auto !important;\n  }\n  .align-self-md-start {\n    -ms-flex-item-align: start !important;\n    align-self: flex-start !important;\n  }\n  .align-self-md-end {\n    -ms-flex-item-align: end !important;\n    align-self: flex-end !important;\n  }\n  .align-self-md-center {\n    -ms-flex-item-align: center !important;\n    align-self: center !important;\n  }\n  .align-self-md-baseline {\n    -ms-flex-item-align: baseline !important;\n    align-self: baseline !important;\n  }\n  .align-self-md-stretch {\n    -ms-flex-item-align: stretch !important;\n    align-self: stretch !important;\n  }\n}\n\n@media (min-width: 992px) {\n  .flex-lg-row {\n    -ms-flex-direction: row !important;\n    flex-direction: row !important;\n  }\n  .flex-lg-column {\n    -ms-flex-direction: column !important;\n    flex-direction: column !important;\n  }\n  .flex-lg-row-reverse {\n    -ms-flex-direction: row-reverse !important;\n    flex-direction: row-reverse !important;\n  }\n  .flex-lg-column-reverse {\n    -ms-flex-direction: column-reverse !important;\n    flex-direction: column-reverse !important;\n  }\n  .flex-lg-wrap {\n    -ms-flex-wrap: wrap !important;\n    flex-wrap: wrap !important;\n  }\n  .flex-lg-nowrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n  }\n  .flex-lg-wrap-reverse {\n    -ms-flex-wrap: wrap-reverse !important;\n    flex-wrap: wrap-reverse !important;\n  }\n  .flex-lg-fill {\n    -ms-flex: 1 1 auto !important;\n    flex: 1 1 auto !important;\n  }\n  .flex-lg-grow-0 {\n    -ms-flex-positive: 0 !important;\n    flex-grow: 0 !important;\n  }\n  .flex-lg-grow-1 {\n    -ms-flex-positive: 1 !important;\n    flex-grow: 1 !important;\n  }\n  .flex-lg-shrink-0 {\n    -ms-flex-negative: 0 !important;\n    flex-shrink: 0 !important;\n  }\n  .flex-lg-shrink-1 {\n    -ms-flex-negative: 1 !important;\n    flex-shrink: 1 !important;\n  }\n  .justify-content-lg-start {\n    -ms-flex-pack: start !important;\n    justify-content: flex-start !important;\n  }\n  .justify-content-lg-end {\n    -ms-flex-pack: end !important;\n    justify-content: flex-end !important;\n  }\n  .justify-content-lg-center {\n    -ms-flex-pack: center !important;\n    justify-content: center !important;\n  }\n  .justify-content-lg-between {\n    -ms-flex-pack: justify !important;\n    justify-content: space-between !important;\n  }\n  .justify-content-lg-around {\n    -ms-flex-pack: distribute !important;\n    justify-content: space-around !important;\n  }\n  .align-items-lg-start {\n    -ms-flex-align: start !important;\n    align-items: flex-start !important;\n  }\n  .align-items-lg-end {\n    -ms-flex-align: end !important;\n    align-items: flex-end !important;\n  }\n  .align-items-lg-center {\n    -ms-flex-align: center !important;\n    align-items: center !important;\n  }\n  .align-items-lg-baseline {\n    -ms-flex-align: baseline !important;\n    align-items: baseline !important;\n  }\n  .align-items-lg-stretch {\n    -ms-flex-align: stretch !important;\n    align-items: stretch !important;\n  }\n  .align-content-lg-start {\n    -ms-flex-line-pack: start !important;\n    align-content: flex-start !important;\n  }\n  .align-content-lg-end {\n    -ms-flex-line-pack: end !important;\n    align-content: flex-end !important;\n  }\n  .align-content-lg-center {\n    -ms-flex-line-pack: center !important;\n    align-content: center !important;\n  }\n  .align-content-lg-between {\n    -ms-flex-line-pack: justify !important;\n    align-content: space-between !important;\n  }\n  .align-content-lg-around {\n    -ms-flex-line-pack: distribute !important;\n    align-content: space-around !important;\n  }\n  .align-content-lg-stretch {\n    -ms-flex-line-pack: stretch !important;\n    align-content: stretch !important;\n  }\n  .align-self-lg-auto {\n    -ms-flex-item-align: auto !important;\n    align-self: auto !important;\n  }\n  .align-self-lg-start {\n    -ms-flex-item-align: start !important;\n    align-self: flex-start !important;\n  }\n  .align-self-lg-end {\n    -ms-flex-item-align: end !important;\n    align-self: flex-end !important;\n  }\n  .align-self-lg-center {\n    -ms-flex-item-align: center !important;\n    align-self: center !important;\n  }\n  .align-self-lg-baseline {\n    -ms-flex-item-align: baseline !important;\n    align-self: baseline !important;\n  }\n  .align-self-lg-stretch {\n    -ms-flex-item-align: stretch !important;\n    align-self: stretch !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .flex-xl-row {\n    -ms-flex-direction: row !important;\n    flex-direction: row !important;\n  }\n  .flex-xl-column {\n    -ms-flex-direction: column !important;\n    flex-direction: column !important;\n  }\n  .flex-xl-row-reverse {\n    -ms-flex-direction: row-reverse !important;\n    flex-direction: row-reverse !important;\n  }\n  .flex-xl-column-reverse {\n    -ms-flex-direction: column-reverse !important;\n    flex-direction: column-reverse !important;\n  }\n  .flex-xl-wrap {\n    -ms-flex-wrap: wrap !important;\n    flex-wrap: wrap !important;\n  }\n  .flex-xl-nowrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n  }\n  .flex-xl-wrap-reverse {\n    -ms-flex-wrap: wrap-reverse !important;\n    flex-wrap: wrap-reverse !important;\n  }\n  .flex-xl-fill {\n    -ms-flex: 1 1 auto !important;\n    flex: 1 1 auto !important;\n  }\n  .flex-xl-grow-0 {\n    -ms-flex-positive: 0 !important;\n    flex-grow: 0 !important;\n  }\n  .flex-xl-grow-1 {\n    -ms-flex-positive: 1 !important;\n    flex-grow: 1 !important;\n  }\n  .flex-xl-shrink-0 {\n    -ms-flex-negative: 0 !important;\n    flex-shrink: 0 !important;\n  }\n  .flex-xl-shrink-1 {\n    -ms-flex-negative: 1 !important;\n    flex-shrink: 1 !important;\n  }\n  .justify-content-xl-start {\n    -ms-flex-pack: start !important;\n    justify-content: flex-start !important;\n  }\n  .justify-content-xl-end {\n    -ms-flex-pack: end !important;\n    justify-content: flex-end !important;\n  }\n  .justify-content-xl-center {\n    -ms-flex-pack: center !important;\n    justify-content: center !important;\n  }\n  .justify-content-xl-between {\n    -ms-flex-pack: justify !important;\n    justify-content: space-between !important;\n  }\n  .justify-content-xl-around {\n    -ms-flex-pack: distribute !important;\n    justify-content: space-around !important;\n  }\n  .align-items-xl-start {\n    -ms-flex-align: start !important;\n    align-items: flex-start !important;\n  }\n  .align-items-xl-end {\n    -ms-flex-align: end !important;\n    align-items: flex-end !important;\n  }\n  .align-items-xl-center {\n    -ms-flex-align: center !important;\n    align-items: center !important;\n  }\n  .align-items-xl-baseline {\n    -ms-flex-align: baseline !important;\n    align-items: baseline !important;\n  }\n  .align-items-xl-stretch {\n    -ms-flex-align: stretch !important;\n    align-items: stretch !important;\n  }\n  .align-content-xl-start {\n    -ms-flex-line-pack: start !important;\n    align-content: flex-start !important;\n  }\n  .align-content-xl-end {\n    -ms-flex-line-pack: end !important;\n    align-content: flex-end !important;\n  }\n  .align-content-xl-center {\n    -ms-flex-line-pack: center !important;\n    align-content: center !important;\n  }\n  .align-content-xl-between {\n    -ms-flex-line-pack: justify !important;\n    align-content: space-between !important;\n  }\n  .align-content-xl-around {\n    -ms-flex-line-pack: distribute !important;\n    align-content: space-around !important;\n  }\n  .align-content-xl-stretch {\n    -ms-flex-line-pack: stretch !important;\n    align-content: stretch !important;\n  }\n  .align-self-xl-auto {\n    -ms-flex-item-align: auto !important;\n    align-self: auto !important;\n  }\n  .align-self-xl-start {\n    -ms-flex-item-align: start !important;\n    align-self: flex-start !important;\n  }\n  .align-self-xl-end {\n    -ms-flex-item-align: end !important;\n    align-self: flex-end !important;\n  }\n  .align-self-xl-center {\n    -ms-flex-item-align: center !important;\n    align-self: center !important;\n  }\n  .align-self-xl-baseline {\n    -ms-flex-item-align: baseline !important;\n    align-self: baseline !important;\n  }\n  .align-self-xl-stretch {\n    -ms-flex-item-align: stretch !important;\n    align-self: stretch !important;\n  }\n}\n\n.m-0 {\n  margin: 0 !important;\n}\n\n.mt-0,\n.my-0 {\n  margin-top: 0 !important;\n}\n\n.mr-0,\n.mx-0 {\n  margin-right: 0 !important;\n}\n\n.mb-0,\n.my-0 {\n  margin-bottom: 0 !important;\n}\n\n.ml-0,\n.mx-0 {\n  margin-left: 0 !important;\n}\n\n.m-1 {\n  margin: 0.25rem !important;\n}\n\n.mt-1,\n.my-1 {\n  margin-top: 0.25rem !important;\n}\n\n.mr-1,\n.mx-1 {\n  margin-right: 0.25rem !important;\n}\n\n.mb-1,\n.my-1 {\n  margin-bottom: 0.25rem !important;\n}\n\n.ml-1,\n.mx-1 {\n  margin-left: 0.25rem !important;\n}\n\n.m-2 {\n  margin: 0.5rem !important;\n}\n\n.mt-2,\n.my-2 {\n  margin-top: 0.5rem !important;\n}\n\n.mr-2,\n.mx-2 {\n  margin-right: 0.5rem !important;\n}\n\n.mb-2,\n.my-2 {\n  margin-bottom: 0.5rem !important;\n}\n\n.ml-2,\n.mx-2 {\n  margin-left: 0.5rem !important;\n}\n\n.m-3 {\n  margin: 1rem !important;\n}\n\n.mt-3,\n.my-3 {\n  margin-top: 1rem !important;\n}\n\n.mr-3,\n.mx-3 {\n  margin-right: 1rem !important;\n}\n\n.mb-3,\n.my-3 {\n  margin-bottom: 1rem !important;\n}\n\n.ml-3,\n.mx-3 {\n  margin-left: 1rem !important;\n}\n\n.m-4 {\n  margin: 1.5rem !important;\n}\n\n.mt-4,\n.my-4 {\n  margin-top: 1.5rem !important;\n}\n\n.mr-4,\n.mx-4 {\n  margin-right: 1.5rem !important;\n}\n\n.mb-4,\n.my-4 {\n  margin-bottom: 1.5rem !important;\n}\n\n.ml-4,\n.mx-4 {\n  margin-left: 1.5rem !important;\n}\n\n.m-5 {\n  margin: 3rem !important;\n}\n\n.mt-5,\n.my-5 {\n  margin-top: 3rem !important;\n}\n\n.mr-5,\n.mx-5 {\n  margin-right: 3rem !important;\n}\n\n.mb-5,\n.my-5 {\n  margin-bottom: 3rem !important;\n}\n\n.ml-5,\n.mx-5 {\n  margin-left: 3rem !important;\n}\n\n.p-0 {\n  padding: 0 !important;\n}\n\n.pt-0,\n.py-0 {\n  padding-top: 0 !important;\n}\n\n.pr-0,\n.px-0 {\n  padding-right: 0 !important;\n}\n\n.pb-0,\n.py-0 {\n  padding-bottom: 0 !important;\n}\n\n.pl-0,\n.px-0 {\n  padding-left: 0 !important;\n}\n\n.p-1 {\n  padding: 0.25rem !important;\n}\n\n.pt-1,\n.py-1 {\n  padding-top: 0.25rem !important;\n}\n\n.pr-1,\n.px-1 {\n  padding-right: 0.25rem !important;\n}\n\n.pb-1,\n.py-1 {\n  padding-bottom: 0.25rem !important;\n}\n\n.pl-1,\n.px-1 {\n  padding-left: 0.25rem !important;\n}\n\n.p-2 {\n  padding: 0.5rem !important;\n}\n\n.pt-2,\n.py-2 {\n  padding-top: 0.5rem !important;\n}\n\n.pr-2,\n.px-2 {\n  padding-right: 0.5rem !important;\n}\n\n.pb-2,\n.py-2 {\n  padding-bottom: 0.5rem !important;\n}\n\n.pl-2,\n.px-2 {\n  padding-left: 0.5rem !important;\n}\n\n.p-3 {\n  padding: 1rem !important;\n}\n\n.pt-3,\n.py-3 {\n  padding-top: 1rem !important;\n}\n\n.pr-3,\n.px-3 {\n  padding-right: 1rem !important;\n}\n\n.pb-3,\n.py-3 {\n  padding-bottom: 1rem !important;\n}\n\n.pl-3,\n.px-3 {\n  padding-left: 1rem !important;\n}\n\n.p-4 {\n  padding: 1.5rem !important;\n}\n\n.pt-4,\n.py-4 {\n  padding-top: 1.5rem !important;\n}\n\n.pr-4,\n.px-4 {\n  padding-right: 1.5rem !important;\n}\n\n.pb-4,\n.py-4 {\n  padding-bottom: 1.5rem !important;\n}\n\n.pl-4,\n.px-4 {\n  padding-left: 1.5rem !important;\n}\n\n.p-5 {\n  padding: 3rem !important;\n}\n\n.pt-5,\n.py-5 {\n  padding-top: 3rem !important;\n}\n\n.pr-5,\n.px-5 {\n  padding-right: 3rem !important;\n}\n\n.pb-5,\n.py-5 {\n  padding-bottom: 3rem !important;\n}\n\n.pl-5,\n.px-5 {\n  padding-left: 3rem !important;\n}\n\n.m-n1 {\n  margin: -0.25rem !important;\n}\n\n.mt-n1,\n.my-n1 {\n  margin-top: -0.25rem !important;\n}\n\n.mr-n1,\n.mx-n1 {\n  margin-right: -0.25rem !important;\n}\n\n.mb-n1,\n.my-n1 {\n  margin-bottom: -0.25rem !important;\n}\n\n.ml-n1,\n.mx-n1 {\n  margin-left: -0.25rem !important;\n}\n\n.m-n2 {\n  margin: -0.5rem !important;\n}\n\n.mt-n2,\n.my-n2 {\n  margin-top: -0.5rem !important;\n}\n\n.mr-n2,\n.mx-n2 {\n  margin-right: -0.5rem !important;\n}\n\n.mb-n2,\n.my-n2 {\n  margin-bottom: -0.5rem !important;\n}\n\n.ml-n2,\n.mx-n2 {\n  margin-left: -0.5rem !important;\n}\n\n.m-n3 {\n  margin: -1rem !important;\n}\n\n.mt-n3,\n.my-n3 {\n  margin-top: -1rem !important;\n}\n\n.mr-n3,\n.mx-n3 {\n  margin-right: -1rem !important;\n}\n\n.mb-n3,\n.my-n3 {\n  margin-bottom: -1rem !important;\n}\n\n.ml-n3,\n.mx-n3 {\n  margin-left: -1rem !important;\n}\n\n.m-n4 {\n  margin: -1.5rem !important;\n}\n\n.mt-n4,\n.my-n4 {\n  margin-top: -1.5rem !important;\n}\n\n.mr-n4,\n.mx-n4 {\n  margin-right: -1.5rem !important;\n}\n\n.mb-n4,\n.my-n4 {\n  margin-bottom: -1.5rem !important;\n}\n\n.ml-n4,\n.mx-n4 {\n  margin-left: -1.5rem !important;\n}\n\n.m-n5 {\n  margin: -3rem !important;\n}\n\n.mt-n5,\n.my-n5 {\n  margin-top: -3rem !important;\n}\n\n.mr-n5,\n.mx-n5 {\n  margin-right: -3rem !important;\n}\n\n.mb-n5,\n.my-n5 {\n  margin-bottom: -3rem !important;\n}\n\n.ml-n5,\n.mx-n5 {\n  margin-left: -3rem !important;\n}\n\n.m-auto {\n  margin: auto !important;\n}\n\n.mt-auto,\n.my-auto {\n  margin-top: auto !important;\n}\n\n.mr-auto,\n.mx-auto {\n  margin-right: auto !important;\n}\n\n.mb-auto,\n.my-auto {\n  margin-bottom: auto !important;\n}\n\n.ml-auto,\n.mx-auto {\n  margin-left: auto !important;\n}\n\n@media (min-width: 576px) {\n  .m-sm-0 {\n    margin: 0 !important;\n  }\n  .mt-sm-0,\n  .my-sm-0 {\n    margin-top: 0 !important;\n  }\n  .mr-sm-0,\n  .mx-sm-0 {\n    margin-right: 0 !important;\n  }\n  .mb-sm-0,\n  .my-sm-0 {\n    margin-bottom: 0 !important;\n  }\n  .ml-sm-0,\n  .mx-sm-0 {\n    margin-left: 0 !important;\n  }\n  .m-sm-1 {\n    margin: 0.25rem !important;\n  }\n  .mt-sm-1,\n  .my-sm-1 {\n    margin-top: 0.25rem !important;\n  }\n  .mr-sm-1,\n  .mx-sm-1 {\n    margin-right: 0.25rem !important;\n  }\n  .mb-sm-1,\n  .my-sm-1 {\n    margin-bottom: 0.25rem !important;\n  }\n  .ml-sm-1,\n  .mx-sm-1 {\n    margin-left: 0.25rem !important;\n  }\n  .m-sm-2 {\n    margin: 0.5rem !important;\n  }\n  .mt-sm-2,\n  .my-sm-2 {\n    margin-top: 0.5rem !important;\n  }\n  .mr-sm-2,\n  .mx-sm-2 {\n    margin-right: 0.5rem !important;\n  }\n  .mb-sm-2,\n  .my-sm-2 {\n    margin-bottom: 0.5rem !important;\n  }\n  .ml-sm-2,\n  .mx-sm-2 {\n    margin-left: 0.5rem !important;\n  }\n  .m-sm-3 {\n    margin: 1rem !important;\n  }\n  .mt-sm-3,\n  .my-sm-3 {\n    margin-top: 1rem !important;\n  }\n  .mr-sm-3,\n  .mx-sm-3 {\n    margin-right: 1rem !important;\n  }\n  .mb-sm-3,\n  .my-sm-3 {\n    margin-bottom: 1rem !important;\n  }\n  .ml-sm-3,\n  .mx-sm-3 {\n    margin-left: 1rem !important;\n  }\n  .m-sm-4 {\n    margin: 1.5rem !important;\n  }\n  .mt-sm-4,\n  .my-sm-4 {\n    margin-top: 1.5rem !important;\n  }\n  .mr-sm-4,\n  .mx-sm-4 {\n    margin-right: 1.5rem !important;\n  }\n  .mb-sm-4,\n  .my-sm-4 {\n    margin-bottom: 1.5rem !important;\n  }\n  .ml-sm-4,\n  .mx-sm-4 {\n    margin-left: 1.5rem !important;\n  }\n  .m-sm-5 {\n    margin: 3rem !important;\n  }\n  .mt-sm-5,\n  .my-sm-5 {\n    margin-top: 3rem !important;\n  }\n  .mr-sm-5,\n  .mx-sm-5 {\n    margin-right: 3rem !important;\n  }\n  .mb-sm-5,\n  .my-sm-5 {\n    margin-bottom: 3rem !important;\n  }\n  .ml-sm-5,\n  .mx-sm-5 {\n    margin-left: 3rem !important;\n  }\n  .p-sm-0 {\n    padding: 0 !important;\n  }\n  .pt-sm-0,\n  .py-sm-0 {\n    padding-top: 0 !important;\n  }\n  .pr-sm-0,\n  .px-sm-0 {\n    padding-right: 0 !important;\n  }\n  .pb-sm-0,\n  .py-sm-0 {\n    padding-bottom: 0 !important;\n  }\n  .pl-sm-0,\n  .px-sm-0 {\n    padding-left: 0 !important;\n  }\n  .p-sm-1 {\n    padding: 0.25rem !important;\n  }\n  .pt-sm-1,\n  .py-sm-1 {\n    padding-top: 0.25rem !important;\n  }\n  .pr-sm-1,\n  .px-sm-1 {\n    padding-right: 0.25rem !important;\n  }\n  .pb-sm-1,\n  .py-sm-1 {\n    padding-bottom: 0.25rem !important;\n  }\n  .pl-sm-1,\n  .px-sm-1 {\n    padding-left: 0.25rem !important;\n  }\n  .p-sm-2 {\n    padding: 0.5rem !important;\n  }\n  .pt-sm-2,\n  .py-sm-2 {\n    padding-top: 0.5rem !important;\n  }\n  .pr-sm-2,\n  .px-sm-2 {\n    padding-right: 0.5rem !important;\n  }\n  .pb-sm-2,\n  .py-sm-2 {\n    padding-bottom: 0.5rem !important;\n  }\n  .pl-sm-2,\n  .px-sm-2 {\n    padding-left: 0.5rem !important;\n  }\n  .p-sm-3 {\n    padding: 1rem !important;\n  }\n  .pt-sm-3,\n  .py-sm-3 {\n    padding-top: 1rem !important;\n  }\n  .pr-sm-3,\n  .px-sm-3 {\n    padding-right: 1rem !important;\n  }\n  .pb-sm-3,\n  .py-sm-3 {\n    padding-bottom: 1rem !important;\n  }\n  .pl-sm-3,\n  .px-sm-3 {\n    padding-left: 1rem !important;\n  }\n  .p-sm-4 {\n    padding: 1.5rem !important;\n  }\n  .pt-sm-4,\n  .py-sm-4 {\n    padding-top: 1.5rem !important;\n  }\n  .pr-sm-4,\n  .px-sm-4 {\n    padding-right: 1.5rem !important;\n  }\n  .pb-sm-4,\n  .py-sm-4 {\n    padding-bottom: 1.5rem !important;\n  }\n  .pl-sm-4,\n  .px-sm-4 {\n    padding-left: 1.5rem !important;\n  }\n  .p-sm-5 {\n    padding: 3rem !important;\n  }\n  .pt-sm-5,\n  .py-sm-5 {\n    padding-top: 3rem !important;\n  }\n  .pr-sm-5,\n  .px-sm-5 {\n    padding-right: 3rem !important;\n  }\n  .pb-sm-5,\n  .py-sm-5 {\n    padding-bottom: 3rem !important;\n  }\n  .pl-sm-5,\n  .px-sm-5 {\n    padding-left: 3rem !important;\n  }\n  .m-sm-n1 {\n    margin: -0.25rem !important;\n  }\n  .mt-sm-n1,\n  .my-sm-n1 {\n    margin-top: -0.25rem !important;\n  }\n  .mr-sm-n1,\n  .mx-sm-n1 {\n    margin-right: -0.25rem !important;\n  }\n  .mb-sm-n1,\n  .my-sm-n1 {\n    margin-bottom: -0.25rem !important;\n  }\n  .ml-sm-n1,\n  .mx-sm-n1 {\n    margin-left: -0.25rem !important;\n  }\n  .m-sm-n2 {\n    margin: -0.5rem !important;\n  }\n  .mt-sm-n2,\n  .my-sm-n2 {\n    margin-top: -0.5rem !important;\n  }\n  .mr-sm-n2,\n  .mx-sm-n2 {\n    margin-right: -0.5rem !important;\n  }\n  .mb-sm-n2,\n  .my-sm-n2 {\n    margin-bottom: -0.5rem !important;\n  }\n  .ml-sm-n2,\n  .mx-sm-n2 {\n    margin-left: -0.5rem !important;\n  }\n  .m-sm-n3 {\n    margin: -1rem !important;\n  }\n  .mt-sm-n3,\n  .my-sm-n3 {\n    margin-top: -1rem !important;\n  }\n  .mr-sm-n3,\n  .mx-sm-n3 {\n    margin-right: -1rem !important;\n  }\n  .mb-sm-n3,\n  .my-sm-n3 {\n    margin-bottom: -1rem !important;\n  }\n  .ml-sm-n3,\n  .mx-sm-n3 {\n    margin-left: -1rem !important;\n  }\n  .m-sm-n4 {\n    margin: -1.5rem !important;\n  }\n  .mt-sm-n4,\n  .my-sm-n4 {\n    margin-top: -1.5rem !important;\n  }\n  .mr-sm-n4,\n  .mx-sm-n4 {\n    margin-right: -1.5rem !important;\n  }\n  .mb-sm-n4,\n  .my-sm-n4 {\n    margin-bottom: -1.5rem !important;\n  }\n  .ml-sm-n4,\n  .mx-sm-n4 {\n    margin-left: -1.5rem !important;\n  }\n  .m-sm-n5 {\n    margin: -3rem !important;\n  }\n  .mt-sm-n5,\n  .my-sm-n5 {\n    margin-top: -3rem !important;\n  }\n  .mr-sm-n5,\n  .mx-sm-n5 {\n    margin-right: -3rem !important;\n  }\n  .mb-sm-n5,\n  .my-sm-n5 {\n    margin-bottom: -3rem !important;\n  }\n  .ml-sm-n5,\n  .mx-sm-n5 {\n    margin-left: -3rem !important;\n  }\n  .m-sm-auto {\n    margin: auto !important;\n  }\n  .mt-sm-auto,\n  .my-sm-auto {\n    margin-top: auto !important;\n  }\n  .mr-sm-auto,\n  .mx-sm-auto {\n    margin-right: auto !important;\n  }\n  .mb-sm-auto,\n  .my-sm-auto {\n    margin-bottom: auto !important;\n  }\n  .ml-sm-auto,\n  .mx-sm-auto {\n    margin-left: auto !important;\n  }\n}\n\n@media (min-width: 768px) {\n  .m-md-0 {\n    margin: 0 !important;\n  }\n  .mt-md-0,\n  .my-md-0 {\n    margin-top: 0 !important;\n  }\n  .mr-md-0,\n  .mx-md-0 {\n    margin-right: 0 !important;\n  }\n  .mb-md-0,\n  .my-md-0 {\n    margin-bottom: 0 !important;\n  }\n  .ml-md-0,\n  .mx-md-0 {\n    margin-left: 0 !important;\n  }\n  .m-md-1 {\n    margin: 0.25rem !important;\n  }\n  .mt-md-1,\n  .my-md-1 {\n    margin-top: 0.25rem !important;\n  }\n  .mr-md-1,\n  .mx-md-1 {\n    margin-right: 0.25rem !important;\n  }\n  .mb-md-1,\n  .my-md-1 {\n    margin-bottom: 0.25rem !important;\n  }\n  .ml-md-1,\n  .mx-md-1 {\n    margin-left: 0.25rem !important;\n  }\n  .m-md-2 {\n    margin: 0.5rem !important;\n  }\n  .mt-md-2,\n  .my-md-2 {\n    margin-top: 0.5rem !important;\n  }\n  .mr-md-2,\n  .mx-md-2 {\n    margin-right: 0.5rem !important;\n  }\n  .mb-md-2,\n  .my-md-2 {\n    margin-bottom: 0.5rem !important;\n  }\n  .ml-md-2,\n  .mx-md-2 {\n    margin-left: 0.5rem !important;\n  }\n  .m-md-3 {\n    margin: 1rem !important;\n  }\n  .mt-md-3,\n  .my-md-3 {\n    margin-top: 1rem !important;\n  }\n  .mr-md-3,\n  .mx-md-3 {\n    margin-right: 1rem !important;\n  }\n  .mb-md-3,\n  .my-md-3 {\n    margin-bottom: 1rem !important;\n  }\n  .ml-md-3,\n  .mx-md-3 {\n    margin-left: 1rem !important;\n  }\n  .m-md-4 {\n    margin: 1.5rem !important;\n  }\n  .mt-md-4,\n  .my-md-4 {\n    margin-top: 1.5rem !important;\n  }\n  .mr-md-4,\n  .mx-md-4 {\n    margin-right: 1.5rem !important;\n  }\n  .mb-md-4,\n  .my-md-4 {\n    margin-bottom: 1.5rem !important;\n  }\n  .ml-md-4,\n  .mx-md-4 {\n    margin-left: 1.5rem !important;\n  }\n  .m-md-5 {\n    margin: 3rem !important;\n  }\n  .mt-md-5,\n  .my-md-5 {\n    margin-top: 3rem !important;\n  }\n  .mr-md-5,\n  .mx-md-5 {\n    margin-right: 3rem !important;\n  }\n  .mb-md-5,\n  .my-md-5 {\n    margin-bottom: 3rem !important;\n  }\n  .ml-md-5,\n  .mx-md-5 {\n    margin-left: 3rem !important;\n  }\n  .p-md-0 {\n    padding: 0 !important;\n  }\n  .pt-md-0,\n  .py-md-0 {\n    padding-top: 0 !important;\n  }\n  .pr-md-0,\n  .px-md-0 {\n    padding-right: 0 !important;\n  }\n  .pb-md-0,\n  .py-md-0 {\n    padding-bottom: 0 !important;\n  }\n  .pl-md-0,\n  .px-md-0 {\n    padding-left: 0 !important;\n  }\n  .p-md-1 {\n    padding: 0.25rem !important;\n  }\n  .pt-md-1,\n  .py-md-1 {\n    padding-top: 0.25rem !important;\n  }\n  .pr-md-1,\n  .px-md-1 {\n    padding-right: 0.25rem !important;\n  }\n  .pb-md-1,\n  .py-md-1 {\n    padding-bottom: 0.25rem !important;\n  }\n  .pl-md-1,\n  .px-md-1 {\n    padding-left: 0.25rem !important;\n  }\n  .p-md-2 {\n    padding: 0.5rem !important;\n  }\n  .pt-md-2,\n  .py-md-2 {\n    padding-top: 0.5rem !important;\n  }\n  .pr-md-2,\n  .px-md-2 {\n    padding-right: 0.5rem !important;\n  }\n  .pb-md-2,\n  .py-md-2 {\n    padding-bottom: 0.5rem !important;\n  }\n  .pl-md-2,\n  .px-md-2 {\n    padding-left: 0.5rem !important;\n  }\n  .p-md-3 {\n    padding: 1rem !important;\n  }\n  .pt-md-3,\n  .py-md-3 {\n    padding-top: 1rem !important;\n  }\n  .pr-md-3,\n  .px-md-3 {\n    padding-right: 1rem !important;\n  }\n  .pb-md-3,\n  .py-md-3 {\n    padding-bottom: 1rem !important;\n  }\n  .pl-md-3,\n  .px-md-3 {\n    padding-left: 1rem !important;\n  }\n  .p-md-4 {\n    padding: 1.5rem !important;\n  }\n  .pt-md-4,\n  .py-md-4 {\n    padding-top: 1.5rem !important;\n  }\n  .pr-md-4,\n  .px-md-4 {\n    padding-right: 1.5rem !important;\n  }\n  .pb-md-4,\n  .py-md-4 {\n    padding-bottom: 1.5rem !important;\n  }\n  .pl-md-4,\n  .px-md-4 {\n    padding-left: 1.5rem !important;\n  }\n  .p-md-5 {\n    padding: 3rem !important;\n  }\n  .pt-md-5,\n  .py-md-5 {\n    padding-top: 3rem !important;\n  }\n  .pr-md-5,\n  .px-md-5 {\n    padding-right: 3rem !important;\n  }\n  .pb-md-5,\n  .py-md-5 {\n    padding-bottom: 3rem !important;\n  }\n  .pl-md-5,\n  .px-md-5 {\n    padding-left: 3rem !important;\n  }\n  .m-md-n1 {\n    margin: -0.25rem !important;\n  }\n  .mt-md-n1,\n  .my-md-n1 {\n    margin-top: -0.25rem !important;\n  }\n  .mr-md-n1,\n  .mx-md-n1 {\n    margin-right: -0.25rem !important;\n  }\n  .mb-md-n1,\n  .my-md-n1 {\n    margin-bottom: -0.25rem !important;\n  }\n  .ml-md-n1,\n  .mx-md-n1 {\n    margin-left: -0.25rem !important;\n  }\n  .m-md-n2 {\n    margin: -0.5rem !important;\n  }\n  .mt-md-n2,\n  .my-md-n2 {\n    margin-top: -0.5rem !important;\n  }\n  .mr-md-n2,\n  .mx-md-n2 {\n    margin-right: -0.5rem !important;\n  }\n  .mb-md-n2,\n  .my-md-n2 {\n    margin-bottom: -0.5rem !important;\n  }\n  .ml-md-n2,\n  .mx-md-n2 {\n    margin-left: -0.5rem !important;\n  }\n  .m-md-n3 {\n    margin: -1rem !important;\n  }\n  .mt-md-n3,\n  .my-md-n3 {\n    margin-top: -1rem !important;\n  }\n  .mr-md-n3,\n  .mx-md-n3 {\n    margin-right: -1rem !important;\n  }\n  .mb-md-n3,\n  .my-md-n3 {\n    margin-bottom: -1rem !important;\n  }\n  .ml-md-n3,\n  .mx-md-n3 {\n    margin-left: -1rem !important;\n  }\n  .m-md-n4 {\n    margin: -1.5rem !important;\n  }\n  .mt-md-n4,\n  .my-md-n4 {\n    margin-top: -1.5rem !important;\n  }\n  .mr-md-n4,\n  .mx-md-n4 {\n    margin-right: -1.5rem !important;\n  }\n  .mb-md-n4,\n  .my-md-n4 {\n    margin-bottom: -1.5rem !important;\n  }\n  .ml-md-n4,\n  .mx-md-n4 {\n    margin-left: -1.5rem !important;\n  }\n  .m-md-n5 {\n    margin: -3rem !important;\n  }\n  .mt-md-n5,\n  .my-md-n5 {\n    margin-top: -3rem !important;\n  }\n  .mr-md-n5,\n  .mx-md-n5 {\n    margin-right: -3rem !important;\n  }\n  .mb-md-n5,\n  .my-md-n5 {\n    margin-bottom: -3rem !important;\n  }\n  .ml-md-n5,\n  .mx-md-n5 {\n    margin-left: -3rem !important;\n  }\n  .m-md-auto {\n    margin: auto !important;\n  }\n  .mt-md-auto,\n  .my-md-auto {\n    margin-top: auto !important;\n  }\n  .mr-md-auto,\n  .mx-md-auto {\n    margin-right: auto !important;\n  }\n  .mb-md-auto,\n  .my-md-auto {\n    margin-bottom: auto !important;\n  }\n  .ml-md-auto,\n  .mx-md-auto {\n    margin-left: auto !important;\n  }\n}\n\n@media (min-width: 992px) {\n  .m-lg-0 {\n    margin: 0 !important;\n  }\n  .mt-lg-0,\n  .my-lg-0 {\n    margin-top: 0 !important;\n  }\n  .mr-lg-0,\n  .mx-lg-0 {\n    margin-right: 0 !important;\n  }\n  .mb-lg-0,\n  .my-lg-0 {\n    margin-bottom: 0 !important;\n  }\n  .ml-lg-0,\n  .mx-lg-0 {\n    margin-left: 0 !important;\n  }\n  .m-lg-1 {\n    margin: 0.25rem !important;\n  }\n  .mt-lg-1,\n  .my-lg-1 {\n    margin-top: 0.25rem !important;\n  }\n  .mr-lg-1,\n  .mx-lg-1 {\n    margin-right: 0.25rem !important;\n  }\n  .mb-lg-1,\n  .my-lg-1 {\n    margin-bottom: 0.25rem !important;\n  }\n  .ml-lg-1,\n  .mx-lg-1 {\n    margin-left: 0.25rem !important;\n  }\n  .m-lg-2 {\n    margin: 0.5rem !important;\n  }\n  .mt-lg-2,\n  .my-lg-2 {\n    margin-top: 0.5rem !important;\n  }\n  .mr-lg-2,\n  .mx-lg-2 {\n    margin-right: 0.5rem !important;\n  }\n  .mb-lg-2,\n  .my-lg-2 {\n    margin-bottom: 0.5rem !important;\n  }\n  .ml-lg-2,\n  .mx-lg-2 {\n    margin-left: 0.5rem !important;\n  }\n  .m-lg-3 {\n    margin: 1rem !important;\n  }\n  .mt-lg-3,\n  .my-lg-3 {\n    margin-top: 1rem !important;\n  }\n  .mr-lg-3,\n  .mx-lg-3 {\n    margin-right: 1rem !important;\n  }\n  .mb-lg-3,\n  .my-lg-3 {\n    margin-bottom: 1rem !important;\n  }\n  .ml-lg-3,\n  .mx-lg-3 {\n    margin-left: 1rem !important;\n  }\n  .m-lg-4 {\n    margin: 1.5rem !important;\n  }\n  .mt-lg-4,\n  .my-lg-4 {\n    margin-top: 1.5rem !important;\n  }\n  .mr-lg-4,\n  .mx-lg-4 {\n    margin-right: 1.5rem !important;\n  }\n  .mb-lg-4,\n  .my-lg-4 {\n    margin-bottom: 1.5rem !important;\n  }\n  .ml-lg-4,\n  .mx-lg-4 {\n    margin-left: 1.5rem !important;\n  }\n  .m-lg-5 {\n    margin: 3rem !important;\n  }\n  .mt-lg-5,\n  .my-lg-5 {\n    margin-top: 3rem !important;\n  }\n  .mr-lg-5,\n  .mx-lg-5 {\n    margin-right: 3rem !important;\n  }\n  .mb-lg-5,\n  .my-lg-5 {\n    margin-bottom: 3rem !important;\n  }\n  .ml-lg-5,\n  .mx-lg-5 {\n    margin-left: 3rem !important;\n  }\n  .p-lg-0 {\n    padding: 0 !important;\n  }\n  .pt-lg-0,\n  .py-lg-0 {\n    padding-top: 0 !important;\n  }\n  .pr-lg-0,\n  .px-lg-0 {\n    padding-right: 0 !important;\n  }\n  .pb-lg-0,\n  .py-lg-0 {\n    padding-bottom: 0 !important;\n  }\n  .pl-lg-0,\n  .px-lg-0 {\n    padding-left: 0 !important;\n  }\n  .p-lg-1 {\n    padding: 0.25rem !important;\n  }\n  .pt-lg-1,\n  .py-lg-1 {\n    padding-top: 0.25rem !important;\n  }\n  .pr-lg-1,\n  .px-lg-1 {\n    padding-right: 0.25rem !important;\n  }\n  .pb-lg-1,\n  .py-lg-1 {\n    padding-bottom: 0.25rem !important;\n  }\n  .pl-lg-1,\n  .px-lg-1 {\n    padding-left: 0.25rem !important;\n  }\n  .p-lg-2 {\n    padding: 0.5rem !important;\n  }\n  .pt-lg-2,\n  .py-lg-2 {\n    padding-top: 0.5rem !important;\n  }\n  .pr-lg-2,\n  .px-lg-2 {\n    padding-right: 0.5rem !important;\n  }\n  .pb-lg-2,\n  .py-lg-2 {\n    padding-bottom: 0.5rem !important;\n  }\n  .pl-lg-2,\n  .px-lg-2 {\n    padding-left: 0.5rem !important;\n  }\n  .p-lg-3 {\n    padding: 1rem !important;\n  }\n  .pt-lg-3,\n  .py-lg-3 {\n    padding-top: 1rem !important;\n  }\n  .pr-lg-3,\n  .px-lg-3 {\n    padding-right: 1rem !important;\n  }\n  .pb-lg-3,\n  .py-lg-3 {\n    padding-bottom: 1rem !important;\n  }\n  .pl-lg-3,\n  .px-lg-3 {\n    padding-left: 1rem !important;\n  }\n  .p-lg-4 {\n    padding: 1.5rem !important;\n  }\n  .pt-lg-4,\n  .py-lg-4 {\n    padding-top: 1.5rem !important;\n  }\n  .pr-lg-4,\n  .px-lg-4 {\n    padding-right: 1.5rem !important;\n  }\n  .pb-lg-4,\n  .py-lg-4 {\n    padding-bottom: 1.5rem !important;\n  }\n  .pl-lg-4,\n  .px-lg-4 {\n    padding-left: 1.5rem !important;\n  }\n  .p-lg-5 {\n    padding: 3rem !important;\n  }\n  .pt-lg-5,\n  .py-lg-5 {\n    padding-top: 3rem !important;\n  }\n  .pr-lg-5,\n  .px-lg-5 {\n    padding-right: 3rem !important;\n  }\n  .pb-lg-5,\n  .py-lg-5 {\n    padding-bottom: 3rem !important;\n  }\n  .pl-lg-5,\n  .px-lg-5 {\n    padding-left: 3rem !important;\n  }\n  .m-lg-n1 {\n    margin: -0.25rem !important;\n  }\n  .mt-lg-n1,\n  .my-lg-n1 {\n    margin-top: -0.25rem !important;\n  }\n  .mr-lg-n1,\n  .mx-lg-n1 {\n    margin-right: -0.25rem !important;\n  }\n  .mb-lg-n1,\n  .my-lg-n1 {\n    margin-bottom: -0.25rem !important;\n  }\n  .ml-lg-n1,\n  .mx-lg-n1 {\n    margin-left: -0.25rem !important;\n  }\n  .m-lg-n2 {\n    margin: -0.5rem !important;\n  }\n  .mt-lg-n2,\n  .my-lg-n2 {\n    margin-top: -0.5rem !important;\n  }\n  .mr-lg-n2,\n  .mx-lg-n2 {\n    margin-right: -0.5rem !important;\n  }\n  .mb-lg-n2,\n  .my-lg-n2 {\n    margin-bottom: -0.5rem !important;\n  }\n  .ml-lg-n2,\n  .mx-lg-n2 {\n    margin-left: -0.5rem !important;\n  }\n  .m-lg-n3 {\n    margin: -1rem !important;\n  }\n  .mt-lg-n3,\n  .my-lg-n3 {\n    margin-top: -1rem !important;\n  }\n  .mr-lg-n3,\n  .mx-lg-n3 {\n    margin-right: -1rem !important;\n  }\n  .mb-lg-n3,\n  .my-lg-n3 {\n    margin-bottom: -1rem !important;\n  }\n  .ml-lg-n3,\n  .mx-lg-n3 {\n    margin-left: -1rem !important;\n  }\n  .m-lg-n4 {\n    margin: -1.5rem !important;\n  }\n  .mt-lg-n4,\n  .my-lg-n4 {\n    margin-top: -1.5rem !important;\n  }\n  .mr-lg-n4,\n  .mx-lg-n4 {\n    margin-right: -1.5rem !important;\n  }\n  .mb-lg-n4,\n  .my-lg-n4 {\n    margin-bottom: -1.5rem !important;\n  }\n  .ml-lg-n4,\n  .mx-lg-n4 {\n    margin-left: -1.5rem !important;\n  }\n  .m-lg-n5 {\n    margin: -3rem !important;\n  }\n  .mt-lg-n5,\n  .my-lg-n5 {\n    margin-top: -3rem !important;\n  }\n  .mr-lg-n5,\n  .mx-lg-n5 {\n    margin-right: -3rem !important;\n  }\n  .mb-lg-n5,\n  .my-lg-n5 {\n    margin-bottom: -3rem !important;\n  }\n  .ml-lg-n5,\n  .mx-lg-n5 {\n    margin-left: -3rem !important;\n  }\n  .m-lg-auto {\n    margin: auto !important;\n  }\n  .mt-lg-auto,\n  .my-lg-auto {\n    margin-top: auto !important;\n  }\n  .mr-lg-auto,\n  .mx-lg-auto {\n    margin-right: auto !important;\n  }\n  .mb-lg-auto,\n  .my-lg-auto {\n    margin-bottom: auto !important;\n  }\n  .ml-lg-auto,\n  .mx-lg-auto {\n    margin-left: auto !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .m-xl-0 {\n    margin: 0 !important;\n  }\n  .mt-xl-0,\n  .my-xl-0 {\n    margin-top: 0 !important;\n  }\n  .mr-xl-0,\n  .mx-xl-0 {\n    margin-right: 0 !important;\n  }\n  .mb-xl-0,\n  .my-xl-0 {\n    margin-bottom: 0 !important;\n  }\n  .ml-xl-0,\n  .mx-xl-0 {\n    margin-left: 0 !important;\n  }\n  .m-xl-1 {\n    margin: 0.25rem !important;\n  }\n  .mt-xl-1,\n  .my-xl-1 {\n    margin-top: 0.25rem !important;\n  }\n  .mr-xl-1,\n  .mx-xl-1 {\n    margin-right: 0.25rem !important;\n  }\n  .mb-xl-1,\n  .my-xl-1 {\n    margin-bottom: 0.25rem !important;\n  }\n  .ml-xl-1,\n  .mx-xl-1 {\n    margin-left: 0.25rem !important;\n  }\n  .m-xl-2 {\n    margin: 0.5rem !important;\n  }\n  .mt-xl-2,\n  .my-xl-2 {\n    margin-top: 0.5rem !important;\n  }\n  .mr-xl-2,\n  .mx-xl-2 {\n    margin-right: 0.5rem !important;\n  }\n  .mb-xl-2,\n  .my-xl-2 {\n    margin-bottom: 0.5rem !important;\n  }\n  .ml-xl-2,\n  .mx-xl-2 {\n    margin-left: 0.5rem !important;\n  }\n  .m-xl-3 {\n    margin: 1rem !important;\n  }\n  .mt-xl-3,\n  .my-xl-3 {\n    margin-top: 1rem !important;\n  }\n  .mr-xl-3,\n  .mx-xl-3 {\n    margin-right: 1rem !important;\n  }\n  .mb-xl-3,\n  .my-xl-3 {\n    margin-bottom: 1rem !important;\n  }\n  .ml-xl-3,\n  .mx-xl-3 {\n    margin-left: 1rem !important;\n  }\n  .m-xl-4 {\n    margin: 1.5rem !important;\n  }\n  .mt-xl-4,\n  .my-xl-4 {\n    margin-top: 1.5rem !important;\n  }\n  .mr-xl-4,\n  .mx-xl-4 {\n    margin-right: 1.5rem !important;\n  }\n  .mb-xl-4,\n  .my-xl-4 {\n    margin-bottom: 1.5rem !important;\n  }\n  .ml-xl-4,\n  .mx-xl-4 {\n    margin-left: 1.5rem !important;\n  }\n  .m-xl-5 {\n    margin: 3rem !important;\n  }\n  .mt-xl-5,\n  .my-xl-5 {\n    margin-top: 3rem !important;\n  }\n  .mr-xl-5,\n  .mx-xl-5 {\n    margin-right: 3rem !important;\n  }\n  .mb-xl-5,\n  .my-xl-5 {\n    margin-bottom: 3rem !important;\n  }\n  .ml-xl-5,\n  .mx-xl-5 {\n    margin-left: 3rem !important;\n  }\n  .p-xl-0 {\n    padding: 0 !important;\n  }\n  .pt-xl-0,\n  .py-xl-0 {\n    padding-top: 0 !important;\n  }\n  .pr-xl-0,\n  .px-xl-0 {\n    padding-right: 0 !important;\n  }\n  .pb-xl-0,\n  .py-xl-0 {\n    padding-bottom: 0 !important;\n  }\n  .pl-xl-0,\n  .px-xl-0 {\n    padding-left: 0 !important;\n  }\n  .p-xl-1 {\n    padding: 0.25rem !important;\n  }\n  .pt-xl-1,\n  .py-xl-1 {\n    padding-top: 0.25rem !important;\n  }\n  .pr-xl-1,\n  .px-xl-1 {\n    padding-right: 0.25rem !important;\n  }\n  .pb-xl-1,\n  .py-xl-1 {\n    padding-bottom: 0.25rem !important;\n  }\n  .pl-xl-1,\n  .px-xl-1 {\n    padding-left: 0.25rem !important;\n  }\n  .p-xl-2 {\n    padding: 0.5rem !important;\n  }\n  .pt-xl-2,\n  .py-xl-2 {\n    padding-top: 0.5rem !important;\n  }\n  .pr-xl-2,\n  .px-xl-2 {\n    padding-right: 0.5rem !important;\n  }\n  .pb-xl-2,\n  .py-xl-2 {\n    padding-bottom: 0.5rem !important;\n  }\n  .pl-xl-2,\n  .px-xl-2 {\n    padding-left: 0.5rem !important;\n  }\n  .p-xl-3 {\n    padding: 1rem !important;\n  }\n  .pt-xl-3,\n  .py-xl-3 {\n    padding-top: 1rem !important;\n  }\n  .pr-xl-3,\n  .px-xl-3 {\n    padding-right: 1rem !important;\n  }\n  .pb-xl-3,\n  .py-xl-3 {\n    padding-bottom: 1rem !important;\n  }\n  .pl-xl-3,\n  .px-xl-3 {\n    padding-left: 1rem !important;\n  }\n  .p-xl-4 {\n    padding: 1.5rem !important;\n  }\n  .pt-xl-4,\n  .py-xl-4 {\n    padding-top: 1.5rem !important;\n  }\n  .pr-xl-4,\n  .px-xl-4 {\n    padding-right: 1.5rem !important;\n  }\n  .pb-xl-4,\n  .py-xl-4 {\n    padding-bottom: 1.5rem !important;\n  }\n  .pl-xl-4,\n  .px-xl-4 {\n    padding-left: 1.5rem !important;\n  }\n  .p-xl-5 {\n    padding: 3rem !important;\n  }\n  .pt-xl-5,\n  .py-xl-5 {\n    padding-top: 3rem !important;\n  }\n  .pr-xl-5,\n  .px-xl-5 {\n    padding-right: 3rem !important;\n  }\n  .pb-xl-5,\n  .py-xl-5 {\n    padding-bottom: 3rem !important;\n  }\n  .pl-xl-5,\n  .px-xl-5 {\n    padding-left: 3rem !important;\n  }\n  .m-xl-n1 {\n    margin: -0.25rem !important;\n  }\n  .mt-xl-n1,\n  .my-xl-n1 {\n    margin-top: -0.25rem !important;\n  }\n  .mr-xl-n1,\n  .mx-xl-n1 {\n    margin-right: -0.25rem !important;\n  }\n  .mb-xl-n1,\n  .my-xl-n1 {\n    margin-bottom: -0.25rem !important;\n  }\n  .ml-xl-n1,\n  .mx-xl-n1 {\n    margin-left: -0.25rem !important;\n  }\n  .m-xl-n2 {\n    margin: -0.5rem !important;\n  }\n  .mt-xl-n2,\n  .my-xl-n2 {\n    margin-top: -0.5rem !important;\n  }\n  .mr-xl-n2,\n  .mx-xl-n2 {\n    margin-right: -0.5rem !important;\n  }\n  .mb-xl-n2,\n  .my-xl-n2 {\n    margin-bottom: -0.5rem !important;\n  }\n  .ml-xl-n2,\n  .mx-xl-n2 {\n    margin-left: -0.5rem !important;\n  }\n  .m-xl-n3 {\n    margin: -1rem !important;\n  }\n  .mt-xl-n3,\n  .my-xl-n3 {\n    margin-top: -1rem !important;\n  }\n  .mr-xl-n3,\n  .mx-xl-n3 {\n    margin-right: -1rem !important;\n  }\n  .mb-xl-n3,\n  .my-xl-n3 {\n    margin-bottom: -1rem !important;\n  }\n  .ml-xl-n3,\n  .mx-xl-n3 {\n    margin-left: -1rem !important;\n  }\n  .m-xl-n4 {\n    margin: -1.5rem !important;\n  }\n  .mt-xl-n4,\n  .my-xl-n4 {\n    margin-top: -1.5rem !important;\n  }\n  .mr-xl-n4,\n  .mx-xl-n4 {\n    margin-right: -1.5rem !important;\n  }\n  .mb-xl-n4,\n  .my-xl-n4 {\n    margin-bottom: -1.5rem !important;\n  }\n  .ml-xl-n4,\n  .mx-xl-n4 {\n    margin-left: -1.5rem !important;\n  }\n  .m-xl-n5 {\n    margin: -3rem !important;\n  }\n  .mt-xl-n5,\n  .my-xl-n5 {\n    margin-top: -3rem !important;\n  }\n  .mr-xl-n5,\n  .mx-xl-n5 {\n    margin-right: -3rem !important;\n  }\n  .mb-xl-n5,\n  .my-xl-n5 {\n    margin-bottom: -3rem !important;\n  }\n  .ml-xl-n5,\n  .mx-xl-n5 {\n    margin-left: -3rem !important;\n  }\n  .m-xl-auto {\n    margin: auto !important;\n  }\n  .mt-xl-auto,\n  .my-xl-auto {\n    margin-top: auto !important;\n  }\n  .mr-xl-auto,\n  .mx-xl-auto {\n    margin-right: auto !important;\n  }\n  .mb-xl-auto,\n  .my-xl-auto {\n    margin-bottom: auto !important;\n  }\n  .ml-xl-auto,\n  .mx-xl-auto {\n    margin-left: auto !important;\n  }\n}\n/*# sourceMappingURL=bootstrap-grid.css.map */"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css",
    "content": "/*!\n * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)\n */\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\nhtml {\n  font-family: sans-serif;\n  line-height: 1.15;\n  -webkit-text-size-adjust: 100%;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\narticle, aside, figcaption, figure, footer, header, hgroup, main, nav, section {\n  display: block;\n}\n\nbody {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n  font-size: 1rem;\n  font-weight: 400;\n  line-height: 1.5;\n  color: #212529;\n  text-align: left;\n  background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n  outline: 0 !important;\n}\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n  overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n  margin-top: 0;\n  margin-bottom: 0.5rem;\n}\n\np {\n  margin-top: 0;\n  margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n  text-decoration: underline;\n  -webkit-text-decoration: underline dotted;\n  text-decoration: underline dotted;\n  cursor: help;\n  border-bottom: 0;\n  -webkit-text-decoration-skip-ink: none;\n  text-decoration-skip-ink: none;\n}\n\naddress {\n  margin-bottom: 1rem;\n  font-style: normal;\n  line-height: inherit;\n}\n\nol,\nul,\ndl {\n  margin-top: 0;\n  margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n  margin-bottom: 0;\n}\n\ndt {\n  font-weight: 700;\n}\n\ndd {\n  margin-bottom: .5rem;\n  margin-left: 0;\n}\n\nblockquote {\n  margin: 0 0 1rem;\n}\n\nb,\nstrong {\n  font-weight: bolder;\n}\n\nsmall {\n  font-size: 80%;\n}\n\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\n\nsub {\n  bottom: -.25em;\n}\n\nsup {\n  top: -.5em;\n}\n\na {\n  color: #007bff;\n  text-decoration: none;\n  background-color: transparent;\n}\n\na:hover {\n  color: #0056b3;\n  text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n  color: inherit;\n  text-decoration: none;\n}\n\na:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {\n  color: inherit;\n  text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n  outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n  font-family: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n  font-size: 1em;\n}\n\npre {\n  margin-top: 0;\n  margin-bottom: 1rem;\n  overflow: auto;\n}\n\nfigure {\n  margin: 0 0 1rem;\n}\n\nimg {\n  vertical-align: middle;\n  border-style: none;\n}\n\nsvg {\n  overflow: hidden;\n  vertical-align: middle;\n}\n\ntable {\n  border-collapse: collapse;\n}\n\ncaption {\n  padding-top: 0.75rem;\n  padding-bottom: 0.75rem;\n  color: #6c757d;\n  text-align: left;\n  caption-side: bottom;\n}\n\nth {\n  text-align: inherit;\n}\n\nlabel {\n  display: inline-block;\n  margin-bottom: 0.5rem;\n}\n\nbutton {\n  border-radius: 0;\n}\n\nbutton:focus {\n  outline: 1px dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n  margin: 0;\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\nbutton,\ninput {\n  overflow: visible;\n}\n\nbutton,\nselect {\n  text-transform: none;\n}\n\nselect {\n  word-wrap: normal;\n}\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n  -webkit-appearance: button;\n}\n\nbutton:not(:disabled),\n[type=\"button\"]:not(:disabled),\n[type=\"reset\"]:not(:disabled),\n[type=\"submit\"]:not(:disabled) {\n  cursor: pointer;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n  padding: 0;\n  border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n  -webkit-appearance: listbox;\n}\n\ntextarea {\n  overflow: auto;\n  resize: vertical;\n}\n\nfieldset {\n  min-width: 0;\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  max-width: 100%;\n  padding: 0;\n  margin-bottom: .5rem;\n  font-size: 1.5rem;\n  line-height: inherit;\n  color: inherit;\n  white-space: normal;\n}\n\nprogress {\n  vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n[type=\"search\"] {\n  outline-offset: -2px;\n  -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n  font: inherit;\n  -webkit-appearance: button;\n}\n\noutput {\n  display: inline-block;\n}\n\nsummary {\n  display: list-item;\n  cursor: pointer;\n}\n\ntemplate {\n  display: none;\n}\n\n[hidden] {\n  display: none !important;\n}\n/*# sourceMappingURL=bootstrap-reboot.css.map */"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/bootstrap/dist/css/bootstrap.css",
    "content": "/*!\n * Bootstrap v4.3.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 The Bootstrap Authors\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n:root {\n  --blue: #007bff;\n  --indigo: #6610f2;\n  --purple: #6f42c1;\n  --pink: #e83e8c;\n  --red: #dc3545;\n  --orange: #fd7e14;\n  --yellow: #ffc107;\n  --green: #28a745;\n  --teal: #20c997;\n  --cyan: #17a2b8;\n  --white: #fff;\n  --gray: #6c757d;\n  --gray-dark: #343a40;\n  --primary: #007bff;\n  --secondary: #6c757d;\n  --success: #28a745;\n  --info: #17a2b8;\n  --warning: #ffc107;\n  --danger: #dc3545;\n  --light: #f8f9fa;\n  --dark: #343a40;\n  --breakpoint-xs: 0;\n  --breakpoint-sm: 576px;\n  --breakpoint-md: 768px;\n  --breakpoint-lg: 992px;\n  --breakpoint-xl: 1200px;\n  --font-family-sans-serif: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n  --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\nhtml {\n  font-family: sans-serif;\n  line-height: 1.15;\n  -webkit-text-size-adjust: 100%;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\narticle, aside, figcaption, figure, footer, header, hgroup, main, nav, section {\n  display: block;\n}\n\nbody {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n  font-size: 1rem;\n  font-weight: 400;\n  line-height: 1.5;\n  color: #212529;\n  text-align: left;\n  background-color: #fff;\n}\n\n[tabindex=\"-1\"]:focus {\n  outline: 0 !important;\n}\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n  overflow: visible;\n}\n\nh1, h2, h3, h4, h5, h6 {\n  margin-top: 0;\n  margin-bottom: 0.5rem;\n}\n\np {\n  margin-top: 0;\n  margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-original-title] {\n  text-decoration: underline;\n  -webkit-text-decoration: underline dotted;\n  text-decoration: underline dotted;\n  cursor: help;\n  border-bottom: 0;\n  -webkit-text-decoration-skip-ink: none;\n  text-decoration-skip-ink: none;\n}\n\naddress {\n  margin-bottom: 1rem;\n  font-style: normal;\n  line-height: inherit;\n}\n\nol,\nul,\ndl {\n  margin-top: 0;\n  margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n  margin-bottom: 0;\n}\n\ndt {\n  font-weight: 700;\n}\n\ndd {\n  margin-bottom: .5rem;\n  margin-left: 0;\n}\n\nblockquote {\n  margin: 0 0 1rem;\n}\n\nb,\nstrong {\n  font-weight: bolder;\n}\n\nsmall {\n  font-size: 80%;\n}\n\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\n\nsub {\n  bottom: -.25em;\n}\n\nsup {\n  top: -.5em;\n}\n\na {\n  color: #007bff;\n  text-decoration: none;\n  background-color: transparent;\n}\n\na:hover {\n  color: #0056b3;\n  text-decoration: underline;\n}\n\na:not([href]):not([tabindex]) {\n  color: inherit;\n  text-decoration: none;\n}\n\na:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {\n  color: inherit;\n  text-decoration: none;\n}\n\na:not([href]):not([tabindex]):focus {\n  outline: 0;\n}\n\npre,\ncode,\nkbd,\nsamp {\n  font-family: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n  font-size: 1em;\n}\n\npre {\n  margin-top: 0;\n  margin-bottom: 1rem;\n  overflow: auto;\n}\n\nfigure {\n  margin: 0 0 1rem;\n}\n\nimg {\n  vertical-align: middle;\n  border-style: none;\n}\n\nsvg {\n  overflow: hidden;\n  vertical-align: middle;\n}\n\ntable {\n  border-collapse: collapse;\n}\n\ncaption {\n  padding-top: 0.75rem;\n  padding-bottom: 0.75rem;\n  color: #6c757d;\n  text-align: left;\n  caption-side: bottom;\n}\n\nth {\n  text-align: inherit;\n}\n\nlabel {\n  display: inline-block;\n  margin-bottom: 0.5rem;\n}\n\nbutton {\n  border-radius: 0;\n}\n\nbutton:focus {\n  outline: 1px dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n  margin: 0;\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\nbutton,\ninput {\n  overflow: visible;\n}\n\nbutton,\nselect {\n  text-transform: none;\n}\n\nselect {\n  word-wrap: normal;\n}\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n  -webkit-appearance: button;\n}\n\nbutton:not(:disabled),\n[type=\"button\"]:not(:disabled),\n[type=\"reset\"]:not(:disabled),\n[type=\"submit\"]:not(:disabled) {\n  cursor: pointer;\n}\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n  padding: 0;\n  border-style: none;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n  -webkit-appearance: listbox;\n}\n\ntextarea {\n  overflow: auto;\n  resize: vertical;\n}\n\nfieldset {\n  min-width: 0;\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  max-width: 100%;\n  padding: 0;\n  margin-bottom: .5rem;\n  font-size: 1.5rem;\n  line-height: inherit;\n  color: inherit;\n  white-space: normal;\n}\n\nprogress {\n  vertical-align: baseline;\n}\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n[type=\"search\"] {\n  outline-offset: -2px;\n  -webkit-appearance: none;\n}\n\n[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n::-webkit-file-upload-button {\n  font: inherit;\n  -webkit-appearance: button;\n}\n\noutput {\n  display: inline-block;\n}\n\nsummary {\n  display: list-item;\n  cursor: pointer;\n}\n\ntemplate {\n  display: none;\n}\n\n[hidden] {\n  display: none !important;\n}\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n  margin-bottom: 0.5rem;\n  font-weight: 500;\n  line-height: 1.2;\n}\n\nh1, .h1 {\n  font-size: 2.5rem;\n}\n\nh2, .h2 {\n  font-size: 2rem;\n}\n\nh3, .h3 {\n  font-size: 1.75rem;\n}\n\nh4, .h4 {\n  font-size: 1.5rem;\n}\n\nh5, .h5 {\n  font-size: 1.25rem;\n}\n\nh6, .h6 {\n  font-size: 1rem;\n}\n\n.lead {\n  font-size: 1.25rem;\n  font-weight: 300;\n}\n\n.display-1 {\n  font-size: 6rem;\n  font-weight: 300;\n  line-height: 1.2;\n}\n\n.display-2 {\n  font-size: 5.5rem;\n  font-weight: 300;\n  line-height: 1.2;\n}\n\n.display-3 {\n  font-size: 4.5rem;\n  font-weight: 300;\n  line-height: 1.2;\n}\n\n.display-4 {\n  font-size: 3.5rem;\n  font-weight: 300;\n  line-height: 1.2;\n}\n\nhr {\n  margin-top: 1rem;\n  margin-bottom: 1rem;\n  border: 0;\n  border-top: 1px solid rgba(0, 0, 0, 0.1);\n}\n\nsmall,\n.small {\n  font-size: 80%;\n  font-weight: 400;\n}\n\nmark,\n.mark {\n  padding: 0.2em;\n  background-color: #fcf8e3;\n}\n\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n\n.list-inline {\n  padding-left: 0;\n  list-style: none;\n}\n\n.list-inline-item {\n  display: inline-block;\n}\n\n.list-inline-item:not(:last-child) {\n  margin-right: 0.5rem;\n}\n\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\n.blockquote {\n  margin-bottom: 1rem;\n  font-size: 1.25rem;\n}\n\n.blockquote-footer {\n  display: block;\n  font-size: 80%;\n  color: #6c757d;\n}\n\n.blockquote-footer::before {\n  content: \"\\2014\\00A0\";\n}\n\n.img-fluid {\n  max-width: 100%;\n  height: auto;\n}\n\n.img-thumbnail {\n  padding: 0.25rem;\n  background-color: #fff;\n  border: 1px solid #dee2e6;\n  border-radius: 0.25rem;\n  max-width: 100%;\n  height: auto;\n}\n\n.figure {\n  display: inline-block;\n}\n\n.figure-img {\n  margin-bottom: 0.5rem;\n  line-height: 1;\n}\n\n.figure-caption {\n  font-size: 90%;\n  color: #6c757d;\n}\n\ncode {\n  font-size: 87.5%;\n  color: #e83e8c;\n  word-break: break-word;\n}\n\na > code {\n  color: inherit;\n}\n\nkbd {\n  padding: 0.2rem 0.4rem;\n  font-size: 87.5%;\n  color: #fff;\n  background-color: #212529;\n  border-radius: 0.2rem;\n}\n\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: 700;\n}\n\npre {\n  display: block;\n  font-size: 87.5%;\n  color: #212529;\n}\n\npre code {\n  font-size: inherit;\n  color: inherit;\n  word-break: normal;\n}\n\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n\n.container {\n  width: 100%;\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n\n@media (min-width: 576px) {\n  .container {\n    max-width: 540px;\n  }\n}\n\n@media (min-width: 768px) {\n  .container {\n    max-width: 720px;\n  }\n}\n\n@media (min-width: 992px) {\n  .container {\n    max-width: 960px;\n  }\n}\n\n@media (min-width: 1200px) {\n  .container {\n    max-width: 1140px;\n  }\n}\n\n.container-fluid {\n  width: 100%;\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n\n.row {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  margin-right: -15px;\n  margin-left: -15px;\n}\n\n.no-gutters {\n  margin-right: 0;\n  margin-left: 0;\n}\n\n.no-gutters > .col,\n.no-gutters > [class*=\"col-\"] {\n  padding-right: 0;\n  padding-left: 0;\n}\n\n.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,\n.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,\n.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,\n.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,\n.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,\n.col-xl-auto {\n  position: relative;\n  width: 100%;\n  padding-right: 15px;\n  padding-left: 15px;\n}\n\n.col {\n  -ms-flex-preferred-size: 0;\n  flex-basis: 0;\n  -ms-flex-positive: 1;\n  flex-grow: 1;\n  max-width: 100%;\n}\n\n.col-auto {\n  -ms-flex: 0 0 auto;\n  flex: 0 0 auto;\n  width: auto;\n  max-width: 100%;\n}\n\n.col-1 {\n  -ms-flex: 0 0 8.333333%;\n  flex: 0 0 8.333333%;\n  max-width: 8.333333%;\n}\n\n.col-2 {\n  -ms-flex: 0 0 16.666667%;\n  flex: 0 0 16.666667%;\n  max-width: 16.666667%;\n}\n\n.col-3 {\n  -ms-flex: 0 0 25%;\n  flex: 0 0 25%;\n  max-width: 25%;\n}\n\n.col-4 {\n  -ms-flex: 0 0 33.333333%;\n  flex: 0 0 33.333333%;\n  max-width: 33.333333%;\n}\n\n.col-5 {\n  -ms-flex: 0 0 41.666667%;\n  flex: 0 0 41.666667%;\n  max-width: 41.666667%;\n}\n\n.col-6 {\n  -ms-flex: 0 0 50%;\n  flex: 0 0 50%;\n  max-width: 50%;\n}\n\n.col-7 {\n  -ms-flex: 0 0 58.333333%;\n  flex: 0 0 58.333333%;\n  max-width: 58.333333%;\n}\n\n.col-8 {\n  -ms-flex: 0 0 66.666667%;\n  flex: 0 0 66.666667%;\n  max-width: 66.666667%;\n}\n\n.col-9 {\n  -ms-flex: 0 0 75%;\n  flex: 0 0 75%;\n  max-width: 75%;\n}\n\n.col-10 {\n  -ms-flex: 0 0 83.333333%;\n  flex: 0 0 83.333333%;\n  max-width: 83.333333%;\n}\n\n.col-11 {\n  -ms-flex: 0 0 91.666667%;\n  flex: 0 0 91.666667%;\n  max-width: 91.666667%;\n}\n\n.col-12 {\n  -ms-flex: 0 0 100%;\n  flex: 0 0 100%;\n  max-width: 100%;\n}\n\n.order-first {\n  -ms-flex-order: -1;\n  order: -1;\n}\n\n.order-last {\n  -ms-flex-order: 13;\n  order: 13;\n}\n\n.order-0 {\n  -ms-flex-order: 0;\n  order: 0;\n}\n\n.order-1 {\n  -ms-flex-order: 1;\n  order: 1;\n}\n\n.order-2 {\n  -ms-flex-order: 2;\n  order: 2;\n}\n\n.order-3 {\n  -ms-flex-order: 3;\n  order: 3;\n}\n\n.order-4 {\n  -ms-flex-order: 4;\n  order: 4;\n}\n\n.order-5 {\n  -ms-flex-order: 5;\n  order: 5;\n}\n\n.order-6 {\n  -ms-flex-order: 6;\n  order: 6;\n}\n\n.order-7 {\n  -ms-flex-order: 7;\n  order: 7;\n}\n\n.order-8 {\n  -ms-flex-order: 8;\n  order: 8;\n}\n\n.order-9 {\n  -ms-flex-order: 9;\n  order: 9;\n}\n\n.order-10 {\n  -ms-flex-order: 10;\n  order: 10;\n}\n\n.order-11 {\n  -ms-flex-order: 11;\n  order: 11;\n}\n\n.order-12 {\n  -ms-flex-order: 12;\n  order: 12;\n}\n\n.offset-1 {\n  margin-left: 8.333333%;\n}\n\n.offset-2 {\n  margin-left: 16.666667%;\n}\n\n.offset-3 {\n  margin-left: 25%;\n}\n\n.offset-4 {\n  margin-left: 33.333333%;\n}\n\n.offset-5 {\n  margin-left: 41.666667%;\n}\n\n.offset-6 {\n  margin-left: 50%;\n}\n\n.offset-7 {\n  margin-left: 58.333333%;\n}\n\n.offset-8 {\n  margin-left: 66.666667%;\n}\n\n.offset-9 {\n  margin-left: 75%;\n}\n\n.offset-10 {\n  margin-left: 83.333333%;\n}\n\n.offset-11 {\n  margin-left: 91.666667%;\n}\n\n@media (min-width: 576px) {\n  .col-sm {\n    -ms-flex-preferred-size: 0;\n    flex-basis: 0;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n    max-width: 100%;\n  }\n  .col-sm-auto {\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    width: auto;\n    max-width: 100%;\n  }\n  .col-sm-1 {\n    -ms-flex: 0 0 8.333333%;\n    flex: 0 0 8.333333%;\n    max-width: 8.333333%;\n  }\n  .col-sm-2 {\n    -ms-flex: 0 0 16.666667%;\n    flex: 0 0 16.666667%;\n    max-width: 16.666667%;\n  }\n  .col-sm-3 {\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-sm-4 {\n    -ms-flex: 0 0 33.333333%;\n    flex: 0 0 33.333333%;\n    max-width: 33.333333%;\n  }\n  .col-sm-5 {\n    -ms-flex: 0 0 41.666667%;\n    flex: 0 0 41.666667%;\n    max-width: 41.666667%;\n  }\n  .col-sm-6 {\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-sm-7 {\n    -ms-flex: 0 0 58.333333%;\n    flex: 0 0 58.333333%;\n    max-width: 58.333333%;\n  }\n  .col-sm-8 {\n    -ms-flex: 0 0 66.666667%;\n    flex: 0 0 66.666667%;\n    max-width: 66.666667%;\n  }\n  .col-sm-9 {\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-sm-10 {\n    -ms-flex: 0 0 83.333333%;\n    flex: 0 0 83.333333%;\n    max-width: 83.333333%;\n  }\n  .col-sm-11 {\n    -ms-flex: 0 0 91.666667%;\n    flex: 0 0 91.666667%;\n    max-width: 91.666667%;\n  }\n  .col-sm-12 {\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .order-sm-first {\n    -ms-flex-order: -1;\n    order: -1;\n  }\n  .order-sm-last {\n    -ms-flex-order: 13;\n    order: 13;\n  }\n  .order-sm-0 {\n    -ms-flex-order: 0;\n    order: 0;\n  }\n  .order-sm-1 {\n    -ms-flex-order: 1;\n    order: 1;\n  }\n  .order-sm-2 {\n    -ms-flex-order: 2;\n    order: 2;\n  }\n  .order-sm-3 {\n    -ms-flex-order: 3;\n    order: 3;\n  }\n  .order-sm-4 {\n    -ms-flex-order: 4;\n    order: 4;\n  }\n  .order-sm-5 {\n    -ms-flex-order: 5;\n    order: 5;\n  }\n  .order-sm-6 {\n    -ms-flex-order: 6;\n    order: 6;\n  }\n  .order-sm-7 {\n    -ms-flex-order: 7;\n    order: 7;\n  }\n  .order-sm-8 {\n    -ms-flex-order: 8;\n    order: 8;\n  }\n  .order-sm-9 {\n    -ms-flex-order: 9;\n    order: 9;\n  }\n  .order-sm-10 {\n    -ms-flex-order: 10;\n    order: 10;\n  }\n  .order-sm-11 {\n    -ms-flex-order: 11;\n    order: 11;\n  }\n  .order-sm-12 {\n    -ms-flex-order: 12;\n    order: 12;\n  }\n  .offset-sm-0 {\n    margin-left: 0;\n  }\n  .offset-sm-1 {\n    margin-left: 8.333333%;\n  }\n  .offset-sm-2 {\n    margin-left: 16.666667%;\n  }\n  .offset-sm-3 {\n    margin-left: 25%;\n  }\n  .offset-sm-4 {\n    margin-left: 33.333333%;\n  }\n  .offset-sm-5 {\n    margin-left: 41.666667%;\n  }\n  .offset-sm-6 {\n    margin-left: 50%;\n  }\n  .offset-sm-7 {\n    margin-left: 58.333333%;\n  }\n  .offset-sm-8 {\n    margin-left: 66.666667%;\n  }\n  .offset-sm-9 {\n    margin-left: 75%;\n  }\n  .offset-sm-10 {\n    margin-left: 83.333333%;\n  }\n  .offset-sm-11 {\n    margin-left: 91.666667%;\n  }\n}\n\n@media (min-width: 768px) {\n  .col-md {\n    -ms-flex-preferred-size: 0;\n    flex-basis: 0;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n    max-width: 100%;\n  }\n  .col-md-auto {\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    width: auto;\n    max-width: 100%;\n  }\n  .col-md-1 {\n    -ms-flex: 0 0 8.333333%;\n    flex: 0 0 8.333333%;\n    max-width: 8.333333%;\n  }\n  .col-md-2 {\n    -ms-flex: 0 0 16.666667%;\n    flex: 0 0 16.666667%;\n    max-width: 16.666667%;\n  }\n  .col-md-3 {\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-md-4 {\n    -ms-flex: 0 0 33.333333%;\n    flex: 0 0 33.333333%;\n    max-width: 33.333333%;\n  }\n  .col-md-5 {\n    -ms-flex: 0 0 41.666667%;\n    flex: 0 0 41.666667%;\n    max-width: 41.666667%;\n  }\n  .col-md-6 {\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-md-7 {\n    -ms-flex: 0 0 58.333333%;\n    flex: 0 0 58.333333%;\n    max-width: 58.333333%;\n  }\n  .col-md-8 {\n    -ms-flex: 0 0 66.666667%;\n    flex: 0 0 66.666667%;\n    max-width: 66.666667%;\n  }\n  .col-md-9 {\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-md-10 {\n    -ms-flex: 0 0 83.333333%;\n    flex: 0 0 83.333333%;\n    max-width: 83.333333%;\n  }\n  .col-md-11 {\n    -ms-flex: 0 0 91.666667%;\n    flex: 0 0 91.666667%;\n    max-width: 91.666667%;\n  }\n  .col-md-12 {\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .order-md-first {\n    -ms-flex-order: -1;\n    order: -1;\n  }\n  .order-md-last {\n    -ms-flex-order: 13;\n    order: 13;\n  }\n  .order-md-0 {\n    -ms-flex-order: 0;\n    order: 0;\n  }\n  .order-md-1 {\n    -ms-flex-order: 1;\n    order: 1;\n  }\n  .order-md-2 {\n    -ms-flex-order: 2;\n    order: 2;\n  }\n  .order-md-3 {\n    -ms-flex-order: 3;\n    order: 3;\n  }\n  .order-md-4 {\n    -ms-flex-order: 4;\n    order: 4;\n  }\n  .order-md-5 {\n    -ms-flex-order: 5;\n    order: 5;\n  }\n  .order-md-6 {\n    -ms-flex-order: 6;\n    order: 6;\n  }\n  .order-md-7 {\n    -ms-flex-order: 7;\n    order: 7;\n  }\n  .order-md-8 {\n    -ms-flex-order: 8;\n    order: 8;\n  }\n  .order-md-9 {\n    -ms-flex-order: 9;\n    order: 9;\n  }\n  .order-md-10 {\n    -ms-flex-order: 10;\n    order: 10;\n  }\n  .order-md-11 {\n    -ms-flex-order: 11;\n    order: 11;\n  }\n  .order-md-12 {\n    -ms-flex-order: 12;\n    order: 12;\n  }\n  .offset-md-0 {\n    margin-left: 0;\n  }\n  .offset-md-1 {\n    margin-left: 8.333333%;\n  }\n  .offset-md-2 {\n    margin-left: 16.666667%;\n  }\n  .offset-md-3 {\n    margin-left: 25%;\n  }\n  .offset-md-4 {\n    margin-left: 33.333333%;\n  }\n  .offset-md-5 {\n    margin-left: 41.666667%;\n  }\n  .offset-md-6 {\n    margin-left: 50%;\n  }\n  .offset-md-7 {\n    margin-left: 58.333333%;\n  }\n  .offset-md-8 {\n    margin-left: 66.666667%;\n  }\n  .offset-md-9 {\n    margin-left: 75%;\n  }\n  .offset-md-10 {\n    margin-left: 83.333333%;\n  }\n  .offset-md-11 {\n    margin-left: 91.666667%;\n  }\n}\n\n@media (min-width: 992px) {\n  .col-lg {\n    -ms-flex-preferred-size: 0;\n    flex-basis: 0;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n    max-width: 100%;\n  }\n  .col-lg-auto {\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    width: auto;\n    max-width: 100%;\n  }\n  .col-lg-1 {\n    -ms-flex: 0 0 8.333333%;\n    flex: 0 0 8.333333%;\n    max-width: 8.333333%;\n  }\n  .col-lg-2 {\n    -ms-flex: 0 0 16.666667%;\n    flex: 0 0 16.666667%;\n    max-width: 16.666667%;\n  }\n  .col-lg-3 {\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-lg-4 {\n    -ms-flex: 0 0 33.333333%;\n    flex: 0 0 33.333333%;\n    max-width: 33.333333%;\n  }\n  .col-lg-5 {\n    -ms-flex: 0 0 41.666667%;\n    flex: 0 0 41.666667%;\n    max-width: 41.666667%;\n  }\n  .col-lg-6 {\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-lg-7 {\n    -ms-flex: 0 0 58.333333%;\n    flex: 0 0 58.333333%;\n    max-width: 58.333333%;\n  }\n  .col-lg-8 {\n    -ms-flex: 0 0 66.666667%;\n    flex: 0 0 66.666667%;\n    max-width: 66.666667%;\n  }\n  .col-lg-9 {\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-lg-10 {\n    -ms-flex: 0 0 83.333333%;\n    flex: 0 0 83.333333%;\n    max-width: 83.333333%;\n  }\n  .col-lg-11 {\n    -ms-flex: 0 0 91.666667%;\n    flex: 0 0 91.666667%;\n    max-width: 91.666667%;\n  }\n  .col-lg-12 {\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .order-lg-first {\n    -ms-flex-order: -1;\n    order: -1;\n  }\n  .order-lg-last {\n    -ms-flex-order: 13;\n    order: 13;\n  }\n  .order-lg-0 {\n    -ms-flex-order: 0;\n    order: 0;\n  }\n  .order-lg-1 {\n    -ms-flex-order: 1;\n    order: 1;\n  }\n  .order-lg-2 {\n    -ms-flex-order: 2;\n    order: 2;\n  }\n  .order-lg-3 {\n    -ms-flex-order: 3;\n    order: 3;\n  }\n  .order-lg-4 {\n    -ms-flex-order: 4;\n    order: 4;\n  }\n  .order-lg-5 {\n    -ms-flex-order: 5;\n    order: 5;\n  }\n  .order-lg-6 {\n    -ms-flex-order: 6;\n    order: 6;\n  }\n  .order-lg-7 {\n    -ms-flex-order: 7;\n    order: 7;\n  }\n  .order-lg-8 {\n    -ms-flex-order: 8;\n    order: 8;\n  }\n  .order-lg-9 {\n    -ms-flex-order: 9;\n    order: 9;\n  }\n  .order-lg-10 {\n    -ms-flex-order: 10;\n    order: 10;\n  }\n  .order-lg-11 {\n    -ms-flex-order: 11;\n    order: 11;\n  }\n  .order-lg-12 {\n    -ms-flex-order: 12;\n    order: 12;\n  }\n  .offset-lg-0 {\n    margin-left: 0;\n  }\n  .offset-lg-1 {\n    margin-left: 8.333333%;\n  }\n  .offset-lg-2 {\n    margin-left: 16.666667%;\n  }\n  .offset-lg-3 {\n    margin-left: 25%;\n  }\n  .offset-lg-4 {\n    margin-left: 33.333333%;\n  }\n  .offset-lg-5 {\n    margin-left: 41.666667%;\n  }\n  .offset-lg-6 {\n    margin-left: 50%;\n  }\n  .offset-lg-7 {\n    margin-left: 58.333333%;\n  }\n  .offset-lg-8 {\n    margin-left: 66.666667%;\n  }\n  .offset-lg-9 {\n    margin-left: 75%;\n  }\n  .offset-lg-10 {\n    margin-left: 83.333333%;\n  }\n  .offset-lg-11 {\n    margin-left: 91.666667%;\n  }\n}\n\n@media (min-width: 1200px) {\n  .col-xl {\n    -ms-flex-preferred-size: 0;\n    flex-basis: 0;\n    -ms-flex-positive: 1;\n    flex-grow: 1;\n    max-width: 100%;\n  }\n  .col-xl-auto {\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    width: auto;\n    max-width: 100%;\n  }\n  .col-xl-1 {\n    -ms-flex: 0 0 8.333333%;\n    flex: 0 0 8.333333%;\n    max-width: 8.333333%;\n  }\n  .col-xl-2 {\n    -ms-flex: 0 0 16.666667%;\n    flex: 0 0 16.666667%;\n    max-width: 16.666667%;\n  }\n  .col-xl-3 {\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-xl-4 {\n    -ms-flex: 0 0 33.333333%;\n    flex: 0 0 33.333333%;\n    max-width: 33.333333%;\n  }\n  .col-xl-5 {\n    -ms-flex: 0 0 41.666667%;\n    flex: 0 0 41.666667%;\n    max-width: 41.666667%;\n  }\n  .col-xl-6 {\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-xl-7 {\n    -ms-flex: 0 0 58.333333%;\n    flex: 0 0 58.333333%;\n    max-width: 58.333333%;\n  }\n  .col-xl-8 {\n    -ms-flex: 0 0 66.666667%;\n    flex: 0 0 66.666667%;\n    max-width: 66.666667%;\n  }\n  .col-xl-9 {\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-xl-10 {\n    -ms-flex: 0 0 83.333333%;\n    flex: 0 0 83.333333%;\n    max-width: 83.333333%;\n  }\n  .col-xl-11 {\n    -ms-flex: 0 0 91.666667%;\n    flex: 0 0 91.666667%;\n    max-width: 91.666667%;\n  }\n  .col-xl-12 {\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .order-xl-first {\n    -ms-flex-order: -1;\n    order: -1;\n  }\n  .order-xl-last {\n    -ms-flex-order: 13;\n    order: 13;\n  }\n  .order-xl-0 {\n    -ms-flex-order: 0;\n    order: 0;\n  }\n  .order-xl-1 {\n    -ms-flex-order: 1;\n    order: 1;\n  }\n  .order-xl-2 {\n    -ms-flex-order: 2;\n    order: 2;\n  }\n  .order-xl-3 {\n    -ms-flex-order: 3;\n    order: 3;\n  }\n  .order-xl-4 {\n    -ms-flex-order: 4;\n    order: 4;\n  }\n  .order-xl-5 {\n    -ms-flex-order: 5;\n    order: 5;\n  }\n  .order-xl-6 {\n    -ms-flex-order: 6;\n    order: 6;\n  }\n  .order-xl-7 {\n    -ms-flex-order: 7;\n    order: 7;\n  }\n  .order-xl-8 {\n    -ms-flex-order: 8;\n    order: 8;\n  }\n  .order-xl-9 {\n    -ms-flex-order: 9;\n    order: 9;\n  }\n  .order-xl-10 {\n    -ms-flex-order: 10;\n    order: 10;\n  }\n  .order-xl-11 {\n    -ms-flex-order: 11;\n    order: 11;\n  }\n  .order-xl-12 {\n    -ms-flex-order: 12;\n    order: 12;\n  }\n  .offset-xl-0 {\n    margin-left: 0;\n  }\n  .offset-xl-1 {\n    margin-left: 8.333333%;\n  }\n  .offset-xl-2 {\n    margin-left: 16.666667%;\n  }\n  .offset-xl-3 {\n    margin-left: 25%;\n  }\n  .offset-xl-4 {\n    margin-left: 33.333333%;\n  }\n  .offset-xl-5 {\n    margin-left: 41.666667%;\n  }\n  .offset-xl-6 {\n    margin-left: 50%;\n  }\n  .offset-xl-7 {\n    margin-left: 58.333333%;\n  }\n  .offset-xl-8 {\n    margin-left: 66.666667%;\n  }\n  .offset-xl-9 {\n    margin-left: 75%;\n  }\n  .offset-xl-10 {\n    margin-left: 83.333333%;\n  }\n  .offset-xl-11 {\n    margin-left: 91.666667%;\n  }\n}\n\n.table {\n  width: 100%;\n  margin-bottom: 1rem;\n  color: #212529;\n}\n\n.table th,\n.table td {\n  padding: 0.75rem;\n  vertical-align: top;\n  border-top: 1px solid #dee2e6;\n}\n\n.table thead th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #dee2e6;\n}\n\n.table tbody + tbody {\n  border-top: 2px solid #dee2e6;\n}\n\n.table-sm th,\n.table-sm td {\n  padding: 0.3rem;\n}\n\n.table-bordered {\n  border: 1px solid #dee2e6;\n}\n\n.table-bordered th,\n.table-bordered td {\n  border: 1px solid #dee2e6;\n}\n\n.table-bordered thead th,\n.table-bordered thead td {\n  border-bottom-width: 2px;\n}\n\n.table-borderless th,\n.table-borderless td,\n.table-borderless thead th,\n.table-borderless tbody + tbody {\n  border: 0;\n}\n\n.table-striped tbody tr:nth-of-type(odd) {\n  background-color: rgba(0, 0, 0, 0.05);\n}\n\n.table-hover tbody tr:hover {\n  color: #212529;\n  background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-primary,\n.table-primary > th,\n.table-primary > td {\n  background-color: #b8daff;\n}\n\n.table-primary th,\n.table-primary td,\n.table-primary thead th,\n.table-primary tbody + tbody {\n  border-color: #7abaff;\n}\n\n.table-hover .table-primary:hover {\n  background-color: #9fcdff;\n}\n\n.table-hover .table-primary:hover > td,\n.table-hover .table-primary:hover > th {\n  background-color: #9fcdff;\n}\n\n.table-secondary,\n.table-secondary > th,\n.table-secondary > td {\n  background-color: #d6d8db;\n}\n\n.table-secondary th,\n.table-secondary td,\n.table-secondary thead th,\n.table-secondary tbody + tbody {\n  border-color: #b3b7bb;\n}\n\n.table-hover .table-secondary:hover {\n  background-color: #c8cbcf;\n}\n\n.table-hover .table-secondary:hover > td,\n.table-hover .table-secondary:hover > th {\n  background-color: #c8cbcf;\n}\n\n.table-success,\n.table-success > th,\n.table-success > td {\n  background-color: #c3e6cb;\n}\n\n.table-success th,\n.table-success td,\n.table-success thead th,\n.table-success tbody + tbody {\n  border-color: #8fd19e;\n}\n\n.table-hover .table-success:hover {\n  background-color: #b1dfbb;\n}\n\n.table-hover .table-success:hover > td,\n.table-hover .table-success:hover > th {\n  background-color: #b1dfbb;\n}\n\n.table-info,\n.table-info > th,\n.table-info > td {\n  background-color: #bee5eb;\n}\n\n.table-info th,\n.table-info td,\n.table-info thead th,\n.table-info tbody + tbody {\n  border-color: #86cfda;\n}\n\n.table-hover .table-info:hover {\n  background-color: #abdde5;\n}\n\n.table-hover .table-info:hover > td,\n.table-hover .table-info:hover > th {\n  background-color: #abdde5;\n}\n\n.table-warning,\n.table-warning > th,\n.table-warning > td {\n  background-color: #ffeeba;\n}\n\n.table-warning th,\n.table-warning td,\n.table-warning thead th,\n.table-warning tbody + tbody {\n  border-color: #ffdf7e;\n}\n\n.table-hover .table-warning:hover {\n  background-color: #ffe8a1;\n}\n\n.table-hover .table-warning:hover > td,\n.table-hover .table-warning:hover > th {\n  background-color: #ffe8a1;\n}\n\n.table-danger,\n.table-danger > th,\n.table-danger > td {\n  background-color: #f5c6cb;\n}\n\n.table-danger th,\n.table-danger td,\n.table-danger thead th,\n.table-danger tbody + tbody {\n  border-color: #ed969e;\n}\n\n.table-hover .table-danger:hover {\n  background-color: #f1b0b7;\n}\n\n.table-hover .table-danger:hover > td,\n.table-hover .table-danger:hover > th {\n  background-color: #f1b0b7;\n}\n\n.table-light,\n.table-light > th,\n.table-light > td {\n  background-color: #fdfdfe;\n}\n\n.table-light th,\n.table-light td,\n.table-light thead th,\n.table-light tbody + tbody {\n  border-color: #fbfcfc;\n}\n\n.table-hover .table-light:hover {\n  background-color: #ececf6;\n}\n\n.table-hover .table-light:hover > td,\n.table-hover .table-light:hover > th {\n  background-color: #ececf6;\n}\n\n.table-dark,\n.table-dark > th,\n.table-dark > td {\n  background-color: #c6c8ca;\n}\n\n.table-dark th,\n.table-dark td,\n.table-dark thead th,\n.table-dark tbody + tbody {\n  border-color: #95999c;\n}\n\n.table-hover .table-dark:hover {\n  background-color: #b9bbbe;\n}\n\n.table-hover .table-dark:hover > td,\n.table-hover .table-dark:hover > th {\n  background-color: #b9bbbe;\n}\n\n.table-active,\n.table-active > th,\n.table-active > td {\n  background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-hover .table-active:hover {\n  background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table-hover .table-active:hover > td,\n.table-hover .table-active:hover > th {\n  background-color: rgba(0, 0, 0, 0.075);\n}\n\n.table .thead-dark th {\n  color: #fff;\n  background-color: #343a40;\n  border-color: #454d55;\n}\n\n.table .thead-light th {\n  color: #495057;\n  background-color: #e9ecef;\n  border-color: #dee2e6;\n}\n\n.table-dark {\n  color: #fff;\n  background-color: #343a40;\n}\n\n.table-dark th,\n.table-dark td,\n.table-dark thead th {\n  border-color: #454d55;\n}\n\n.table-dark.table-bordered {\n  border: 0;\n}\n\n.table-dark.table-striped tbody tr:nth-of-type(odd) {\n  background-color: rgba(255, 255, 255, 0.05);\n}\n\n.table-dark.table-hover tbody tr:hover {\n  color: #fff;\n  background-color: rgba(255, 255, 255, 0.075);\n}\n\n@media (max-width: 575.98px) {\n  .table-responsive-sm {\n    display: block;\n    width: 100%;\n    overflow-x: auto;\n    -webkit-overflow-scrolling: touch;\n  }\n  .table-responsive-sm > .table-bordered {\n    border: 0;\n  }\n}\n\n@media (max-width: 767.98px) {\n  .table-responsive-md {\n    display: block;\n    width: 100%;\n    overflow-x: auto;\n    -webkit-overflow-scrolling: touch;\n  }\n  .table-responsive-md > .table-bordered {\n    border: 0;\n  }\n}\n\n@media (max-width: 991.98px) {\n  .table-responsive-lg {\n    display: block;\n    width: 100%;\n    overflow-x: auto;\n    -webkit-overflow-scrolling: touch;\n  }\n  .table-responsive-lg > .table-bordered {\n    border: 0;\n  }\n}\n\n@media (max-width: 1199.98px) {\n  .table-responsive-xl {\n    display: block;\n    width: 100%;\n    overflow-x: auto;\n    -webkit-overflow-scrolling: touch;\n  }\n  .table-responsive-xl > .table-bordered {\n    border: 0;\n  }\n}\n\n.table-responsive {\n  display: block;\n  width: 100%;\n  overflow-x: auto;\n  -webkit-overflow-scrolling: touch;\n}\n\n.table-responsive > .table-bordered {\n  border: 0;\n}\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: calc(1.5em + 0.75rem + 2px);\n  padding: 0.375rem 0.75rem;\n  font-size: 1rem;\n  font-weight: 400;\n  line-height: 1.5;\n  color: #495057;\n  background-color: #fff;\n  background-clip: padding-box;\n  border: 1px solid #ced4da;\n  border-radius: 0.25rem;\n  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .form-control {\n    transition: none;\n  }\n}\n\n.form-control::-ms-expand {\n  background-color: transparent;\n  border: 0;\n}\n\n.form-control:focus {\n  color: #495057;\n  background-color: #fff;\n  border-color: #80bdff;\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.form-control::-webkit-input-placeholder {\n  color: #6c757d;\n  opacity: 1;\n}\n\n.form-control::-moz-placeholder {\n  color: #6c757d;\n  opacity: 1;\n}\n\n.form-control:-ms-input-placeholder {\n  color: #6c757d;\n  opacity: 1;\n}\n\n.form-control::-ms-input-placeholder {\n  color: #6c757d;\n  opacity: 1;\n}\n\n.form-control::placeholder {\n  color: #6c757d;\n  opacity: 1;\n}\n\n.form-control:disabled, .form-control[readonly] {\n  background-color: #e9ecef;\n  opacity: 1;\n}\n\nselect.form-control:focus::-ms-value {\n  color: #495057;\n  background-color: #fff;\n}\n\n.form-control-file,\n.form-control-range {\n  display: block;\n  width: 100%;\n}\n\n.col-form-label {\n  padding-top: calc(0.375rem + 1px);\n  padding-bottom: calc(0.375rem + 1px);\n  margin-bottom: 0;\n  font-size: inherit;\n  line-height: 1.5;\n}\n\n.col-form-label-lg {\n  padding-top: calc(0.5rem + 1px);\n  padding-bottom: calc(0.5rem + 1px);\n  font-size: 1.25rem;\n  line-height: 1.5;\n}\n\n.col-form-label-sm {\n  padding-top: calc(0.25rem + 1px);\n  padding-bottom: calc(0.25rem + 1px);\n  font-size: 0.875rem;\n  line-height: 1.5;\n}\n\n.form-control-plaintext {\n  display: block;\n  width: 100%;\n  padding-top: 0.375rem;\n  padding-bottom: 0.375rem;\n  margin-bottom: 0;\n  line-height: 1.5;\n  color: #212529;\n  background-color: transparent;\n  border: solid transparent;\n  border-width: 1px 0;\n}\n\n.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {\n  padding-right: 0;\n  padding-left: 0;\n}\n\n.form-control-sm {\n  height: calc(1.5em + 0.5rem + 2px);\n  padding: 0.25rem 0.5rem;\n  font-size: 0.875rem;\n  line-height: 1.5;\n  border-radius: 0.2rem;\n}\n\n.form-control-lg {\n  height: calc(1.5em + 1rem + 2px);\n  padding: 0.5rem 1rem;\n  font-size: 1.25rem;\n  line-height: 1.5;\n  border-radius: 0.3rem;\n}\n\nselect.form-control[size], select.form-control[multiple] {\n  height: auto;\n}\n\ntextarea.form-control {\n  height: auto;\n}\n\n.form-group {\n  margin-bottom: 1rem;\n}\n\n.form-text {\n  display: block;\n  margin-top: 0.25rem;\n}\n\n.form-row {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  margin-right: -5px;\n  margin-left: -5px;\n}\n\n.form-row > .col,\n.form-row > [class*=\"col-\"] {\n  padding-right: 5px;\n  padding-left: 5px;\n}\n\n.form-check {\n  position: relative;\n  display: block;\n  padding-left: 1.25rem;\n}\n\n.form-check-input {\n  position: absolute;\n  margin-top: 0.3rem;\n  margin-left: -1.25rem;\n}\n\n.form-check-input:disabled ~ .form-check-label {\n  color: #6c757d;\n}\n\n.form-check-label {\n  margin-bottom: 0;\n}\n\n.form-check-inline {\n  display: -ms-inline-flexbox;\n  display: inline-flex;\n  -ms-flex-align: center;\n  align-items: center;\n  padding-left: 0;\n  margin-right: 0.75rem;\n}\n\n.form-check-inline .form-check-input {\n  position: static;\n  margin-top: 0;\n  margin-right: 0.3125rem;\n  margin-left: 0;\n}\n\n.valid-feedback {\n  display: none;\n  width: 100%;\n  margin-top: 0.25rem;\n  font-size: 80%;\n  color: #28a745;\n}\n\n.valid-tooltip {\n  position: absolute;\n  top: 100%;\n  z-index: 5;\n  display: none;\n  max-width: 100%;\n  padding: 0.25rem 0.5rem;\n  margin-top: .1rem;\n  font-size: 0.875rem;\n  line-height: 1.5;\n  color: #fff;\n  background-color: rgba(40, 167, 69, 0.9);\n  border-radius: 0.25rem;\n}\n\n.was-validated .form-control:valid, .form-control.is-valid {\n  border-color: #28a745;\n  padding-right: calc(1.5em + 0.75rem);\n  background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n  background-repeat: no-repeat;\n  background-position: center right calc(0.375em + 0.1875rem);\n  background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .form-control:valid:focus, .form-control.is-valid:focus {\n  border-color: #28a745;\n  box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .form-control:valid ~ .valid-feedback,\n.was-validated .form-control:valid ~ .valid-tooltip, .form-control.is-valid ~ .valid-feedback,\n.form-control.is-valid ~ .valid-tooltip {\n  display: block;\n}\n\n.was-validated textarea.form-control:valid, textarea.form-control.is-valid {\n  padding-right: calc(1.5em + 0.75rem);\n  background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .custom-select:valid, .custom-select.is-valid {\n  border-color: #28a745;\n  padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem);\n  background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px, url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .custom-select:valid:focus, .custom-select.is-valid:focus {\n  border-color: #28a745;\n  box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .custom-select:valid ~ .valid-feedback,\n.was-validated .custom-select:valid ~ .valid-tooltip, .custom-select.is-valid ~ .valid-feedback,\n.custom-select.is-valid ~ .valid-tooltip {\n  display: block;\n}\n\n.was-validated .form-control-file:valid ~ .valid-feedback,\n.was-validated .form-control-file:valid ~ .valid-tooltip, .form-control-file.is-valid ~ .valid-feedback,\n.form-control-file.is-valid ~ .valid-tooltip {\n  display: block;\n}\n\n.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {\n  color: #28a745;\n}\n\n.was-validated .form-check-input:valid ~ .valid-feedback,\n.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback,\n.form-check-input.is-valid ~ .valid-tooltip {\n  display: block;\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label {\n  color: #28a745;\n}\n\n.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before {\n  border-color: #28a745;\n}\n\n.was-validated .custom-control-input:valid ~ .valid-feedback,\n.was-validated .custom-control-input:valid ~ .valid-tooltip, .custom-control-input.is-valid ~ .valid-feedback,\n.custom-control-input.is-valid ~ .valid-tooltip {\n  display: block;\n}\n\n.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before {\n  border-color: #34ce57;\n  background-color: #34ce57;\n}\n\n.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before {\n  box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.was-validated .custom-control-input:valid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-valid:focus:not(:checked) ~ .custom-control-label::before {\n  border-color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label {\n  border-color: #28a745;\n}\n\n.was-validated .custom-file-input:valid ~ .valid-feedback,\n.was-validated .custom-file-input:valid ~ .valid-tooltip, .custom-file-input.is-valid ~ .valid-feedback,\n.custom-file-input.is-valid ~ .valid-tooltip {\n  display: block;\n}\n\n.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label {\n  border-color: #28a745;\n  box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);\n}\n\n.invalid-feedback {\n  display: none;\n  width: 100%;\n  margin-top: 0.25rem;\n  font-size: 80%;\n  color: #dc3545;\n}\n\n.invalid-tooltip {\n  position: absolute;\n  top: 100%;\n  z-index: 5;\n  display: none;\n  max-width: 100%;\n  padding: 0.25rem 0.5rem;\n  margin-top: .1rem;\n  font-size: 0.875rem;\n  line-height: 1.5;\n  color: #fff;\n  background-color: rgba(220, 53, 69, 0.9);\n  border-radius: 0.25rem;\n}\n\n.was-validated .form-control:invalid, .form-control.is-invalid {\n  border-color: #dc3545;\n  padding-right: calc(1.5em + 0.75rem);\n  background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E\");\n  background-repeat: no-repeat;\n  background-position: center right calc(0.375em + 0.1875rem);\n  background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {\n  border-color: #dc3545;\n  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .form-control:invalid ~ .invalid-feedback,\n.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback,\n.form-control.is-invalid ~ .invalid-tooltip {\n  display: block;\n}\n\n.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {\n  padding-right: calc(1.5em + 0.75rem);\n  background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .custom-select:invalid, .custom-select.is-invalid {\n  border-color: #dc3545;\n  padding-right: calc((1em + 0.75rem) * 3 / 4 + 1.75rem);\n  background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px, url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E\") #fff no-repeat center right 1.75rem/calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n\n.was-validated .custom-select:invalid:focus, .custom-select.is-invalid:focus {\n  border-color: #dc3545;\n  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .custom-select:invalid ~ .invalid-feedback,\n.was-validated .custom-select:invalid ~ .invalid-tooltip, .custom-select.is-invalid ~ .invalid-feedback,\n.custom-select.is-invalid ~ .invalid-tooltip {\n  display: block;\n}\n\n.was-validated .form-control-file:invalid ~ .invalid-feedback,\n.was-validated .form-control-file:invalid ~ .invalid-tooltip, .form-control-file.is-invalid ~ .invalid-feedback,\n.form-control-file.is-invalid ~ .invalid-tooltip {\n  display: block;\n}\n\n.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {\n  color: #dc3545;\n}\n\n.was-validated .form-check-input:invalid ~ .invalid-feedback,\n.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback,\n.form-check-input.is-invalid ~ .invalid-tooltip {\n  display: block;\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label {\n  color: #dc3545;\n}\n\n.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before {\n  border-color: #dc3545;\n}\n\n.was-validated .custom-control-input:invalid ~ .invalid-feedback,\n.was-validated .custom-control-input:invalid ~ .invalid-tooltip, .custom-control-input.is-invalid ~ .invalid-feedback,\n.custom-control-input.is-invalid ~ .invalid-tooltip {\n  display: block;\n}\n\n.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before {\n  border-color: #e4606d;\n  background-color: #e4606d;\n}\n\n.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before {\n  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .custom-control-input:invalid:focus:not(:checked) ~ .custom-control-label::before, .custom-control-input.is-invalid:focus:not(:checked) ~ .custom-control-label::before {\n  border-color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label {\n  border-color: #dc3545;\n}\n\n.was-validated .custom-file-input:invalid ~ .invalid-feedback,\n.was-validated .custom-file-input:invalid ~ .invalid-tooltip, .custom-file-input.is-invalid ~ .invalid-feedback,\n.custom-file-input.is-invalid ~ .invalid-tooltip {\n  display: block;\n}\n\n.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label {\n  border-color: #dc3545;\n  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);\n}\n\n.form-inline {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-flow: row wrap;\n  flex-flow: row wrap;\n  -ms-flex-align: center;\n  align-items: center;\n}\n\n.form-inline .form-check {\n  width: 100%;\n}\n\n@media (min-width: 576px) {\n  .form-inline label {\n    display: -ms-flexbox;\n    display: flex;\n    -ms-flex-align: center;\n    align-items: center;\n    -ms-flex-pack: center;\n    justify-content: center;\n    margin-bottom: 0;\n  }\n  .form-inline .form-group {\n    display: -ms-flexbox;\n    display: flex;\n    -ms-flex: 0 0 auto;\n    flex: 0 0 auto;\n    -ms-flex-flow: row wrap;\n    flex-flow: row wrap;\n    -ms-flex-align: center;\n    align-items: center;\n    margin-bottom: 0;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .form-control-plaintext {\n    display: inline-block;\n  }\n  .form-inline .input-group,\n  .form-inline .custom-select {\n    width: auto;\n  }\n  .form-inline .form-check {\n    display: -ms-flexbox;\n    display: flex;\n    -ms-flex-align: center;\n    align-items: center;\n    -ms-flex-pack: center;\n    justify-content: center;\n    width: auto;\n    padding-left: 0;\n  }\n  .form-inline .form-check-input {\n    position: relative;\n    -ms-flex-negative: 0;\n    flex-shrink: 0;\n    margin-top: 0;\n    margin-right: 0.25rem;\n    margin-left: 0;\n  }\n  .form-inline .custom-control {\n    -ms-flex-align: center;\n    align-items: center;\n    -ms-flex-pack: center;\n    justify-content: center;\n  }\n  .form-inline .custom-control-label {\n    margin-bottom: 0;\n  }\n}\n\n.btn {\n  display: inline-block;\n  font-weight: 400;\n  color: #212529;\n  text-align: center;\n  vertical-align: middle;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  background-color: transparent;\n  border: 1px solid transparent;\n  padding: 0.375rem 0.75rem;\n  font-size: 1rem;\n  line-height: 1.5;\n  border-radius: 0.25rem;\n  transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .btn {\n    transition: none;\n  }\n}\n\n.btn:hover {\n  color: #212529;\n  text-decoration: none;\n}\n\n.btn:focus, .btn.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.btn.disabled, .btn:disabled {\n  opacity: 0.65;\n}\n\na.btn.disabled,\nfieldset:disabled a.btn {\n  pointer-events: none;\n}\n\n.btn-primary {\n  color: #fff;\n  background-color: #007bff;\n  border-color: #007bff;\n}\n\n.btn-primary:hover {\n  color: #fff;\n  background-color: #0069d9;\n  border-color: #0062cc;\n}\n\n.btn-primary:focus, .btn-primary.focus {\n  box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);\n}\n\n.btn-primary.disabled, .btn-primary:disabled {\n  color: #fff;\n  background-color: #007bff;\n  border-color: #007bff;\n}\n\n.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active,\n.show > .btn-primary.dropdown-toggle {\n  color: #fff;\n  background-color: #0062cc;\n  border-color: #005cbf;\n}\n\n.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-primary.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);\n}\n\n.btn-secondary {\n  color: #fff;\n  background-color: #6c757d;\n  border-color: #6c757d;\n}\n\n.btn-secondary:hover {\n  color: #fff;\n  background-color: #5a6268;\n  border-color: #545b62;\n}\n\n.btn-secondary:focus, .btn-secondary.focus {\n  box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5);\n}\n\n.btn-secondary.disabled, .btn-secondary:disabled {\n  color: #fff;\n  background-color: #6c757d;\n  border-color: #6c757d;\n}\n\n.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active,\n.show > .btn-secondary.dropdown-toggle {\n  color: #fff;\n  background-color: #545b62;\n  border-color: #4e555b;\n}\n\n.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-secondary.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5);\n}\n\n.btn-success {\n  color: #fff;\n  background-color: #28a745;\n  border-color: #28a745;\n}\n\n.btn-success:hover {\n  color: #fff;\n  background-color: #218838;\n  border-color: #1e7e34;\n}\n\n.btn-success:focus, .btn-success.focus {\n  box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5);\n}\n\n.btn-success.disabled, .btn-success:disabled {\n  color: #fff;\n  background-color: #28a745;\n  border-color: #28a745;\n}\n\n.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active,\n.show > .btn-success.dropdown-toggle {\n  color: #fff;\n  background-color: #1e7e34;\n  border-color: #1c7430;\n}\n\n.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus,\n.show > .btn-success.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(72, 180, 97, 0.5);\n}\n\n.btn-info {\n  color: #fff;\n  background-color: #17a2b8;\n  border-color: #17a2b8;\n}\n\n.btn-info:hover {\n  color: #fff;\n  background-color: #138496;\n  border-color: #117a8b;\n}\n\n.btn-info:focus, .btn-info.focus {\n  box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5);\n}\n\n.btn-info.disabled, .btn-info:disabled {\n  color: #fff;\n  background-color: #17a2b8;\n  border-color: #17a2b8;\n}\n\n.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,\n.show > .btn-info.dropdown-toggle {\n  color: #fff;\n  background-color: #117a8b;\n  border-color: #10707f;\n}\n\n.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,\n.show > .btn-info.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(58, 176, 195, 0.5);\n}\n\n.btn-warning {\n  color: #212529;\n  background-color: #ffc107;\n  border-color: #ffc107;\n}\n\n.btn-warning:hover {\n  color: #212529;\n  background-color: #e0a800;\n  border-color: #d39e00;\n}\n\n.btn-warning:focus, .btn-warning.focus {\n  box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5);\n}\n\n.btn-warning.disabled, .btn-warning:disabled {\n  color: #212529;\n  background-color: #ffc107;\n  border-color: #ffc107;\n}\n\n.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active,\n.show > .btn-warning.dropdown-toggle {\n  color: #212529;\n  background-color: #d39e00;\n  border-color: #c69500;\n}\n\n.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus,\n.show > .btn-warning.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(222, 170, 12, 0.5);\n}\n\n.btn-danger {\n  color: #fff;\n  background-color: #dc3545;\n  border-color: #dc3545;\n}\n\n.btn-danger:hover {\n  color: #fff;\n  background-color: #c82333;\n  border-color: #bd2130;\n}\n\n.btn-danger:focus, .btn-danger.focus {\n  box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5);\n}\n\n.btn-danger.disabled, .btn-danger:disabled {\n  color: #fff;\n  background-color: #dc3545;\n  border-color: #dc3545;\n}\n\n.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active,\n.show > .btn-danger.dropdown-toggle {\n  color: #fff;\n  background-color: #bd2130;\n  border-color: #b21f2d;\n}\n\n.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus,\n.show > .btn-danger.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5);\n}\n\n.btn-light {\n  color: #212529;\n  background-color: #f8f9fa;\n  border-color: #f8f9fa;\n}\n\n.btn-light:hover {\n  color: #212529;\n  background-color: #e2e6ea;\n  border-color: #dae0e5;\n}\n\n.btn-light:focus, .btn-light.focus {\n  box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5);\n}\n\n.btn-light.disabled, .btn-light:disabled {\n  color: #212529;\n  background-color: #f8f9fa;\n  border-color: #f8f9fa;\n}\n\n.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active,\n.show > .btn-light.dropdown-toggle {\n  color: #212529;\n  background-color: #dae0e5;\n  border-color: #d3d9df;\n}\n\n.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus,\n.show > .btn-light.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(216, 217, 219, 0.5);\n}\n\n.btn-dark {\n  color: #fff;\n  background-color: #343a40;\n  border-color: #343a40;\n}\n\n.btn-dark:hover {\n  color: #fff;\n  background-color: #23272b;\n  border-color: #1d2124;\n}\n\n.btn-dark:focus, .btn-dark.focus {\n  box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);\n}\n\n.btn-dark.disabled, .btn-dark:disabled {\n  color: #fff;\n  background-color: #343a40;\n  border-color: #343a40;\n}\n\n.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active,\n.show > .btn-dark.dropdown-toggle {\n  color: #fff;\n  background-color: #1d2124;\n  border-color: #171a1d;\n}\n\n.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus,\n.show > .btn-dark.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);\n}\n\n.btn-outline-primary {\n  color: #007bff;\n  border-color: #007bff;\n}\n\n.btn-outline-primary:hover {\n  color: #fff;\n  background-color: #007bff;\n  border-color: #007bff;\n}\n\n.btn-outline-primary:focus, .btn-outline-primary.focus {\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.btn-outline-primary.disabled, .btn-outline-primary:disabled {\n  color: #007bff;\n  background-color: transparent;\n}\n\n.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active,\n.show > .btn-outline-primary.dropdown-toggle {\n  color: #fff;\n  background-color: #007bff;\n  border-color: #007bff;\n}\n\n.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-primary.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.btn-outline-secondary {\n  color: #6c757d;\n  border-color: #6c757d;\n}\n\n.btn-outline-secondary:hover {\n  color: #fff;\n  background-color: #6c757d;\n  border-color: #6c757d;\n}\n\n.btn-outline-secondary:focus, .btn-outline-secondary.focus {\n  box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {\n  color: #6c757d;\n  background-color: transparent;\n}\n\n.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active,\n.show > .btn-outline-secondary.dropdown-toggle {\n  color: #fff;\n  background-color: #6c757d;\n  border-color: #6c757d;\n}\n\n.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-secondary.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.btn-outline-success {\n  color: #28a745;\n  border-color: #28a745;\n}\n\n.btn-outline-success:hover {\n  color: #fff;\n  background-color: #28a745;\n  border-color: #28a745;\n}\n\n.btn-outline-success:focus, .btn-outline-success.focus {\n  box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.btn-outline-success.disabled, .btn-outline-success:disabled {\n  color: #28a745;\n  background-color: transparent;\n}\n\n.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active,\n.show > .btn-outline-success.dropdown-toggle {\n  color: #fff;\n  background-color: #28a745;\n  border-color: #28a745;\n}\n\n.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-success.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.btn-outline-info {\n  color: #17a2b8;\n  border-color: #17a2b8;\n}\n\n.btn-outline-info:hover {\n  color: #fff;\n  background-color: #17a2b8;\n  border-color: #17a2b8;\n}\n\n.btn-outline-info:focus, .btn-outline-info.focus {\n  box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.btn-outline-info.disabled, .btn-outline-info:disabled {\n  color: #17a2b8;\n  background-color: transparent;\n}\n\n.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,\n.show > .btn-outline-info.dropdown-toggle {\n  color: #fff;\n  background-color: #17a2b8;\n  border-color: #17a2b8;\n}\n\n.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-info.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.btn-outline-warning {\n  color: #ffc107;\n  border-color: #ffc107;\n}\n\n.btn-outline-warning:hover {\n  color: #212529;\n  background-color: #ffc107;\n  border-color: #ffc107;\n}\n\n.btn-outline-warning:focus, .btn-outline-warning.focus {\n  box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.btn-outline-warning.disabled, .btn-outline-warning:disabled {\n  color: #ffc107;\n  background-color: transparent;\n}\n\n.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active,\n.show > .btn-outline-warning.dropdown-toggle {\n  color: #212529;\n  background-color: #ffc107;\n  border-color: #ffc107;\n}\n\n.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-warning.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.btn-outline-danger {\n  color: #dc3545;\n  border-color: #dc3545;\n}\n\n.btn-outline-danger:hover {\n  color: #fff;\n  background-color: #dc3545;\n  border-color: #dc3545;\n}\n\n.btn-outline-danger:focus, .btn-outline-danger.focus {\n  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.btn-outline-danger.disabled, .btn-outline-danger:disabled {\n  color: #dc3545;\n  background-color: transparent;\n}\n\n.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active,\n.show > .btn-outline-danger.dropdown-toggle {\n  color: #fff;\n  background-color: #dc3545;\n  border-color: #dc3545;\n}\n\n.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-danger.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.btn-outline-light {\n  color: #f8f9fa;\n  border-color: #f8f9fa;\n}\n\n.btn-outline-light:hover {\n  color: #212529;\n  background-color: #f8f9fa;\n  border-color: #f8f9fa;\n}\n\n.btn-outline-light:focus, .btn-outline-light.focus {\n  box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.btn-outline-light.disabled, .btn-outline-light:disabled {\n  color: #f8f9fa;\n  background-color: transparent;\n}\n\n.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active,\n.show > .btn-outline-light.dropdown-toggle {\n  color: #212529;\n  background-color: #f8f9fa;\n  border-color: #f8f9fa;\n}\n\n.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-light.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.btn-outline-dark {\n  color: #343a40;\n  border-color: #343a40;\n}\n\n.btn-outline-dark:hover {\n  color: #fff;\n  background-color: #343a40;\n  border-color: #343a40;\n}\n\n.btn-outline-dark:focus, .btn-outline-dark.focus {\n  box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.btn-outline-dark.disabled, .btn-outline-dark:disabled {\n  color: #343a40;\n  background-color: transparent;\n}\n\n.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active,\n.show > .btn-outline-dark.dropdown-toggle {\n  color: #fff;\n  background-color: #343a40;\n  border-color: #343a40;\n}\n\n.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus,\n.show > .btn-outline-dark.dropdown-toggle:focus {\n  box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.btn-link {\n  font-weight: 400;\n  color: #007bff;\n  text-decoration: none;\n}\n\n.btn-link:hover {\n  color: #0056b3;\n  text-decoration: underline;\n}\n\n.btn-link:focus, .btn-link.focus {\n  text-decoration: underline;\n  box-shadow: none;\n}\n\n.btn-link:disabled, .btn-link.disabled {\n  color: #6c757d;\n  pointer-events: none;\n}\n\n.btn-lg, .btn-group-lg > .btn {\n  padding: 0.5rem 1rem;\n  font-size: 1.25rem;\n  line-height: 1.5;\n  border-radius: 0.3rem;\n}\n\n.btn-sm, .btn-group-sm > .btn {\n  padding: 0.25rem 0.5rem;\n  font-size: 0.875rem;\n  line-height: 1.5;\n  border-radius: 0.2rem;\n}\n\n.btn-block {\n  display: block;\n  width: 100%;\n}\n\n.btn-block + .btn-block {\n  margin-top: 0.5rem;\n}\n\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n\n.fade {\n  transition: opacity 0.15s linear;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .fade {\n    transition: none;\n  }\n}\n\n.fade:not(.show) {\n  opacity: 0;\n}\n\n.collapse:not(.show) {\n  display: none;\n}\n\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  transition: height 0.35s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .collapsing {\n    transition: none;\n  }\n}\n\n.dropup,\n.dropright,\n.dropdown,\n.dropleft {\n  position: relative;\n}\n\n.dropdown-toggle {\n  white-space: nowrap;\n}\n\n.dropdown-toggle::after {\n  display: inline-block;\n  margin-left: 0.255em;\n  vertical-align: 0.255em;\n  content: \"\";\n  border-top: 0.3em solid;\n  border-right: 0.3em solid transparent;\n  border-bottom: 0;\n  border-left: 0.3em solid transparent;\n}\n\n.dropdown-toggle:empty::after {\n  margin-left: 0;\n}\n\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 10rem;\n  padding: 0.5rem 0;\n  margin: 0.125rem 0 0;\n  font-size: 1rem;\n  color: #212529;\n  text-align: left;\n  list-style: none;\n  background-color: #fff;\n  background-clip: padding-box;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  border-radius: 0.25rem;\n}\n\n.dropdown-menu-left {\n  right: auto;\n  left: 0;\n}\n\n.dropdown-menu-right {\n  right: 0;\n  left: auto;\n}\n\n@media (min-width: 576px) {\n  .dropdown-menu-sm-left {\n    right: auto;\n    left: 0;\n  }\n  .dropdown-menu-sm-right {\n    right: 0;\n    left: auto;\n  }\n}\n\n@media (min-width: 768px) {\n  .dropdown-menu-md-left {\n    right: auto;\n    left: 0;\n  }\n  .dropdown-menu-md-right {\n    right: 0;\n    left: auto;\n  }\n}\n\n@media (min-width: 992px) {\n  .dropdown-menu-lg-left {\n    right: auto;\n    left: 0;\n  }\n  .dropdown-menu-lg-right {\n    right: 0;\n    left: auto;\n  }\n}\n\n@media (min-width: 1200px) {\n  .dropdown-menu-xl-left {\n    right: auto;\n    left: 0;\n  }\n  .dropdown-menu-xl-right {\n    right: 0;\n    left: auto;\n  }\n}\n\n.dropup .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-top: 0;\n  margin-bottom: 0.125rem;\n}\n\n.dropup .dropdown-toggle::after {\n  display: inline-block;\n  margin-left: 0.255em;\n  vertical-align: 0.255em;\n  content: \"\";\n  border-top: 0;\n  border-right: 0.3em solid transparent;\n  border-bottom: 0.3em solid;\n  border-left: 0.3em solid transparent;\n}\n\n.dropup .dropdown-toggle:empty::after {\n  margin-left: 0;\n}\n\n.dropright .dropdown-menu {\n  top: 0;\n  right: auto;\n  left: 100%;\n  margin-top: 0;\n  margin-left: 0.125rem;\n}\n\n.dropright .dropdown-toggle::after {\n  display: inline-block;\n  margin-left: 0.255em;\n  vertical-align: 0.255em;\n  content: \"\";\n  border-top: 0.3em solid transparent;\n  border-right: 0;\n  border-bottom: 0.3em solid transparent;\n  border-left: 0.3em solid;\n}\n\n.dropright .dropdown-toggle:empty::after {\n  margin-left: 0;\n}\n\n.dropright .dropdown-toggle::after {\n  vertical-align: 0;\n}\n\n.dropleft .dropdown-menu {\n  top: 0;\n  right: 100%;\n  left: auto;\n  margin-top: 0;\n  margin-right: 0.125rem;\n}\n\n.dropleft .dropdown-toggle::after {\n  display: inline-block;\n  margin-left: 0.255em;\n  vertical-align: 0.255em;\n  content: \"\";\n}\n\n.dropleft .dropdown-toggle::after {\n  display: none;\n}\n\n.dropleft .dropdown-toggle::before {\n  display: inline-block;\n  margin-right: 0.255em;\n  vertical-align: 0.255em;\n  content: \"\";\n  border-top: 0.3em solid transparent;\n  border-right: 0.3em solid;\n  border-bottom: 0.3em solid transparent;\n}\n\n.dropleft .dropdown-toggle:empty::after {\n  margin-left: 0;\n}\n\n.dropleft .dropdown-toggle::before {\n  vertical-align: 0;\n}\n\n.dropdown-menu[x-placement^=\"top\"], .dropdown-menu[x-placement^=\"right\"], .dropdown-menu[x-placement^=\"bottom\"], .dropdown-menu[x-placement^=\"left\"] {\n  right: auto;\n  bottom: auto;\n}\n\n.dropdown-divider {\n  height: 0;\n  margin: 0.5rem 0;\n  overflow: hidden;\n  border-top: 1px solid #e9ecef;\n}\n\n.dropdown-item {\n  display: block;\n  width: 100%;\n  padding: 0.25rem 1.5rem;\n  clear: both;\n  font-weight: 400;\n  color: #212529;\n  text-align: inherit;\n  white-space: nowrap;\n  background-color: transparent;\n  border: 0;\n}\n\n.dropdown-item:hover, .dropdown-item:focus {\n  color: #16181b;\n  text-decoration: none;\n  background-color: #f8f9fa;\n}\n\n.dropdown-item.active, .dropdown-item:active {\n  color: #fff;\n  text-decoration: none;\n  background-color: #007bff;\n}\n\n.dropdown-item.disabled, .dropdown-item:disabled {\n  color: #6c757d;\n  pointer-events: none;\n  background-color: transparent;\n}\n\n.dropdown-menu.show {\n  display: block;\n}\n\n.dropdown-header {\n  display: block;\n  padding: 0.5rem 1.5rem;\n  margin-bottom: 0;\n  font-size: 0.875rem;\n  color: #6c757d;\n  white-space: nowrap;\n}\n\n.dropdown-item-text {\n  display: block;\n  padding: 0.25rem 1.5rem;\n  color: #212529;\n}\n\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: -ms-inline-flexbox;\n  display: inline-flex;\n  vertical-align: middle;\n}\n\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  -ms-flex: 1 1 auto;\n  flex: 1 1 auto;\n}\n\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover {\n  z-index: 1;\n}\n\n.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n  z-index: 1;\n}\n\n.btn-toolbar {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  -ms-flex-pack: start;\n  justify-content: flex-start;\n}\n\n.btn-toolbar .input-group {\n  width: auto;\n}\n\n.btn-group > .btn:not(:first-child),\n.btn-group > .btn-group:not(:first-child) {\n  margin-left: -1px;\n}\n\n.btn-group > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group > .btn-group:not(:last-child) > .btn {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n\n.btn-group > .btn:not(:first-child),\n.btn-group > .btn-group:not(:first-child) > .btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.dropdown-toggle-split {\n  padding-right: 0.5625rem;\n  padding-left: 0.5625rem;\n}\n\n.dropdown-toggle-split::after,\n.dropup .dropdown-toggle-split::after,\n.dropright .dropdown-toggle-split::after {\n  margin-left: 0;\n}\n\n.dropleft .dropdown-toggle-split::before {\n  margin-right: 0;\n}\n\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\n  padding-right: 0.375rem;\n  padding-left: 0.375rem;\n}\n\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\n  padding-right: 0.75rem;\n  padding-left: 0.75rem;\n}\n\n.btn-group-vertical {\n  -ms-flex-direction: column;\n  flex-direction: column;\n  -ms-flex-align: start;\n  align-items: flex-start;\n  -ms-flex-pack: center;\n  justify-content: center;\n}\n\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group {\n  width: 100%;\n}\n\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) {\n  margin-top: -1px;\n}\n\n.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group-vertical > .btn-group:not(:last-child) > .btn {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) > .btn {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.btn-group-toggle > .btn,\n.btn-group-toggle > .btn-group > .btn {\n  margin-bottom: 0;\n}\n\n.btn-group-toggle > .btn input[type=\"radio\"],\n.btn-group-toggle > .btn input[type=\"checkbox\"],\n.btn-group-toggle > .btn-group > .btn input[type=\"radio\"],\n.btn-group-toggle > .btn-group > .btn input[type=\"checkbox\"] {\n  position: absolute;\n  clip: rect(0, 0, 0, 0);\n  pointer-events: none;\n}\n\n.input-group {\n  position: relative;\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  -ms-flex-align: stretch;\n  align-items: stretch;\n  width: 100%;\n}\n\n.input-group > .form-control,\n.input-group > .form-control-plaintext,\n.input-group > .custom-select,\n.input-group > .custom-file {\n  position: relative;\n  -ms-flex: 1 1 auto;\n  flex: 1 1 auto;\n  width: 1%;\n  margin-bottom: 0;\n}\n\n.input-group > .form-control + .form-control,\n.input-group > .form-control + .custom-select,\n.input-group > .form-control + .custom-file,\n.input-group > .form-control-plaintext + .form-control,\n.input-group > .form-control-plaintext + .custom-select,\n.input-group > .form-control-plaintext + .custom-file,\n.input-group > .custom-select + .form-control,\n.input-group > .custom-select + .custom-select,\n.input-group > .custom-select + .custom-file,\n.input-group > .custom-file + .form-control,\n.input-group > .custom-file + .custom-select,\n.input-group > .custom-file + .custom-file {\n  margin-left: -1px;\n}\n\n.input-group > .form-control:focus,\n.input-group > .custom-select:focus,\n.input-group > .custom-file .custom-file-input:focus ~ .custom-file-label {\n  z-index: 3;\n}\n\n.input-group > .custom-file .custom-file-input:focus {\n  z-index: 4;\n}\n\n.input-group > .form-control:not(:last-child),\n.input-group > .custom-select:not(:last-child) {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n\n.input-group > .form-control:not(:first-child),\n.input-group > .custom-select:not(:first-child) {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.input-group > .custom-file {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-align: center;\n  align-items: center;\n}\n\n.input-group > .custom-file:not(:last-child) .custom-file-label,\n.input-group > .custom-file:not(:last-child) .custom-file-label::after {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n\n.input-group > .custom-file:not(:first-child) .custom-file-label {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.input-group-prepend,\n.input-group-append {\n  display: -ms-flexbox;\n  display: flex;\n}\n\n.input-group-prepend .btn,\n.input-group-append .btn {\n  position: relative;\n  z-index: 2;\n}\n\n.input-group-prepend .btn:focus,\n.input-group-append .btn:focus {\n  z-index: 3;\n}\n\n.input-group-prepend .btn + .btn,\n.input-group-prepend .btn + .input-group-text,\n.input-group-prepend .input-group-text + .input-group-text,\n.input-group-prepend .input-group-text + .btn,\n.input-group-append .btn + .btn,\n.input-group-append .btn + .input-group-text,\n.input-group-append .input-group-text + .input-group-text,\n.input-group-append .input-group-text + .btn {\n  margin-left: -1px;\n}\n\n.input-group-prepend {\n  margin-right: -1px;\n}\n\n.input-group-append {\n  margin-left: -1px;\n}\n\n.input-group-text {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-align: center;\n  align-items: center;\n  padding: 0.375rem 0.75rem;\n  margin-bottom: 0;\n  font-size: 1rem;\n  font-weight: 400;\n  line-height: 1.5;\n  color: #495057;\n  text-align: center;\n  white-space: nowrap;\n  background-color: #e9ecef;\n  border: 1px solid #ced4da;\n  border-radius: 0.25rem;\n}\n\n.input-group-text input[type=\"radio\"],\n.input-group-text input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n\n.input-group-lg > .form-control:not(textarea),\n.input-group-lg > .custom-select {\n  height: calc(1.5em + 1rem + 2px);\n}\n\n.input-group-lg > .form-control,\n.input-group-lg > .custom-select,\n.input-group-lg > .input-group-prepend > .input-group-text,\n.input-group-lg > .input-group-append > .input-group-text,\n.input-group-lg > .input-group-prepend > .btn,\n.input-group-lg > .input-group-append > .btn {\n  padding: 0.5rem 1rem;\n  font-size: 1.25rem;\n  line-height: 1.5;\n  border-radius: 0.3rem;\n}\n\n.input-group-sm > .form-control:not(textarea),\n.input-group-sm > .custom-select {\n  height: calc(1.5em + 0.5rem + 2px);\n}\n\n.input-group-sm > .form-control,\n.input-group-sm > .custom-select,\n.input-group-sm > .input-group-prepend > .input-group-text,\n.input-group-sm > .input-group-append > .input-group-text,\n.input-group-sm > .input-group-prepend > .btn,\n.input-group-sm > .input-group-append > .btn {\n  padding: 0.25rem 0.5rem;\n  font-size: 0.875rem;\n  line-height: 1.5;\n  border-radius: 0.2rem;\n}\n\n.input-group-lg > .custom-select,\n.input-group-sm > .custom-select {\n  padding-right: 1.75rem;\n}\n\n.input-group > .input-group-prepend > .btn,\n.input-group > .input-group-prepend > .input-group-text,\n.input-group > .input-group-append:not(:last-child) > .btn,\n.input-group > .input-group-append:not(:last-child) > .input-group-text,\n.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n\n.input-group > .input-group-append > .btn,\n.input-group > .input-group-append > .input-group-text,\n.input-group > .input-group-prepend:not(:first-child) > .btn,\n.input-group > .input-group-prepend:not(:first-child) > .input-group-text,\n.input-group > .input-group-prepend:first-child > .btn:not(:first-child),\n.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.custom-control {\n  position: relative;\n  display: block;\n  min-height: 1.5rem;\n  padding-left: 1.5rem;\n}\n\n.custom-control-inline {\n  display: -ms-inline-flexbox;\n  display: inline-flex;\n  margin-right: 1rem;\n}\n\n.custom-control-input {\n  position: absolute;\n  z-index: -1;\n  opacity: 0;\n}\n\n.custom-control-input:checked ~ .custom-control-label::before {\n  color: #fff;\n  border-color: #007bff;\n  background-color: #007bff;\n}\n\n.custom-control-input:focus ~ .custom-control-label::before {\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-control-input:focus:not(:checked) ~ .custom-control-label::before {\n  border-color: #80bdff;\n}\n\n.custom-control-input:not(:disabled):active ~ .custom-control-label::before {\n  color: #fff;\n  background-color: #b3d7ff;\n  border-color: #b3d7ff;\n}\n\n.custom-control-input:disabled ~ .custom-control-label {\n  color: #6c757d;\n}\n\n.custom-control-input:disabled ~ .custom-control-label::before {\n  background-color: #e9ecef;\n}\n\n.custom-control-label {\n  position: relative;\n  margin-bottom: 0;\n  vertical-align: top;\n}\n\n.custom-control-label::before {\n  position: absolute;\n  top: 0.25rem;\n  left: -1.5rem;\n  display: block;\n  width: 1rem;\n  height: 1rem;\n  pointer-events: none;\n  content: \"\";\n  background-color: #fff;\n  border: #adb5bd solid 1px;\n}\n\n.custom-control-label::after {\n  position: absolute;\n  top: 0.25rem;\n  left: -1.5rem;\n  display: block;\n  width: 1rem;\n  height: 1rem;\n  content: \"\";\n  background: no-repeat 50% / 50% 50%;\n}\n\n.custom-checkbox .custom-control-label::before {\n  border-radius: 0.25rem;\n}\n\n.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {\n  background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e\");\n}\n\n.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before {\n  border-color: #007bff;\n  background-color: #007bff;\n}\n\n.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after {\n  background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e\");\n}\n\n.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before {\n  background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before {\n  background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-radio .custom-control-label::before {\n  border-radius: 50%;\n}\n\n.custom-radio .custom-control-input:checked ~ .custom-control-label::after {\n  background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e\");\n}\n\n.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before {\n  background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-switch {\n  padding-left: 2.25rem;\n}\n\n.custom-switch .custom-control-label::before {\n  left: -2.25rem;\n  width: 1.75rem;\n  pointer-events: all;\n  border-radius: 0.5rem;\n}\n\n.custom-switch .custom-control-label::after {\n  top: calc(0.25rem + 2px);\n  left: calc(-2.25rem + 2px);\n  width: calc(1rem - 4px);\n  height: calc(1rem - 4px);\n  background-color: #adb5bd;\n  border-radius: 0.5rem;\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out;\n  transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n  transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-transform 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .custom-switch .custom-control-label::after {\n    transition: none;\n  }\n}\n\n.custom-switch .custom-control-input:checked ~ .custom-control-label::after {\n  background-color: #fff;\n  -webkit-transform: translateX(0.75rem);\n  transform: translateX(0.75rem);\n}\n\n.custom-switch .custom-control-input:disabled:checked ~ .custom-control-label::before {\n  background-color: rgba(0, 123, 255, 0.5);\n}\n\n.custom-select {\n  display: inline-block;\n  width: 100%;\n  height: calc(1.5em + 0.75rem + 2px);\n  padding: 0.375rem 1.75rem 0.375rem 0.75rem;\n  font-size: 1rem;\n  font-weight: 400;\n  line-height: 1.5;\n  color: #495057;\n  vertical-align: middle;\n  background: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e\") no-repeat right 0.75rem center/8px 10px;\n  background-color: #fff;\n  border: 1px solid #ced4da;\n  border-radius: 0.25rem;\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  appearance: none;\n}\n\n.custom-select:focus {\n  border-color: #80bdff;\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-select:focus::-ms-value {\n  color: #495057;\n  background-color: #fff;\n}\n\n.custom-select[multiple], .custom-select[size]:not([size=\"1\"]) {\n  height: auto;\n  padding-right: 0.75rem;\n  background-image: none;\n}\n\n.custom-select:disabled {\n  color: #6c757d;\n  background-color: #e9ecef;\n}\n\n.custom-select::-ms-expand {\n  display: none;\n}\n\n.custom-select-sm {\n  height: calc(1.5em + 0.5rem + 2px);\n  padding-top: 0.25rem;\n  padding-bottom: 0.25rem;\n  padding-left: 0.5rem;\n  font-size: 0.875rem;\n}\n\n.custom-select-lg {\n  height: calc(1.5em + 1rem + 2px);\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n  padding-left: 1rem;\n  font-size: 1.25rem;\n}\n\n.custom-file {\n  position: relative;\n  display: inline-block;\n  width: 100%;\n  height: calc(1.5em + 0.75rem + 2px);\n  margin-bottom: 0;\n}\n\n.custom-file-input {\n  position: relative;\n  z-index: 2;\n  width: 100%;\n  height: calc(1.5em + 0.75rem + 2px);\n  margin: 0;\n  opacity: 0;\n}\n\n.custom-file-input:focus ~ .custom-file-label {\n  border-color: #80bdff;\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-file-input:disabled ~ .custom-file-label {\n  background-color: #e9ecef;\n}\n\n.custom-file-input:lang(en) ~ .custom-file-label::after {\n  content: \"Browse\";\n}\n\n.custom-file-input ~ .custom-file-label[data-browse]::after {\n  content: attr(data-browse);\n}\n\n.custom-file-label {\n  position: absolute;\n  top: 0;\n  right: 0;\n  left: 0;\n  z-index: 1;\n  height: calc(1.5em + 0.75rem + 2px);\n  padding: 0.375rem 0.75rem;\n  font-weight: 400;\n  line-height: 1.5;\n  color: #495057;\n  background-color: #fff;\n  border: 1px solid #ced4da;\n  border-radius: 0.25rem;\n}\n\n.custom-file-label::after {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 3;\n  display: block;\n  height: calc(1.5em + 0.75rem);\n  padding: 0.375rem 0.75rem;\n  line-height: 1.5;\n  color: #495057;\n  content: \"Browse\";\n  background-color: #e9ecef;\n  border-left: inherit;\n  border-radius: 0 0.25rem 0.25rem 0;\n}\n\n.custom-range {\n  width: 100%;\n  height: calc(1rem + 0.4rem);\n  padding: 0;\n  background-color: transparent;\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  appearance: none;\n}\n\n.custom-range:focus {\n  outline: none;\n}\n\n.custom-range:focus::-webkit-slider-thumb {\n  box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range:focus::-moz-range-thumb {\n  box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range:focus::-ms-thumb {\n  box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.custom-range::-moz-focus-outer {\n  border: 0;\n}\n\n.custom-range::-webkit-slider-thumb {\n  width: 1rem;\n  height: 1rem;\n  margin-top: -0.25rem;\n  background-color: #007bff;\n  border: 0;\n  border-radius: 1rem;\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n  -webkit-appearance: none;\n  appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .custom-range::-webkit-slider-thumb {\n    transition: none;\n  }\n}\n\n.custom-range::-webkit-slider-thumb:active {\n  background-color: #b3d7ff;\n}\n\n.custom-range::-webkit-slider-runnable-track {\n  width: 100%;\n  height: 0.5rem;\n  color: transparent;\n  cursor: pointer;\n  background-color: #dee2e6;\n  border-color: transparent;\n  border-radius: 1rem;\n}\n\n.custom-range::-moz-range-thumb {\n  width: 1rem;\n  height: 1rem;\n  background-color: #007bff;\n  border: 0;\n  border-radius: 1rem;\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n  -moz-appearance: none;\n  appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .custom-range::-moz-range-thumb {\n    transition: none;\n  }\n}\n\n.custom-range::-moz-range-thumb:active {\n  background-color: #b3d7ff;\n}\n\n.custom-range::-moz-range-track {\n  width: 100%;\n  height: 0.5rem;\n  color: transparent;\n  cursor: pointer;\n  background-color: #dee2e6;\n  border-color: transparent;\n  border-radius: 1rem;\n}\n\n.custom-range::-ms-thumb {\n  width: 1rem;\n  height: 1rem;\n  margin-top: 0;\n  margin-right: 0.2rem;\n  margin-left: 0.2rem;\n  background-color: #007bff;\n  border: 0;\n  border-radius: 1rem;\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n  appearance: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .custom-range::-ms-thumb {\n    transition: none;\n  }\n}\n\n.custom-range::-ms-thumb:active {\n  background-color: #b3d7ff;\n}\n\n.custom-range::-ms-track {\n  width: 100%;\n  height: 0.5rem;\n  color: transparent;\n  cursor: pointer;\n  background-color: transparent;\n  border-color: transparent;\n  border-width: 0.5rem;\n}\n\n.custom-range::-ms-fill-lower {\n  background-color: #dee2e6;\n  border-radius: 1rem;\n}\n\n.custom-range::-ms-fill-upper {\n  margin-right: 15px;\n  background-color: #dee2e6;\n  border-radius: 1rem;\n}\n\n.custom-range:disabled::-webkit-slider-thumb {\n  background-color: #adb5bd;\n}\n\n.custom-range:disabled::-webkit-slider-runnable-track {\n  cursor: default;\n}\n\n.custom-range:disabled::-moz-range-thumb {\n  background-color: #adb5bd;\n}\n\n.custom-range:disabled::-moz-range-track {\n  cursor: default;\n}\n\n.custom-range:disabled::-ms-thumb {\n  background-color: #adb5bd;\n}\n\n.custom-control-label::before,\n.custom-file-label,\n.custom-select {\n  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .custom-control-label::before,\n  .custom-file-label,\n  .custom-select {\n    transition: none;\n  }\n}\n\n.nav {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  padding-left: 0;\n  margin-bottom: 0;\n  list-style: none;\n}\n\n.nav-link {\n  display: block;\n  padding: 0.5rem 1rem;\n}\n\n.nav-link:hover, .nav-link:focus {\n  text-decoration: none;\n}\n\n.nav-link.disabled {\n  color: #6c757d;\n  pointer-events: none;\n  cursor: default;\n}\n\n.nav-tabs {\n  border-bottom: 1px solid #dee2e6;\n}\n\n.nav-tabs .nav-item {\n  margin-bottom: -1px;\n}\n\n.nav-tabs .nav-link {\n  border: 1px solid transparent;\n  border-top-left-radius: 0.25rem;\n  border-top-right-radius: 0.25rem;\n}\n\n.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {\n  border-color: #e9ecef #e9ecef #dee2e6;\n}\n\n.nav-tabs .nav-link.disabled {\n  color: #6c757d;\n  background-color: transparent;\n  border-color: transparent;\n}\n\n.nav-tabs .nav-link.active,\n.nav-tabs .nav-item.show .nav-link {\n  color: #495057;\n  background-color: #fff;\n  border-color: #dee2e6 #dee2e6 #fff;\n}\n\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.nav-pills .nav-link {\n  border-radius: 0.25rem;\n}\n\n.nav-pills .nav-link.active,\n.nav-pills .show > .nav-link {\n  color: #fff;\n  background-color: #007bff;\n}\n\n.nav-fill .nav-item {\n  -ms-flex: 1 1 auto;\n  flex: 1 1 auto;\n  text-align: center;\n}\n\n.nav-justified .nav-item {\n  -ms-flex-preferred-size: 0;\n  flex-basis: 0;\n  -ms-flex-positive: 1;\n  flex-grow: 1;\n  text-align: center;\n}\n\n.tab-content > .tab-pane {\n  display: none;\n}\n\n.tab-content > .active {\n  display: block;\n}\n\n.navbar {\n  position: relative;\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  -ms-flex-align: center;\n  align-items: center;\n  -ms-flex-pack: justify;\n  justify-content: space-between;\n  padding: 0.5rem 1rem;\n}\n\n.navbar > .container,\n.navbar > .container-fluid {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  -ms-flex-align: center;\n  align-items: center;\n  -ms-flex-pack: justify;\n  justify-content: space-between;\n}\n\n.navbar-brand {\n  display: inline-block;\n  padding-top: 0.3125rem;\n  padding-bottom: 0.3125rem;\n  margin-right: 1rem;\n  font-size: 1.25rem;\n  line-height: inherit;\n  white-space: nowrap;\n}\n\n.navbar-brand:hover, .navbar-brand:focus {\n  text-decoration: none;\n}\n\n.navbar-nav {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-direction: column;\n  flex-direction: column;\n  padding-left: 0;\n  margin-bottom: 0;\n  list-style: none;\n}\n\n.navbar-nav .nav-link {\n  padding-right: 0;\n  padding-left: 0;\n}\n\n.navbar-nav .dropdown-menu {\n  position: static;\n  float: none;\n}\n\n.navbar-text {\n  display: inline-block;\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n}\n\n.navbar-collapse {\n  -ms-flex-preferred-size: 100%;\n  flex-basis: 100%;\n  -ms-flex-positive: 1;\n  flex-grow: 1;\n  -ms-flex-align: center;\n  align-items: center;\n}\n\n.navbar-toggler {\n  padding: 0.25rem 0.75rem;\n  font-size: 1.25rem;\n  line-height: 1;\n  background-color: transparent;\n  border: 1px solid transparent;\n  border-radius: 0.25rem;\n}\n\n.navbar-toggler:hover, .navbar-toggler:focus {\n  text-decoration: none;\n}\n\n.navbar-toggler-icon {\n  display: inline-block;\n  width: 1.5em;\n  height: 1.5em;\n  vertical-align: middle;\n  content: \"\";\n  background: no-repeat center center;\n  background-size: 100% 100%;\n}\n\n@media (max-width: 575.98px) {\n  .navbar-expand-sm > .container,\n  .navbar-expand-sm > .container-fluid {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n\n@media (min-width: 576px) {\n  .navbar-expand-sm {\n    -ms-flex-flow: row nowrap;\n    flex-flow: row nowrap;\n    -ms-flex-pack: start;\n    justify-content: flex-start;\n  }\n  .navbar-expand-sm .navbar-nav {\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .navbar-expand-sm .navbar-nav .dropdown-menu {\n    position: absolute;\n  }\n  .navbar-expand-sm .navbar-nav .nav-link {\n    padding-right: 0.5rem;\n    padding-left: 0.5rem;\n  }\n  .navbar-expand-sm > .container,\n  .navbar-expand-sm > .container-fluid {\n    -ms-flex-wrap: nowrap;\n    flex-wrap: nowrap;\n  }\n  .navbar-expand-sm .navbar-collapse {\n    display: -ms-flexbox !important;\n    display: flex !important;\n    -ms-flex-preferred-size: auto;\n    flex-basis: auto;\n  }\n  .navbar-expand-sm .navbar-toggler {\n    display: none;\n  }\n}\n\n@media (max-width: 767.98px) {\n  .navbar-expand-md > .container,\n  .navbar-expand-md > .container-fluid {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n\n@media (min-width: 768px) {\n  .navbar-expand-md {\n    -ms-flex-flow: row nowrap;\n    flex-flow: row nowrap;\n    -ms-flex-pack: start;\n    justify-content: flex-start;\n  }\n  .navbar-expand-md .navbar-nav {\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .navbar-expand-md .navbar-nav .dropdown-menu {\n    position: absolute;\n  }\n  .navbar-expand-md .navbar-nav .nav-link {\n    padding-right: 0.5rem;\n    padding-left: 0.5rem;\n  }\n  .navbar-expand-md > .container,\n  .navbar-expand-md > .container-fluid {\n    -ms-flex-wrap: nowrap;\n    flex-wrap: nowrap;\n  }\n  .navbar-expand-md .navbar-collapse {\n    display: -ms-flexbox !important;\n    display: flex !important;\n    -ms-flex-preferred-size: auto;\n    flex-basis: auto;\n  }\n  .navbar-expand-md .navbar-toggler {\n    display: none;\n  }\n}\n\n@media (max-width: 991.98px) {\n  .navbar-expand-lg > .container,\n  .navbar-expand-lg > .container-fluid {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n\n@media (min-width: 992px) {\n  .navbar-expand-lg {\n    -ms-flex-flow: row nowrap;\n    flex-flow: row nowrap;\n    -ms-flex-pack: start;\n    justify-content: flex-start;\n  }\n  .navbar-expand-lg .navbar-nav {\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .navbar-expand-lg .navbar-nav .dropdown-menu {\n    position: absolute;\n  }\n  .navbar-expand-lg .navbar-nav .nav-link {\n    padding-right: 0.5rem;\n    padding-left: 0.5rem;\n  }\n  .navbar-expand-lg > .container,\n  .navbar-expand-lg > .container-fluid {\n    -ms-flex-wrap: nowrap;\n    flex-wrap: nowrap;\n  }\n  .navbar-expand-lg .navbar-collapse {\n    display: -ms-flexbox !important;\n    display: flex !important;\n    -ms-flex-preferred-size: auto;\n    flex-basis: auto;\n  }\n  .navbar-expand-lg .navbar-toggler {\n    display: none;\n  }\n}\n\n@media (max-width: 1199.98px) {\n  .navbar-expand-xl > .container,\n  .navbar-expand-xl > .container-fluid {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n\n@media (min-width: 1200px) {\n  .navbar-expand-xl {\n    -ms-flex-flow: row nowrap;\n    flex-flow: row nowrap;\n    -ms-flex-pack: start;\n    justify-content: flex-start;\n  }\n  .navbar-expand-xl .navbar-nav {\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .navbar-expand-xl .navbar-nav .dropdown-menu {\n    position: absolute;\n  }\n  .navbar-expand-xl .navbar-nav .nav-link {\n    padding-right: 0.5rem;\n    padding-left: 0.5rem;\n  }\n  .navbar-expand-xl > .container,\n  .navbar-expand-xl > .container-fluid {\n    -ms-flex-wrap: nowrap;\n    flex-wrap: nowrap;\n  }\n  .navbar-expand-xl .navbar-collapse {\n    display: -ms-flexbox !important;\n    display: flex !important;\n    -ms-flex-preferred-size: auto;\n    flex-basis: auto;\n  }\n  .navbar-expand-xl .navbar-toggler {\n    display: none;\n  }\n}\n\n.navbar-expand {\n  -ms-flex-flow: row nowrap;\n  flex-flow: row nowrap;\n  -ms-flex-pack: start;\n  justify-content: flex-start;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n  padding-right: 0;\n  padding-left: 0;\n}\n\n.navbar-expand .navbar-nav {\n  -ms-flex-direction: row;\n  flex-direction: row;\n}\n\n.navbar-expand .navbar-nav .dropdown-menu {\n  position: absolute;\n}\n\n.navbar-expand .navbar-nav .nav-link {\n  padding-right: 0.5rem;\n  padding-left: 0.5rem;\n}\n\n.navbar-expand > .container,\n.navbar-expand > .container-fluid {\n  -ms-flex-wrap: nowrap;\n  flex-wrap: nowrap;\n}\n\n.navbar-expand .navbar-collapse {\n  display: -ms-flexbox !important;\n  display: flex !important;\n  -ms-flex-preferred-size: auto;\n  flex-basis: auto;\n}\n\n.navbar-expand .navbar-toggler {\n  display: none;\n}\n\n.navbar-light .navbar-brand {\n  color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {\n  color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-nav .nav-link {\n  color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {\n  color: rgba(0, 0, 0, 0.7);\n}\n\n.navbar-light .navbar-nav .nav-link.disabled {\n  color: rgba(0, 0, 0, 0.3);\n}\n\n.navbar-light .navbar-nav .show > .nav-link,\n.navbar-light .navbar-nav .active > .nav-link,\n.navbar-light .navbar-nav .nav-link.show,\n.navbar-light .navbar-nav .nav-link.active {\n  color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-toggler {\n  color: rgba(0, 0, 0, 0.5);\n  border-color: rgba(0, 0, 0, 0.1);\n}\n\n.navbar-light .navbar-toggler-icon {\n  background-image: url(\"data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n.navbar-light .navbar-text {\n  color: rgba(0, 0, 0, 0.5);\n}\n\n.navbar-light .navbar-text a {\n  color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus {\n  color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-dark .navbar-brand {\n  color: #fff;\n}\n\n.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {\n  color: #fff;\n}\n\n.navbar-dark .navbar-nav .nav-link {\n  color: rgba(255, 255, 255, 0.5);\n}\n\n.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {\n  color: rgba(255, 255, 255, 0.75);\n}\n\n.navbar-dark .navbar-nav .nav-link.disabled {\n  color: rgba(255, 255, 255, 0.25);\n}\n\n.navbar-dark .navbar-nav .show > .nav-link,\n.navbar-dark .navbar-nav .active > .nav-link,\n.navbar-dark .navbar-nav .nav-link.show,\n.navbar-dark .navbar-nav .nav-link.active {\n  color: #fff;\n}\n\n.navbar-dark .navbar-toggler {\n  color: rgba(255, 255, 255, 0.5);\n  border-color: rgba(255, 255, 255, 0.1);\n}\n\n.navbar-dark .navbar-toggler-icon {\n  background-image: url(\"data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n\n.navbar-dark .navbar-text {\n  color: rgba(255, 255, 255, 0.5);\n}\n\n.navbar-dark .navbar-text a {\n  color: #fff;\n}\n\n.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus {\n  color: #fff;\n}\n\n.card {\n  position: relative;\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-direction: column;\n  flex-direction: column;\n  min-width: 0;\n  word-wrap: break-word;\n  background-color: #fff;\n  background-clip: border-box;\n  border: 1px solid rgba(0, 0, 0, 0.125);\n  border-radius: 0.25rem;\n}\n\n.card > hr {\n  margin-right: 0;\n  margin-left: 0;\n}\n\n.card > .list-group:first-child .list-group-item:first-child {\n  border-top-left-radius: 0.25rem;\n  border-top-right-radius: 0.25rem;\n}\n\n.card > .list-group:last-child .list-group-item:last-child {\n  border-bottom-right-radius: 0.25rem;\n  border-bottom-left-radius: 0.25rem;\n}\n\n.card-body {\n  -ms-flex: 1 1 auto;\n  flex: 1 1 auto;\n  padding: 1.25rem;\n}\n\n.card-title {\n  margin-bottom: 0.75rem;\n}\n\n.card-subtitle {\n  margin-top: -0.375rem;\n  margin-bottom: 0;\n}\n\n.card-text:last-child {\n  margin-bottom: 0;\n}\n\n.card-link:hover {\n  text-decoration: none;\n}\n\n.card-link + .card-link {\n  margin-left: 1.25rem;\n}\n\n.card-header {\n  padding: 0.75rem 1.25rem;\n  margin-bottom: 0;\n  background-color: rgba(0, 0, 0, 0.03);\n  border-bottom: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-header:first-child {\n  border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;\n}\n\n.card-header + .list-group .list-group-item:first-child {\n  border-top: 0;\n}\n\n.card-footer {\n  padding: 0.75rem 1.25rem;\n  background-color: rgba(0, 0, 0, 0.03);\n  border-top: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.card-footer:last-child {\n  border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);\n}\n\n.card-header-tabs {\n  margin-right: -0.625rem;\n  margin-bottom: -0.75rem;\n  margin-left: -0.625rem;\n  border-bottom: 0;\n}\n\n.card-header-pills {\n  margin-right: -0.625rem;\n  margin-left: -0.625rem;\n}\n\n.card-img-overlay {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  padding: 1.25rem;\n}\n\n.card-img {\n  width: 100%;\n  border-radius: calc(0.25rem - 1px);\n}\n\n.card-img-top {\n  width: 100%;\n  border-top-left-radius: calc(0.25rem - 1px);\n  border-top-right-radius: calc(0.25rem - 1px);\n}\n\n.card-img-bottom {\n  width: 100%;\n  border-bottom-right-radius: calc(0.25rem - 1px);\n  border-bottom-left-radius: calc(0.25rem - 1px);\n}\n\n.card-deck {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-direction: column;\n  flex-direction: column;\n}\n\n.card-deck .card {\n  margin-bottom: 15px;\n}\n\n@media (min-width: 576px) {\n  .card-deck {\n    -ms-flex-flow: row wrap;\n    flex-flow: row wrap;\n    margin-right: -15px;\n    margin-left: -15px;\n  }\n  .card-deck .card {\n    display: -ms-flexbox;\n    display: flex;\n    -ms-flex: 1 0 0%;\n    flex: 1 0 0%;\n    -ms-flex-direction: column;\n    flex-direction: column;\n    margin-right: 15px;\n    margin-bottom: 0;\n    margin-left: 15px;\n  }\n}\n\n.card-group {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-direction: column;\n  flex-direction: column;\n}\n\n.card-group > .card {\n  margin-bottom: 15px;\n}\n\n@media (min-width: 576px) {\n  .card-group {\n    -ms-flex-flow: row wrap;\n    flex-flow: row wrap;\n  }\n  .card-group > .card {\n    -ms-flex: 1 0 0%;\n    flex: 1 0 0%;\n    margin-bottom: 0;\n  }\n  .card-group > .card + .card {\n    margin-left: 0;\n    border-left: 0;\n  }\n  .card-group > .card:not(:last-child) {\n    border-top-right-radius: 0;\n    border-bottom-right-radius: 0;\n  }\n  .card-group > .card:not(:last-child) .card-img-top,\n  .card-group > .card:not(:last-child) .card-header {\n    border-top-right-radius: 0;\n  }\n  .card-group > .card:not(:last-child) .card-img-bottom,\n  .card-group > .card:not(:last-child) .card-footer {\n    border-bottom-right-radius: 0;\n  }\n  .card-group > .card:not(:first-child) {\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n  .card-group > .card:not(:first-child) .card-img-top,\n  .card-group > .card:not(:first-child) .card-header {\n    border-top-left-radius: 0;\n  }\n  .card-group > .card:not(:first-child) .card-img-bottom,\n  .card-group > .card:not(:first-child) .card-footer {\n    border-bottom-left-radius: 0;\n  }\n}\n\n.card-columns .card {\n  margin-bottom: 0.75rem;\n}\n\n@media (min-width: 576px) {\n  .card-columns {\n    -webkit-column-count: 3;\n    -moz-column-count: 3;\n    column-count: 3;\n    -webkit-column-gap: 1.25rem;\n    -moz-column-gap: 1.25rem;\n    column-gap: 1.25rem;\n    orphans: 1;\n    widows: 1;\n  }\n  .card-columns .card {\n    display: inline-block;\n    width: 100%;\n  }\n}\n\n.accordion > .card {\n  overflow: hidden;\n}\n\n.accordion > .card:not(:first-of-type) .card-header:first-child {\n  border-radius: 0;\n}\n\n.accordion > .card:not(:first-of-type):not(:last-of-type) {\n  border-bottom: 0;\n  border-radius: 0;\n}\n\n.accordion > .card:first-of-type {\n  border-bottom: 0;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.accordion > .card:last-of-type {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.accordion > .card .card-header {\n  margin-bottom: -1px;\n}\n\n.breadcrumb {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-wrap: wrap;\n  flex-wrap: wrap;\n  padding: 0.75rem 1rem;\n  margin-bottom: 1rem;\n  list-style: none;\n  background-color: #e9ecef;\n  border-radius: 0.25rem;\n}\n\n.breadcrumb-item + .breadcrumb-item {\n  padding-left: 0.5rem;\n}\n\n.breadcrumb-item + .breadcrumb-item::before {\n  display: inline-block;\n  padding-right: 0.5rem;\n  color: #6c757d;\n  content: \"/\";\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n  text-decoration: underline;\n}\n\n.breadcrumb-item + .breadcrumb-item:hover::before {\n  text-decoration: none;\n}\n\n.breadcrumb-item.active {\n  color: #6c757d;\n}\n\n.pagination {\n  display: -ms-flexbox;\n  display: flex;\n  padding-left: 0;\n  list-style: none;\n  border-radius: 0.25rem;\n}\n\n.page-link {\n  position: relative;\n  display: block;\n  padding: 0.5rem 0.75rem;\n  margin-left: -1px;\n  line-height: 1.25;\n  color: #007bff;\n  background-color: #fff;\n  border: 1px solid #dee2e6;\n}\n\n.page-link:hover {\n  z-index: 2;\n  color: #0056b3;\n  text-decoration: none;\n  background-color: #e9ecef;\n  border-color: #dee2e6;\n}\n\n.page-link:focus {\n  z-index: 2;\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);\n}\n\n.page-item:first-child .page-link {\n  margin-left: 0;\n  border-top-left-radius: 0.25rem;\n  border-bottom-left-radius: 0.25rem;\n}\n\n.page-item:last-child .page-link {\n  border-top-right-radius: 0.25rem;\n  border-bottom-right-radius: 0.25rem;\n}\n\n.page-item.active .page-link {\n  z-index: 1;\n  color: #fff;\n  background-color: #007bff;\n  border-color: #007bff;\n}\n\n.page-item.disabled .page-link {\n  color: #6c757d;\n  pointer-events: none;\n  cursor: auto;\n  background-color: #fff;\n  border-color: #dee2e6;\n}\n\n.pagination-lg .page-link {\n  padding: 0.75rem 1.5rem;\n  font-size: 1.25rem;\n  line-height: 1.5;\n}\n\n.pagination-lg .page-item:first-child .page-link {\n  border-top-left-radius: 0.3rem;\n  border-bottom-left-radius: 0.3rem;\n}\n\n.pagination-lg .page-item:last-child .page-link {\n  border-top-right-radius: 0.3rem;\n  border-bottom-right-radius: 0.3rem;\n}\n\n.pagination-sm .page-link {\n  padding: 0.25rem 0.5rem;\n  font-size: 0.875rem;\n  line-height: 1.5;\n}\n\n.pagination-sm .page-item:first-child .page-link {\n  border-top-left-radius: 0.2rem;\n  border-bottom-left-radius: 0.2rem;\n}\n\n.pagination-sm .page-item:last-child .page-link {\n  border-top-right-radius: 0.2rem;\n  border-bottom-right-radius: 0.2rem;\n}\n\n.badge {\n  display: inline-block;\n  padding: 0.25em 0.4em;\n  font-size: 75%;\n  font-weight: 700;\n  line-height: 1;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: 0.25rem;\n  transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .badge {\n    transition: none;\n  }\n}\n\na.badge:hover, a.badge:focus {\n  text-decoration: none;\n}\n\n.badge:empty {\n  display: none;\n}\n\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n\n.badge-pill {\n  padding-right: 0.6em;\n  padding-left: 0.6em;\n  border-radius: 10rem;\n}\n\n.badge-primary {\n  color: #fff;\n  background-color: #007bff;\n}\n\na.badge-primary:hover, a.badge-primary:focus {\n  color: #fff;\n  background-color: #0062cc;\n}\n\na.badge-primary:focus, a.badge-primary.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);\n}\n\n.badge-secondary {\n  color: #fff;\n  background-color: #6c757d;\n}\n\na.badge-secondary:hover, a.badge-secondary:focus {\n  color: #fff;\n  background-color: #545b62;\n}\n\na.badge-secondary:focus, a.badge-secondary.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);\n}\n\n.badge-success {\n  color: #fff;\n  background-color: #28a745;\n}\n\na.badge-success:hover, a.badge-success:focus {\n  color: #fff;\n  background-color: #1e7e34;\n}\n\na.badge-success:focus, a.badge-success.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);\n}\n\n.badge-info {\n  color: #fff;\n  background-color: #17a2b8;\n}\n\na.badge-info:hover, a.badge-info:focus {\n  color: #fff;\n  background-color: #117a8b;\n}\n\na.badge-info:focus, a.badge-info.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);\n}\n\n.badge-warning {\n  color: #212529;\n  background-color: #ffc107;\n}\n\na.badge-warning:hover, a.badge-warning:focus {\n  color: #212529;\n  background-color: #d39e00;\n}\n\na.badge-warning:focus, a.badge-warning.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);\n}\n\n.badge-danger {\n  color: #fff;\n  background-color: #dc3545;\n}\n\na.badge-danger:hover, a.badge-danger:focus {\n  color: #fff;\n  background-color: #bd2130;\n}\n\na.badge-danger:focus, a.badge-danger.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);\n}\n\n.badge-light {\n  color: #212529;\n  background-color: #f8f9fa;\n}\n\na.badge-light:hover, a.badge-light:focus {\n  color: #212529;\n  background-color: #dae0e5;\n}\n\na.badge-light:focus, a.badge-light.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);\n}\n\n.badge-dark {\n  color: #fff;\n  background-color: #343a40;\n}\n\na.badge-dark:hover, a.badge-dark:focus {\n  color: #fff;\n  background-color: #1d2124;\n}\n\na.badge-dark:focus, a.badge-dark.focus {\n  outline: 0;\n  box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);\n}\n\n.jumbotron {\n  padding: 2rem 1rem;\n  margin-bottom: 2rem;\n  background-color: #e9ecef;\n  border-radius: 0.3rem;\n}\n\n@media (min-width: 576px) {\n  .jumbotron {\n    padding: 4rem 2rem;\n  }\n}\n\n.jumbotron-fluid {\n  padding-right: 0;\n  padding-left: 0;\n  border-radius: 0;\n}\n\n.alert {\n  position: relative;\n  padding: 0.75rem 1.25rem;\n  margin-bottom: 1rem;\n  border: 1px solid transparent;\n  border-radius: 0.25rem;\n}\n\n.alert-heading {\n  color: inherit;\n}\n\n.alert-link {\n  font-weight: 700;\n}\n\n.alert-dismissible {\n  padding-right: 4rem;\n}\n\n.alert-dismissible .close {\n  position: absolute;\n  top: 0;\n  right: 0;\n  padding: 0.75rem 1.25rem;\n  color: inherit;\n}\n\n.alert-primary {\n  color: #004085;\n  background-color: #cce5ff;\n  border-color: #b8daff;\n}\n\n.alert-primary hr {\n  border-top-color: #9fcdff;\n}\n\n.alert-primary .alert-link {\n  color: #002752;\n}\n\n.alert-secondary {\n  color: #383d41;\n  background-color: #e2e3e5;\n  border-color: #d6d8db;\n}\n\n.alert-secondary hr {\n  border-top-color: #c8cbcf;\n}\n\n.alert-secondary .alert-link {\n  color: #202326;\n}\n\n.alert-success {\n  color: #155724;\n  background-color: #d4edda;\n  border-color: #c3e6cb;\n}\n\n.alert-success hr {\n  border-top-color: #b1dfbb;\n}\n\n.alert-success .alert-link {\n  color: #0b2e13;\n}\n\n.alert-info {\n  color: #0c5460;\n  background-color: #d1ecf1;\n  border-color: #bee5eb;\n}\n\n.alert-info hr {\n  border-top-color: #abdde5;\n}\n\n.alert-info .alert-link {\n  color: #062c33;\n}\n\n.alert-warning {\n  color: #856404;\n  background-color: #fff3cd;\n  border-color: #ffeeba;\n}\n\n.alert-warning hr {\n  border-top-color: #ffe8a1;\n}\n\n.alert-warning .alert-link {\n  color: #533f03;\n}\n\n.alert-danger {\n  color: #721c24;\n  background-color: #f8d7da;\n  border-color: #f5c6cb;\n}\n\n.alert-danger hr {\n  border-top-color: #f1b0b7;\n}\n\n.alert-danger .alert-link {\n  color: #491217;\n}\n\n.alert-light {\n  color: #818182;\n  background-color: #fefefe;\n  border-color: #fdfdfe;\n}\n\n.alert-light hr {\n  border-top-color: #ececf6;\n}\n\n.alert-light .alert-link {\n  color: #686868;\n}\n\n.alert-dark {\n  color: #1b1e21;\n  background-color: #d6d8d9;\n  border-color: #c6c8ca;\n}\n\n.alert-dark hr {\n  border-top-color: #b9bbbe;\n}\n\n.alert-dark .alert-link {\n  color: #040505;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 1rem 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 1rem 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n.progress {\n  display: -ms-flexbox;\n  display: flex;\n  height: 1rem;\n  overflow: hidden;\n  font-size: 0.75rem;\n  background-color: #e9ecef;\n  border-radius: 0.25rem;\n}\n\n.progress-bar {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-direction: column;\n  flex-direction: column;\n  -ms-flex-pack: center;\n  justify-content: center;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  background-color: #007bff;\n  transition: width 0.6s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .progress-bar {\n    transition: none;\n  }\n}\n\n.progress-bar-striped {\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-size: 1rem 1rem;\n}\n\n.progress-bar-animated {\n  -webkit-animation: progress-bar-stripes 1s linear infinite;\n  animation: progress-bar-stripes 1s linear infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .progress-bar-animated {\n    -webkit-animation: none;\n    animation: none;\n  }\n}\n\n.media {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-align: start;\n  align-items: flex-start;\n}\n\n.media-body {\n  -ms-flex: 1;\n  flex: 1;\n}\n\n.list-group {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-direction: column;\n  flex-direction: column;\n  padding-left: 0;\n  margin-bottom: 0;\n}\n\n.list-group-item-action {\n  width: 100%;\n  color: #495057;\n  text-align: inherit;\n}\n\n.list-group-item-action:hover, .list-group-item-action:focus {\n  z-index: 1;\n  color: #495057;\n  text-decoration: none;\n  background-color: #f8f9fa;\n}\n\n.list-group-item-action:active {\n  color: #212529;\n  background-color: #e9ecef;\n}\n\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 0.75rem 1.25rem;\n  margin-bottom: -1px;\n  background-color: #fff;\n  border: 1px solid rgba(0, 0, 0, 0.125);\n}\n\n.list-group-item:first-child {\n  border-top-left-radius: 0.25rem;\n  border-top-right-radius: 0.25rem;\n}\n\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 0.25rem;\n  border-bottom-left-radius: 0.25rem;\n}\n\n.list-group-item.disabled, .list-group-item:disabled {\n  color: #6c757d;\n  pointer-events: none;\n  background-color: #fff;\n}\n\n.list-group-item.active {\n  z-index: 2;\n  color: #fff;\n  background-color: #007bff;\n  border-color: #007bff;\n}\n\n.list-group-horizontal {\n  -ms-flex-direction: row;\n  flex-direction: row;\n}\n\n.list-group-horizontal .list-group-item {\n  margin-right: -1px;\n  margin-bottom: 0;\n}\n\n.list-group-horizontal .list-group-item:first-child {\n  border-top-left-radius: 0.25rem;\n  border-bottom-left-radius: 0.25rem;\n  border-top-right-radius: 0;\n}\n\n.list-group-horizontal .list-group-item:last-child {\n  margin-right: 0;\n  border-top-right-radius: 0.25rem;\n  border-bottom-right-radius: 0.25rem;\n  border-bottom-left-radius: 0;\n}\n\n@media (min-width: 576px) {\n  .list-group-horizontal-sm {\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .list-group-horizontal-sm .list-group-item {\n    margin-right: -1px;\n    margin-bottom: 0;\n  }\n  .list-group-horizontal-sm .list-group-item:first-child {\n    border-top-left-radius: 0.25rem;\n    border-bottom-left-radius: 0.25rem;\n    border-top-right-radius: 0;\n  }\n  .list-group-horizontal-sm .list-group-item:last-child {\n    margin-right: 0;\n    border-top-right-radius: 0.25rem;\n    border-bottom-right-radius: 0.25rem;\n    border-bottom-left-radius: 0;\n  }\n}\n\n@media (min-width: 768px) {\n  .list-group-horizontal-md {\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .list-group-horizontal-md .list-group-item {\n    margin-right: -1px;\n    margin-bottom: 0;\n  }\n  .list-group-horizontal-md .list-group-item:first-child {\n    border-top-left-radius: 0.25rem;\n    border-bottom-left-radius: 0.25rem;\n    border-top-right-radius: 0;\n  }\n  .list-group-horizontal-md .list-group-item:last-child {\n    margin-right: 0;\n    border-top-right-radius: 0.25rem;\n    border-bottom-right-radius: 0.25rem;\n    border-bottom-left-radius: 0;\n  }\n}\n\n@media (min-width: 992px) {\n  .list-group-horizontal-lg {\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .list-group-horizontal-lg .list-group-item {\n    margin-right: -1px;\n    margin-bottom: 0;\n  }\n  .list-group-horizontal-lg .list-group-item:first-child {\n    border-top-left-radius: 0.25rem;\n    border-bottom-left-radius: 0.25rem;\n    border-top-right-radius: 0;\n  }\n  .list-group-horizontal-lg .list-group-item:last-child {\n    margin-right: 0;\n    border-top-right-radius: 0.25rem;\n    border-bottom-right-radius: 0.25rem;\n    border-bottom-left-radius: 0;\n  }\n}\n\n@media (min-width: 1200px) {\n  .list-group-horizontal-xl {\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .list-group-horizontal-xl .list-group-item {\n    margin-right: -1px;\n    margin-bottom: 0;\n  }\n  .list-group-horizontal-xl .list-group-item:first-child {\n    border-top-left-radius: 0.25rem;\n    border-bottom-left-radius: 0.25rem;\n    border-top-right-radius: 0;\n  }\n  .list-group-horizontal-xl .list-group-item:last-child {\n    margin-right: 0;\n    border-top-right-radius: 0.25rem;\n    border-bottom-right-radius: 0.25rem;\n    border-bottom-left-radius: 0;\n  }\n}\n\n.list-group-flush .list-group-item {\n  border-right: 0;\n  border-left: 0;\n  border-radius: 0;\n}\n\n.list-group-flush .list-group-item:last-child {\n  margin-bottom: -1px;\n}\n\n.list-group-flush:first-child .list-group-item:first-child {\n  border-top: 0;\n}\n\n.list-group-flush:last-child .list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom: 0;\n}\n\n.list-group-item-primary {\n  color: #004085;\n  background-color: #b8daff;\n}\n\n.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {\n  color: #004085;\n  background-color: #9fcdff;\n}\n\n.list-group-item-primary.list-group-item-action.active {\n  color: #fff;\n  background-color: #004085;\n  border-color: #004085;\n}\n\n.list-group-item-secondary {\n  color: #383d41;\n  background-color: #d6d8db;\n}\n\n.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {\n  color: #383d41;\n  background-color: #c8cbcf;\n}\n\n.list-group-item-secondary.list-group-item-action.active {\n  color: #fff;\n  background-color: #383d41;\n  border-color: #383d41;\n}\n\n.list-group-item-success {\n  color: #155724;\n  background-color: #c3e6cb;\n}\n\n.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {\n  color: #155724;\n  background-color: #b1dfbb;\n}\n\n.list-group-item-success.list-group-item-action.active {\n  color: #fff;\n  background-color: #155724;\n  border-color: #155724;\n}\n\n.list-group-item-info {\n  color: #0c5460;\n  background-color: #bee5eb;\n}\n\n.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {\n  color: #0c5460;\n  background-color: #abdde5;\n}\n\n.list-group-item-info.list-group-item-action.active {\n  color: #fff;\n  background-color: #0c5460;\n  border-color: #0c5460;\n}\n\n.list-group-item-warning {\n  color: #856404;\n  background-color: #ffeeba;\n}\n\n.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {\n  color: #856404;\n  background-color: #ffe8a1;\n}\n\n.list-group-item-warning.list-group-item-action.active {\n  color: #fff;\n  background-color: #856404;\n  border-color: #856404;\n}\n\n.list-group-item-danger {\n  color: #721c24;\n  background-color: #f5c6cb;\n}\n\n.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {\n  color: #721c24;\n  background-color: #f1b0b7;\n}\n\n.list-group-item-danger.list-group-item-action.active {\n  color: #fff;\n  background-color: #721c24;\n  border-color: #721c24;\n}\n\n.list-group-item-light {\n  color: #818182;\n  background-color: #fdfdfe;\n}\n\n.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {\n  color: #818182;\n  background-color: #ececf6;\n}\n\n.list-group-item-light.list-group-item-action.active {\n  color: #fff;\n  background-color: #818182;\n  border-color: #818182;\n}\n\n.list-group-item-dark {\n  color: #1b1e21;\n  background-color: #c6c8ca;\n}\n\n.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {\n  color: #1b1e21;\n  background-color: #b9bbbe;\n}\n\n.list-group-item-dark.list-group-item-action.active {\n  color: #fff;\n  background-color: #1b1e21;\n  border-color: #1b1e21;\n}\n\n.close {\n  float: right;\n  font-size: 1.5rem;\n  font-weight: 700;\n  line-height: 1;\n  color: #000;\n  text-shadow: 0 1px 0 #fff;\n  opacity: .5;\n}\n\n.close:hover {\n  color: #000;\n  text-decoration: none;\n}\n\n.close:not(:disabled):not(.disabled):hover, .close:not(:disabled):not(.disabled):focus {\n  opacity: .75;\n}\n\nbutton.close {\n  padding: 0;\n  background-color: transparent;\n  border: 0;\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  appearance: none;\n}\n\na.close.disabled {\n  pointer-events: none;\n}\n\n.toast {\n  max-width: 350px;\n  overflow: hidden;\n  font-size: 0.875rem;\n  background-color: rgba(255, 255, 255, 0.85);\n  background-clip: padding-box;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n  box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);\n  -webkit-backdrop-filter: blur(10px);\n  backdrop-filter: blur(10px);\n  opacity: 0;\n  border-radius: 0.25rem;\n}\n\n.toast:not(:last-child) {\n  margin-bottom: 0.75rem;\n}\n\n.toast.showing {\n  opacity: 1;\n}\n\n.toast.show {\n  display: block;\n  opacity: 1;\n}\n\n.toast.hide {\n  display: none;\n}\n\n.toast-header {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-align: center;\n  align-items: center;\n  padding: 0.25rem 0.75rem;\n  color: #6c757d;\n  background-color: rgba(255, 255, 255, 0.85);\n  background-clip: padding-box;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n}\n\n.toast-body {\n  padding: 0.75rem;\n}\n\n.modal-open {\n  overflow: hidden;\n}\n\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n\n.modal {\n  position: fixed;\n  top: 0;\n  left: 0;\n  z-index: 1050;\n  display: none;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n  outline: 0;\n}\n\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 0.5rem;\n  pointer-events: none;\n}\n\n.modal.fade .modal-dialog {\n  transition: -webkit-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n  transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out;\n  -webkit-transform: translate(0, -50px);\n  transform: translate(0, -50px);\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .modal.fade .modal-dialog {\n    transition: none;\n  }\n}\n\n.modal.show .modal-dialog {\n  -webkit-transform: none;\n  transform: none;\n}\n\n.modal-dialog-scrollable {\n  display: -ms-flexbox;\n  display: flex;\n  max-height: calc(100% - 1rem);\n}\n\n.modal-dialog-scrollable .modal-content {\n  max-height: calc(100vh - 1rem);\n  overflow: hidden;\n}\n\n.modal-dialog-scrollable .modal-header,\n.modal-dialog-scrollable .modal-footer {\n  -ms-flex-negative: 0;\n  flex-shrink: 0;\n}\n\n.modal-dialog-scrollable .modal-body {\n  overflow-y: auto;\n}\n\n.modal-dialog-centered {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-align: center;\n  align-items: center;\n  min-height: calc(100% - 1rem);\n}\n\n.modal-dialog-centered::before {\n  display: block;\n  height: calc(100vh - 1rem);\n  content: \"\";\n}\n\n.modal-dialog-centered.modal-dialog-scrollable {\n  -ms-flex-direction: column;\n  flex-direction: column;\n  -ms-flex-pack: center;\n  justify-content: center;\n  height: 100%;\n}\n\n.modal-dialog-centered.modal-dialog-scrollable .modal-content {\n  max-height: none;\n}\n\n.modal-dialog-centered.modal-dialog-scrollable::before {\n  content: none;\n}\n\n.modal-content {\n  position: relative;\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-direction: column;\n  flex-direction: column;\n  width: 100%;\n  pointer-events: auto;\n  background-color: #fff;\n  background-clip: padding-box;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 0.3rem;\n  outline: 0;\n}\n\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  left: 0;\n  z-index: 1040;\n  width: 100vw;\n  height: 100vh;\n  background-color: #000;\n}\n\n.modal-backdrop.fade {\n  opacity: 0;\n}\n\n.modal-backdrop.show {\n  opacity: 0.5;\n}\n\n.modal-header {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-align: start;\n  align-items: flex-start;\n  -ms-flex-pack: justify;\n  justify-content: space-between;\n  padding: 1rem 1rem;\n  border-bottom: 1px solid #dee2e6;\n  border-top-left-radius: 0.3rem;\n  border-top-right-radius: 0.3rem;\n}\n\n.modal-header .close {\n  padding: 1rem 1rem;\n  margin: -1rem -1rem -1rem auto;\n}\n\n.modal-title {\n  margin-bottom: 0;\n  line-height: 1.5;\n}\n\n.modal-body {\n  position: relative;\n  -ms-flex: 1 1 auto;\n  flex: 1 1 auto;\n  padding: 1rem;\n}\n\n.modal-footer {\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-align: center;\n  align-items: center;\n  -ms-flex-pack: end;\n  justify-content: flex-end;\n  padding: 1rem;\n  border-top: 1px solid #dee2e6;\n  border-bottom-right-radius: 0.3rem;\n  border-bottom-left-radius: 0.3rem;\n}\n\n.modal-footer > :not(:first-child) {\n  margin-left: .25rem;\n}\n\n.modal-footer > :not(:last-child) {\n  margin-right: .25rem;\n}\n\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n\n@media (min-width: 576px) {\n  .modal-dialog {\n    max-width: 500px;\n    margin: 1.75rem auto;\n  }\n  .modal-dialog-scrollable {\n    max-height: calc(100% - 3.5rem);\n  }\n  .modal-dialog-scrollable .modal-content {\n    max-height: calc(100vh - 3.5rem);\n  }\n  .modal-dialog-centered {\n    min-height: calc(100% - 3.5rem);\n  }\n  .modal-dialog-centered::before {\n    height: calc(100vh - 3.5rem);\n  }\n  .modal-sm {\n    max-width: 300px;\n  }\n}\n\n@media (min-width: 992px) {\n  .modal-lg,\n  .modal-xl {\n    max-width: 800px;\n  }\n}\n\n@media (min-width: 1200px) {\n  .modal-xl {\n    max-width: 1140px;\n  }\n}\n\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n  font-style: normal;\n  font-weight: 400;\n  line-height: 1.5;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  white-space: normal;\n  line-break: auto;\n  font-size: 0.875rem;\n  word-wrap: break-word;\n  opacity: 0;\n}\n\n.tooltip.show {\n  opacity: 0.9;\n}\n\n.tooltip .arrow {\n  position: absolute;\n  display: block;\n  width: 0.8rem;\n  height: 0.4rem;\n}\n\n.tooltip .arrow::before {\n  position: absolute;\n  content: \"\";\n  border-color: transparent;\n  border-style: solid;\n}\n\n.bs-tooltip-top, .bs-tooltip-auto[x-placement^=\"top\"] {\n  padding: 0.4rem 0;\n}\n\n.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^=\"top\"] .arrow {\n  bottom: 0;\n}\n\n.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^=\"top\"] .arrow::before {\n  top: 0;\n  border-width: 0.4rem 0.4rem 0;\n  border-top-color: #000;\n}\n\n.bs-tooltip-right, .bs-tooltip-auto[x-placement^=\"right\"] {\n  padding: 0 0.4rem;\n}\n\n.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^=\"right\"] .arrow {\n  left: 0;\n  width: 0.4rem;\n  height: 0.8rem;\n}\n\n.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^=\"right\"] .arrow::before {\n  right: 0;\n  border-width: 0.4rem 0.4rem 0.4rem 0;\n  border-right-color: #000;\n}\n\n.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^=\"bottom\"] {\n  padding: 0.4rem 0;\n}\n\n.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^=\"bottom\"] .arrow {\n  top: 0;\n}\n\n.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^=\"bottom\"] .arrow::before {\n  bottom: 0;\n  border-width: 0 0.4rem 0.4rem;\n  border-bottom-color: #000;\n}\n\n.bs-tooltip-left, .bs-tooltip-auto[x-placement^=\"left\"] {\n  padding: 0 0.4rem;\n}\n\n.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^=\"left\"] .arrow {\n  right: 0;\n  width: 0.4rem;\n  height: 0.8rem;\n}\n\n.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^=\"left\"] .arrow::before {\n  left: 0;\n  border-width: 0.4rem 0 0.4rem 0.4rem;\n  border-left-color: #000;\n}\n\n.tooltip-inner {\n  max-width: 200px;\n  padding: 0.25rem 0.5rem;\n  color: #fff;\n  text-align: center;\n  background-color: #000;\n  border-radius: 0.25rem;\n}\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: block;\n  max-width: 276px;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n  font-style: normal;\n  font-weight: 400;\n  line-height: 1.5;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  white-space: normal;\n  line-break: auto;\n  font-size: 0.875rem;\n  word-wrap: break-word;\n  background-color: #fff;\n  background-clip: padding-box;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 0.3rem;\n}\n\n.popover .arrow {\n  position: absolute;\n  display: block;\n  width: 1rem;\n  height: 0.5rem;\n  margin: 0 0.3rem;\n}\n\n.popover .arrow::before, .popover .arrow::after {\n  position: absolute;\n  display: block;\n  content: \"\";\n  border-color: transparent;\n  border-style: solid;\n}\n\n.bs-popover-top, .bs-popover-auto[x-placement^=\"top\"] {\n  margin-bottom: 0.5rem;\n}\n\n.bs-popover-top > .arrow, .bs-popover-auto[x-placement^=\"top\"] > .arrow {\n  bottom: calc((0.5rem + 1px) * -1);\n}\n\n.bs-popover-top > .arrow::before, .bs-popover-auto[x-placement^=\"top\"] > .arrow::before {\n  bottom: 0;\n  border-width: 0.5rem 0.5rem 0;\n  border-top-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-top > .arrow::after, .bs-popover-auto[x-placement^=\"top\"] > .arrow::after {\n  bottom: 1px;\n  border-width: 0.5rem 0.5rem 0;\n  border-top-color: #fff;\n}\n\n.bs-popover-right, .bs-popover-auto[x-placement^=\"right\"] {\n  margin-left: 0.5rem;\n}\n\n.bs-popover-right > .arrow, .bs-popover-auto[x-placement^=\"right\"] > .arrow {\n  left: calc((0.5rem + 1px) * -1);\n  width: 0.5rem;\n  height: 1rem;\n  margin: 0.3rem 0;\n}\n\n.bs-popover-right > .arrow::before, .bs-popover-auto[x-placement^=\"right\"] > .arrow::before {\n  left: 0;\n  border-width: 0.5rem 0.5rem 0.5rem 0;\n  border-right-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-right > .arrow::after, .bs-popover-auto[x-placement^=\"right\"] > .arrow::after {\n  left: 1px;\n  border-width: 0.5rem 0.5rem 0.5rem 0;\n  border-right-color: #fff;\n}\n\n.bs-popover-bottom, .bs-popover-auto[x-placement^=\"bottom\"] {\n  margin-top: 0.5rem;\n}\n\n.bs-popover-bottom > .arrow, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow {\n  top: calc((0.5rem + 1px) * -1);\n}\n\n.bs-popover-bottom > .arrow::before, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow::before {\n  top: 0;\n  border-width: 0 0.5rem 0.5rem 0.5rem;\n  border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-bottom > .arrow::after, .bs-popover-auto[x-placement^=\"bottom\"] > .arrow::after {\n  top: 1px;\n  border-width: 0 0.5rem 0.5rem 0.5rem;\n  border-bottom-color: #fff;\n}\n\n.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^=\"bottom\"] .popover-header::before {\n  position: absolute;\n  top: 0;\n  left: 50%;\n  display: block;\n  width: 1rem;\n  margin-left: -0.5rem;\n  content: \"\";\n  border-bottom: 1px solid #f7f7f7;\n}\n\n.bs-popover-left, .bs-popover-auto[x-placement^=\"left\"] {\n  margin-right: 0.5rem;\n}\n\n.bs-popover-left > .arrow, .bs-popover-auto[x-placement^=\"left\"] > .arrow {\n  right: calc((0.5rem + 1px) * -1);\n  width: 0.5rem;\n  height: 1rem;\n  margin: 0.3rem 0;\n}\n\n.bs-popover-left > .arrow::before, .bs-popover-auto[x-placement^=\"left\"] > .arrow::before {\n  right: 0;\n  border-width: 0.5rem 0 0.5rem 0.5rem;\n  border-left-color: rgba(0, 0, 0, 0.25);\n}\n\n.bs-popover-left > .arrow::after, .bs-popover-auto[x-placement^=\"left\"] > .arrow::after {\n  right: 1px;\n  border-width: 0.5rem 0 0.5rem 0.5rem;\n  border-left-color: #fff;\n}\n\n.popover-header {\n  padding: 0.5rem 0.75rem;\n  margin-bottom: 0;\n  font-size: 1rem;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-top-left-radius: calc(0.3rem - 1px);\n  border-top-right-radius: calc(0.3rem - 1px);\n}\n\n.popover-header:empty {\n  display: none;\n}\n\n.popover-body {\n  padding: 0.5rem 0.75rem;\n  color: #212529;\n}\n\n.carousel {\n  position: relative;\n}\n\n.carousel.pointer-event {\n  -ms-touch-action: pan-y;\n  touch-action: pan-y;\n}\n\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n\n.carousel-inner::after {\n  display: block;\n  clear: both;\n  content: \"\";\n}\n\n.carousel-item {\n  position: relative;\n  display: none;\n  float: left;\n  width: 100%;\n  margin-right: -100%;\n  -webkit-backface-visibility: hidden;\n  backface-visibility: hidden;\n  transition: -webkit-transform 0.6s ease-in-out;\n  transition: transform 0.6s ease-in-out;\n  transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .carousel-item {\n    transition: none;\n  }\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n  display: block;\n}\n\n.carousel-item-next:not(.carousel-item-left),\n.active.carousel-item-right {\n  -webkit-transform: translateX(100%);\n  transform: translateX(100%);\n}\n\n.carousel-item-prev:not(.carousel-item-right),\n.active.carousel-item-left {\n  -webkit-transform: translateX(-100%);\n  transform: translateX(-100%);\n}\n\n.carousel-fade .carousel-item {\n  opacity: 0;\n  transition-property: opacity;\n  -webkit-transform: none;\n  transform: none;\n}\n\n.carousel-fade .carousel-item.active,\n.carousel-fade .carousel-item-next.carousel-item-left,\n.carousel-fade .carousel-item-prev.carousel-item-right {\n  z-index: 1;\n  opacity: 1;\n}\n\n.carousel-fade .active.carousel-item-left,\n.carousel-fade .active.carousel-item-right {\n  z-index: 0;\n  opacity: 0;\n  transition: 0s 0.6s opacity;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .carousel-fade .active.carousel-item-left,\n  .carousel-fade .active.carousel-item-right {\n    transition: none;\n  }\n}\n\n.carousel-control-prev,\n.carousel-control-next {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  z-index: 1;\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-align: center;\n  align-items: center;\n  -ms-flex-pack: center;\n  justify-content: center;\n  width: 15%;\n  color: #fff;\n  text-align: center;\n  opacity: 0.5;\n  transition: opacity 0.15s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .carousel-control-prev,\n  .carousel-control-next {\n    transition: none;\n  }\n}\n\n.carousel-control-prev:hover, .carousel-control-prev:focus,\n.carousel-control-next:hover,\n.carousel-control-next:focus {\n  color: #fff;\n  text-decoration: none;\n  outline: 0;\n  opacity: 0.9;\n}\n\n.carousel-control-prev {\n  left: 0;\n}\n\n.carousel-control-next {\n  right: 0;\n}\n\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n  display: inline-block;\n  width: 20px;\n  height: 20px;\n  background: no-repeat 50% / 100% 100%;\n}\n\n.carousel-control-prev-icon {\n  background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e\");\n}\n\n.carousel-control-next-icon {\n  background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e\");\n}\n\n.carousel-indicators {\n  position: absolute;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 15;\n  display: -ms-flexbox;\n  display: flex;\n  -ms-flex-pack: center;\n  justify-content: center;\n  padding-left: 0;\n  margin-right: 15%;\n  margin-left: 15%;\n  list-style: none;\n}\n\n.carousel-indicators li {\n  box-sizing: content-box;\n  -ms-flex: 0 1 auto;\n  flex: 0 1 auto;\n  width: 30px;\n  height: 3px;\n  margin-right: 3px;\n  margin-left: 3px;\n  text-indent: -999px;\n  cursor: pointer;\n  background-color: #fff;\n  background-clip: padding-box;\n  border-top: 10px solid transparent;\n  border-bottom: 10px solid transparent;\n  opacity: .5;\n  transition: opacity 0.6s ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .carousel-indicators li {\n    transition: none;\n  }\n}\n\n.carousel-indicators .active {\n  opacity: 1;\n}\n\n.carousel-caption {\n  position: absolute;\n  right: 15%;\n  bottom: 20px;\n  left: 15%;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #fff;\n  text-align: center;\n}\n\n@-webkit-keyframes spinner-border {\n  to {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes spinner-border {\n  to {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n\n.spinner-border {\n  display: inline-block;\n  width: 2rem;\n  height: 2rem;\n  vertical-align: text-bottom;\n  border: 0.25em solid currentColor;\n  border-right-color: transparent;\n  border-radius: 50%;\n  -webkit-animation: spinner-border .75s linear infinite;\n  animation: spinner-border .75s linear infinite;\n}\n\n.spinner-border-sm {\n  width: 1rem;\n  height: 1rem;\n  border-width: 0.2em;\n}\n\n@-webkit-keyframes spinner-grow {\n  0% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  50% {\n    opacity: 1;\n  }\n}\n\n@keyframes spinner-grow {\n  0% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  50% {\n    opacity: 1;\n  }\n}\n\n.spinner-grow {\n  display: inline-block;\n  width: 2rem;\n  height: 2rem;\n  vertical-align: text-bottom;\n  background-color: currentColor;\n  border-radius: 50%;\n  opacity: 0;\n  -webkit-animation: spinner-grow .75s linear infinite;\n  animation: spinner-grow .75s linear infinite;\n}\n\n.spinner-grow-sm {\n  width: 1rem;\n  height: 1rem;\n}\n\n.align-baseline {\n  vertical-align: baseline !important;\n}\n\n.align-top {\n  vertical-align: top !important;\n}\n\n.align-middle {\n  vertical-align: middle !important;\n}\n\n.align-bottom {\n  vertical-align: bottom !important;\n}\n\n.align-text-bottom {\n  vertical-align: text-bottom !important;\n}\n\n.align-text-top {\n  vertical-align: text-top !important;\n}\n\n.bg-primary {\n  background-color: #007bff !important;\n}\n\na.bg-primary:hover, a.bg-primary:focus,\nbutton.bg-primary:hover,\nbutton.bg-primary:focus {\n  background-color: #0062cc !important;\n}\n\n.bg-secondary {\n  background-color: #6c757d !important;\n}\n\na.bg-secondary:hover, a.bg-secondary:focus,\nbutton.bg-secondary:hover,\nbutton.bg-secondary:focus {\n  background-color: #545b62 !important;\n}\n\n.bg-success {\n  background-color: #28a745 !important;\n}\n\na.bg-success:hover, a.bg-success:focus,\nbutton.bg-success:hover,\nbutton.bg-success:focus {\n  background-color: #1e7e34 !important;\n}\n\n.bg-info {\n  background-color: #17a2b8 !important;\n}\n\na.bg-info:hover, a.bg-info:focus,\nbutton.bg-info:hover,\nbutton.bg-info:focus {\n  background-color: #117a8b !important;\n}\n\n.bg-warning {\n  background-color: #ffc107 !important;\n}\n\na.bg-warning:hover, a.bg-warning:focus,\nbutton.bg-warning:hover,\nbutton.bg-warning:focus {\n  background-color: #d39e00 !important;\n}\n\n.bg-danger {\n  background-color: #dc3545 !important;\n}\n\na.bg-danger:hover, a.bg-danger:focus,\nbutton.bg-danger:hover,\nbutton.bg-danger:focus {\n  background-color: #bd2130 !important;\n}\n\n.bg-light {\n  background-color: #f8f9fa !important;\n}\n\na.bg-light:hover, a.bg-light:focus,\nbutton.bg-light:hover,\nbutton.bg-light:focus {\n  background-color: #dae0e5 !important;\n}\n\n.bg-dark {\n  background-color: #343a40 !important;\n}\n\na.bg-dark:hover, a.bg-dark:focus,\nbutton.bg-dark:hover,\nbutton.bg-dark:focus {\n  background-color: #1d2124 !important;\n}\n\n.bg-white {\n  background-color: #fff !important;\n}\n\n.bg-transparent {\n  background-color: transparent !important;\n}\n\n.border {\n  border: 1px solid #dee2e6 !important;\n}\n\n.border-top {\n  border-top: 1px solid #dee2e6 !important;\n}\n\n.border-right {\n  border-right: 1px solid #dee2e6 !important;\n}\n\n.border-bottom {\n  border-bottom: 1px solid #dee2e6 !important;\n}\n\n.border-left {\n  border-left: 1px solid #dee2e6 !important;\n}\n\n.border-0 {\n  border: 0 !important;\n}\n\n.border-top-0 {\n  border-top: 0 !important;\n}\n\n.border-right-0 {\n  border-right: 0 !important;\n}\n\n.border-bottom-0 {\n  border-bottom: 0 !important;\n}\n\n.border-left-0 {\n  border-left: 0 !important;\n}\n\n.border-primary {\n  border-color: #007bff !important;\n}\n\n.border-secondary {\n  border-color: #6c757d !important;\n}\n\n.border-success {\n  border-color: #28a745 !important;\n}\n\n.border-info {\n  border-color: #17a2b8 !important;\n}\n\n.border-warning {\n  border-color: #ffc107 !important;\n}\n\n.border-danger {\n  border-color: #dc3545 !important;\n}\n\n.border-light {\n  border-color: #f8f9fa !important;\n}\n\n.border-dark {\n  border-color: #343a40 !important;\n}\n\n.border-white {\n  border-color: #fff !important;\n}\n\n.rounded-sm {\n  border-radius: 0.2rem !important;\n}\n\n.rounded {\n  border-radius: 0.25rem !important;\n}\n\n.rounded-top {\n  border-top-left-radius: 0.25rem !important;\n  border-top-right-radius: 0.25rem !important;\n}\n\n.rounded-right {\n  border-top-right-radius: 0.25rem !important;\n  border-bottom-right-radius: 0.25rem !important;\n}\n\n.rounded-bottom {\n  border-bottom-right-radius: 0.25rem !important;\n  border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-left {\n  border-top-left-radius: 0.25rem !important;\n  border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-lg {\n  border-radius: 0.3rem !important;\n}\n\n.rounded-circle {\n  border-radius: 50% !important;\n}\n\n.rounded-pill {\n  border-radius: 50rem !important;\n}\n\n.rounded-0 {\n  border-radius: 0 !important;\n}\n\n.clearfix::after {\n  display: block;\n  clear: both;\n  content: \"\";\n}\n\n.d-none {\n  display: none !important;\n}\n\n.d-inline {\n  display: inline !important;\n}\n\n.d-inline-block {\n  display: inline-block !important;\n}\n\n.d-block {\n  display: block !important;\n}\n\n.d-table {\n  display: table !important;\n}\n\n.d-table-row {\n  display: table-row !important;\n}\n\n.d-table-cell {\n  display: table-cell !important;\n}\n\n.d-flex {\n  display: -ms-flexbox !important;\n  display: flex !important;\n}\n\n.d-inline-flex {\n  display: -ms-inline-flexbox !important;\n  display: inline-flex !important;\n}\n\n@media (min-width: 576px) {\n  .d-sm-none {\n    display: none !important;\n  }\n  .d-sm-inline {\n    display: inline !important;\n  }\n  .d-sm-inline-block {\n    display: inline-block !important;\n  }\n  .d-sm-block {\n    display: block !important;\n  }\n  .d-sm-table {\n    display: table !important;\n  }\n  .d-sm-table-row {\n    display: table-row !important;\n  }\n  .d-sm-table-cell {\n    display: table-cell !important;\n  }\n  .d-sm-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-sm-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n@media (min-width: 768px) {\n  .d-md-none {\n    display: none !important;\n  }\n  .d-md-inline {\n    display: inline !important;\n  }\n  .d-md-inline-block {\n    display: inline-block !important;\n  }\n  .d-md-block {\n    display: block !important;\n  }\n  .d-md-table {\n    display: table !important;\n  }\n  .d-md-table-row {\n    display: table-row !important;\n  }\n  .d-md-table-cell {\n    display: table-cell !important;\n  }\n  .d-md-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-md-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n@media (min-width: 992px) {\n  .d-lg-none {\n    display: none !important;\n  }\n  .d-lg-inline {\n    display: inline !important;\n  }\n  .d-lg-inline-block {\n    display: inline-block !important;\n  }\n  .d-lg-block {\n    display: block !important;\n  }\n  .d-lg-table {\n    display: table !important;\n  }\n  .d-lg-table-row {\n    display: table-row !important;\n  }\n  .d-lg-table-cell {\n    display: table-cell !important;\n  }\n  .d-lg-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-lg-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .d-xl-none {\n    display: none !important;\n  }\n  .d-xl-inline {\n    display: inline !important;\n  }\n  .d-xl-inline-block {\n    display: inline-block !important;\n  }\n  .d-xl-block {\n    display: block !important;\n  }\n  .d-xl-table {\n    display: table !important;\n  }\n  .d-xl-table-row {\n    display: table-row !important;\n  }\n  .d-xl-table-cell {\n    display: table-cell !important;\n  }\n  .d-xl-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-xl-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n@media print {\n  .d-print-none {\n    display: none !important;\n  }\n  .d-print-inline {\n    display: inline !important;\n  }\n  .d-print-inline-block {\n    display: inline-block !important;\n  }\n  .d-print-block {\n    display: block !important;\n  }\n  .d-print-table {\n    display: table !important;\n  }\n  .d-print-table-row {\n    display: table-row !important;\n  }\n  .d-print-table-cell {\n    display: table-cell !important;\n  }\n  .d-print-flex {\n    display: -ms-flexbox !important;\n    display: flex !important;\n  }\n  .d-print-inline-flex {\n    display: -ms-inline-flexbox !important;\n    display: inline-flex !important;\n  }\n}\n\n.embed-responsive {\n  position: relative;\n  display: block;\n  width: 100%;\n  padding: 0;\n  overflow: hidden;\n}\n\n.embed-responsive::before {\n  display: block;\n  content: \"\";\n}\n\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  border: 0;\n}\n\n.embed-responsive-21by9::before {\n  padding-top: 42.857143%;\n}\n\n.embed-responsive-16by9::before {\n  padding-top: 56.25%;\n}\n\n.embed-responsive-4by3::before {\n  padding-top: 75%;\n}\n\n.embed-responsive-1by1::before {\n  padding-top: 100%;\n}\n\n.flex-row {\n  -ms-flex-direction: row !important;\n  flex-direction: row !important;\n}\n\n.flex-column {\n  -ms-flex-direction: column !important;\n  flex-direction: column !important;\n}\n\n.flex-row-reverse {\n  -ms-flex-direction: row-reverse !important;\n  flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n  -ms-flex-direction: column-reverse !important;\n  flex-direction: column-reverse !important;\n}\n\n.flex-wrap {\n  -ms-flex-wrap: wrap !important;\n  flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n  -ms-flex-wrap: nowrap !important;\n  flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n  -ms-flex-wrap: wrap-reverse !important;\n  flex-wrap: wrap-reverse !important;\n}\n\n.flex-fill {\n  -ms-flex: 1 1 auto !important;\n  flex: 1 1 auto !important;\n}\n\n.flex-grow-0 {\n  -ms-flex-positive: 0 !important;\n  flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n  -ms-flex-positive: 1 !important;\n  flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n  -ms-flex-negative: 0 !important;\n  flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n  -ms-flex-negative: 1 !important;\n  flex-shrink: 1 !important;\n}\n\n.justify-content-start {\n  -ms-flex-pack: start !important;\n  justify-content: flex-start !important;\n}\n\n.justify-content-end {\n  -ms-flex-pack: end !important;\n  justify-content: flex-end !important;\n}\n\n.justify-content-center {\n  -ms-flex-pack: center !important;\n  justify-content: center !important;\n}\n\n.justify-content-between {\n  -ms-flex-pack: justify !important;\n  justify-content: space-between !important;\n}\n\n.justify-content-around {\n  -ms-flex-pack: distribute !important;\n  justify-content: space-around !important;\n}\n\n.align-items-start {\n  -ms-flex-align: start !important;\n  align-items: flex-start !important;\n}\n\n.align-items-end {\n  -ms-flex-align: end !important;\n  align-items: flex-end !important;\n}\n\n.align-items-center {\n  -ms-flex-align: center !important;\n  align-items: center !important;\n}\n\n.align-items-baseline {\n  -ms-flex-align: baseline !important;\n  align-items: baseline !important;\n}\n\n.align-items-stretch {\n  -ms-flex-align: stretch !important;\n  align-items: stretch !important;\n}\n\n.align-content-start {\n  -ms-flex-line-pack: start !important;\n  align-content: flex-start !important;\n}\n\n.align-content-end {\n  -ms-flex-line-pack: end !important;\n  align-content: flex-end !important;\n}\n\n.align-content-center {\n  -ms-flex-line-pack: center !important;\n  align-content: center !important;\n}\n\n.align-content-between {\n  -ms-flex-line-pack: justify !important;\n  align-content: space-between !important;\n}\n\n.align-content-around {\n  -ms-flex-line-pack: distribute !important;\n  align-content: space-around !important;\n}\n\n.align-content-stretch {\n  -ms-flex-line-pack: stretch !important;\n  align-content: stretch !important;\n}\n\n.align-self-auto {\n  -ms-flex-item-align: auto !important;\n  align-self: auto !important;\n}\n\n.align-self-start {\n  -ms-flex-item-align: start !important;\n  align-self: flex-start !important;\n}\n\n.align-self-end {\n  -ms-flex-item-align: end !important;\n  align-self: flex-end !important;\n}\n\n.align-self-center {\n  -ms-flex-item-align: center !important;\n  align-self: center !important;\n}\n\n.align-self-baseline {\n  -ms-flex-item-align: baseline !important;\n  align-self: baseline !important;\n}\n\n.align-self-stretch {\n  -ms-flex-item-align: stretch !important;\n  align-self: stretch !important;\n}\n\n@media (min-width: 576px) {\n  .flex-sm-row {\n    -ms-flex-direction: row !important;\n    flex-direction: row !important;\n  }\n  .flex-sm-column {\n    -ms-flex-direction: column !important;\n    flex-direction: column !important;\n  }\n  .flex-sm-row-reverse {\n    -ms-flex-direction: row-reverse !important;\n    flex-direction: row-reverse !important;\n  }\n  .flex-sm-column-reverse {\n    -ms-flex-direction: column-reverse !important;\n    flex-direction: column-reverse !important;\n  }\n  .flex-sm-wrap {\n    -ms-flex-wrap: wrap !important;\n    flex-wrap: wrap !important;\n  }\n  .flex-sm-nowrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n  }\n  .flex-sm-wrap-reverse {\n    -ms-flex-wrap: wrap-reverse !important;\n    flex-wrap: wrap-reverse !important;\n  }\n  .flex-sm-fill {\n    -ms-flex: 1 1 auto !important;\n    flex: 1 1 auto !important;\n  }\n  .flex-sm-grow-0 {\n    -ms-flex-positive: 0 !important;\n    flex-grow: 0 !important;\n  }\n  .flex-sm-grow-1 {\n    -ms-flex-positive: 1 !important;\n    flex-grow: 1 !important;\n  }\n  .flex-sm-shrink-0 {\n    -ms-flex-negative: 0 !important;\n    flex-shrink: 0 !important;\n  }\n  .flex-sm-shrink-1 {\n    -ms-flex-negative: 1 !important;\n    flex-shrink: 1 !important;\n  }\n  .justify-content-sm-start {\n    -ms-flex-pack: start !important;\n    justify-content: flex-start !important;\n  }\n  .justify-content-sm-end {\n    -ms-flex-pack: end !important;\n    justify-content: flex-end !important;\n  }\n  .justify-content-sm-center {\n    -ms-flex-pack: center !important;\n    justify-content: center !important;\n  }\n  .justify-content-sm-between {\n    -ms-flex-pack: justify !important;\n    justify-content: space-between !important;\n  }\n  .justify-content-sm-around {\n    -ms-flex-pack: distribute !important;\n    justify-content: space-around !important;\n  }\n  .align-items-sm-start {\n    -ms-flex-align: start !important;\n    align-items: flex-start !important;\n  }\n  .align-items-sm-end {\n    -ms-flex-align: end !important;\n    align-items: flex-end !important;\n  }\n  .align-items-sm-center {\n    -ms-flex-align: center !important;\n    align-items: center !important;\n  }\n  .align-items-sm-baseline {\n    -ms-flex-align: baseline !important;\n    align-items: baseline !important;\n  }\n  .align-items-sm-stretch {\n    -ms-flex-align: stretch !important;\n    align-items: stretch !important;\n  }\n  .align-content-sm-start {\n    -ms-flex-line-pack: start !important;\n    align-content: flex-start !important;\n  }\n  .align-content-sm-end {\n    -ms-flex-line-pack: end !important;\n    align-content: flex-end !important;\n  }\n  .align-content-sm-center {\n    -ms-flex-line-pack: center !important;\n    align-content: center !important;\n  }\n  .align-content-sm-between {\n    -ms-flex-line-pack: justify !important;\n    align-content: space-between !important;\n  }\n  .align-content-sm-around {\n    -ms-flex-line-pack: distribute !important;\n    align-content: space-around !important;\n  }\n  .align-content-sm-stretch {\n    -ms-flex-line-pack: stretch !important;\n    align-content: stretch !important;\n  }\n  .align-self-sm-auto {\n    -ms-flex-item-align: auto !important;\n    align-self: auto !important;\n  }\n  .align-self-sm-start {\n    -ms-flex-item-align: start !important;\n    align-self: flex-start !important;\n  }\n  .align-self-sm-end {\n    -ms-flex-item-align: end !important;\n    align-self: flex-end !important;\n  }\n  .align-self-sm-center {\n    -ms-flex-item-align: center !important;\n    align-self: center !important;\n  }\n  .align-self-sm-baseline {\n    -ms-flex-item-align: baseline !important;\n    align-self: baseline !important;\n  }\n  .align-self-sm-stretch {\n    -ms-flex-item-align: stretch !important;\n    align-self: stretch !important;\n  }\n}\n\n@media (min-width: 768px) {\n  .flex-md-row {\n    -ms-flex-direction: row !important;\n    flex-direction: row !important;\n  }\n  .flex-md-column {\n    -ms-flex-direction: column !important;\n    flex-direction: column !important;\n  }\n  .flex-md-row-reverse {\n    -ms-flex-direction: row-reverse !important;\n    flex-direction: row-reverse !important;\n  }\n  .flex-md-column-reverse {\n    -ms-flex-direction: column-reverse !important;\n    flex-direction: column-reverse !important;\n  }\n  .flex-md-wrap {\n    -ms-flex-wrap: wrap !important;\n    flex-wrap: wrap !important;\n  }\n  .flex-md-nowrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n  }\n  .flex-md-wrap-reverse {\n    -ms-flex-wrap: wrap-reverse !important;\n    flex-wrap: wrap-reverse !important;\n  }\n  .flex-md-fill {\n    -ms-flex: 1 1 auto !important;\n    flex: 1 1 auto !important;\n  }\n  .flex-md-grow-0 {\n    -ms-flex-positive: 0 !important;\n    flex-grow: 0 !important;\n  }\n  .flex-md-grow-1 {\n    -ms-flex-positive: 1 !important;\n    flex-grow: 1 !important;\n  }\n  .flex-md-shrink-0 {\n    -ms-flex-negative: 0 !important;\n    flex-shrink: 0 !important;\n  }\n  .flex-md-shrink-1 {\n    -ms-flex-negative: 1 !important;\n    flex-shrink: 1 !important;\n  }\n  .justify-content-md-start {\n    -ms-flex-pack: start !important;\n    justify-content: flex-start !important;\n  }\n  .justify-content-md-end {\n    -ms-flex-pack: end !important;\n    justify-content: flex-end !important;\n  }\n  .justify-content-md-center {\n    -ms-flex-pack: center !important;\n    justify-content: center !important;\n  }\n  .justify-content-md-between {\n    -ms-flex-pack: justify !important;\n    justify-content: space-between !important;\n  }\n  .justify-content-md-around {\n    -ms-flex-pack: distribute !important;\n    justify-content: space-around !important;\n  }\n  .align-items-md-start {\n    -ms-flex-align: start !important;\n    align-items: flex-start !important;\n  }\n  .align-items-md-end {\n    -ms-flex-align: end !important;\n    align-items: flex-end !important;\n  }\n  .align-items-md-center {\n    -ms-flex-align: center !important;\n    align-items: center !important;\n  }\n  .align-items-md-baseline {\n    -ms-flex-align: baseline !important;\n    align-items: baseline !important;\n  }\n  .align-items-md-stretch {\n    -ms-flex-align: stretch !important;\n    align-items: stretch !important;\n  }\n  .align-content-md-start {\n    -ms-flex-line-pack: start !important;\n    align-content: flex-start !important;\n  }\n  .align-content-md-end {\n    -ms-flex-line-pack: end !important;\n    align-content: flex-end !important;\n  }\n  .align-content-md-center {\n    -ms-flex-line-pack: center !important;\n    align-content: center !important;\n  }\n  .align-content-md-between {\n    -ms-flex-line-pack: justify !important;\n    align-content: space-between !important;\n  }\n  .align-content-md-around {\n    -ms-flex-line-pack: distribute !important;\n    align-content: space-around !important;\n  }\n  .align-content-md-stretch {\n    -ms-flex-line-pack: stretch !important;\n    align-content: stretch !important;\n  }\n  .align-self-md-auto {\n    -ms-flex-item-align: auto !important;\n    align-self: auto !important;\n  }\n  .align-self-md-start {\n    -ms-flex-item-align: start !important;\n    align-self: flex-start !important;\n  }\n  .align-self-md-end {\n    -ms-flex-item-align: end !important;\n    align-self: flex-end !important;\n  }\n  .align-self-md-center {\n    -ms-flex-item-align: center !important;\n    align-self: center !important;\n  }\n  .align-self-md-baseline {\n    -ms-flex-item-align: baseline !important;\n    align-self: baseline !important;\n  }\n  .align-self-md-stretch {\n    -ms-flex-item-align: stretch !important;\n    align-self: stretch !important;\n  }\n}\n\n@media (min-width: 992px) {\n  .flex-lg-row {\n    -ms-flex-direction: row !important;\n    flex-direction: row !important;\n  }\n  .flex-lg-column {\n    -ms-flex-direction: column !important;\n    flex-direction: column !important;\n  }\n  .flex-lg-row-reverse {\n    -ms-flex-direction: row-reverse !important;\n    flex-direction: row-reverse !important;\n  }\n  .flex-lg-column-reverse {\n    -ms-flex-direction: column-reverse !important;\n    flex-direction: column-reverse !important;\n  }\n  .flex-lg-wrap {\n    -ms-flex-wrap: wrap !important;\n    flex-wrap: wrap !important;\n  }\n  .flex-lg-nowrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n  }\n  .flex-lg-wrap-reverse {\n    -ms-flex-wrap: wrap-reverse !important;\n    flex-wrap: wrap-reverse !important;\n  }\n  .flex-lg-fill {\n    -ms-flex: 1 1 auto !important;\n    flex: 1 1 auto !important;\n  }\n  .flex-lg-grow-0 {\n    -ms-flex-positive: 0 !important;\n    flex-grow: 0 !important;\n  }\n  .flex-lg-grow-1 {\n    -ms-flex-positive: 1 !important;\n    flex-grow: 1 !important;\n  }\n  .flex-lg-shrink-0 {\n    -ms-flex-negative: 0 !important;\n    flex-shrink: 0 !important;\n  }\n  .flex-lg-shrink-1 {\n    -ms-flex-negative: 1 !important;\n    flex-shrink: 1 !important;\n  }\n  .justify-content-lg-start {\n    -ms-flex-pack: start !important;\n    justify-content: flex-start !important;\n  }\n  .justify-content-lg-end {\n    -ms-flex-pack: end !important;\n    justify-content: flex-end !important;\n  }\n  .justify-content-lg-center {\n    -ms-flex-pack: center !important;\n    justify-content: center !important;\n  }\n  .justify-content-lg-between {\n    -ms-flex-pack: justify !important;\n    justify-content: space-between !important;\n  }\n  .justify-content-lg-around {\n    -ms-flex-pack: distribute !important;\n    justify-content: space-around !important;\n  }\n  .align-items-lg-start {\n    -ms-flex-align: start !important;\n    align-items: flex-start !important;\n  }\n  .align-items-lg-end {\n    -ms-flex-align: end !important;\n    align-items: flex-end !important;\n  }\n  .align-items-lg-center {\n    -ms-flex-align: center !important;\n    align-items: center !important;\n  }\n  .align-items-lg-baseline {\n    -ms-flex-align: baseline !important;\n    align-items: baseline !important;\n  }\n  .align-items-lg-stretch {\n    -ms-flex-align: stretch !important;\n    align-items: stretch !important;\n  }\n  .align-content-lg-start {\n    -ms-flex-line-pack: start !important;\n    align-content: flex-start !important;\n  }\n  .align-content-lg-end {\n    -ms-flex-line-pack: end !important;\n    align-content: flex-end !important;\n  }\n  .align-content-lg-center {\n    -ms-flex-line-pack: center !important;\n    align-content: center !important;\n  }\n  .align-content-lg-between {\n    -ms-flex-line-pack: justify !important;\n    align-content: space-between !important;\n  }\n  .align-content-lg-around {\n    -ms-flex-line-pack: distribute !important;\n    align-content: space-around !important;\n  }\n  .align-content-lg-stretch {\n    -ms-flex-line-pack: stretch !important;\n    align-content: stretch !important;\n  }\n  .align-self-lg-auto {\n    -ms-flex-item-align: auto !important;\n    align-self: auto !important;\n  }\n  .align-self-lg-start {\n    -ms-flex-item-align: start !important;\n    align-self: flex-start !important;\n  }\n  .align-self-lg-end {\n    -ms-flex-item-align: end !important;\n    align-self: flex-end !important;\n  }\n  .align-self-lg-center {\n    -ms-flex-item-align: center !important;\n    align-self: center !important;\n  }\n  .align-self-lg-baseline {\n    -ms-flex-item-align: baseline !important;\n    align-self: baseline !important;\n  }\n  .align-self-lg-stretch {\n    -ms-flex-item-align: stretch !important;\n    align-self: stretch !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .flex-xl-row {\n    -ms-flex-direction: row !important;\n    flex-direction: row !important;\n  }\n  .flex-xl-column {\n    -ms-flex-direction: column !important;\n    flex-direction: column !important;\n  }\n  .flex-xl-row-reverse {\n    -ms-flex-direction: row-reverse !important;\n    flex-direction: row-reverse !important;\n  }\n  .flex-xl-column-reverse {\n    -ms-flex-direction: column-reverse !important;\n    flex-direction: column-reverse !important;\n  }\n  .flex-xl-wrap {\n    -ms-flex-wrap: wrap !important;\n    flex-wrap: wrap !important;\n  }\n  .flex-xl-nowrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n  }\n  .flex-xl-wrap-reverse {\n    -ms-flex-wrap: wrap-reverse !important;\n    flex-wrap: wrap-reverse !important;\n  }\n  .flex-xl-fill {\n    -ms-flex: 1 1 auto !important;\n    flex: 1 1 auto !important;\n  }\n  .flex-xl-grow-0 {\n    -ms-flex-positive: 0 !important;\n    flex-grow: 0 !important;\n  }\n  .flex-xl-grow-1 {\n    -ms-flex-positive: 1 !important;\n    flex-grow: 1 !important;\n  }\n  .flex-xl-shrink-0 {\n    -ms-flex-negative: 0 !important;\n    flex-shrink: 0 !important;\n  }\n  .flex-xl-shrink-1 {\n    -ms-flex-negative: 1 !important;\n    flex-shrink: 1 !important;\n  }\n  .justify-content-xl-start {\n    -ms-flex-pack: start !important;\n    justify-content: flex-start !important;\n  }\n  .justify-content-xl-end {\n    -ms-flex-pack: end !important;\n    justify-content: flex-end !important;\n  }\n  .justify-content-xl-center {\n    -ms-flex-pack: center !important;\n    justify-content: center !important;\n  }\n  .justify-content-xl-between {\n    -ms-flex-pack: justify !important;\n    justify-content: space-between !important;\n  }\n  .justify-content-xl-around {\n    -ms-flex-pack: distribute !important;\n    justify-content: space-around !important;\n  }\n  .align-items-xl-start {\n    -ms-flex-align: start !important;\n    align-items: flex-start !important;\n  }\n  .align-items-xl-end {\n    -ms-flex-align: end !important;\n    align-items: flex-end !important;\n  }\n  .align-items-xl-center {\n    -ms-flex-align: center !important;\n    align-items: center !important;\n  }\n  .align-items-xl-baseline {\n    -ms-flex-align: baseline !important;\n    align-items: baseline !important;\n  }\n  .align-items-xl-stretch {\n    -ms-flex-align: stretch !important;\n    align-items: stretch !important;\n  }\n  .align-content-xl-start {\n    -ms-flex-line-pack: start !important;\n    align-content: flex-start !important;\n  }\n  .align-content-xl-end {\n    -ms-flex-line-pack: end !important;\n    align-content: flex-end !important;\n  }\n  .align-content-xl-center {\n    -ms-flex-line-pack: center !important;\n    align-content: center !important;\n  }\n  .align-content-xl-between {\n    -ms-flex-line-pack: justify !important;\n    align-content: space-between !important;\n  }\n  .align-content-xl-around {\n    -ms-flex-line-pack: distribute !important;\n    align-content: space-around !important;\n  }\n  .align-content-xl-stretch {\n    -ms-flex-line-pack: stretch !important;\n    align-content: stretch !important;\n  }\n  .align-self-xl-auto {\n    -ms-flex-item-align: auto !important;\n    align-self: auto !important;\n  }\n  .align-self-xl-start {\n    -ms-flex-item-align: start !important;\n    align-self: flex-start !important;\n  }\n  .align-self-xl-end {\n    -ms-flex-item-align: end !important;\n    align-self: flex-end !important;\n  }\n  .align-self-xl-center {\n    -ms-flex-item-align: center !important;\n    align-self: center !important;\n  }\n  .align-self-xl-baseline {\n    -ms-flex-item-align: baseline !important;\n    align-self: baseline !important;\n  }\n  .align-self-xl-stretch {\n    -ms-flex-item-align: stretch !important;\n    align-self: stretch !important;\n  }\n}\n\n.float-left {\n  float: left !important;\n}\n\n.float-right {\n  float: right !important;\n}\n\n.float-none {\n  float: none !important;\n}\n\n@media (min-width: 576px) {\n  .float-sm-left {\n    float: left !important;\n  }\n  .float-sm-right {\n    float: right !important;\n  }\n  .float-sm-none {\n    float: none !important;\n  }\n}\n\n@media (min-width: 768px) {\n  .float-md-left {\n    float: left !important;\n  }\n  .float-md-right {\n    float: right !important;\n  }\n  .float-md-none {\n    float: none !important;\n  }\n}\n\n@media (min-width: 992px) {\n  .float-lg-left {\n    float: left !important;\n  }\n  .float-lg-right {\n    float: right !important;\n  }\n  .float-lg-none {\n    float: none !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .float-xl-left {\n    float: left !important;\n  }\n  .float-xl-right {\n    float: right !important;\n  }\n  .float-xl-none {\n    float: none !important;\n  }\n}\n\n.overflow-auto {\n  overflow: auto !important;\n}\n\n.overflow-hidden {\n  overflow: hidden !important;\n}\n\n.position-static {\n  position: static !important;\n}\n\n.position-relative {\n  position: relative !important;\n}\n\n.position-absolute {\n  position: absolute !important;\n}\n\n.position-fixed {\n  position: fixed !important;\n}\n\n.position-sticky {\n  position: -webkit-sticky !important;\n  position: sticky !important;\n}\n\n.fixed-top {\n  position: fixed;\n  top: 0;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n\n.fixed-bottom {\n  position: fixed;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1030;\n}\n\n@supports ((position: -webkit-sticky) or (position: sticky)) {\n  .sticky-top {\n    position: -webkit-sticky;\n    position: sticky;\n    top: 0;\n    z-index: 1020;\n  }\n}\n\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border: 0;\n}\n\n.sr-only-focusable:active, .sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  overflow: visible;\n  clip: auto;\n  white-space: normal;\n}\n\n.shadow-sm {\n  box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;\n}\n\n.shadow {\n  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;\n}\n\n.shadow-lg {\n  box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;\n}\n\n.shadow-none {\n  box-shadow: none !important;\n}\n\n.w-25 {\n  width: 25% !important;\n}\n\n.w-50 {\n  width: 50% !important;\n}\n\n.w-75 {\n  width: 75% !important;\n}\n\n.w-100 {\n  width: 100% !important;\n}\n\n.w-auto {\n  width: auto !important;\n}\n\n.h-25 {\n  height: 25% !important;\n}\n\n.h-50 {\n  height: 50% !important;\n}\n\n.h-75 {\n  height: 75% !important;\n}\n\n.h-100 {\n  height: 100% !important;\n}\n\n.h-auto {\n  height: auto !important;\n}\n\n.mw-100 {\n  max-width: 100% !important;\n}\n\n.mh-100 {\n  max-height: 100% !important;\n}\n\n.min-vw-100 {\n  min-width: 100vw !important;\n}\n\n.min-vh-100 {\n  min-height: 100vh !important;\n}\n\n.vw-100 {\n  width: 100vw !important;\n}\n\n.vh-100 {\n  height: 100vh !important;\n}\n\n.stretched-link::after {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1;\n  pointer-events: auto;\n  content: \"\";\n  background-color: rgba(0, 0, 0, 0);\n}\n\n.m-0 {\n  margin: 0 !important;\n}\n\n.mt-0,\n.my-0 {\n  margin-top: 0 !important;\n}\n\n.mr-0,\n.mx-0 {\n  margin-right: 0 !important;\n}\n\n.mb-0,\n.my-0 {\n  margin-bottom: 0 !important;\n}\n\n.ml-0,\n.mx-0 {\n  margin-left: 0 !important;\n}\n\n.m-1 {\n  margin: 0.25rem !important;\n}\n\n.mt-1,\n.my-1 {\n  margin-top: 0.25rem !important;\n}\n\n.mr-1,\n.mx-1 {\n  margin-right: 0.25rem !important;\n}\n\n.mb-1,\n.my-1 {\n  margin-bottom: 0.25rem !important;\n}\n\n.ml-1,\n.mx-1 {\n  margin-left: 0.25rem !important;\n}\n\n.m-2 {\n  margin: 0.5rem !important;\n}\n\n.mt-2,\n.my-2 {\n  margin-top: 0.5rem !important;\n}\n\n.mr-2,\n.mx-2 {\n  margin-right: 0.5rem !important;\n}\n\n.mb-2,\n.my-2 {\n  margin-bottom: 0.5rem !important;\n}\n\n.ml-2,\n.mx-2 {\n  margin-left: 0.5rem !important;\n}\n\n.m-3 {\n  margin: 1rem !important;\n}\n\n.mt-3,\n.my-3 {\n  margin-top: 1rem !important;\n}\n\n.mr-3,\n.mx-3 {\n  margin-right: 1rem !important;\n}\n\n.mb-3,\n.my-3 {\n  margin-bottom: 1rem !important;\n}\n\n.ml-3,\n.mx-3 {\n  margin-left: 1rem !important;\n}\n\n.m-4 {\n  margin: 1.5rem !important;\n}\n\n.mt-4,\n.my-4 {\n  margin-top: 1.5rem !important;\n}\n\n.mr-4,\n.mx-4 {\n  margin-right: 1.5rem !important;\n}\n\n.mb-4,\n.my-4 {\n  margin-bottom: 1.5rem !important;\n}\n\n.ml-4,\n.mx-4 {\n  margin-left: 1.5rem !important;\n}\n\n.m-5 {\n  margin: 3rem !important;\n}\n\n.mt-5,\n.my-5 {\n  margin-top: 3rem !important;\n}\n\n.mr-5,\n.mx-5 {\n  margin-right: 3rem !important;\n}\n\n.mb-5,\n.my-5 {\n  margin-bottom: 3rem !important;\n}\n\n.ml-5,\n.mx-5 {\n  margin-left: 3rem !important;\n}\n\n.p-0 {\n  padding: 0 !important;\n}\n\n.pt-0,\n.py-0 {\n  padding-top: 0 !important;\n}\n\n.pr-0,\n.px-0 {\n  padding-right: 0 !important;\n}\n\n.pb-0,\n.py-0 {\n  padding-bottom: 0 !important;\n}\n\n.pl-0,\n.px-0 {\n  padding-left: 0 !important;\n}\n\n.p-1 {\n  padding: 0.25rem !important;\n}\n\n.pt-1,\n.py-1 {\n  padding-top: 0.25rem !important;\n}\n\n.pr-1,\n.px-1 {\n  padding-right: 0.25rem !important;\n}\n\n.pb-1,\n.py-1 {\n  padding-bottom: 0.25rem !important;\n}\n\n.pl-1,\n.px-1 {\n  padding-left: 0.25rem !important;\n}\n\n.p-2 {\n  padding: 0.5rem !important;\n}\n\n.pt-2,\n.py-2 {\n  padding-top: 0.5rem !important;\n}\n\n.pr-2,\n.px-2 {\n  padding-right: 0.5rem !important;\n}\n\n.pb-2,\n.py-2 {\n  padding-bottom: 0.5rem !important;\n}\n\n.pl-2,\n.px-2 {\n  padding-left: 0.5rem !important;\n}\n\n.p-3 {\n  padding: 1rem !important;\n}\n\n.pt-3,\n.py-3 {\n  padding-top: 1rem !important;\n}\n\n.pr-3,\n.px-3 {\n  padding-right: 1rem !important;\n}\n\n.pb-3,\n.py-3 {\n  padding-bottom: 1rem !important;\n}\n\n.pl-3,\n.px-3 {\n  padding-left: 1rem !important;\n}\n\n.p-4 {\n  padding: 1.5rem !important;\n}\n\n.pt-4,\n.py-4 {\n  padding-top: 1.5rem !important;\n}\n\n.pr-4,\n.px-4 {\n  padding-right: 1.5rem !important;\n}\n\n.pb-4,\n.py-4 {\n  padding-bottom: 1.5rem !important;\n}\n\n.pl-4,\n.px-4 {\n  padding-left: 1.5rem !important;\n}\n\n.p-5 {\n  padding: 3rem !important;\n}\n\n.pt-5,\n.py-5 {\n  padding-top: 3rem !important;\n}\n\n.pr-5,\n.px-5 {\n  padding-right: 3rem !important;\n}\n\n.pb-5,\n.py-5 {\n  padding-bottom: 3rem !important;\n}\n\n.pl-5,\n.px-5 {\n  padding-left: 3rem !important;\n}\n\n.m-n1 {\n  margin: -0.25rem !important;\n}\n\n.mt-n1,\n.my-n1 {\n  margin-top: -0.25rem !important;\n}\n\n.mr-n1,\n.mx-n1 {\n  margin-right: -0.25rem !important;\n}\n\n.mb-n1,\n.my-n1 {\n  margin-bottom: -0.25rem !important;\n}\n\n.ml-n1,\n.mx-n1 {\n  margin-left: -0.25rem !important;\n}\n\n.m-n2 {\n  margin: -0.5rem !important;\n}\n\n.mt-n2,\n.my-n2 {\n  margin-top: -0.5rem !important;\n}\n\n.mr-n2,\n.mx-n2 {\n  margin-right: -0.5rem !important;\n}\n\n.mb-n2,\n.my-n2 {\n  margin-bottom: -0.5rem !important;\n}\n\n.ml-n2,\n.mx-n2 {\n  margin-left: -0.5rem !important;\n}\n\n.m-n3 {\n  margin: -1rem !important;\n}\n\n.mt-n3,\n.my-n3 {\n  margin-top: -1rem !important;\n}\n\n.mr-n3,\n.mx-n3 {\n  margin-right: -1rem !important;\n}\n\n.mb-n3,\n.my-n3 {\n  margin-bottom: -1rem !important;\n}\n\n.ml-n3,\n.mx-n3 {\n  margin-left: -1rem !important;\n}\n\n.m-n4 {\n  margin: -1.5rem !important;\n}\n\n.mt-n4,\n.my-n4 {\n  margin-top: -1.5rem !important;\n}\n\n.mr-n4,\n.mx-n4 {\n  margin-right: -1.5rem !important;\n}\n\n.mb-n4,\n.my-n4 {\n  margin-bottom: -1.5rem !important;\n}\n\n.ml-n4,\n.mx-n4 {\n  margin-left: -1.5rem !important;\n}\n\n.m-n5 {\n  margin: -3rem !important;\n}\n\n.mt-n5,\n.my-n5 {\n  margin-top: -3rem !important;\n}\n\n.mr-n5,\n.mx-n5 {\n  margin-right: -3rem !important;\n}\n\n.mb-n5,\n.my-n5 {\n  margin-bottom: -3rem !important;\n}\n\n.ml-n5,\n.mx-n5 {\n  margin-left: -3rem !important;\n}\n\n.m-auto {\n  margin: auto !important;\n}\n\n.mt-auto,\n.my-auto {\n  margin-top: auto !important;\n}\n\n.mr-auto,\n.mx-auto {\n  margin-right: auto !important;\n}\n\n.mb-auto,\n.my-auto {\n  margin-bottom: auto !important;\n}\n\n.ml-auto,\n.mx-auto {\n  margin-left: auto !important;\n}\n\n@media (min-width: 576px) {\n  .m-sm-0 {\n    margin: 0 !important;\n  }\n  .mt-sm-0,\n  .my-sm-0 {\n    margin-top: 0 !important;\n  }\n  .mr-sm-0,\n  .mx-sm-0 {\n    margin-right: 0 !important;\n  }\n  .mb-sm-0,\n  .my-sm-0 {\n    margin-bottom: 0 !important;\n  }\n  .ml-sm-0,\n  .mx-sm-0 {\n    margin-left: 0 !important;\n  }\n  .m-sm-1 {\n    margin: 0.25rem !important;\n  }\n  .mt-sm-1,\n  .my-sm-1 {\n    margin-top: 0.25rem !important;\n  }\n  .mr-sm-1,\n  .mx-sm-1 {\n    margin-right: 0.25rem !important;\n  }\n  .mb-sm-1,\n  .my-sm-1 {\n    margin-bottom: 0.25rem !important;\n  }\n  .ml-sm-1,\n  .mx-sm-1 {\n    margin-left: 0.25rem !important;\n  }\n  .m-sm-2 {\n    margin: 0.5rem !important;\n  }\n  .mt-sm-2,\n  .my-sm-2 {\n    margin-top: 0.5rem !important;\n  }\n  .mr-sm-2,\n  .mx-sm-2 {\n    margin-right: 0.5rem !important;\n  }\n  .mb-sm-2,\n  .my-sm-2 {\n    margin-bottom: 0.5rem !important;\n  }\n  .ml-sm-2,\n  .mx-sm-2 {\n    margin-left: 0.5rem !important;\n  }\n  .m-sm-3 {\n    margin: 1rem !important;\n  }\n  .mt-sm-3,\n  .my-sm-3 {\n    margin-top: 1rem !important;\n  }\n  .mr-sm-3,\n  .mx-sm-3 {\n    margin-right: 1rem !important;\n  }\n  .mb-sm-3,\n  .my-sm-3 {\n    margin-bottom: 1rem !important;\n  }\n  .ml-sm-3,\n  .mx-sm-3 {\n    margin-left: 1rem !important;\n  }\n  .m-sm-4 {\n    margin: 1.5rem !important;\n  }\n  .mt-sm-4,\n  .my-sm-4 {\n    margin-top: 1.5rem !important;\n  }\n  .mr-sm-4,\n  .mx-sm-4 {\n    margin-right: 1.5rem !important;\n  }\n  .mb-sm-4,\n  .my-sm-4 {\n    margin-bottom: 1.5rem !important;\n  }\n  .ml-sm-4,\n  .mx-sm-4 {\n    margin-left: 1.5rem !important;\n  }\n  .m-sm-5 {\n    margin: 3rem !important;\n  }\n  .mt-sm-5,\n  .my-sm-5 {\n    margin-top: 3rem !important;\n  }\n  .mr-sm-5,\n  .mx-sm-5 {\n    margin-right: 3rem !important;\n  }\n  .mb-sm-5,\n  .my-sm-5 {\n    margin-bottom: 3rem !important;\n  }\n  .ml-sm-5,\n  .mx-sm-5 {\n    margin-left: 3rem !important;\n  }\n  .p-sm-0 {\n    padding: 0 !important;\n  }\n  .pt-sm-0,\n  .py-sm-0 {\n    padding-top: 0 !important;\n  }\n  .pr-sm-0,\n  .px-sm-0 {\n    padding-right: 0 !important;\n  }\n  .pb-sm-0,\n  .py-sm-0 {\n    padding-bottom: 0 !important;\n  }\n  .pl-sm-0,\n  .px-sm-0 {\n    padding-left: 0 !important;\n  }\n  .p-sm-1 {\n    padding: 0.25rem !important;\n  }\n  .pt-sm-1,\n  .py-sm-1 {\n    padding-top: 0.25rem !important;\n  }\n  .pr-sm-1,\n  .px-sm-1 {\n    padding-right: 0.25rem !important;\n  }\n  .pb-sm-1,\n  .py-sm-1 {\n    padding-bottom: 0.25rem !important;\n  }\n  .pl-sm-1,\n  .px-sm-1 {\n    padding-left: 0.25rem !important;\n  }\n  .p-sm-2 {\n    padding: 0.5rem !important;\n  }\n  .pt-sm-2,\n  .py-sm-2 {\n    padding-top: 0.5rem !important;\n  }\n  .pr-sm-2,\n  .px-sm-2 {\n    padding-right: 0.5rem !important;\n  }\n  .pb-sm-2,\n  .py-sm-2 {\n    padding-bottom: 0.5rem !important;\n  }\n  .pl-sm-2,\n  .px-sm-2 {\n    padding-left: 0.5rem !important;\n  }\n  .p-sm-3 {\n    padding: 1rem !important;\n  }\n  .pt-sm-3,\n  .py-sm-3 {\n    padding-top: 1rem !important;\n  }\n  .pr-sm-3,\n  .px-sm-3 {\n    padding-right: 1rem !important;\n  }\n  .pb-sm-3,\n  .py-sm-3 {\n    padding-bottom: 1rem !important;\n  }\n  .pl-sm-3,\n  .px-sm-3 {\n    padding-left: 1rem !important;\n  }\n  .p-sm-4 {\n    padding: 1.5rem !important;\n  }\n  .pt-sm-4,\n  .py-sm-4 {\n    padding-top: 1.5rem !important;\n  }\n  .pr-sm-4,\n  .px-sm-4 {\n    padding-right: 1.5rem !important;\n  }\n  .pb-sm-4,\n  .py-sm-4 {\n    padding-bottom: 1.5rem !important;\n  }\n  .pl-sm-4,\n  .px-sm-4 {\n    padding-left: 1.5rem !important;\n  }\n  .p-sm-5 {\n    padding: 3rem !important;\n  }\n  .pt-sm-5,\n  .py-sm-5 {\n    padding-top: 3rem !important;\n  }\n  .pr-sm-5,\n  .px-sm-5 {\n    padding-right: 3rem !important;\n  }\n  .pb-sm-5,\n  .py-sm-5 {\n    padding-bottom: 3rem !important;\n  }\n  .pl-sm-5,\n  .px-sm-5 {\n    padding-left: 3rem !important;\n  }\n  .m-sm-n1 {\n    margin: -0.25rem !important;\n  }\n  .mt-sm-n1,\n  .my-sm-n1 {\n    margin-top: -0.25rem !important;\n  }\n  .mr-sm-n1,\n  .mx-sm-n1 {\n    margin-right: -0.25rem !important;\n  }\n  .mb-sm-n1,\n  .my-sm-n1 {\n    margin-bottom: -0.25rem !important;\n  }\n  .ml-sm-n1,\n  .mx-sm-n1 {\n    margin-left: -0.25rem !important;\n  }\n  .m-sm-n2 {\n    margin: -0.5rem !important;\n  }\n  .mt-sm-n2,\n  .my-sm-n2 {\n    margin-top: -0.5rem !important;\n  }\n  .mr-sm-n2,\n  .mx-sm-n2 {\n    margin-right: -0.5rem !important;\n  }\n  .mb-sm-n2,\n  .my-sm-n2 {\n    margin-bottom: -0.5rem !important;\n  }\n  .ml-sm-n2,\n  .mx-sm-n2 {\n    margin-left: -0.5rem !important;\n  }\n  .m-sm-n3 {\n    margin: -1rem !important;\n  }\n  .mt-sm-n3,\n  .my-sm-n3 {\n    margin-top: -1rem !important;\n  }\n  .mr-sm-n3,\n  .mx-sm-n3 {\n    margin-right: -1rem !important;\n  }\n  .mb-sm-n3,\n  .my-sm-n3 {\n    margin-bottom: -1rem !important;\n  }\n  .ml-sm-n3,\n  .mx-sm-n3 {\n    margin-left: -1rem !important;\n  }\n  .m-sm-n4 {\n    margin: -1.5rem !important;\n  }\n  .mt-sm-n4,\n  .my-sm-n4 {\n    margin-top: -1.5rem !important;\n  }\n  .mr-sm-n4,\n  .mx-sm-n4 {\n    margin-right: -1.5rem !important;\n  }\n  .mb-sm-n4,\n  .my-sm-n4 {\n    margin-bottom: -1.5rem !important;\n  }\n  .ml-sm-n4,\n  .mx-sm-n4 {\n    margin-left: -1.5rem !important;\n  }\n  .m-sm-n5 {\n    margin: -3rem !important;\n  }\n  .mt-sm-n5,\n  .my-sm-n5 {\n    margin-top: -3rem !important;\n  }\n  .mr-sm-n5,\n  .mx-sm-n5 {\n    margin-right: -3rem !important;\n  }\n  .mb-sm-n5,\n  .my-sm-n5 {\n    margin-bottom: -3rem !important;\n  }\n  .ml-sm-n5,\n  .mx-sm-n5 {\n    margin-left: -3rem !important;\n  }\n  .m-sm-auto {\n    margin: auto !important;\n  }\n  .mt-sm-auto,\n  .my-sm-auto {\n    margin-top: auto !important;\n  }\n  .mr-sm-auto,\n  .mx-sm-auto {\n    margin-right: auto !important;\n  }\n  .mb-sm-auto,\n  .my-sm-auto {\n    margin-bottom: auto !important;\n  }\n  .ml-sm-auto,\n  .mx-sm-auto {\n    margin-left: auto !important;\n  }\n}\n\n@media (min-width: 768px) {\n  .m-md-0 {\n    margin: 0 !important;\n  }\n  .mt-md-0,\n  .my-md-0 {\n    margin-top: 0 !important;\n  }\n  .mr-md-0,\n  .mx-md-0 {\n    margin-right: 0 !important;\n  }\n  .mb-md-0,\n  .my-md-0 {\n    margin-bottom: 0 !important;\n  }\n  .ml-md-0,\n  .mx-md-0 {\n    margin-left: 0 !important;\n  }\n  .m-md-1 {\n    margin: 0.25rem !important;\n  }\n  .mt-md-1,\n  .my-md-1 {\n    margin-top: 0.25rem !important;\n  }\n  .mr-md-1,\n  .mx-md-1 {\n    margin-right: 0.25rem !important;\n  }\n  .mb-md-1,\n  .my-md-1 {\n    margin-bottom: 0.25rem !important;\n  }\n  .ml-md-1,\n  .mx-md-1 {\n    margin-left: 0.25rem !important;\n  }\n  .m-md-2 {\n    margin: 0.5rem !important;\n  }\n  .mt-md-2,\n  .my-md-2 {\n    margin-top: 0.5rem !important;\n  }\n  .mr-md-2,\n  .mx-md-2 {\n    margin-right: 0.5rem !important;\n  }\n  .mb-md-2,\n  .my-md-2 {\n    margin-bottom: 0.5rem !important;\n  }\n  .ml-md-2,\n  .mx-md-2 {\n    margin-left: 0.5rem !important;\n  }\n  .m-md-3 {\n    margin: 1rem !important;\n  }\n  .mt-md-3,\n  .my-md-3 {\n    margin-top: 1rem !important;\n  }\n  .mr-md-3,\n  .mx-md-3 {\n    margin-right: 1rem !important;\n  }\n  .mb-md-3,\n  .my-md-3 {\n    margin-bottom: 1rem !important;\n  }\n  .ml-md-3,\n  .mx-md-3 {\n    margin-left: 1rem !important;\n  }\n  .m-md-4 {\n    margin: 1.5rem !important;\n  }\n  .mt-md-4,\n  .my-md-4 {\n    margin-top: 1.5rem !important;\n  }\n  .mr-md-4,\n  .mx-md-4 {\n    margin-right: 1.5rem !important;\n  }\n  .mb-md-4,\n  .my-md-4 {\n    margin-bottom: 1.5rem !important;\n  }\n  .ml-md-4,\n  .mx-md-4 {\n    margin-left: 1.5rem !important;\n  }\n  .m-md-5 {\n    margin: 3rem !important;\n  }\n  .mt-md-5,\n  .my-md-5 {\n    margin-top: 3rem !important;\n  }\n  .mr-md-5,\n  .mx-md-5 {\n    margin-right: 3rem !important;\n  }\n  .mb-md-5,\n  .my-md-5 {\n    margin-bottom: 3rem !important;\n  }\n  .ml-md-5,\n  .mx-md-5 {\n    margin-left: 3rem !important;\n  }\n  .p-md-0 {\n    padding: 0 !important;\n  }\n  .pt-md-0,\n  .py-md-0 {\n    padding-top: 0 !important;\n  }\n  .pr-md-0,\n  .px-md-0 {\n    padding-right: 0 !important;\n  }\n  .pb-md-0,\n  .py-md-0 {\n    padding-bottom: 0 !important;\n  }\n  .pl-md-0,\n  .px-md-0 {\n    padding-left: 0 !important;\n  }\n  .p-md-1 {\n    padding: 0.25rem !important;\n  }\n  .pt-md-1,\n  .py-md-1 {\n    padding-top: 0.25rem !important;\n  }\n  .pr-md-1,\n  .px-md-1 {\n    padding-right: 0.25rem !important;\n  }\n  .pb-md-1,\n  .py-md-1 {\n    padding-bottom: 0.25rem !important;\n  }\n  .pl-md-1,\n  .px-md-1 {\n    padding-left: 0.25rem !important;\n  }\n  .p-md-2 {\n    padding: 0.5rem !important;\n  }\n  .pt-md-2,\n  .py-md-2 {\n    padding-top: 0.5rem !important;\n  }\n  .pr-md-2,\n  .px-md-2 {\n    padding-right: 0.5rem !important;\n  }\n  .pb-md-2,\n  .py-md-2 {\n    padding-bottom: 0.5rem !important;\n  }\n  .pl-md-2,\n  .px-md-2 {\n    padding-left: 0.5rem !important;\n  }\n  .p-md-3 {\n    padding: 1rem !important;\n  }\n  .pt-md-3,\n  .py-md-3 {\n    padding-top: 1rem !important;\n  }\n  .pr-md-3,\n  .px-md-3 {\n    padding-right: 1rem !important;\n  }\n  .pb-md-3,\n  .py-md-3 {\n    padding-bottom: 1rem !important;\n  }\n  .pl-md-3,\n  .px-md-3 {\n    padding-left: 1rem !important;\n  }\n  .p-md-4 {\n    padding: 1.5rem !important;\n  }\n  .pt-md-4,\n  .py-md-4 {\n    padding-top: 1.5rem !important;\n  }\n  .pr-md-4,\n  .px-md-4 {\n    padding-right: 1.5rem !important;\n  }\n  .pb-md-4,\n  .py-md-4 {\n    padding-bottom: 1.5rem !important;\n  }\n  .pl-md-4,\n  .px-md-4 {\n    padding-left: 1.5rem !important;\n  }\n  .p-md-5 {\n    padding: 3rem !important;\n  }\n  .pt-md-5,\n  .py-md-5 {\n    padding-top: 3rem !important;\n  }\n  .pr-md-5,\n  .px-md-5 {\n    padding-right: 3rem !important;\n  }\n  .pb-md-5,\n  .py-md-5 {\n    padding-bottom: 3rem !important;\n  }\n  .pl-md-5,\n  .px-md-5 {\n    padding-left: 3rem !important;\n  }\n  .m-md-n1 {\n    margin: -0.25rem !important;\n  }\n  .mt-md-n1,\n  .my-md-n1 {\n    margin-top: -0.25rem !important;\n  }\n  .mr-md-n1,\n  .mx-md-n1 {\n    margin-right: -0.25rem !important;\n  }\n  .mb-md-n1,\n  .my-md-n1 {\n    margin-bottom: -0.25rem !important;\n  }\n  .ml-md-n1,\n  .mx-md-n1 {\n    margin-left: -0.25rem !important;\n  }\n  .m-md-n2 {\n    margin: -0.5rem !important;\n  }\n  .mt-md-n2,\n  .my-md-n2 {\n    margin-top: -0.5rem !important;\n  }\n  .mr-md-n2,\n  .mx-md-n2 {\n    margin-right: -0.5rem !important;\n  }\n  .mb-md-n2,\n  .my-md-n2 {\n    margin-bottom: -0.5rem !important;\n  }\n  .ml-md-n2,\n  .mx-md-n2 {\n    margin-left: -0.5rem !important;\n  }\n  .m-md-n3 {\n    margin: -1rem !important;\n  }\n  .mt-md-n3,\n  .my-md-n3 {\n    margin-top: -1rem !important;\n  }\n  .mr-md-n3,\n  .mx-md-n3 {\n    margin-right: -1rem !important;\n  }\n  .mb-md-n3,\n  .my-md-n3 {\n    margin-bottom: -1rem !important;\n  }\n  .ml-md-n3,\n  .mx-md-n3 {\n    margin-left: -1rem !important;\n  }\n  .m-md-n4 {\n    margin: -1.5rem !important;\n  }\n  .mt-md-n4,\n  .my-md-n4 {\n    margin-top: -1.5rem !important;\n  }\n  .mr-md-n4,\n  .mx-md-n4 {\n    margin-right: -1.5rem !important;\n  }\n  .mb-md-n4,\n  .my-md-n4 {\n    margin-bottom: -1.5rem !important;\n  }\n  .ml-md-n4,\n  .mx-md-n4 {\n    margin-left: -1.5rem !important;\n  }\n  .m-md-n5 {\n    margin: -3rem !important;\n  }\n  .mt-md-n5,\n  .my-md-n5 {\n    margin-top: -3rem !important;\n  }\n  .mr-md-n5,\n  .mx-md-n5 {\n    margin-right: -3rem !important;\n  }\n  .mb-md-n5,\n  .my-md-n5 {\n    margin-bottom: -3rem !important;\n  }\n  .ml-md-n5,\n  .mx-md-n5 {\n    margin-left: -3rem !important;\n  }\n  .m-md-auto {\n    margin: auto !important;\n  }\n  .mt-md-auto,\n  .my-md-auto {\n    margin-top: auto !important;\n  }\n  .mr-md-auto,\n  .mx-md-auto {\n    margin-right: auto !important;\n  }\n  .mb-md-auto,\n  .my-md-auto {\n    margin-bottom: auto !important;\n  }\n  .ml-md-auto,\n  .mx-md-auto {\n    margin-left: auto !important;\n  }\n}\n\n@media (min-width: 992px) {\n  .m-lg-0 {\n    margin: 0 !important;\n  }\n  .mt-lg-0,\n  .my-lg-0 {\n    margin-top: 0 !important;\n  }\n  .mr-lg-0,\n  .mx-lg-0 {\n    margin-right: 0 !important;\n  }\n  .mb-lg-0,\n  .my-lg-0 {\n    margin-bottom: 0 !important;\n  }\n  .ml-lg-0,\n  .mx-lg-0 {\n    margin-left: 0 !important;\n  }\n  .m-lg-1 {\n    margin: 0.25rem !important;\n  }\n  .mt-lg-1,\n  .my-lg-1 {\n    margin-top: 0.25rem !important;\n  }\n  .mr-lg-1,\n  .mx-lg-1 {\n    margin-right: 0.25rem !important;\n  }\n  .mb-lg-1,\n  .my-lg-1 {\n    margin-bottom: 0.25rem !important;\n  }\n  .ml-lg-1,\n  .mx-lg-1 {\n    margin-left: 0.25rem !important;\n  }\n  .m-lg-2 {\n    margin: 0.5rem !important;\n  }\n  .mt-lg-2,\n  .my-lg-2 {\n    margin-top: 0.5rem !important;\n  }\n  .mr-lg-2,\n  .mx-lg-2 {\n    margin-right: 0.5rem !important;\n  }\n  .mb-lg-2,\n  .my-lg-2 {\n    margin-bottom: 0.5rem !important;\n  }\n  .ml-lg-2,\n  .mx-lg-2 {\n    margin-left: 0.5rem !important;\n  }\n  .m-lg-3 {\n    margin: 1rem !important;\n  }\n  .mt-lg-3,\n  .my-lg-3 {\n    margin-top: 1rem !important;\n  }\n  .mr-lg-3,\n  .mx-lg-3 {\n    margin-right: 1rem !important;\n  }\n  .mb-lg-3,\n  .my-lg-3 {\n    margin-bottom: 1rem !important;\n  }\n  .ml-lg-3,\n  .mx-lg-3 {\n    margin-left: 1rem !important;\n  }\n  .m-lg-4 {\n    margin: 1.5rem !important;\n  }\n  .mt-lg-4,\n  .my-lg-4 {\n    margin-top: 1.5rem !important;\n  }\n  .mr-lg-4,\n  .mx-lg-4 {\n    margin-right: 1.5rem !important;\n  }\n  .mb-lg-4,\n  .my-lg-4 {\n    margin-bottom: 1.5rem !important;\n  }\n  .ml-lg-4,\n  .mx-lg-4 {\n    margin-left: 1.5rem !important;\n  }\n  .m-lg-5 {\n    margin: 3rem !important;\n  }\n  .mt-lg-5,\n  .my-lg-5 {\n    margin-top: 3rem !important;\n  }\n  .mr-lg-5,\n  .mx-lg-5 {\n    margin-right: 3rem !important;\n  }\n  .mb-lg-5,\n  .my-lg-5 {\n    margin-bottom: 3rem !important;\n  }\n  .ml-lg-5,\n  .mx-lg-5 {\n    margin-left: 3rem !important;\n  }\n  .p-lg-0 {\n    padding: 0 !important;\n  }\n  .pt-lg-0,\n  .py-lg-0 {\n    padding-top: 0 !important;\n  }\n  .pr-lg-0,\n  .px-lg-0 {\n    padding-right: 0 !important;\n  }\n  .pb-lg-0,\n  .py-lg-0 {\n    padding-bottom: 0 !important;\n  }\n  .pl-lg-0,\n  .px-lg-0 {\n    padding-left: 0 !important;\n  }\n  .p-lg-1 {\n    padding: 0.25rem !important;\n  }\n  .pt-lg-1,\n  .py-lg-1 {\n    padding-top: 0.25rem !important;\n  }\n  .pr-lg-1,\n  .px-lg-1 {\n    padding-right: 0.25rem !important;\n  }\n  .pb-lg-1,\n  .py-lg-1 {\n    padding-bottom: 0.25rem !important;\n  }\n  .pl-lg-1,\n  .px-lg-1 {\n    padding-left: 0.25rem !important;\n  }\n  .p-lg-2 {\n    padding: 0.5rem !important;\n  }\n  .pt-lg-2,\n  .py-lg-2 {\n    padding-top: 0.5rem !important;\n  }\n  .pr-lg-2,\n  .px-lg-2 {\n    padding-right: 0.5rem !important;\n  }\n  .pb-lg-2,\n  .py-lg-2 {\n    padding-bottom: 0.5rem !important;\n  }\n  .pl-lg-2,\n  .px-lg-2 {\n    padding-left: 0.5rem !important;\n  }\n  .p-lg-3 {\n    padding: 1rem !important;\n  }\n  .pt-lg-3,\n  .py-lg-3 {\n    padding-top: 1rem !important;\n  }\n  .pr-lg-3,\n  .px-lg-3 {\n    padding-right: 1rem !important;\n  }\n  .pb-lg-3,\n  .py-lg-3 {\n    padding-bottom: 1rem !important;\n  }\n  .pl-lg-3,\n  .px-lg-3 {\n    padding-left: 1rem !important;\n  }\n  .p-lg-4 {\n    padding: 1.5rem !important;\n  }\n  .pt-lg-4,\n  .py-lg-4 {\n    padding-top: 1.5rem !important;\n  }\n  .pr-lg-4,\n  .px-lg-4 {\n    padding-right: 1.5rem !important;\n  }\n  .pb-lg-4,\n  .py-lg-4 {\n    padding-bottom: 1.5rem !important;\n  }\n  .pl-lg-4,\n  .px-lg-4 {\n    padding-left: 1.5rem !important;\n  }\n  .p-lg-5 {\n    padding: 3rem !important;\n  }\n  .pt-lg-5,\n  .py-lg-5 {\n    padding-top: 3rem !important;\n  }\n  .pr-lg-5,\n  .px-lg-5 {\n    padding-right: 3rem !important;\n  }\n  .pb-lg-5,\n  .py-lg-5 {\n    padding-bottom: 3rem !important;\n  }\n  .pl-lg-5,\n  .px-lg-5 {\n    padding-left: 3rem !important;\n  }\n  .m-lg-n1 {\n    margin: -0.25rem !important;\n  }\n  .mt-lg-n1,\n  .my-lg-n1 {\n    margin-top: -0.25rem !important;\n  }\n  .mr-lg-n1,\n  .mx-lg-n1 {\n    margin-right: -0.25rem !important;\n  }\n  .mb-lg-n1,\n  .my-lg-n1 {\n    margin-bottom: -0.25rem !important;\n  }\n  .ml-lg-n1,\n  .mx-lg-n1 {\n    margin-left: -0.25rem !important;\n  }\n  .m-lg-n2 {\n    margin: -0.5rem !important;\n  }\n  .mt-lg-n2,\n  .my-lg-n2 {\n    margin-top: -0.5rem !important;\n  }\n  .mr-lg-n2,\n  .mx-lg-n2 {\n    margin-right: -0.5rem !important;\n  }\n  .mb-lg-n2,\n  .my-lg-n2 {\n    margin-bottom: -0.5rem !important;\n  }\n  .ml-lg-n2,\n  .mx-lg-n2 {\n    margin-left: -0.5rem !important;\n  }\n  .m-lg-n3 {\n    margin: -1rem !important;\n  }\n  .mt-lg-n3,\n  .my-lg-n3 {\n    margin-top: -1rem !important;\n  }\n  .mr-lg-n3,\n  .mx-lg-n3 {\n    margin-right: -1rem !important;\n  }\n  .mb-lg-n3,\n  .my-lg-n3 {\n    margin-bottom: -1rem !important;\n  }\n  .ml-lg-n3,\n  .mx-lg-n3 {\n    margin-left: -1rem !important;\n  }\n  .m-lg-n4 {\n    margin: -1.5rem !important;\n  }\n  .mt-lg-n4,\n  .my-lg-n4 {\n    margin-top: -1.5rem !important;\n  }\n  .mr-lg-n4,\n  .mx-lg-n4 {\n    margin-right: -1.5rem !important;\n  }\n  .mb-lg-n4,\n  .my-lg-n4 {\n    margin-bottom: -1.5rem !important;\n  }\n  .ml-lg-n4,\n  .mx-lg-n4 {\n    margin-left: -1.5rem !important;\n  }\n  .m-lg-n5 {\n    margin: -3rem !important;\n  }\n  .mt-lg-n5,\n  .my-lg-n5 {\n    margin-top: -3rem !important;\n  }\n  .mr-lg-n5,\n  .mx-lg-n5 {\n    margin-right: -3rem !important;\n  }\n  .mb-lg-n5,\n  .my-lg-n5 {\n    margin-bottom: -3rem !important;\n  }\n  .ml-lg-n5,\n  .mx-lg-n5 {\n    margin-left: -3rem !important;\n  }\n  .m-lg-auto {\n    margin: auto !important;\n  }\n  .mt-lg-auto,\n  .my-lg-auto {\n    margin-top: auto !important;\n  }\n  .mr-lg-auto,\n  .mx-lg-auto {\n    margin-right: auto !important;\n  }\n  .mb-lg-auto,\n  .my-lg-auto {\n    margin-bottom: auto !important;\n  }\n  .ml-lg-auto,\n  .mx-lg-auto {\n    margin-left: auto !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .m-xl-0 {\n    margin: 0 !important;\n  }\n  .mt-xl-0,\n  .my-xl-0 {\n    margin-top: 0 !important;\n  }\n  .mr-xl-0,\n  .mx-xl-0 {\n    margin-right: 0 !important;\n  }\n  .mb-xl-0,\n  .my-xl-0 {\n    margin-bottom: 0 !important;\n  }\n  .ml-xl-0,\n  .mx-xl-0 {\n    margin-left: 0 !important;\n  }\n  .m-xl-1 {\n    margin: 0.25rem !important;\n  }\n  .mt-xl-1,\n  .my-xl-1 {\n    margin-top: 0.25rem !important;\n  }\n  .mr-xl-1,\n  .mx-xl-1 {\n    margin-right: 0.25rem !important;\n  }\n  .mb-xl-1,\n  .my-xl-1 {\n    margin-bottom: 0.25rem !important;\n  }\n  .ml-xl-1,\n  .mx-xl-1 {\n    margin-left: 0.25rem !important;\n  }\n  .m-xl-2 {\n    margin: 0.5rem !important;\n  }\n  .mt-xl-2,\n  .my-xl-2 {\n    margin-top: 0.5rem !important;\n  }\n  .mr-xl-2,\n  .mx-xl-2 {\n    margin-right: 0.5rem !important;\n  }\n  .mb-xl-2,\n  .my-xl-2 {\n    margin-bottom: 0.5rem !important;\n  }\n  .ml-xl-2,\n  .mx-xl-2 {\n    margin-left: 0.5rem !important;\n  }\n  .m-xl-3 {\n    margin: 1rem !important;\n  }\n  .mt-xl-3,\n  .my-xl-3 {\n    margin-top: 1rem !important;\n  }\n  .mr-xl-3,\n  .mx-xl-3 {\n    margin-right: 1rem !important;\n  }\n  .mb-xl-3,\n  .my-xl-3 {\n    margin-bottom: 1rem !important;\n  }\n  .ml-xl-3,\n  .mx-xl-3 {\n    margin-left: 1rem !important;\n  }\n  .m-xl-4 {\n    margin: 1.5rem !important;\n  }\n  .mt-xl-4,\n  .my-xl-4 {\n    margin-top: 1.5rem !important;\n  }\n  .mr-xl-4,\n  .mx-xl-4 {\n    margin-right: 1.5rem !important;\n  }\n  .mb-xl-4,\n  .my-xl-4 {\n    margin-bottom: 1.5rem !important;\n  }\n  .ml-xl-4,\n  .mx-xl-4 {\n    margin-left: 1.5rem !important;\n  }\n  .m-xl-5 {\n    margin: 3rem !important;\n  }\n  .mt-xl-5,\n  .my-xl-5 {\n    margin-top: 3rem !important;\n  }\n  .mr-xl-5,\n  .mx-xl-5 {\n    margin-right: 3rem !important;\n  }\n  .mb-xl-5,\n  .my-xl-5 {\n    margin-bottom: 3rem !important;\n  }\n  .ml-xl-5,\n  .mx-xl-5 {\n    margin-left: 3rem !important;\n  }\n  .p-xl-0 {\n    padding: 0 !important;\n  }\n  .pt-xl-0,\n  .py-xl-0 {\n    padding-top: 0 !important;\n  }\n  .pr-xl-0,\n  .px-xl-0 {\n    padding-right: 0 !important;\n  }\n  .pb-xl-0,\n  .py-xl-0 {\n    padding-bottom: 0 !important;\n  }\n  .pl-xl-0,\n  .px-xl-0 {\n    padding-left: 0 !important;\n  }\n  .p-xl-1 {\n    padding: 0.25rem !important;\n  }\n  .pt-xl-1,\n  .py-xl-1 {\n    padding-top: 0.25rem !important;\n  }\n  .pr-xl-1,\n  .px-xl-1 {\n    padding-right: 0.25rem !important;\n  }\n  .pb-xl-1,\n  .py-xl-1 {\n    padding-bottom: 0.25rem !important;\n  }\n  .pl-xl-1,\n  .px-xl-1 {\n    padding-left: 0.25rem !important;\n  }\n  .p-xl-2 {\n    padding: 0.5rem !important;\n  }\n  .pt-xl-2,\n  .py-xl-2 {\n    padding-top: 0.5rem !important;\n  }\n  .pr-xl-2,\n  .px-xl-2 {\n    padding-right: 0.5rem !important;\n  }\n  .pb-xl-2,\n  .py-xl-2 {\n    padding-bottom: 0.5rem !important;\n  }\n  .pl-xl-2,\n  .px-xl-2 {\n    padding-left: 0.5rem !important;\n  }\n  .p-xl-3 {\n    padding: 1rem !important;\n  }\n  .pt-xl-3,\n  .py-xl-3 {\n    padding-top: 1rem !important;\n  }\n  .pr-xl-3,\n  .px-xl-3 {\n    padding-right: 1rem !important;\n  }\n  .pb-xl-3,\n  .py-xl-3 {\n    padding-bottom: 1rem !important;\n  }\n  .pl-xl-3,\n  .px-xl-3 {\n    padding-left: 1rem !important;\n  }\n  .p-xl-4 {\n    padding: 1.5rem !important;\n  }\n  .pt-xl-4,\n  .py-xl-4 {\n    padding-top: 1.5rem !important;\n  }\n  .pr-xl-4,\n  .px-xl-4 {\n    padding-right: 1.5rem !important;\n  }\n  .pb-xl-4,\n  .py-xl-4 {\n    padding-bottom: 1.5rem !important;\n  }\n  .pl-xl-4,\n  .px-xl-4 {\n    padding-left: 1.5rem !important;\n  }\n  .p-xl-5 {\n    padding: 3rem !important;\n  }\n  .pt-xl-5,\n  .py-xl-5 {\n    padding-top: 3rem !important;\n  }\n  .pr-xl-5,\n  .px-xl-5 {\n    padding-right: 3rem !important;\n  }\n  .pb-xl-5,\n  .py-xl-5 {\n    padding-bottom: 3rem !important;\n  }\n  .pl-xl-5,\n  .px-xl-5 {\n    padding-left: 3rem !important;\n  }\n  .m-xl-n1 {\n    margin: -0.25rem !important;\n  }\n  .mt-xl-n1,\n  .my-xl-n1 {\n    margin-top: -0.25rem !important;\n  }\n  .mr-xl-n1,\n  .mx-xl-n1 {\n    margin-right: -0.25rem !important;\n  }\n  .mb-xl-n1,\n  .my-xl-n1 {\n    margin-bottom: -0.25rem !important;\n  }\n  .ml-xl-n1,\n  .mx-xl-n1 {\n    margin-left: -0.25rem !important;\n  }\n  .m-xl-n2 {\n    margin: -0.5rem !important;\n  }\n  .mt-xl-n2,\n  .my-xl-n2 {\n    margin-top: -0.5rem !important;\n  }\n  .mr-xl-n2,\n  .mx-xl-n2 {\n    margin-right: -0.5rem !important;\n  }\n  .mb-xl-n2,\n  .my-xl-n2 {\n    margin-bottom: -0.5rem !important;\n  }\n  .ml-xl-n2,\n  .mx-xl-n2 {\n    margin-left: -0.5rem !important;\n  }\n  .m-xl-n3 {\n    margin: -1rem !important;\n  }\n  .mt-xl-n3,\n  .my-xl-n3 {\n    margin-top: -1rem !important;\n  }\n  .mr-xl-n3,\n  .mx-xl-n3 {\n    margin-right: -1rem !important;\n  }\n  .mb-xl-n3,\n  .my-xl-n3 {\n    margin-bottom: -1rem !important;\n  }\n  .ml-xl-n3,\n  .mx-xl-n3 {\n    margin-left: -1rem !important;\n  }\n  .m-xl-n4 {\n    margin: -1.5rem !important;\n  }\n  .mt-xl-n4,\n  .my-xl-n4 {\n    margin-top: -1.5rem !important;\n  }\n  .mr-xl-n4,\n  .mx-xl-n4 {\n    margin-right: -1.5rem !important;\n  }\n  .mb-xl-n4,\n  .my-xl-n4 {\n    margin-bottom: -1.5rem !important;\n  }\n  .ml-xl-n4,\n  .mx-xl-n4 {\n    margin-left: -1.5rem !important;\n  }\n  .m-xl-n5 {\n    margin: -3rem !important;\n  }\n  .mt-xl-n5,\n  .my-xl-n5 {\n    margin-top: -3rem !important;\n  }\n  .mr-xl-n5,\n  .mx-xl-n5 {\n    margin-right: -3rem !important;\n  }\n  .mb-xl-n5,\n  .my-xl-n5 {\n    margin-bottom: -3rem !important;\n  }\n  .ml-xl-n5,\n  .mx-xl-n5 {\n    margin-left: -3rem !important;\n  }\n  .m-xl-auto {\n    margin: auto !important;\n  }\n  .mt-xl-auto,\n  .my-xl-auto {\n    margin-top: auto !important;\n  }\n  .mr-xl-auto,\n  .mx-xl-auto {\n    margin-right: auto !important;\n  }\n  .mb-xl-auto,\n  .my-xl-auto {\n    margin-bottom: auto !important;\n  }\n  .ml-xl-auto,\n  .mx-xl-auto {\n    margin-left: auto !important;\n  }\n}\n\n.text-monospace {\n  font-family: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace !important;\n}\n\n.text-justify {\n  text-align: justify !important;\n}\n\n.text-wrap {\n  white-space: normal !important;\n}\n\n.text-nowrap {\n  white-space: nowrap !important;\n}\n\n.text-truncate {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.text-left {\n  text-align: left !important;\n}\n\n.text-right {\n  text-align: right !important;\n}\n\n.text-center {\n  text-align: center !important;\n}\n\n@media (min-width: 576px) {\n  .text-sm-left {\n    text-align: left !important;\n  }\n  .text-sm-right {\n    text-align: right !important;\n  }\n  .text-sm-center {\n    text-align: center !important;\n  }\n}\n\n@media (min-width: 768px) {\n  .text-md-left {\n    text-align: left !important;\n  }\n  .text-md-right {\n    text-align: right !important;\n  }\n  .text-md-center {\n    text-align: center !important;\n  }\n}\n\n@media (min-width: 992px) {\n  .text-lg-left {\n    text-align: left !important;\n  }\n  .text-lg-right {\n    text-align: right !important;\n  }\n  .text-lg-center {\n    text-align: center !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .text-xl-left {\n    text-align: left !important;\n  }\n  .text-xl-right {\n    text-align: right !important;\n  }\n  .text-xl-center {\n    text-align: center !important;\n  }\n}\n\n.text-lowercase {\n  text-transform: lowercase !important;\n}\n\n.text-uppercase {\n  text-transform: uppercase !important;\n}\n\n.text-capitalize {\n  text-transform: capitalize !important;\n}\n\n.font-weight-light {\n  font-weight: 300 !important;\n}\n\n.font-weight-lighter {\n  font-weight: lighter !important;\n}\n\n.font-weight-normal {\n  font-weight: 400 !important;\n}\n\n.font-weight-bold {\n  font-weight: 700 !important;\n}\n\n.font-weight-bolder {\n  font-weight: bolder !important;\n}\n\n.font-italic {\n  font-style: italic !important;\n}\n\n.text-white {\n  color: #fff !important;\n}\n\n.text-primary {\n  color: #007bff !important;\n}\n\na.text-primary:hover, a.text-primary:focus {\n  color: #0056b3 !important;\n}\n\n.text-secondary {\n  color: #6c757d !important;\n}\n\na.text-secondary:hover, a.text-secondary:focus {\n  color: #494f54 !important;\n}\n\n.text-success {\n  color: #28a745 !important;\n}\n\na.text-success:hover, a.text-success:focus {\n  color: #19692c !important;\n}\n\n.text-info {\n  color: #17a2b8 !important;\n}\n\na.text-info:hover, a.text-info:focus {\n  color: #0f6674 !important;\n}\n\n.text-warning {\n  color: #ffc107 !important;\n}\n\na.text-warning:hover, a.text-warning:focus {\n  color: #ba8b00 !important;\n}\n\n.text-danger {\n  color: #dc3545 !important;\n}\n\na.text-danger:hover, a.text-danger:focus {\n  color: #a71d2a !important;\n}\n\n.text-light {\n  color: #f8f9fa !important;\n}\n\na.text-light:hover, a.text-light:focus {\n  color: #cbd3da !important;\n}\n\n.text-dark {\n  color: #343a40 !important;\n}\n\na.text-dark:hover, a.text-dark:focus {\n  color: #121416 !important;\n}\n\n.text-body {\n  color: #212529 !important;\n}\n\n.text-muted {\n  color: #6c757d !important;\n}\n\n.text-black-50 {\n  color: rgba(0, 0, 0, 0.5) !important;\n}\n\n.text-white-50 {\n  color: rgba(255, 255, 255, 0.5) !important;\n}\n\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n.text-decoration-none {\n  text-decoration: none !important;\n}\n\n.text-break {\n  word-break: break-word !important;\n  overflow-wrap: break-word !important;\n}\n\n.text-reset {\n  color: inherit !important;\n}\n\n.visible {\n  visibility: visible !important;\n}\n\n.invisible {\n  visibility: hidden !important;\n}\n\n@media print {\n  *,\n  *::before,\n  *::after {\n    text-shadow: none !important;\n    box-shadow: none !important;\n  }\n  a:not(.btn) {\n    text-decoration: underline;\n  }\n  abbr[title]::after {\n    content: \" (\" attr(title) \")\";\n  }\n  pre {\n    white-space: pre-wrap !important;\n  }\n  pre,\n  blockquote {\n    border: 1px solid #adb5bd;\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  @page {\n    size: a3;\n  }\n  body {\n    min-width: 992px !important;\n  }\n  .container {\n    min-width: 992px !important;\n  }\n  .navbar {\n    display: none;\n  }\n  .badge {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #dee2e6 !important;\n  }\n  .table-dark {\n    color: inherit;\n  }\n  .table-dark th,\n  .table-dark td,\n  .table-dark thead th,\n  .table-dark tbody + tbody {\n    border-color: #dee2e6;\n  }\n  .table .thead-dark th {\n    color: inherit;\n    border-color: #dee2e6;\n  }\n}\n/*# sourceMappingURL=bootstrap.css.map */"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js",
    "content": "/*!\n  * Bootstrap v4.3.1 (https://getbootstrap.com/)\n  * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n  */\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery')) :\n  typeof define === 'function' && define.amd ? define(['exports', 'jquery'], factory) :\n  (global = global || self, factory(global.bootstrap = {}, global.jQuery));\n}(this, function (exports, $) { 'use strict';\n\n  $ = $ && $.hasOwnProperty('default') ? $['default'] : $;\n\n  function _defineProperties(target, props) {\n    for (var i = 0; i < props.length; i++) {\n      var descriptor = props[i];\n      descriptor.enumerable = descriptor.enumerable || false;\n      descriptor.configurable = true;\n      if (\"value\" in descriptor) descriptor.writable = true;\n      Object.defineProperty(target, descriptor.key, descriptor);\n    }\n  }\n\n  function _createClass(Constructor, protoProps, staticProps) {\n    if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n    if (staticProps) _defineProperties(Constructor, staticProps);\n    return Constructor;\n  }\n\n  function _defineProperty(obj, key, value) {\n    if (key in obj) {\n      Object.defineProperty(obj, key, {\n        value: value,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      });\n    } else {\n      obj[key] = value;\n    }\n\n    return obj;\n  }\n\n  function _objectSpread(target) {\n    for (var i = 1; i < arguments.length; i++) {\n      var source = arguments[i] != null ? arguments[i] : {};\n      var ownKeys = Object.keys(source);\n\n      if (typeof Object.getOwnPropertySymbols === 'function') {\n        ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {\n          return Object.getOwnPropertyDescriptor(source, sym).enumerable;\n        }));\n      }\n\n      ownKeys.forEach(function (key) {\n        _defineProperty(target, key, source[key]);\n      });\n    }\n\n    return target;\n  }\n\n  function _inheritsLoose(subClass, superClass) {\n    subClass.prototype = Object.create(superClass.prototype);\n    subClass.prototype.constructor = subClass;\n    subClass.__proto__ = superClass;\n  }\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.3.1): util.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n  /**\n   * ------------------------------------------------------------------------\n   * Private TransitionEnd Helpers\n   * ------------------------------------------------------------------------\n   */\n\n  var TRANSITION_END = 'transitionend';\n  var MAX_UID = 1000000;\n  var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)\n\n  function toType(obj) {\n    return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase();\n  }\n\n  function getSpecialTransitionEndEvent() {\n    return {\n      bindType: TRANSITION_END,\n      delegateType: TRANSITION_END,\n      handle: function handle(event) {\n        if ($(event.target).is(this)) {\n          return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params\n        }\n\n        return undefined; // eslint-disable-line no-undefined\n      }\n    };\n  }\n\n  function transitionEndEmulator(duration) {\n    var _this = this;\n\n    var called = false;\n    $(this).one(Util.TRANSITION_END, function () {\n      called = true;\n    });\n    setTimeout(function () {\n      if (!called) {\n        Util.triggerTransitionEnd(_this);\n      }\n    }, duration);\n    return this;\n  }\n\n  function setTransitionEndSupport() {\n    $.fn.emulateTransitionEnd = transitionEndEmulator;\n    $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();\n  }\n  /**\n   * --------------------------------------------------------------------------\n   * Public Util Api\n   * --------------------------------------------------------------------------\n   */\n\n\n  var Util = {\n    TRANSITION_END: 'bsTransitionEnd',\n    getUID: function getUID(prefix) {\n      do {\n        // eslint-disable-next-line no-bitwise\n        prefix += ~~(Math.random() * MAX_UID); // \"~~\" acts like a faster Math.floor() here\n      } while (document.getElementById(prefix));\n\n      return prefix;\n    },\n    getSelectorFromElement: function getSelectorFromElement(element) {\n      var selector = element.getAttribute('data-target');\n\n      if (!selector || selector === '#') {\n        var hrefAttr = element.getAttribute('href');\n        selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '';\n      }\n\n      try {\n        return document.querySelector(selector) ? selector : null;\n      } catch (err) {\n        return null;\n      }\n    },\n    getTransitionDurationFromElement: function getTransitionDurationFromElement(element) {\n      if (!element) {\n        return 0;\n      } // Get transition-duration of the element\n\n\n      var transitionDuration = $(element).css('transition-duration');\n      var transitionDelay = $(element).css('transition-delay');\n      var floatTransitionDuration = parseFloat(transitionDuration);\n      var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found\n\n      if (!floatTransitionDuration && !floatTransitionDelay) {\n        return 0;\n      } // If multiple durations are defined, take the first\n\n\n      transitionDuration = transitionDuration.split(',')[0];\n      transitionDelay = transitionDelay.split(',')[0];\n      return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;\n    },\n    reflow: function reflow(element) {\n      return element.offsetHeight;\n    },\n    triggerTransitionEnd: function triggerTransitionEnd(element) {\n      $(element).trigger(TRANSITION_END);\n    },\n    // TODO: Remove in v5\n    supportsTransitionEnd: function supportsTransitionEnd() {\n      return Boolean(TRANSITION_END);\n    },\n    isElement: function isElement(obj) {\n      return (obj[0] || obj).nodeType;\n    },\n    typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {\n      for (var property in configTypes) {\n        if (Object.prototype.hasOwnProperty.call(configTypes, property)) {\n          var expectedTypes = configTypes[property];\n          var value = config[property];\n          var valueType = value && Util.isElement(value) ? 'element' : toType(value);\n\n          if (!new RegExp(expectedTypes).test(valueType)) {\n            throw new Error(componentName.toUpperCase() + \": \" + (\"Option \\\"\" + property + \"\\\" provided type \\\"\" + valueType + \"\\\" \") + (\"but expected type \\\"\" + expectedTypes + \"\\\".\"));\n          }\n        }\n      }\n    },\n    findShadowRoot: function findShadowRoot(element) {\n      if (!document.documentElement.attachShadow) {\n        return null;\n      } // Can find the shadow root otherwise it'll return the document\n\n\n      if (typeof element.getRootNode === 'function') {\n        var root = element.getRootNode();\n        return root instanceof ShadowRoot ? root : null;\n      }\n\n      if (element instanceof ShadowRoot) {\n        return element;\n      } // when we don't find a shadow root\n\n\n      if (!element.parentNode) {\n        return null;\n      }\n\n      return Util.findShadowRoot(element.parentNode);\n    }\n  };\n  setTransitionEndSupport();\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME = 'alert';\n  var VERSION = '4.3.1';\n  var DATA_KEY = 'bs.alert';\n  var EVENT_KEY = \".\" + DATA_KEY;\n  var DATA_API_KEY = '.data-api';\n  var JQUERY_NO_CONFLICT = $.fn[NAME];\n  var Selector = {\n    DISMISS: '[data-dismiss=\"alert\"]'\n  };\n  var Event = {\n    CLOSE: \"close\" + EVENT_KEY,\n    CLOSED: \"closed\" + EVENT_KEY,\n    CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY\n  };\n  var ClassName = {\n    ALERT: 'alert',\n    FADE: 'fade',\n    SHOW: 'show'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Alert =\n  /*#__PURE__*/\n  function () {\n    function Alert(element) {\n      this._element = element;\n    } // Getters\n\n\n    var _proto = Alert.prototype;\n\n    // Public\n    _proto.close = function close(element) {\n      var rootElement = this._element;\n\n      if (element) {\n        rootElement = this._getRootElement(element);\n      }\n\n      var customEvent = this._triggerCloseEvent(rootElement);\n\n      if (customEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      this._removeElement(rootElement);\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY);\n      this._element = null;\n    } // Private\n    ;\n\n    _proto._getRootElement = function _getRootElement(element) {\n      var selector = Util.getSelectorFromElement(element);\n      var parent = false;\n\n      if (selector) {\n        parent = document.querySelector(selector);\n      }\n\n      if (!parent) {\n        parent = $(element).closest(\".\" + ClassName.ALERT)[0];\n      }\n\n      return parent;\n    };\n\n    _proto._triggerCloseEvent = function _triggerCloseEvent(element) {\n      var closeEvent = $.Event(Event.CLOSE);\n      $(element).trigger(closeEvent);\n      return closeEvent;\n    };\n\n    _proto._removeElement = function _removeElement(element) {\n      var _this = this;\n\n      $(element).removeClass(ClassName.SHOW);\n\n      if (!$(element).hasClass(ClassName.FADE)) {\n        this._destroyElement(element);\n\n        return;\n      }\n\n      var transitionDuration = Util.getTransitionDurationFromElement(element);\n      $(element).one(Util.TRANSITION_END, function (event) {\n        return _this._destroyElement(element, event);\n      }).emulateTransitionEnd(transitionDuration);\n    };\n\n    _proto._destroyElement = function _destroyElement(element) {\n      $(element).detach().trigger(Event.CLOSED).remove();\n    } // Static\n    ;\n\n    Alert._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var $element = $(this);\n        var data = $element.data(DATA_KEY);\n\n        if (!data) {\n          data = new Alert(this);\n          $element.data(DATA_KEY, data);\n        }\n\n        if (config === 'close') {\n          data[config](this);\n        }\n      });\n    };\n\n    Alert._handleDismiss = function _handleDismiss(alertInstance) {\n      return function (event) {\n        if (event) {\n          event.preventDefault();\n        }\n\n        alertInstance.close(this);\n      };\n    };\n\n    _createClass(Alert, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION;\n      }\n    }]);\n\n    return Alert;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME] = Alert._jQueryInterface;\n  $.fn[NAME].Constructor = Alert;\n\n  $.fn[NAME].noConflict = function () {\n    $.fn[NAME] = JQUERY_NO_CONFLICT;\n    return Alert._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$1 = 'button';\n  var VERSION$1 = '4.3.1';\n  var DATA_KEY$1 = 'bs.button';\n  var EVENT_KEY$1 = \".\" + DATA_KEY$1;\n  var DATA_API_KEY$1 = '.data-api';\n  var JQUERY_NO_CONFLICT$1 = $.fn[NAME$1];\n  var ClassName$1 = {\n    ACTIVE: 'active',\n    BUTTON: 'btn',\n    FOCUS: 'focus'\n  };\n  var Selector$1 = {\n    DATA_TOGGLE_CARROT: '[data-toggle^=\"button\"]',\n    DATA_TOGGLE: '[data-toggle=\"buttons\"]',\n    INPUT: 'input:not([type=\"hidden\"])',\n    ACTIVE: '.active',\n    BUTTON: '.btn'\n  };\n  var Event$1 = {\n    CLICK_DATA_API: \"click\" + EVENT_KEY$1 + DATA_API_KEY$1,\n    FOCUS_BLUR_DATA_API: \"focus\" + EVENT_KEY$1 + DATA_API_KEY$1 + \" \" + (\"blur\" + EVENT_KEY$1 + DATA_API_KEY$1)\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Button =\n  /*#__PURE__*/\n  function () {\n    function Button(element) {\n      this._element = element;\n    } // Getters\n\n\n    var _proto = Button.prototype;\n\n    // Public\n    _proto.toggle = function toggle() {\n      var triggerChangeEvent = true;\n      var addAriaPressed = true;\n      var rootElement = $(this._element).closest(Selector$1.DATA_TOGGLE)[0];\n\n      if (rootElement) {\n        var input = this._element.querySelector(Selector$1.INPUT);\n\n        if (input) {\n          if (input.type === 'radio') {\n            if (input.checked && this._element.classList.contains(ClassName$1.ACTIVE)) {\n              triggerChangeEvent = false;\n            } else {\n              var activeElement = rootElement.querySelector(Selector$1.ACTIVE);\n\n              if (activeElement) {\n                $(activeElement).removeClass(ClassName$1.ACTIVE);\n              }\n            }\n          }\n\n          if (triggerChangeEvent) {\n            if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) {\n              return;\n            }\n\n            input.checked = !this._element.classList.contains(ClassName$1.ACTIVE);\n            $(input).trigger('change');\n          }\n\n          input.focus();\n          addAriaPressed = false;\n        }\n      }\n\n      if (addAriaPressed) {\n        this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName$1.ACTIVE));\n      }\n\n      if (triggerChangeEvent) {\n        $(this._element).toggleClass(ClassName$1.ACTIVE);\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$1);\n      this._element = null;\n    } // Static\n    ;\n\n    Button._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$1);\n\n        if (!data) {\n          data = new Button(this);\n          $(this).data(DATA_KEY$1, data);\n        }\n\n        if (config === 'toggle') {\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Button, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$1;\n      }\n    }]);\n\n    return Button;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$1.CLICK_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {\n    event.preventDefault();\n    var button = event.target;\n\n    if (!$(button).hasClass(ClassName$1.BUTTON)) {\n      button = $(button).closest(Selector$1.BUTTON);\n    }\n\n    Button._jQueryInterface.call($(button), 'toggle');\n  }).on(Event$1.FOCUS_BLUR_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {\n    var button = $(event.target).closest(Selector$1.BUTTON)[0];\n    $(button).toggleClass(ClassName$1.FOCUS, /^focus(in)?$/.test(event.type));\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$1] = Button._jQueryInterface;\n  $.fn[NAME$1].Constructor = Button;\n\n  $.fn[NAME$1].noConflict = function () {\n    $.fn[NAME$1] = JQUERY_NO_CONFLICT$1;\n    return Button._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$2 = 'carousel';\n  var VERSION$2 = '4.3.1';\n  var DATA_KEY$2 = 'bs.carousel';\n  var EVENT_KEY$2 = \".\" + DATA_KEY$2;\n  var DATA_API_KEY$2 = '.data-api';\n  var JQUERY_NO_CONFLICT$2 = $.fn[NAME$2];\n  var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key\n\n  var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key\n\n  var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\n  var SWIPE_THRESHOLD = 40;\n  var Default = {\n    interval: 5000,\n    keyboard: true,\n    slide: false,\n    pause: 'hover',\n    wrap: true,\n    touch: true\n  };\n  var DefaultType = {\n    interval: '(number|boolean)',\n    keyboard: 'boolean',\n    slide: '(boolean|string)',\n    pause: '(string|boolean)',\n    wrap: 'boolean',\n    touch: 'boolean'\n  };\n  var Direction = {\n    NEXT: 'next',\n    PREV: 'prev',\n    LEFT: 'left',\n    RIGHT: 'right'\n  };\n  var Event$2 = {\n    SLIDE: \"slide\" + EVENT_KEY$2,\n    SLID: \"slid\" + EVENT_KEY$2,\n    KEYDOWN: \"keydown\" + EVENT_KEY$2,\n    MOUSEENTER: \"mouseenter\" + EVENT_KEY$2,\n    MOUSELEAVE: \"mouseleave\" + EVENT_KEY$2,\n    TOUCHSTART: \"touchstart\" + EVENT_KEY$2,\n    TOUCHMOVE: \"touchmove\" + EVENT_KEY$2,\n    TOUCHEND: \"touchend\" + EVENT_KEY$2,\n    POINTERDOWN: \"pointerdown\" + EVENT_KEY$2,\n    POINTERUP: \"pointerup\" + EVENT_KEY$2,\n    DRAG_START: \"dragstart\" + EVENT_KEY$2,\n    LOAD_DATA_API: \"load\" + EVENT_KEY$2 + DATA_API_KEY$2,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$2 + DATA_API_KEY$2\n  };\n  var ClassName$2 = {\n    CAROUSEL: 'carousel',\n    ACTIVE: 'active',\n    SLIDE: 'slide',\n    RIGHT: 'carousel-item-right',\n    LEFT: 'carousel-item-left',\n    NEXT: 'carousel-item-next',\n    PREV: 'carousel-item-prev',\n    ITEM: 'carousel-item',\n    POINTER_EVENT: 'pointer-event'\n  };\n  var Selector$2 = {\n    ACTIVE: '.active',\n    ACTIVE_ITEM: '.active.carousel-item',\n    ITEM: '.carousel-item',\n    ITEM_IMG: '.carousel-item img',\n    NEXT_PREV: '.carousel-item-next, .carousel-item-prev',\n    INDICATORS: '.carousel-indicators',\n    DATA_SLIDE: '[data-slide], [data-slide-to]',\n    DATA_RIDE: '[data-ride=\"carousel\"]'\n  };\n  var PointerType = {\n    TOUCH: 'touch',\n    PEN: 'pen'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Carousel =\n  /*#__PURE__*/\n  function () {\n    function Carousel(element, config) {\n      this._items = null;\n      this._interval = null;\n      this._activeElement = null;\n      this._isPaused = false;\n      this._isSliding = false;\n      this.touchTimeout = null;\n      this.touchStartX = 0;\n      this.touchDeltaX = 0;\n      this._config = this._getConfig(config);\n      this._element = element;\n      this._indicatorsElement = this._element.querySelector(Selector$2.INDICATORS);\n      this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;\n      this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent);\n\n      this._addEventListeners();\n    } // Getters\n\n\n    var _proto = Carousel.prototype;\n\n    // Public\n    _proto.next = function next() {\n      if (!this._isSliding) {\n        this._slide(Direction.NEXT);\n      }\n    };\n\n    _proto.nextWhenVisible = function nextWhenVisible() {\n      // Don't call next when the page isn't visible\n      // or the carousel or its parent isn't visible\n      if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') {\n        this.next();\n      }\n    };\n\n    _proto.prev = function prev() {\n      if (!this._isSliding) {\n        this._slide(Direction.PREV);\n      }\n    };\n\n    _proto.pause = function pause(event) {\n      if (!event) {\n        this._isPaused = true;\n      }\n\n      if (this._element.querySelector(Selector$2.NEXT_PREV)) {\n        Util.triggerTransitionEnd(this._element);\n        this.cycle(true);\n      }\n\n      clearInterval(this._interval);\n      this._interval = null;\n    };\n\n    _proto.cycle = function cycle(event) {\n      if (!event) {\n        this._isPaused = false;\n      }\n\n      if (this._interval) {\n        clearInterval(this._interval);\n        this._interval = null;\n      }\n\n      if (this._config.interval && !this._isPaused) {\n        this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);\n      }\n    };\n\n    _proto.to = function to(index) {\n      var _this = this;\n\n      this._activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);\n\n      var activeIndex = this._getItemIndex(this._activeElement);\n\n      if (index > this._items.length - 1 || index < 0) {\n        return;\n      }\n\n      if (this._isSliding) {\n        $(this._element).one(Event$2.SLID, function () {\n          return _this.to(index);\n        });\n        return;\n      }\n\n      if (activeIndex === index) {\n        this.pause();\n        this.cycle();\n        return;\n      }\n\n      var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;\n\n      this._slide(direction, this._items[index]);\n    };\n\n    _proto.dispose = function dispose() {\n      $(this._element).off(EVENT_KEY$2);\n      $.removeData(this._element, DATA_KEY$2);\n      this._items = null;\n      this._config = null;\n      this._element = null;\n      this._interval = null;\n      this._isPaused = null;\n      this._isSliding = null;\n      this._activeElement = null;\n      this._indicatorsElement = null;\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default, config);\n      Util.typeCheckConfig(NAME$2, config, DefaultType);\n      return config;\n    };\n\n    _proto._handleSwipe = function _handleSwipe() {\n      var absDeltax = Math.abs(this.touchDeltaX);\n\n      if (absDeltax <= SWIPE_THRESHOLD) {\n        return;\n      }\n\n      var direction = absDeltax / this.touchDeltaX; // swipe left\n\n      if (direction > 0) {\n        this.prev();\n      } // swipe right\n\n\n      if (direction < 0) {\n        this.next();\n      }\n    };\n\n    _proto._addEventListeners = function _addEventListeners() {\n      var _this2 = this;\n\n      if (this._config.keyboard) {\n        $(this._element).on(Event$2.KEYDOWN, function (event) {\n          return _this2._keydown(event);\n        });\n      }\n\n      if (this._config.pause === 'hover') {\n        $(this._element).on(Event$2.MOUSEENTER, function (event) {\n          return _this2.pause(event);\n        }).on(Event$2.MOUSELEAVE, function (event) {\n          return _this2.cycle(event);\n        });\n      }\n\n      if (this._config.touch) {\n        this._addTouchEventListeners();\n      }\n    };\n\n    _proto._addTouchEventListeners = function _addTouchEventListeners() {\n      var _this3 = this;\n\n      if (!this._touchSupported) {\n        return;\n      }\n\n      var start = function start(event) {\n        if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n          _this3.touchStartX = event.originalEvent.clientX;\n        } else if (!_this3._pointerEvent) {\n          _this3.touchStartX = event.originalEvent.touches[0].clientX;\n        }\n      };\n\n      var move = function move(event) {\n        // ensure swiping with one touch and not pinching\n        if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {\n          _this3.touchDeltaX = 0;\n        } else {\n          _this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX;\n        }\n      };\n\n      var end = function end(event) {\n        if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n          _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX;\n        }\n\n        _this3._handleSwipe();\n\n        if (_this3._config.pause === 'hover') {\n          // If it's a touch-enabled device, mouseenter/leave are fired as\n          // part of the mouse compatibility events on first tap - the carousel\n          // would stop cycling until user tapped out of it;\n          // here, we listen for touchend, explicitly pause the carousel\n          // (as if it's the second time we tap on it, mouseenter compat event\n          // is NOT fired) and after a timeout (to allow for mouse compatibility\n          // events to fire) we explicitly restart cycling\n          _this3.pause();\n\n          if (_this3.touchTimeout) {\n            clearTimeout(_this3.touchTimeout);\n          }\n\n          _this3.touchTimeout = setTimeout(function (event) {\n            return _this3.cycle(event);\n          }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval);\n        }\n      };\n\n      $(this._element.querySelectorAll(Selector$2.ITEM_IMG)).on(Event$2.DRAG_START, function (e) {\n        return e.preventDefault();\n      });\n\n      if (this._pointerEvent) {\n        $(this._element).on(Event$2.POINTERDOWN, function (event) {\n          return start(event);\n        });\n        $(this._element).on(Event$2.POINTERUP, function (event) {\n          return end(event);\n        });\n\n        this._element.classList.add(ClassName$2.POINTER_EVENT);\n      } else {\n        $(this._element).on(Event$2.TOUCHSTART, function (event) {\n          return start(event);\n        });\n        $(this._element).on(Event$2.TOUCHMOVE, function (event) {\n          return move(event);\n        });\n        $(this._element).on(Event$2.TOUCHEND, function (event) {\n          return end(event);\n        });\n      }\n    };\n\n    _proto._keydown = function _keydown(event) {\n      if (/input|textarea/i.test(event.target.tagName)) {\n        return;\n      }\n\n      switch (event.which) {\n        case ARROW_LEFT_KEYCODE:\n          event.preventDefault();\n          this.prev();\n          break;\n\n        case ARROW_RIGHT_KEYCODE:\n          event.preventDefault();\n          this.next();\n          break;\n\n        default:\n      }\n    };\n\n    _proto._getItemIndex = function _getItemIndex(element) {\n      this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector$2.ITEM)) : [];\n      return this._items.indexOf(element);\n    };\n\n    _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {\n      var isNextDirection = direction === Direction.NEXT;\n      var isPrevDirection = direction === Direction.PREV;\n\n      var activeIndex = this._getItemIndex(activeElement);\n\n      var lastItemIndex = this._items.length - 1;\n      var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;\n\n      if (isGoingToWrap && !this._config.wrap) {\n        return activeElement;\n      }\n\n      var delta = direction === Direction.PREV ? -1 : 1;\n      var itemIndex = (activeIndex + delta) % this._items.length;\n      return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];\n    };\n\n    _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {\n      var targetIndex = this._getItemIndex(relatedTarget);\n\n      var fromIndex = this._getItemIndex(this._element.querySelector(Selector$2.ACTIVE_ITEM));\n\n      var slideEvent = $.Event(Event$2.SLIDE, {\n        relatedTarget: relatedTarget,\n        direction: eventDirectionName,\n        from: fromIndex,\n        to: targetIndex\n      });\n      $(this._element).trigger(slideEvent);\n      return slideEvent;\n    };\n\n    _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {\n      if (this._indicatorsElement) {\n        var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector$2.ACTIVE));\n        $(indicators).removeClass(ClassName$2.ACTIVE);\n\n        var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];\n\n        if (nextIndicator) {\n          $(nextIndicator).addClass(ClassName$2.ACTIVE);\n        }\n      }\n    };\n\n    _proto._slide = function _slide(direction, element) {\n      var _this4 = this;\n\n      var activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);\n\n      var activeElementIndex = this._getItemIndex(activeElement);\n\n      var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);\n\n      var nextElementIndex = this._getItemIndex(nextElement);\n\n      var isCycling = Boolean(this._interval);\n      var directionalClassName;\n      var orderClassName;\n      var eventDirectionName;\n\n      if (direction === Direction.NEXT) {\n        directionalClassName = ClassName$2.LEFT;\n        orderClassName = ClassName$2.NEXT;\n        eventDirectionName = Direction.LEFT;\n      } else {\n        directionalClassName = ClassName$2.RIGHT;\n        orderClassName = ClassName$2.PREV;\n        eventDirectionName = Direction.RIGHT;\n      }\n\n      if (nextElement && $(nextElement).hasClass(ClassName$2.ACTIVE)) {\n        this._isSliding = false;\n        return;\n      }\n\n      var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);\n\n      if (slideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      if (!activeElement || !nextElement) {\n        // Some weirdness is happening, so we bail\n        return;\n      }\n\n      this._isSliding = true;\n\n      if (isCycling) {\n        this.pause();\n      }\n\n      this._setActiveIndicatorElement(nextElement);\n\n      var slidEvent = $.Event(Event$2.SLID, {\n        relatedTarget: nextElement,\n        direction: eventDirectionName,\n        from: activeElementIndex,\n        to: nextElementIndex\n      });\n\n      if ($(this._element).hasClass(ClassName$2.SLIDE)) {\n        $(nextElement).addClass(orderClassName);\n        Util.reflow(nextElement);\n        $(activeElement).addClass(directionalClassName);\n        $(nextElement).addClass(directionalClassName);\n        var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10);\n\n        if (nextElementInterval) {\n          this._config.defaultInterval = this._config.defaultInterval || this._config.interval;\n          this._config.interval = nextElementInterval;\n        } else {\n          this._config.interval = this._config.defaultInterval || this._config.interval;\n        }\n\n        var transitionDuration = Util.getTransitionDurationFromElement(activeElement);\n        $(activeElement).one(Util.TRANSITION_END, function () {\n          $(nextElement).removeClass(directionalClassName + \" \" + orderClassName).addClass(ClassName$2.ACTIVE);\n          $(activeElement).removeClass(ClassName$2.ACTIVE + \" \" + orderClassName + \" \" + directionalClassName);\n          _this4._isSliding = false;\n          setTimeout(function () {\n            return $(_this4._element).trigger(slidEvent);\n          }, 0);\n        }).emulateTransitionEnd(transitionDuration);\n      } else {\n        $(activeElement).removeClass(ClassName$2.ACTIVE);\n        $(nextElement).addClass(ClassName$2.ACTIVE);\n        this._isSliding = false;\n        $(this._element).trigger(slidEvent);\n      }\n\n      if (isCycling) {\n        this.cycle();\n      }\n    } // Static\n    ;\n\n    Carousel._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$2);\n\n        var _config = _objectSpread({}, Default, $(this).data());\n\n        if (typeof config === 'object') {\n          _config = _objectSpread({}, _config, config);\n        }\n\n        var action = typeof config === 'string' ? config : _config.slide;\n\n        if (!data) {\n          data = new Carousel(this, _config);\n          $(this).data(DATA_KEY$2, data);\n        }\n\n        if (typeof config === 'number') {\n          data.to(config);\n        } else if (typeof action === 'string') {\n          if (typeof data[action] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + action + \"\\\"\");\n          }\n\n          data[action]();\n        } else if (_config.interval && _config.ride) {\n          data.pause();\n          data.cycle();\n        }\n      });\n    };\n\n    Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {\n      var selector = Util.getSelectorFromElement(this);\n\n      if (!selector) {\n        return;\n      }\n\n      var target = $(selector)[0];\n\n      if (!target || !$(target).hasClass(ClassName$2.CAROUSEL)) {\n        return;\n      }\n\n      var config = _objectSpread({}, $(target).data(), $(this).data());\n\n      var slideIndex = this.getAttribute('data-slide-to');\n\n      if (slideIndex) {\n        config.interval = false;\n      }\n\n      Carousel._jQueryInterface.call($(target), config);\n\n      if (slideIndex) {\n        $(target).data(DATA_KEY$2).to(slideIndex);\n      }\n\n      event.preventDefault();\n    };\n\n    _createClass(Carousel, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$2;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default;\n      }\n    }]);\n\n    return Carousel;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$2.CLICK_DATA_API, Selector$2.DATA_SLIDE, Carousel._dataApiClickHandler);\n  $(window).on(Event$2.LOAD_DATA_API, function () {\n    var carousels = [].slice.call(document.querySelectorAll(Selector$2.DATA_RIDE));\n\n    for (var i = 0, len = carousels.length; i < len; i++) {\n      var $carousel = $(carousels[i]);\n\n      Carousel._jQueryInterface.call($carousel, $carousel.data());\n    }\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$2] = Carousel._jQueryInterface;\n  $.fn[NAME$2].Constructor = Carousel;\n\n  $.fn[NAME$2].noConflict = function () {\n    $.fn[NAME$2] = JQUERY_NO_CONFLICT$2;\n    return Carousel._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$3 = 'collapse';\n  var VERSION$3 = '4.3.1';\n  var DATA_KEY$3 = 'bs.collapse';\n  var EVENT_KEY$3 = \".\" + DATA_KEY$3;\n  var DATA_API_KEY$3 = '.data-api';\n  var JQUERY_NO_CONFLICT$3 = $.fn[NAME$3];\n  var Default$1 = {\n    toggle: true,\n    parent: ''\n  };\n  var DefaultType$1 = {\n    toggle: 'boolean',\n    parent: '(string|element)'\n  };\n  var Event$3 = {\n    SHOW: \"show\" + EVENT_KEY$3,\n    SHOWN: \"shown\" + EVENT_KEY$3,\n    HIDE: \"hide\" + EVENT_KEY$3,\n    HIDDEN: \"hidden\" + EVENT_KEY$3,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$3 + DATA_API_KEY$3\n  };\n  var ClassName$3 = {\n    SHOW: 'show',\n    COLLAPSE: 'collapse',\n    COLLAPSING: 'collapsing',\n    COLLAPSED: 'collapsed'\n  };\n  var Dimension = {\n    WIDTH: 'width',\n    HEIGHT: 'height'\n  };\n  var Selector$3 = {\n    ACTIVES: '.show, .collapsing',\n    DATA_TOGGLE: '[data-toggle=\"collapse\"]'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Collapse =\n  /*#__PURE__*/\n  function () {\n    function Collapse(element, config) {\n      this._isTransitioning = false;\n      this._element = element;\n      this._config = this._getConfig(config);\n      this._triggerArray = [].slice.call(document.querySelectorAll(\"[data-toggle=\\\"collapse\\\"][href=\\\"#\" + element.id + \"\\\"],\" + (\"[data-toggle=\\\"collapse\\\"][data-target=\\\"#\" + element.id + \"\\\"]\")));\n      var toggleList = [].slice.call(document.querySelectorAll(Selector$3.DATA_TOGGLE));\n\n      for (var i = 0, len = toggleList.length; i < len; i++) {\n        var elem = toggleList[i];\n        var selector = Util.getSelectorFromElement(elem);\n        var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {\n          return foundElem === element;\n        });\n\n        if (selector !== null && filterElement.length > 0) {\n          this._selector = selector;\n\n          this._triggerArray.push(elem);\n        }\n      }\n\n      this._parent = this._config.parent ? this._getParent() : null;\n\n      if (!this._config.parent) {\n        this._addAriaAndCollapsedClass(this._element, this._triggerArray);\n      }\n\n      if (this._config.toggle) {\n        this.toggle();\n      }\n    } // Getters\n\n\n    var _proto = Collapse.prototype;\n\n    // Public\n    _proto.toggle = function toggle() {\n      if ($(this._element).hasClass(ClassName$3.SHOW)) {\n        this.hide();\n      } else {\n        this.show();\n      }\n    };\n\n    _proto.show = function show() {\n      var _this = this;\n\n      if (this._isTransitioning || $(this._element).hasClass(ClassName$3.SHOW)) {\n        return;\n      }\n\n      var actives;\n      var activesData;\n\n      if (this._parent) {\n        actives = [].slice.call(this._parent.querySelectorAll(Selector$3.ACTIVES)).filter(function (elem) {\n          if (typeof _this._config.parent === 'string') {\n            return elem.getAttribute('data-parent') === _this._config.parent;\n          }\n\n          return elem.classList.contains(ClassName$3.COLLAPSE);\n        });\n\n        if (actives.length === 0) {\n          actives = null;\n        }\n      }\n\n      if (actives) {\n        activesData = $(actives).not(this._selector).data(DATA_KEY$3);\n\n        if (activesData && activesData._isTransitioning) {\n          return;\n        }\n      }\n\n      var startEvent = $.Event(Event$3.SHOW);\n      $(this._element).trigger(startEvent);\n\n      if (startEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      if (actives) {\n        Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide');\n\n        if (!activesData) {\n          $(actives).data(DATA_KEY$3, null);\n        }\n      }\n\n      var dimension = this._getDimension();\n\n      $(this._element).removeClass(ClassName$3.COLLAPSE).addClass(ClassName$3.COLLAPSING);\n      this._element.style[dimension] = 0;\n\n      if (this._triggerArray.length) {\n        $(this._triggerArray).removeClass(ClassName$3.COLLAPSED).attr('aria-expanded', true);\n      }\n\n      this.setTransitioning(true);\n\n      var complete = function complete() {\n        $(_this._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).addClass(ClassName$3.SHOW);\n        _this._element.style[dimension] = '';\n\n        _this.setTransitioning(false);\n\n        $(_this._element).trigger(Event$3.SHOWN);\n      };\n\n      var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n      var scrollSize = \"scroll\" + capitalizedDimension;\n      var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n      $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      this._element.style[dimension] = this._element[scrollSize] + \"px\";\n    };\n\n    _proto.hide = function hide() {\n      var _this2 = this;\n\n      if (this._isTransitioning || !$(this._element).hasClass(ClassName$3.SHOW)) {\n        return;\n      }\n\n      var startEvent = $.Event(Event$3.HIDE);\n      $(this._element).trigger(startEvent);\n\n      if (startEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      var dimension = this._getDimension();\n\n      this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + \"px\";\n      Util.reflow(this._element);\n      $(this._element).addClass(ClassName$3.COLLAPSING).removeClass(ClassName$3.COLLAPSE).removeClass(ClassName$3.SHOW);\n      var triggerArrayLength = this._triggerArray.length;\n\n      if (triggerArrayLength > 0) {\n        for (var i = 0; i < triggerArrayLength; i++) {\n          var trigger = this._triggerArray[i];\n          var selector = Util.getSelectorFromElement(trigger);\n\n          if (selector !== null) {\n            var $elem = $([].slice.call(document.querySelectorAll(selector)));\n\n            if (!$elem.hasClass(ClassName$3.SHOW)) {\n              $(trigger).addClass(ClassName$3.COLLAPSED).attr('aria-expanded', false);\n            }\n          }\n        }\n      }\n\n      this.setTransitioning(true);\n\n      var complete = function complete() {\n        _this2.setTransitioning(false);\n\n        $(_this2._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).trigger(Event$3.HIDDEN);\n      };\n\n      this._element.style[dimension] = '';\n      var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n      $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n    };\n\n    _proto.setTransitioning = function setTransitioning(isTransitioning) {\n      this._isTransitioning = isTransitioning;\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$3);\n      this._config = null;\n      this._parent = null;\n      this._element = null;\n      this._triggerArray = null;\n      this._isTransitioning = null;\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default$1, config);\n      config.toggle = Boolean(config.toggle); // Coerce string values\n\n      Util.typeCheckConfig(NAME$3, config, DefaultType$1);\n      return config;\n    };\n\n    _proto._getDimension = function _getDimension() {\n      var hasWidth = $(this._element).hasClass(Dimension.WIDTH);\n      return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;\n    };\n\n    _proto._getParent = function _getParent() {\n      var _this3 = this;\n\n      var parent;\n\n      if (Util.isElement(this._config.parent)) {\n        parent = this._config.parent; // It's a jQuery object\n\n        if (typeof this._config.parent.jquery !== 'undefined') {\n          parent = this._config.parent[0];\n        }\n      } else {\n        parent = document.querySelector(this._config.parent);\n      }\n\n      var selector = \"[data-toggle=\\\"collapse\\\"][data-parent=\\\"\" + this._config.parent + \"\\\"]\";\n      var children = [].slice.call(parent.querySelectorAll(selector));\n      $(children).each(function (i, element) {\n        _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);\n      });\n      return parent;\n    };\n\n    _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {\n      var isOpen = $(element).hasClass(ClassName$3.SHOW);\n\n      if (triggerArray.length) {\n        $(triggerArray).toggleClass(ClassName$3.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);\n      }\n    } // Static\n    ;\n\n    Collapse._getTargetFromElement = function _getTargetFromElement(element) {\n      var selector = Util.getSelectorFromElement(element);\n      return selector ? document.querySelector(selector) : null;\n    };\n\n    Collapse._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var $this = $(this);\n        var data = $this.data(DATA_KEY$3);\n\n        var _config = _objectSpread({}, Default$1, $this.data(), typeof config === 'object' && config ? config : {});\n\n        if (!data && _config.toggle && /show|hide/.test(config)) {\n          _config.toggle = false;\n        }\n\n        if (!data) {\n          data = new Collapse(this, _config);\n          $this.data(DATA_KEY$3, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Collapse, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$3;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$1;\n      }\n    }]);\n\n    return Collapse;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$3.CLICK_DATA_API, Selector$3.DATA_TOGGLE, function (event) {\n    // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n    if (event.currentTarget.tagName === 'A') {\n      event.preventDefault();\n    }\n\n    var $trigger = $(this);\n    var selector = Util.getSelectorFromElement(this);\n    var selectors = [].slice.call(document.querySelectorAll(selector));\n    $(selectors).each(function () {\n      var $target = $(this);\n      var data = $target.data(DATA_KEY$3);\n      var config = data ? 'toggle' : $trigger.data();\n\n      Collapse._jQueryInterface.call($target, config);\n    });\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$3] = Collapse._jQueryInterface;\n  $.fn[NAME$3].Constructor = Collapse;\n\n  $.fn[NAME$3].noConflict = function () {\n    $.fn[NAME$3] = JQUERY_NO_CONFLICT$3;\n    return Collapse._jQueryInterface;\n  };\n\n  /**!\n   * @fileOverview Kickass library to create and place poppers near their reference elements.\n   * @version 1.14.7\n   * @license\n   * Copyright (c) 2016 Federico Zivolo and contributors\n   *\n   * Permission is hereby granted, free of charge, to any person obtaining a copy\n   * of this software and associated documentation files (the \"Software\"), to deal\n   * in the Software without restriction, including without limitation the rights\n   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n   * copies of the Software, and to permit persons to whom the Software is\n   * furnished to do so, subject to the following conditions:\n   *\n   * The above copyright notice and this permission notice shall be included in all\n   * copies or substantial portions of the Software.\n   *\n   * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n   * SOFTWARE.\n   */\n  var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';\n\n  var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];\n  var timeoutDuration = 0;\n  for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {\n    if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {\n      timeoutDuration = 1;\n      break;\n    }\n  }\n\n  function microtaskDebounce(fn) {\n    var called = false;\n    return function () {\n      if (called) {\n        return;\n      }\n      called = true;\n      window.Promise.resolve().then(function () {\n        called = false;\n        fn();\n      });\n    };\n  }\n\n  function taskDebounce(fn) {\n    var scheduled = false;\n    return function () {\n      if (!scheduled) {\n        scheduled = true;\n        setTimeout(function () {\n          scheduled = false;\n          fn();\n        }, timeoutDuration);\n      }\n    };\n  }\n\n  var supportsMicroTasks = isBrowser && window.Promise;\n\n  /**\n  * Create a debounced version of a method, that's asynchronously deferred\n  * but called in the minimum time possible.\n  *\n  * @method\n  * @memberof Popper.Utils\n  * @argument {Function} fn\n  * @returns {Function}\n  */\n  var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;\n\n  /**\n   * Check if the given variable is a function\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Any} functionToCheck - variable to check\n   * @returns {Boolean} answer to: is a function?\n   */\n  function isFunction(functionToCheck) {\n    var getType = {};\n    return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';\n  }\n\n  /**\n   * Get CSS computed property of the given element\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Eement} element\n   * @argument {String} property\n   */\n  function getStyleComputedProperty(element, property) {\n    if (element.nodeType !== 1) {\n      return [];\n    }\n    // NOTE: 1 DOM access here\n    var window = element.ownerDocument.defaultView;\n    var css = window.getComputedStyle(element, null);\n    return property ? css[property] : css;\n  }\n\n  /**\n   * Returns the parentNode or the host of the element\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element\n   * @returns {Element} parent\n   */\n  function getParentNode(element) {\n    if (element.nodeName === 'HTML') {\n      return element;\n    }\n    return element.parentNode || element.host;\n  }\n\n  /**\n   * Returns the scrolling parent of the given element\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element\n   * @returns {Element} scroll parent\n   */\n  function getScrollParent(element) {\n    // Return body, `getScroll` will take care to get the correct `scrollTop` from it\n    if (!element) {\n      return document.body;\n    }\n\n    switch (element.nodeName) {\n      case 'HTML':\n      case 'BODY':\n        return element.ownerDocument.body;\n      case '#document':\n        return element.body;\n    }\n\n    // Firefox want us to check `-x` and `-y` variations as well\n\n    var _getStyleComputedProp = getStyleComputedProperty(element),\n        overflow = _getStyleComputedProp.overflow,\n        overflowX = _getStyleComputedProp.overflowX,\n        overflowY = _getStyleComputedProp.overflowY;\n\n    if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {\n      return element;\n    }\n\n    return getScrollParent(getParentNode(element));\n  }\n\n  var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);\n  var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);\n\n  /**\n   * Determines if the browser is Internet Explorer\n   * @method\n   * @memberof Popper.Utils\n   * @param {Number} version to check\n   * @returns {Boolean} isIE\n   */\n  function isIE(version) {\n    if (version === 11) {\n      return isIE11;\n    }\n    if (version === 10) {\n      return isIE10;\n    }\n    return isIE11 || isIE10;\n  }\n\n  /**\n   * Returns the offset parent of the given element\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element\n   * @returns {Element} offset parent\n   */\n  function getOffsetParent(element) {\n    if (!element) {\n      return document.documentElement;\n    }\n\n    var noOffsetParent = isIE(10) ? document.body : null;\n\n    // NOTE: 1 DOM access here\n    var offsetParent = element.offsetParent || null;\n    // Skip hidden elements which don't have an offsetParent\n    while (offsetParent === noOffsetParent && element.nextElementSibling) {\n      offsetParent = (element = element.nextElementSibling).offsetParent;\n    }\n\n    var nodeName = offsetParent && offsetParent.nodeName;\n\n    if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {\n      return element ? element.ownerDocument.documentElement : document.documentElement;\n    }\n\n    // .offsetParent will return the closest TH, TD or TABLE in case\n    // no offsetParent is present, I hate this job...\n    if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {\n      return getOffsetParent(offsetParent);\n    }\n\n    return offsetParent;\n  }\n\n  function isOffsetContainer(element) {\n    var nodeName = element.nodeName;\n\n    if (nodeName === 'BODY') {\n      return false;\n    }\n    return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;\n  }\n\n  /**\n   * Finds the root node (document, shadowDOM root) of the given element\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} node\n   * @returns {Element} root node\n   */\n  function getRoot(node) {\n    if (node.parentNode !== null) {\n      return getRoot(node.parentNode);\n    }\n\n    return node;\n  }\n\n  /**\n   * Finds the offset parent common to the two provided nodes\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element1\n   * @argument {Element} element2\n   * @returns {Element} common offset parent\n   */\n  function findCommonOffsetParent(element1, element2) {\n    // This check is needed to avoid errors in case one of the elements isn't defined for any reason\n    if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {\n      return document.documentElement;\n    }\n\n    // Here we make sure to give as \"start\" the element that comes first in the DOM\n    var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;\n    var start = order ? element1 : element2;\n    var end = order ? element2 : element1;\n\n    // Get common ancestor container\n    var range = document.createRange();\n    range.setStart(start, 0);\n    range.setEnd(end, 0);\n    var commonAncestorContainer = range.commonAncestorContainer;\n\n    // Both nodes are inside #document\n\n    if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {\n      if (isOffsetContainer(commonAncestorContainer)) {\n        return commonAncestorContainer;\n      }\n\n      return getOffsetParent(commonAncestorContainer);\n    }\n\n    // one of the nodes is inside shadowDOM, find which one\n    var element1root = getRoot(element1);\n    if (element1root.host) {\n      return findCommonOffsetParent(element1root.host, element2);\n    } else {\n      return findCommonOffsetParent(element1, getRoot(element2).host);\n    }\n  }\n\n  /**\n   * Gets the scroll value of the given element in the given side (top and left)\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element\n   * @argument {String} side `top` or `left`\n   * @returns {number} amount of scrolled pixels\n   */\n  function getScroll(element) {\n    var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';\n\n    var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';\n    var nodeName = element.nodeName;\n\n    if (nodeName === 'BODY' || nodeName === 'HTML') {\n      var html = element.ownerDocument.documentElement;\n      var scrollingElement = element.ownerDocument.scrollingElement || html;\n      return scrollingElement[upperSide];\n    }\n\n    return element[upperSide];\n  }\n\n  /*\n   * Sum or subtract the element scroll values (left and top) from a given rect object\n   * @method\n   * @memberof Popper.Utils\n   * @param {Object} rect - Rect object you want to change\n   * @param {HTMLElement} element - The element from the function reads the scroll values\n   * @param {Boolean} subtract - set to true if you want to subtract the scroll values\n   * @return {Object} rect - The modifier rect object\n   */\n  function includeScroll(rect, element) {\n    var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n    var scrollTop = getScroll(element, 'top');\n    var scrollLeft = getScroll(element, 'left');\n    var modifier = subtract ? -1 : 1;\n    rect.top += scrollTop * modifier;\n    rect.bottom += scrollTop * modifier;\n    rect.left += scrollLeft * modifier;\n    rect.right += scrollLeft * modifier;\n    return rect;\n  }\n\n  /*\n   * Helper to detect borders of a given element\n   * @method\n   * @memberof Popper.Utils\n   * @param {CSSStyleDeclaration} styles\n   * Result of `getStyleComputedProperty` on the given element\n   * @param {String} axis - `x` or `y`\n   * @return {number} borders - The borders size of the given axis\n   */\n\n  function getBordersSize(styles, axis) {\n    var sideA = axis === 'x' ? 'Left' : 'Top';\n    var sideB = sideA === 'Left' ? 'Right' : 'Bottom';\n\n    return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10);\n  }\n\n  function getSize(axis, body, html, computedStyle) {\n    return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? parseInt(html['offset' + axis]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')]) : 0);\n  }\n\n  function getWindowSizes(document) {\n    var body = document.body;\n    var html = document.documentElement;\n    var computedStyle = isIE(10) && getComputedStyle(html);\n\n    return {\n      height: getSize('Height', body, html, computedStyle),\n      width: getSize('Width', body, html, computedStyle)\n    };\n  }\n\n  var classCallCheck = function (instance, Constructor) {\n    if (!(instance instanceof Constructor)) {\n      throw new TypeError(\"Cannot call a class as a function\");\n    }\n  };\n\n  var createClass = function () {\n    function defineProperties(target, props) {\n      for (var i = 0; i < props.length; i++) {\n        var descriptor = props[i];\n        descriptor.enumerable = descriptor.enumerable || false;\n        descriptor.configurable = true;\n        if (\"value\" in descriptor) descriptor.writable = true;\n        Object.defineProperty(target, descriptor.key, descriptor);\n      }\n    }\n\n    return function (Constructor, protoProps, staticProps) {\n      if (protoProps) defineProperties(Constructor.prototype, protoProps);\n      if (staticProps) defineProperties(Constructor, staticProps);\n      return Constructor;\n    };\n  }();\n\n\n\n\n\n  var defineProperty = function (obj, key, value) {\n    if (key in obj) {\n      Object.defineProperty(obj, key, {\n        value: value,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      });\n    } else {\n      obj[key] = value;\n    }\n\n    return obj;\n  };\n\n  var _extends = Object.assign || function (target) {\n    for (var i = 1; i < arguments.length; i++) {\n      var source = arguments[i];\n\n      for (var key in source) {\n        if (Object.prototype.hasOwnProperty.call(source, key)) {\n          target[key] = source[key];\n        }\n      }\n    }\n\n    return target;\n  };\n\n  /**\n   * Given element offsets, generate an output similar to getBoundingClientRect\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Object} offsets\n   * @returns {Object} ClientRect like output\n   */\n  function getClientRect(offsets) {\n    return _extends({}, offsets, {\n      right: offsets.left + offsets.width,\n      bottom: offsets.top + offsets.height\n    });\n  }\n\n  /**\n   * Get bounding client rect of given element\n   * @method\n   * @memberof Popper.Utils\n   * @param {HTMLElement} element\n   * @return {Object} client rect\n   */\n  function getBoundingClientRect(element) {\n    var rect = {};\n\n    // IE10 10 FIX: Please, don't ask, the element isn't\n    // considered in DOM in some circumstances...\n    // This isn't reproducible in IE10 compatibility mode of IE11\n    try {\n      if (isIE(10)) {\n        rect = element.getBoundingClientRect();\n        var scrollTop = getScroll(element, 'top');\n        var scrollLeft = getScroll(element, 'left');\n        rect.top += scrollTop;\n        rect.left += scrollLeft;\n        rect.bottom += scrollTop;\n        rect.right += scrollLeft;\n      } else {\n        rect = element.getBoundingClientRect();\n      }\n    } catch (e) {}\n\n    var result = {\n      left: rect.left,\n      top: rect.top,\n      width: rect.right - rect.left,\n      height: rect.bottom - rect.top\n    };\n\n    // subtract scrollbar size from sizes\n    var sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {};\n    var width = sizes.width || element.clientWidth || result.right - result.left;\n    var height = sizes.height || element.clientHeight || result.bottom - result.top;\n\n    var horizScrollbar = element.offsetWidth - width;\n    var vertScrollbar = element.offsetHeight - height;\n\n    // if an hypothetical scrollbar is detected, we must be sure it's not a `border`\n    // we make this check conditional for performance reasons\n    if (horizScrollbar || vertScrollbar) {\n      var styles = getStyleComputedProperty(element);\n      horizScrollbar -= getBordersSize(styles, 'x');\n      vertScrollbar -= getBordersSize(styles, 'y');\n\n      result.width -= horizScrollbar;\n      result.height -= vertScrollbar;\n    }\n\n    return getClientRect(result);\n  }\n\n  function getOffsetRectRelativeToArbitraryNode(children, parent) {\n    var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n\n    var isIE10 = isIE(10);\n    var isHTML = parent.nodeName === 'HTML';\n    var childrenRect = getBoundingClientRect(children);\n    var parentRect = getBoundingClientRect(parent);\n    var scrollParent = getScrollParent(children);\n\n    var styles = getStyleComputedProperty(parent);\n    var borderTopWidth = parseFloat(styles.borderTopWidth, 10);\n    var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10);\n\n    // In cases where the parent is fixed, we must ignore negative scroll in offset calc\n    if (fixedPosition && isHTML) {\n      parentRect.top = Math.max(parentRect.top, 0);\n      parentRect.left = Math.max(parentRect.left, 0);\n    }\n    var offsets = getClientRect({\n      top: childrenRect.top - parentRect.top - borderTopWidth,\n      left: childrenRect.left - parentRect.left - borderLeftWidth,\n      width: childrenRect.width,\n      height: childrenRect.height\n    });\n    offsets.marginTop = 0;\n    offsets.marginLeft = 0;\n\n    // Subtract margins of documentElement in case it's being used as parent\n    // we do this only on HTML because it's the only element that behaves\n    // differently when margins are applied to it. The margins are included in\n    // the box of the documentElement, in the other cases not.\n    if (!isIE10 && isHTML) {\n      var marginTop = parseFloat(styles.marginTop, 10);\n      var marginLeft = parseFloat(styles.marginLeft, 10);\n\n      offsets.top -= borderTopWidth - marginTop;\n      offsets.bottom -= borderTopWidth - marginTop;\n      offsets.left -= borderLeftWidth - marginLeft;\n      offsets.right -= borderLeftWidth - marginLeft;\n\n      // Attach marginTop and marginLeft because in some circumstances we may need them\n      offsets.marginTop = marginTop;\n      offsets.marginLeft = marginLeft;\n    }\n\n    if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {\n      offsets = includeScroll(offsets, parent);\n    }\n\n    return offsets;\n  }\n\n  function getViewportOffsetRectRelativeToArtbitraryNode(element) {\n    var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n    var html = element.ownerDocument.documentElement;\n    var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);\n    var width = Math.max(html.clientWidth, window.innerWidth || 0);\n    var height = Math.max(html.clientHeight, window.innerHeight || 0);\n\n    var scrollTop = !excludeScroll ? getScroll(html) : 0;\n    var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;\n\n    var offset = {\n      top: scrollTop - relativeOffset.top + relativeOffset.marginTop,\n      left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,\n      width: width,\n      height: height\n    };\n\n    return getClientRect(offset);\n  }\n\n  /**\n   * Check if the given element is fixed or is inside a fixed parent\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element\n   * @argument {Element} customContainer\n   * @returns {Boolean} answer to \"isFixed?\"\n   */\n  function isFixed(element) {\n    var nodeName = element.nodeName;\n    if (nodeName === 'BODY' || nodeName === 'HTML') {\n      return false;\n    }\n    if (getStyleComputedProperty(element, 'position') === 'fixed') {\n      return true;\n    }\n    var parentNode = getParentNode(element);\n    if (!parentNode) {\n      return false;\n    }\n    return isFixed(parentNode);\n  }\n\n  /**\n   * Finds the first parent of an element that has a transformed property defined\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element\n   * @returns {Element} first transformed parent or documentElement\n   */\n\n  function getFixedPositionOffsetParent(element) {\n    // This check is needed to avoid errors in case one of the elements isn't defined for any reason\n    if (!element || !element.parentElement || isIE()) {\n      return document.documentElement;\n    }\n    var el = element.parentElement;\n    while (el && getStyleComputedProperty(el, 'transform') === 'none') {\n      el = el.parentElement;\n    }\n    return el || document.documentElement;\n  }\n\n  /**\n   * Computed the boundaries limits and return them\n   * @method\n   * @memberof Popper.Utils\n   * @param {HTMLElement} popper\n   * @param {HTMLElement} reference\n   * @param {number} padding\n   * @param {HTMLElement} boundariesElement - Element used to define the boundaries\n   * @param {Boolean} fixedPosition - Is in fixed position mode\n   * @returns {Object} Coordinates of the boundaries\n   */\n  function getBoundaries(popper, reference, padding, boundariesElement) {\n    var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;\n\n    // NOTE: 1 DOM access here\n\n    var boundaries = { top: 0, left: 0 };\n    var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);\n\n    // Handle viewport case\n    if (boundariesElement === 'viewport') {\n      boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);\n    } else {\n      // Handle other cases based on DOM element used as boundaries\n      var boundariesNode = void 0;\n      if (boundariesElement === 'scrollParent') {\n        boundariesNode = getScrollParent(getParentNode(reference));\n        if (boundariesNode.nodeName === 'BODY') {\n          boundariesNode = popper.ownerDocument.documentElement;\n        }\n      } else if (boundariesElement === 'window') {\n        boundariesNode = popper.ownerDocument.documentElement;\n      } else {\n        boundariesNode = boundariesElement;\n      }\n\n      var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);\n\n      // In case of HTML, we need a different computation\n      if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {\n        var _getWindowSizes = getWindowSizes(popper.ownerDocument),\n            height = _getWindowSizes.height,\n            width = _getWindowSizes.width;\n\n        boundaries.top += offsets.top - offsets.marginTop;\n        boundaries.bottom = height + offsets.top;\n        boundaries.left += offsets.left - offsets.marginLeft;\n        boundaries.right = width + offsets.left;\n      } else {\n        // for all the other DOM elements, this one is good\n        boundaries = offsets;\n      }\n    }\n\n    // Add paddings\n    padding = padding || 0;\n    var isPaddingNumber = typeof padding === 'number';\n    boundaries.left += isPaddingNumber ? padding : padding.left || 0;\n    boundaries.top += isPaddingNumber ? padding : padding.top || 0;\n    boundaries.right -= isPaddingNumber ? padding : padding.right || 0;\n    boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;\n\n    return boundaries;\n  }\n\n  function getArea(_ref) {\n    var width = _ref.width,\n        height = _ref.height;\n\n    return width * height;\n  }\n\n  /**\n   * Utility used to transform the `auto` placement to the placement with more\n   * available space.\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Object} data - The data object generated by update method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {\n    var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;\n\n    if (placement.indexOf('auto') === -1) {\n      return placement;\n    }\n\n    var boundaries = getBoundaries(popper, reference, padding, boundariesElement);\n\n    var rects = {\n      top: {\n        width: boundaries.width,\n        height: refRect.top - boundaries.top\n      },\n      right: {\n        width: boundaries.right - refRect.right,\n        height: boundaries.height\n      },\n      bottom: {\n        width: boundaries.width,\n        height: boundaries.bottom - refRect.bottom\n      },\n      left: {\n        width: refRect.left - boundaries.left,\n        height: boundaries.height\n      }\n    };\n\n    var sortedAreas = Object.keys(rects).map(function (key) {\n      return _extends({\n        key: key\n      }, rects[key], {\n        area: getArea(rects[key])\n      });\n    }).sort(function (a, b) {\n      return b.area - a.area;\n    });\n\n    var filteredAreas = sortedAreas.filter(function (_ref2) {\n      var width = _ref2.width,\n          height = _ref2.height;\n      return width >= popper.clientWidth && height >= popper.clientHeight;\n    });\n\n    var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;\n\n    var variation = placement.split('-')[1];\n\n    return computedPlacement + (variation ? '-' + variation : '');\n  }\n\n  /**\n   * Get offsets to the reference element\n   * @method\n   * @memberof Popper.Utils\n   * @param {Object} state\n   * @param {Element} popper - the popper element\n   * @param {Element} reference - the reference element (the popper will be relative to this)\n   * @param {Element} fixedPosition - is in fixed position mode\n   * @returns {Object} An object containing the offsets which will be applied to the popper\n   */\n  function getReferenceOffsets(state, popper, reference) {\n    var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n\n    var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);\n    return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);\n  }\n\n  /**\n   * Get the outer sizes of the given element (offset size + margins)\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element\n   * @returns {Object} object containing width and height properties\n   */\n  function getOuterSizes(element) {\n    var window = element.ownerDocument.defaultView;\n    var styles = window.getComputedStyle(element);\n    var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);\n    var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);\n    var result = {\n      width: element.offsetWidth + y,\n      height: element.offsetHeight + x\n    };\n    return result;\n  }\n\n  /**\n   * Get the opposite placement of the given one\n   * @method\n   * @memberof Popper.Utils\n   * @argument {String} placement\n   * @returns {String} flipped placement\n   */\n  function getOppositePlacement(placement) {\n    var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };\n    return placement.replace(/left|right|bottom|top/g, function (matched) {\n      return hash[matched];\n    });\n  }\n\n  /**\n   * Get offsets to the popper\n   * @method\n   * @memberof Popper.Utils\n   * @param {Object} position - CSS position the Popper will get applied\n   * @param {HTMLElement} popper - the popper element\n   * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)\n   * @param {String} placement - one of the valid placement options\n   * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper\n   */\n  function getPopperOffsets(popper, referenceOffsets, placement) {\n    placement = placement.split('-')[0];\n\n    // Get popper node sizes\n    var popperRect = getOuterSizes(popper);\n\n    // Add position, width and height to our offsets object\n    var popperOffsets = {\n      width: popperRect.width,\n      height: popperRect.height\n    };\n\n    // depending by the popper placement we have to compute its offsets slightly differently\n    var isHoriz = ['right', 'left'].indexOf(placement) !== -1;\n    var mainSide = isHoriz ? 'top' : 'left';\n    var secondarySide = isHoriz ? 'left' : 'top';\n    var measurement = isHoriz ? 'height' : 'width';\n    var secondaryMeasurement = !isHoriz ? 'height' : 'width';\n\n    popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;\n    if (placement === secondarySide) {\n      popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];\n    } else {\n      popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];\n    }\n\n    return popperOffsets;\n  }\n\n  /**\n   * Mimics the `find` method of Array\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Array} arr\n   * @argument prop\n   * @argument value\n   * @returns index or -1\n   */\n  function find(arr, check) {\n    // use native find if supported\n    if (Array.prototype.find) {\n      return arr.find(check);\n    }\n\n    // use `filter` to obtain the same behavior of `find`\n    return arr.filter(check)[0];\n  }\n\n  /**\n   * Return the index of the matching object\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Array} arr\n   * @argument prop\n   * @argument value\n   * @returns index or -1\n   */\n  function findIndex(arr, prop, value) {\n    // use native findIndex if supported\n    if (Array.prototype.findIndex) {\n      return arr.findIndex(function (cur) {\n        return cur[prop] === value;\n      });\n    }\n\n    // use `find` + `indexOf` if `findIndex` isn't supported\n    var match = find(arr, function (obj) {\n      return obj[prop] === value;\n    });\n    return arr.indexOf(match);\n  }\n\n  /**\n   * Loop trough the list of modifiers and run them in order,\n   * each of them will then edit the data object.\n   * @method\n   * @memberof Popper.Utils\n   * @param {dataObject} data\n   * @param {Array} modifiers\n   * @param {String} ends - Optional modifier name used as stopper\n   * @returns {dataObject}\n   */\n  function runModifiers(modifiers, data, ends) {\n    var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));\n\n    modifiersToRun.forEach(function (modifier) {\n      if (modifier['function']) {\n        // eslint-disable-line dot-notation\n        console.warn('`modifier.function` is deprecated, use `modifier.fn`!');\n      }\n      var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation\n      if (modifier.enabled && isFunction(fn)) {\n        // Add properties to offsets to make them a complete clientRect object\n        // we do this before each modifier to make sure the previous one doesn't\n        // mess with these values\n        data.offsets.popper = getClientRect(data.offsets.popper);\n        data.offsets.reference = getClientRect(data.offsets.reference);\n\n        data = fn(data, modifier);\n      }\n    });\n\n    return data;\n  }\n\n  /**\n   * Updates the position of the popper, computing the new offsets and applying\n   * the new style.<br />\n   * Prefer `scheduleUpdate` over `update` because of performance reasons.\n   * @method\n   * @memberof Popper\n   */\n  function update() {\n    // if popper is destroyed, don't perform any further update\n    if (this.state.isDestroyed) {\n      return;\n    }\n\n    var data = {\n      instance: this,\n      styles: {},\n      arrowStyles: {},\n      attributes: {},\n      flipped: false,\n      offsets: {}\n    };\n\n    // compute reference element offsets\n    data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);\n\n    // compute auto placement, store placement inside the data object,\n    // modifiers will be able to edit `placement` if needed\n    // and refer to originalPlacement to know the original value\n    data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);\n\n    // store the computed placement inside `originalPlacement`\n    data.originalPlacement = data.placement;\n\n    data.positionFixed = this.options.positionFixed;\n\n    // compute the popper offsets\n    data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);\n\n    data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';\n\n    // run the modifiers\n    data = runModifiers(this.modifiers, data);\n\n    // the first `update` will call `onCreate` callback\n    // the other ones will call `onUpdate` callback\n    if (!this.state.isCreated) {\n      this.state.isCreated = true;\n      this.options.onCreate(data);\n    } else {\n      this.options.onUpdate(data);\n    }\n  }\n\n  /**\n   * Helper used to know if the given modifier is enabled.\n   * @method\n   * @memberof Popper.Utils\n   * @returns {Boolean}\n   */\n  function isModifierEnabled(modifiers, modifierName) {\n    return modifiers.some(function (_ref) {\n      var name = _ref.name,\n          enabled = _ref.enabled;\n      return enabled && name === modifierName;\n    });\n  }\n\n  /**\n   * Get the prefixed supported property name\n   * @method\n   * @memberof Popper.Utils\n   * @argument {String} property (camelCase)\n   * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)\n   */\n  function getSupportedPropertyName(property) {\n    var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];\n    var upperProp = property.charAt(0).toUpperCase() + property.slice(1);\n\n    for (var i = 0; i < prefixes.length; i++) {\n      var prefix = prefixes[i];\n      var toCheck = prefix ? '' + prefix + upperProp : property;\n      if (typeof document.body.style[toCheck] !== 'undefined') {\n        return toCheck;\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Destroys the popper.\n   * @method\n   * @memberof Popper\n   */\n  function destroy() {\n    this.state.isDestroyed = true;\n\n    // touch DOM only if `applyStyle` modifier is enabled\n    if (isModifierEnabled(this.modifiers, 'applyStyle')) {\n      this.popper.removeAttribute('x-placement');\n      this.popper.style.position = '';\n      this.popper.style.top = '';\n      this.popper.style.left = '';\n      this.popper.style.right = '';\n      this.popper.style.bottom = '';\n      this.popper.style.willChange = '';\n      this.popper.style[getSupportedPropertyName('transform')] = '';\n    }\n\n    this.disableEventListeners();\n\n    // remove the popper if user explicity asked for the deletion on destroy\n    // do not use `remove` because IE11 doesn't support it\n    if (this.options.removeOnDestroy) {\n      this.popper.parentNode.removeChild(this.popper);\n    }\n    return this;\n  }\n\n  /**\n   * Get the window associated with the element\n   * @argument {Element} element\n   * @returns {Window}\n   */\n  function getWindow(element) {\n    var ownerDocument = element.ownerDocument;\n    return ownerDocument ? ownerDocument.defaultView : window;\n  }\n\n  function attachToScrollParents(scrollParent, event, callback, scrollParents) {\n    var isBody = scrollParent.nodeName === 'BODY';\n    var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;\n    target.addEventListener(event, callback, { passive: true });\n\n    if (!isBody) {\n      attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);\n    }\n    scrollParents.push(target);\n  }\n\n  /**\n   * Setup needed event listeners used to update the popper position\n   * @method\n   * @memberof Popper.Utils\n   * @private\n   */\n  function setupEventListeners(reference, options, state, updateBound) {\n    // Resize event listener on window\n    state.updateBound = updateBound;\n    getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });\n\n    // Scroll event listener on scroll parents\n    var scrollElement = getScrollParent(reference);\n    attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);\n    state.scrollElement = scrollElement;\n    state.eventsEnabled = true;\n\n    return state;\n  }\n\n  /**\n   * It will add resize/scroll events and start recalculating\n   * position of the popper element when they are triggered.\n   * @method\n   * @memberof Popper\n   */\n  function enableEventListeners() {\n    if (!this.state.eventsEnabled) {\n      this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);\n    }\n  }\n\n  /**\n   * Remove event listeners used to update the popper position\n   * @method\n   * @memberof Popper.Utils\n   * @private\n   */\n  function removeEventListeners(reference, state) {\n    // Remove resize event listener on window\n    getWindow(reference).removeEventListener('resize', state.updateBound);\n\n    // Remove scroll event listener on scroll parents\n    state.scrollParents.forEach(function (target) {\n      target.removeEventListener('scroll', state.updateBound);\n    });\n\n    // Reset state\n    state.updateBound = null;\n    state.scrollParents = [];\n    state.scrollElement = null;\n    state.eventsEnabled = false;\n    return state;\n  }\n\n  /**\n   * It will remove resize/scroll events and won't recalculate popper position\n   * when they are triggered. It also won't trigger `onUpdate` callback anymore,\n   * unless you call `update` method manually.\n   * @method\n   * @memberof Popper\n   */\n  function disableEventListeners() {\n    if (this.state.eventsEnabled) {\n      cancelAnimationFrame(this.scheduleUpdate);\n      this.state = removeEventListeners(this.reference, this.state);\n    }\n  }\n\n  /**\n   * Tells if a given input is a number\n   * @method\n   * @memberof Popper.Utils\n   * @param {*} input to check\n   * @return {Boolean}\n   */\n  function isNumeric(n) {\n    return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);\n  }\n\n  /**\n   * Set the style to the given popper\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element - Element to apply the style to\n   * @argument {Object} styles\n   * Object with a list of properties and values which will be applied to the element\n   */\n  function setStyles(element, styles) {\n    Object.keys(styles).forEach(function (prop) {\n      var unit = '';\n      // add unit if the value is numeric and is one of the following\n      if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {\n        unit = 'px';\n      }\n      element.style[prop] = styles[prop] + unit;\n    });\n  }\n\n  /**\n   * Set the attributes to the given popper\n   * @method\n   * @memberof Popper.Utils\n   * @argument {Element} element - Element to apply the attributes to\n   * @argument {Object} styles\n   * Object with a list of properties and values which will be applied to the element\n   */\n  function setAttributes(element, attributes) {\n    Object.keys(attributes).forEach(function (prop) {\n      var value = attributes[prop];\n      if (value !== false) {\n        element.setAttribute(prop, attributes[prop]);\n      } else {\n        element.removeAttribute(prop);\n      }\n    });\n  }\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by `update` method\n   * @argument {Object} data.styles - List of style properties - values to apply to popper element\n   * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The same data object\n   */\n  function applyStyle(data) {\n    // any property present in `data.styles` will be applied to the popper,\n    // in this way we can make the 3rd party modifiers add custom styles to it\n    // Be aware, modifiers could override the properties defined in the previous\n    // lines of this modifier!\n    setStyles(data.instance.popper, data.styles);\n\n    // any property present in `data.attributes` will be applied to the popper,\n    // they will be set as HTML attributes of the element\n    setAttributes(data.instance.popper, data.attributes);\n\n    // if arrowElement is defined and arrowStyles has some properties\n    if (data.arrowElement && Object.keys(data.arrowStyles).length) {\n      setStyles(data.arrowElement, data.arrowStyles);\n    }\n\n    return data;\n  }\n\n  /**\n   * Set the x-placement attribute before everything else because it could be used\n   * to add margins to the popper margins needs to be calculated to get the\n   * correct popper offsets.\n   * @method\n   * @memberof Popper.modifiers\n   * @param {HTMLElement} reference - The reference element used to position the popper\n   * @param {HTMLElement} popper - The HTML element used as popper\n   * @param {Object} options - Popper.js options\n   */\n  function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {\n    // compute reference element offsets\n    var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);\n\n    // compute auto placement, store placement inside the data object,\n    // modifiers will be able to edit `placement` if needed\n    // and refer to originalPlacement to know the original value\n    var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);\n\n    popper.setAttribute('x-placement', placement);\n\n    // Apply `position` to popper before anything else because\n    // without the position applied we can't guarantee correct computations\n    setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });\n\n    return options;\n  }\n\n  /**\n   * @function\n   * @memberof Popper.Utils\n   * @argument {Object} data - The data object generated by `update` method\n   * @argument {Boolean} shouldRound - If the offsets should be rounded at all\n   * @returns {Object} The popper's position offsets rounded\n   *\n   * The tale of pixel-perfect positioning. It's still not 100% perfect, but as\n   * good as it can be within reason.\n   * Discussion here: https://github.com/FezVrasta/popper.js/pull/715\n   *\n   * Low DPI screens cause a popper to be blurry if not using full pixels (Safari\n   * as well on High DPI screens).\n   *\n   * Firefox prefers no rounding for positioning and does not have blurriness on\n   * high DPI screens.\n   *\n   * Only horizontal placement and left/right values need to be considered.\n   */\n  function getRoundedOffsets(data, shouldRound) {\n    var _data$offsets = data.offsets,\n        popper = _data$offsets.popper,\n        reference = _data$offsets.reference;\n    var round = Math.round,\n        floor = Math.floor;\n\n    var noRound = function noRound(v) {\n      return v;\n    };\n\n    var referenceWidth = round(reference.width);\n    var popperWidth = round(popper.width);\n\n    var isVertical = ['left', 'right'].indexOf(data.placement) !== -1;\n    var isVariation = data.placement.indexOf('-') !== -1;\n    var sameWidthParity = referenceWidth % 2 === popperWidth % 2;\n    var bothOddWidth = referenceWidth % 2 === 1 && popperWidth % 2 === 1;\n\n    var horizontalToInteger = !shouldRound ? noRound : isVertical || isVariation || sameWidthParity ? round : floor;\n    var verticalToInteger = !shouldRound ? noRound : round;\n\n    return {\n      left: horizontalToInteger(bothOddWidth && !isVariation && shouldRound ? popper.left - 1 : popper.left),\n      top: verticalToInteger(popper.top),\n      bottom: verticalToInteger(popper.bottom),\n      right: horizontalToInteger(popper.right)\n    };\n  }\n\n  var isFirefox = isBrowser && /Firefox/i.test(navigator.userAgent);\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by `update` method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function computeStyle(data, options) {\n    var x = options.x,\n        y = options.y;\n    var popper = data.offsets.popper;\n\n    // Remove this legacy support in Popper.js v2\n\n    var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {\n      return modifier.name === 'applyStyle';\n    }).gpuAcceleration;\n    if (legacyGpuAccelerationOption !== undefined) {\n      console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');\n    }\n    var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;\n\n    var offsetParent = getOffsetParent(data.instance.popper);\n    var offsetParentRect = getBoundingClientRect(offsetParent);\n\n    // Styles\n    var styles = {\n      position: popper.position\n    };\n\n    var offsets = getRoundedOffsets(data, window.devicePixelRatio < 2 || !isFirefox);\n\n    var sideA = x === 'bottom' ? 'top' : 'bottom';\n    var sideB = y === 'right' ? 'left' : 'right';\n\n    // if gpuAcceleration is set to `true` and transform is supported,\n    //  we use `translate3d` to apply the position to the popper we\n    // automatically use the supported prefixed version if needed\n    var prefixedProperty = getSupportedPropertyName('transform');\n\n    // now, let's make a step back and look at this code closely (wtf?)\n    // If the content of the popper grows once it's been positioned, it\n    // may happen that the popper gets misplaced because of the new content\n    // overflowing its reference element\n    // To avoid this problem, we provide two options (x and y), which allow\n    // the consumer to define the offset origin.\n    // If we position a popper on top of a reference element, we can set\n    // `x` to `top` to make the popper grow towards its top instead of\n    // its bottom.\n    var left = void 0,\n        top = void 0;\n    if (sideA === 'bottom') {\n      // when offsetParent is <html> the positioning is relative to the bottom of the screen (excluding the scrollbar)\n      // and not the bottom of the html element\n      if (offsetParent.nodeName === 'HTML') {\n        top = -offsetParent.clientHeight + offsets.bottom;\n      } else {\n        top = -offsetParentRect.height + offsets.bottom;\n      }\n    } else {\n      top = offsets.top;\n    }\n    if (sideB === 'right') {\n      if (offsetParent.nodeName === 'HTML') {\n        left = -offsetParent.clientWidth + offsets.right;\n      } else {\n        left = -offsetParentRect.width + offsets.right;\n      }\n    } else {\n      left = offsets.left;\n    }\n    if (gpuAcceleration && prefixedProperty) {\n      styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';\n      styles[sideA] = 0;\n      styles[sideB] = 0;\n      styles.willChange = 'transform';\n    } else {\n      // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties\n      var invertTop = sideA === 'bottom' ? -1 : 1;\n      var invertLeft = sideB === 'right' ? -1 : 1;\n      styles[sideA] = top * invertTop;\n      styles[sideB] = left * invertLeft;\n      styles.willChange = sideA + ', ' + sideB;\n    }\n\n    // Attributes\n    var attributes = {\n      'x-placement': data.placement\n    };\n\n    // Update `data` attributes, styles and arrowStyles\n    data.attributes = _extends({}, attributes, data.attributes);\n    data.styles = _extends({}, styles, data.styles);\n    data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);\n\n    return data;\n  }\n\n  /**\n   * Helper used to know if the given modifier depends from another one.<br />\n   * It checks if the needed modifier is listed and enabled.\n   * @method\n   * @memberof Popper.Utils\n   * @param {Array} modifiers - list of modifiers\n   * @param {String} requestingName - name of requesting modifier\n   * @param {String} requestedName - name of requested modifier\n   * @returns {Boolean}\n   */\n  function isModifierRequired(modifiers, requestingName, requestedName) {\n    var requesting = find(modifiers, function (_ref) {\n      var name = _ref.name;\n      return name === requestingName;\n    });\n\n    var isRequired = !!requesting && modifiers.some(function (modifier) {\n      return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;\n    });\n\n    if (!isRequired) {\n      var _requesting = '`' + requestingName + '`';\n      var requested = '`' + requestedName + '`';\n      console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');\n    }\n    return isRequired;\n  }\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by update method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function arrow(data, options) {\n    var _data$offsets$arrow;\n\n    // arrow depends on keepTogether in order to work\n    if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {\n      return data;\n    }\n\n    var arrowElement = options.element;\n\n    // if arrowElement is a string, suppose it's a CSS selector\n    if (typeof arrowElement === 'string') {\n      arrowElement = data.instance.popper.querySelector(arrowElement);\n\n      // if arrowElement is not found, don't run the modifier\n      if (!arrowElement) {\n        return data;\n      }\n    } else {\n      // if the arrowElement isn't a query selector we must check that the\n      // provided DOM node is child of its popper node\n      if (!data.instance.popper.contains(arrowElement)) {\n        console.warn('WARNING: `arrow.element` must be child of its popper element!');\n        return data;\n      }\n    }\n\n    var placement = data.placement.split('-')[0];\n    var _data$offsets = data.offsets,\n        popper = _data$offsets.popper,\n        reference = _data$offsets.reference;\n\n    var isVertical = ['left', 'right'].indexOf(placement) !== -1;\n\n    var len = isVertical ? 'height' : 'width';\n    var sideCapitalized = isVertical ? 'Top' : 'Left';\n    var side = sideCapitalized.toLowerCase();\n    var altSide = isVertical ? 'left' : 'top';\n    var opSide = isVertical ? 'bottom' : 'right';\n    var arrowElementSize = getOuterSizes(arrowElement)[len];\n\n    //\n    // extends keepTogether behavior making sure the popper and its\n    // reference have enough pixels in conjunction\n    //\n\n    // top/left side\n    if (reference[opSide] - arrowElementSize < popper[side]) {\n      data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);\n    }\n    // bottom/right side\n    if (reference[side] + arrowElementSize > popper[opSide]) {\n      data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];\n    }\n    data.offsets.popper = getClientRect(data.offsets.popper);\n\n    // compute center of the popper\n    var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;\n\n    // Compute the sideValue using the updated popper offsets\n    // take popper margin in account because we don't have this info available\n    var css = getStyleComputedProperty(data.instance.popper);\n    var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10);\n    var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10);\n    var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;\n\n    // prevent arrowElement from being placed not contiguously to its popper\n    sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);\n\n    data.arrowElement = arrowElement;\n    data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);\n\n    return data;\n  }\n\n  /**\n   * Get the opposite placement variation of the given one\n   * @method\n   * @memberof Popper.Utils\n   * @argument {String} placement variation\n   * @returns {String} flipped placement variation\n   */\n  function getOppositeVariation(variation) {\n    if (variation === 'end') {\n      return 'start';\n    } else if (variation === 'start') {\n      return 'end';\n    }\n    return variation;\n  }\n\n  /**\n   * List of accepted placements to use as values of the `placement` option.<br />\n   * Valid placements are:\n   * - `auto`\n   * - `top`\n   * - `right`\n   * - `bottom`\n   * - `left`\n   *\n   * Each placement can have a variation from this list:\n   * - `-start`\n   * - `-end`\n   *\n   * Variations are interpreted easily if you think of them as the left to right\n   * written languages. Horizontally (`top` and `bottom`), `start` is left and `end`\n   * is right.<br />\n   * Vertically (`left` and `right`), `start` is top and `end` is bottom.\n   *\n   * Some valid examples are:\n   * - `top-end` (on top of reference, right aligned)\n   * - `right-start` (on right of reference, top aligned)\n   * - `bottom` (on bottom, centered)\n   * - `auto-end` (on the side with more space available, alignment depends by placement)\n   *\n   * @static\n   * @type {Array}\n   * @enum {String}\n   * @readonly\n   * @method placements\n   * @memberof Popper\n   */\n  var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];\n\n  // Get rid of `auto` `auto-start` and `auto-end`\n  var validPlacements = placements.slice(3);\n\n  /**\n   * Given an initial placement, returns all the subsequent placements\n   * clockwise (or counter-clockwise).\n   *\n   * @method\n   * @memberof Popper.Utils\n   * @argument {String} placement - A valid placement (it accepts variations)\n   * @argument {Boolean} counter - Set to true to walk the placements counterclockwise\n   * @returns {Array} placements including their variations\n   */\n  function clockwise(placement) {\n    var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n    var index = validPlacements.indexOf(placement);\n    var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));\n    return counter ? arr.reverse() : arr;\n  }\n\n  var BEHAVIORS = {\n    FLIP: 'flip',\n    CLOCKWISE: 'clockwise',\n    COUNTERCLOCKWISE: 'counterclockwise'\n  };\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by update method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function flip(data, options) {\n    // if `inner` modifier is enabled, we can't use the `flip` modifier\n    if (isModifierEnabled(data.instance.modifiers, 'inner')) {\n      return data;\n    }\n\n    if (data.flipped && data.placement === data.originalPlacement) {\n      // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides\n      return data;\n    }\n\n    var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);\n\n    var placement = data.placement.split('-')[0];\n    var placementOpposite = getOppositePlacement(placement);\n    var variation = data.placement.split('-')[1] || '';\n\n    var flipOrder = [];\n\n    switch (options.behavior) {\n      case BEHAVIORS.FLIP:\n        flipOrder = [placement, placementOpposite];\n        break;\n      case BEHAVIORS.CLOCKWISE:\n        flipOrder = clockwise(placement);\n        break;\n      case BEHAVIORS.COUNTERCLOCKWISE:\n        flipOrder = clockwise(placement, true);\n        break;\n      default:\n        flipOrder = options.behavior;\n    }\n\n    flipOrder.forEach(function (step, index) {\n      if (placement !== step || flipOrder.length === index + 1) {\n        return data;\n      }\n\n      placement = data.placement.split('-')[0];\n      placementOpposite = getOppositePlacement(placement);\n\n      var popperOffsets = data.offsets.popper;\n      var refOffsets = data.offsets.reference;\n\n      // using floor because the reference offsets may contain decimals we are not going to consider here\n      var floor = Math.floor;\n      var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);\n\n      var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);\n      var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);\n      var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);\n      var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);\n\n      var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;\n\n      // flip the variation if required\n      var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;\n      var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);\n\n      if (overlapsRef || overflowsBoundaries || flippedVariation) {\n        // this boolean to detect any flip loop\n        data.flipped = true;\n\n        if (overlapsRef || overflowsBoundaries) {\n          placement = flipOrder[index + 1];\n        }\n\n        if (flippedVariation) {\n          variation = getOppositeVariation(variation);\n        }\n\n        data.placement = placement + (variation ? '-' + variation : '');\n\n        // this object contains `position`, we want to preserve it along with\n        // any additional property we may add in the future\n        data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));\n\n        data = runModifiers(data.instance.modifiers, data, 'flip');\n      }\n    });\n    return data;\n  }\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by update method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function keepTogether(data) {\n    var _data$offsets = data.offsets,\n        popper = _data$offsets.popper,\n        reference = _data$offsets.reference;\n\n    var placement = data.placement.split('-')[0];\n    var floor = Math.floor;\n    var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;\n    var side = isVertical ? 'right' : 'bottom';\n    var opSide = isVertical ? 'left' : 'top';\n    var measurement = isVertical ? 'width' : 'height';\n\n    if (popper[side] < floor(reference[opSide])) {\n      data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];\n    }\n    if (popper[opSide] > floor(reference[side])) {\n      data.offsets.popper[opSide] = floor(reference[side]);\n    }\n\n    return data;\n  }\n\n  /**\n   * Converts a string containing value + unit into a px value number\n   * @function\n   * @memberof {modifiers~offset}\n   * @private\n   * @argument {String} str - Value + unit string\n   * @argument {String} measurement - `height` or `width`\n   * @argument {Object} popperOffsets\n   * @argument {Object} referenceOffsets\n   * @returns {Number|String}\n   * Value in pixels, or original string if no values were extracted\n   */\n  function toValue(str, measurement, popperOffsets, referenceOffsets) {\n    // separate value from unit\n    var split = str.match(/((?:\\-|\\+)?\\d*\\.?\\d*)(.*)/);\n    var value = +split[1];\n    var unit = split[2];\n\n    // If it's not a number it's an operator, I guess\n    if (!value) {\n      return str;\n    }\n\n    if (unit.indexOf('%') === 0) {\n      var element = void 0;\n      switch (unit) {\n        case '%p':\n          element = popperOffsets;\n          break;\n        case '%':\n        case '%r':\n        default:\n          element = referenceOffsets;\n      }\n\n      var rect = getClientRect(element);\n      return rect[measurement] / 100 * value;\n    } else if (unit === 'vh' || unit === 'vw') {\n      // if is a vh or vw, we calculate the size based on the viewport\n      var size = void 0;\n      if (unit === 'vh') {\n        size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);\n      } else {\n        size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);\n      }\n      return size / 100 * value;\n    } else {\n      // if is an explicit pixel unit, we get rid of the unit and keep the value\n      // if is an implicit unit, it's px, and we return just the value\n      return value;\n    }\n  }\n\n  /**\n   * Parse an `offset` string to extrapolate `x` and `y` numeric offsets.\n   * @function\n   * @memberof {modifiers~offset}\n   * @private\n   * @argument {String} offset\n   * @argument {Object} popperOffsets\n   * @argument {Object} referenceOffsets\n   * @argument {String} basePlacement\n   * @returns {Array} a two cells array with x and y offsets in numbers\n   */\n  function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {\n    var offsets = [0, 0];\n\n    // Use height if placement is left or right and index is 0 otherwise use width\n    // in this way the first offset will use an axis and the second one\n    // will use the other one\n    var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;\n\n    // Split the offset string to obtain a list of values and operands\n    // The regex addresses values with the plus or minus sign in front (+10, -20, etc)\n    var fragments = offset.split(/(\\+|\\-)/).map(function (frag) {\n      return frag.trim();\n    });\n\n    // Detect if the offset string contains a pair of values or a single one\n    // they could be separated by comma or space\n    var divider = fragments.indexOf(find(fragments, function (frag) {\n      return frag.search(/,|\\s/) !== -1;\n    }));\n\n    if (fragments[divider] && fragments[divider].indexOf(',') === -1) {\n      console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');\n    }\n\n    // If divider is found, we divide the list of values and operands to divide\n    // them by ofset X and Y.\n    var splitRegex = /\\s*,\\s*|\\s+/;\n    var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];\n\n    // Convert the values with units to absolute pixels to allow our computations\n    ops = ops.map(function (op, index) {\n      // Most of the units rely on the orientation of the popper\n      var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';\n      var mergeWithPrevious = false;\n      return op\n      // This aggregates any `+` or `-` sign that aren't considered operators\n      // e.g.: 10 + +5 => [10, +, +5]\n      .reduce(function (a, b) {\n        if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {\n          a[a.length - 1] = b;\n          mergeWithPrevious = true;\n          return a;\n        } else if (mergeWithPrevious) {\n          a[a.length - 1] += b;\n          mergeWithPrevious = false;\n          return a;\n        } else {\n          return a.concat(b);\n        }\n      }, [])\n      // Here we convert the string values into number values (in px)\n      .map(function (str) {\n        return toValue(str, measurement, popperOffsets, referenceOffsets);\n      });\n    });\n\n    // Loop trough the offsets arrays and execute the operations\n    ops.forEach(function (op, index) {\n      op.forEach(function (frag, index2) {\n        if (isNumeric(frag)) {\n          offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);\n        }\n      });\n    });\n    return offsets;\n  }\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by update method\n   * @argument {Object} options - Modifiers configuration and options\n   * @argument {Number|String} options.offset=0\n   * The offset value as described in the modifier description\n   * @returns {Object} The data object, properly modified\n   */\n  function offset(data, _ref) {\n    var offset = _ref.offset;\n    var placement = data.placement,\n        _data$offsets = data.offsets,\n        popper = _data$offsets.popper,\n        reference = _data$offsets.reference;\n\n    var basePlacement = placement.split('-')[0];\n\n    var offsets = void 0;\n    if (isNumeric(+offset)) {\n      offsets = [+offset, 0];\n    } else {\n      offsets = parseOffset(offset, popper, reference, basePlacement);\n    }\n\n    if (basePlacement === 'left') {\n      popper.top += offsets[0];\n      popper.left -= offsets[1];\n    } else if (basePlacement === 'right') {\n      popper.top += offsets[0];\n      popper.left += offsets[1];\n    } else if (basePlacement === 'top') {\n      popper.left += offsets[0];\n      popper.top -= offsets[1];\n    } else if (basePlacement === 'bottom') {\n      popper.left += offsets[0];\n      popper.top += offsets[1];\n    }\n\n    data.popper = popper;\n    return data;\n  }\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by `update` method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function preventOverflow(data, options) {\n    var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);\n\n    // If offsetParent is the reference element, we really want to\n    // go one step up and use the next offsetParent as reference to\n    // avoid to make this modifier completely useless and look like broken\n    if (data.instance.reference === boundariesElement) {\n      boundariesElement = getOffsetParent(boundariesElement);\n    }\n\n    // NOTE: DOM access here\n    // resets the popper's position so that the document size can be calculated excluding\n    // the size of the popper element itself\n    var transformProp = getSupportedPropertyName('transform');\n    var popperStyles = data.instance.popper.style; // assignment to help minification\n    var top = popperStyles.top,\n        left = popperStyles.left,\n        transform = popperStyles[transformProp];\n\n    popperStyles.top = '';\n    popperStyles.left = '';\n    popperStyles[transformProp] = '';\n\n    var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);\n\n    // NOTE: DOM access here\n    // restores the original style properties after the offsets have been computed\n    popperStyles.top = top;\n    popperStyles.left = left;\n    popperStyles[transformProp] = transform;\n\n    options.boundaries = boundaries;\n\n    var order = options.priority;\n    var popper = data.offsets.popper;\n\n    var check = {\n      primary: function primary(placement) {\n        var value = popper[placement];\n        if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {\n          value = Math.max(popper[placement], boundaries[placement]);\n        }\n        return defineProperty({}, placement, value);\n      },\n      secondary: function secondary(placement) {\n        var mainSide = placement === 'right' ? 'left' : 'top';\n        var value = popper[mainSide];\n        if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {\n          value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));\n        }\n        return defineProperty({}, mainSide, value);\n      }\n    };\n\n    order.forEach(function (placement) {\n      var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';\n      popper = _extends({}, popper, check[side](placement));\n    });\n\n    data.offsets.popper = popper;\n\n    return data;\n  }\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by `update` method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function shift(data) {\n    var placement = data.placement;\n    var basePlacement = placement.split('-')[0];\n    var shiftvariation = placement.split('-')[1];\n\n    // if shift shiftvariation is specified, run the modifier\n    if (shiftvariation) {\n      var _data$offsets = data.offsets,\n          reference = _data$offsets.reference,\n          popper = _data$offsets.popper;\n\n      var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;\n      var side = isVertical ? 'left' : 'top';\n      var measurement = isVertical ? 'width' : 'height';\n\n      var shiftOffsets = {\n        start: defineProperty({}, side, reference[side]),\n        end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])\n      };\n\n      data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);\n    }\n\n    return data;\n  }\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by update method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function hide(data) {\n    if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {\n      return data;\n    }\n\n    var refRect = data.offsets.reference;\n    var bound = find(data.instance.modifiers, function (modifier) {\n      return modifier.name === 'preventOverflow';\n    }).boundaries;\n\n    if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {\n      // Avoid unnecessary DOM access if visibility hasn't changed\n      if (data.hide === true) {\n        return data;\n      }\n\n      data.hide = true;\n      data.attributes['x-out-of-boundaries'] = '';\n    } else {\n      // Avoid unnecessary DOM access if visibility hasn't changed\n      if (data.hide === false) {\n        return data;\n      }\n\n      data.hide = false;\n      data.attributes['x-out-of-boundaries'] = false;\n    }\n\n    return data;\n  }\n\n  /**\n   * @function\n   * @memberof Modifiers\n   * @argument {Object} data - The data object generated by `update` method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {Object} The data object, properly modified\n   */\n  function inner(data) {\n    var placement = data.placement;\n    var basePlacement = placement.split('-')[0];\n    var _data$offsets = data.offsets,\n        popper = _data$offsets.popper,\n        reference = _data$offsets.reference;\n\n    var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;\n\n    var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;\n\n    popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);\n\n    data.placement = getOppositePlacement(placement);\n    data.offsets.popper = getClientRect(popper);\n\n    return data;\n  }\n\n  /**\n   * Modifier function, each modifier can have a function of this type assigned\n   * to its `fn` property.<br />\n   * These functions will be called on each update, this means that you must\n   * make sure they are performant enough to avoid performance bottlenecks.\n   *\n   * @function ModifierFn\n   * @argument {dataObject} data - The data object generated by `update` method\n   * @argument {Object} options - Modifiers configuration and options\n   * @returns {dataObject} The data object, properly modified\n   */\n\n  /**\n   * Modifiers are plugins used to alter the behavior of your poppers.<br />\n   * Popper.js uses a set of 9 modifiers to provide all the basic functionalities\n   * needed by the library.\n   *\n   * Usually you don't want to override the `order`, `fn` and `onLoad` props.\n   * All the other properties are configurations that could be tweaked.\n   * @namespace modifiers\n   */\n  var modifiers = {\n    /**\n     * Modifier used to shift the popper on the start or end of its reference\n     * element.<br />\n     * It will read the variation of the `placement` property.<br />\n     * It can be one either `-end` or `-start`.\n     * @memberof modifiers\n     * @inner\n     */\n    shift: {\n      /** @prop {number} order=100 - Index used to define the order of execution */\n      order: 100,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: shift\n    },\n\n    /**\n     * The `offset` modifier can shift your popper on both its axis.\n     *\n     * It accepts the following units:\n     * - `px` or unit-less, interpreted as pixels\n     * - `%` or `%r`, percentage relative to the length of the reference element\n     * - `%p`, percentage relative to the length of the popper element\n     * - `vw`, CSS viewport width unit\n     * - `vh`, CSS viewport height unit\n     *\n     * For length is intended the main axis relative to the placement of the popper.<br />\n     * This means that if the placement is `top` or `bottom`, the length will be the\n     * `width`. In case of `left` or `right`, it will be the `height`.\n     *\n     * You can provide a single value (as `Number` or `String`), or a pair of values\n     * as `String` divided by a comma or one (or more) white spaces.<br />\n     * The latter is a deprecated method because it leads to confusion and will be\n     * removed in v2.<br />\n     * Additionally, it accepts additions and subtractions between different units.\n     * Note that multiplications and divisions aren't supported.\n     *\n     * Valid examples are:\n     * ```\n     * 10\n     * '10%'\n     * '10, 10'\n     * '10%, 10'\n     * '10 + 10%'\n     * '10 - 5vh + 3%'\n     * '-10px + 5vh, 5px - 6%'\n     * ```\n     * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap\n     * > with their reference element, unfortunately, you will have to disable the `flip` modifier.\n     * > You can read more on this at this [issue](https://github.com/FezVrasta/popper.js/issues/373).\n     *\n     * @memberof modifiers\n     * @inner\n     */\n    offset: {\n      /** @prop {number} order=200 - Index used to define the order of execution */\n      order: 200,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: offset,\n      /** @prop {Number|String} offset=0\n       * The offset value as described in the modifier description\n       */\n      offset: 0\n    },\n\n    /**\n     * Modifier used to prevent the popper from being positioned outside the boundary.\n     *\n     * A scenario exists where the reference itself is not within the boundaries.<br />\n     * We can say it has \"escaped the boundaries\" — or just \"escaped\".<br />\n     * In this case we need to decide whether the popper should either:\n     *\n     * - detach from the reference and remain \"trapped\" in the boundaries, or\n     * - if it should ignore the boundary and \"escape with its reference\"\n     *\n     * When `escapeWithReference` is set to`true` and reference is completely\n     * outside its boundaries, the popper will overflow (or completely leave)\n     * the boundaries in order to remain attached to the edge of the reference.\n     *\n     * @memberof modifiers\n     * @inner\n     */\n    preventOverflow: {\n      /** @prop {number} order=300 - Index used to define the order of execution */\n      order: 300,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: preventOverflow,\n      /**\n       * @prop {Array} [priority=['left','right','top','bottom']]\n       * Popper will try to prevent overflow following these priorities by default,\n       * then, it could overflow on the left and on top of the `boundariesElement`\n       */\n      priority: ['left', 'right', 'top', 'bottom'],\n      /**\n       * @prop {number} padding=5\n       * Amount of pixel used to define a minimum distance between the boundaries\n       * and the popper. This makes sure the popper always has a little padding\n       * between the edges of its container\n       */\n      padding: 5,\n      /**\n       * @prop {String|HTMLElement} boundariesElement='scrollParent'\n       * Boundaries used by the modifier. Can be `scrollParent`, `window`,\n       * `viewport` or any DOM element.\n       */\n      boundariesElement: 'scrollParent'\n    },\n\n    /**\n     * Modifier used to make sure the reference and its popper stay near each other\n     * without leaving any gap between the two. Especially useful when the arrow is\n     * enabled and you want to ensure that it points to its reference element.\n     * It cares only about the first axis. You can still have poppers with margin\n     * between the popper and its reference element.\n     * @memberof modifiers\n     * @inner\n     */\n    keepTogether: {\n      /** @prop {number} order=400 - Index used to define the order of execution */\n      order: 400,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: keepTogether\n    },\n\n    /**\n     * This modifier is used to move the `arrowElement` of the popper to make\n     * sure it is positioned between the reference element and its popper element.\n     * It will read the outer size of the `arrowElement` node to detect how many\n     * pixels of conjunction are needed.\n     *\n     * It has no effect if no `arrowElement` is provided.\n     * @memberof modifiers\n     * @inner\n     */\n    arrow: {\n      /** @prop {number} order=500 - Index used to define the order of execution */\n      order: 500,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: arrow,\n      /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */\n      element: '[x-arrow]'\n    },\n\n    /**\n     * Modifier used to flip the popper's placement when it starts to overlap its\n     * reference element.\n     *\n     * Requires the `preventOverflow` modifier before it in order to work.\n     *\n     * **NOTE:** this modifier will interrupt the current update cycle and will\n     * restart it if it detects the need to flip the placement.\n     * @memberof modifiers\n     * @inner\n     */\n    flip: {\n      /** @prop {number} order=600 - Index used to define the order of execution */\n      order: 600,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: flip,\n      /**\n       * @prop {String|Array} behavior='flip'\n       * The behavior used to change the popper's placement. It can be one of\n       * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid\n       * placements (with optional variations)\n       */\n      behavior: 'flip',\n      /**\n       * @prop {number} padding=5\n       * The popper will flip if it hits the edges of the `boundariesElement`\n       */\n      padding: 5,\n      /**\n       * @prop {String|HTMLElement} boundariesElement='viewport'\n       * The element which will define the boundaries of the popper position.\n       * The popper will never be placed outside of the defined boundaries\n       * (except if `keepTogether` is enabled)\n       */\n      boundariesElement: 'viewport'\n    },\n\n    /**\n     * Modifier used to make the popper flow toward the inner of the reference element.\n     * By default, when this modifier is disabled, the popper will be placed outside\n     * the reference element.\n     * @memberof modifiers\n     * @inner\n     */\n    inner: {\n      /** @prop {number} order=700 - Index used to define the order of execution */\n      order: 700,\n      /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */\n      enabled: false,\n      /** @prop {ModifierFn} */\n      fn: inner\n    },\n\n    /**\n     * Modifier used to hide the popper when its reference element is outside of the\n     * popper boundaries. It will set a `x-out-of-boundaries` attribute which can\n     * be used to hide with a CSS selector the popper when its reference is\n     * out of boundaries.\n     *\n     * Requires the `preventOverflow` modifier before it in order to work.\n     * @memberof modifiers\n     * @inner\n     */\n    hide: {\n      /** @prop {number} order=800 - Index used to define the order of execution */\n      order: 800,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: hide\n    },\n\n    /**\n     * Computes the style that will be applied to the popper element to gets\n     * properly positioned.\n     *\n     * Note that this modifier will not touch the DOM, it just prepares the styles\n     * so that `applyStyle` modifier can apply it. This separation is useful\n     * in case you need to replace `applyStyle` with a custom implementation.\n     *\n     * This modifier has `850` as `order` value to maintain backward compatibility\n     * with previous versions of Popper.js. Expect the modifiers ordering method\n     * to change in future major versions of the library.\n     *\n     * @memberof modifiers\n     * @inner\n     */\n    computeStyle: {\n      /** @prop {number} order=850 - Index used to define the order of execution */\n      order: 850,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: computeStyle,\n      /**\n       * @prop {Boolean} gpuAcceleration=true\n       * If true, it uses the CSS 3D transformation to position the popper.\n       * Otherwise, it will use the `top` and `left` properties\n       */\n      gpuAcceleration: true,\n      /**\n       * @prop {string} [x='bottom']\n       * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.\n       * Change this if your popper should grow in a direction different from `bottom`\n       */\n      x: 'bottom',\n      /**\n       * @prop {string} [x='left']\n       * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.\n       * Change this if your popper should grow in a direction different from `right`\n       */\n      y: 'right'\n    },\n\n    /**\n     * Applies the computed styles to the popper element.\n     *\n     * All the DOM manipulations are limited to this modifier. This is useful in case\n     * you want to integrate Popper.js inside a framework or view library and you\n     * want to delegate all the DOM manipulations to it.\n     *\n     * Note that if you disable this modifier, you must make sure the popper element\n     * has its position set to `absolute` before Popper.js can do its work!\n     *\n     * Just disable this modifier and define your own to achieve the desired effect.\n     *\n     * @memberof modifiers\n     * @inner\n     */\n    applyStyle: {\n      /** @prop {number} order=900 - Index used to define the order of execution */\n      order: 900,\n      /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */\n      enabled: true,\n      /** @prop {ModifierFn} */\n      fn: applyStyle,\n      /** @prop {Function} */\n      onLoad: applyStyleOnLoad,\n      /**\n       * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier\n       * @prop {Boolean} gpuAcceleration=true\n       * If true, it uses the CSS 3D transformation to position the popper.\n       * Otherwise, it will use the `top` and `left` properties\n       */\n      gpuAcceleration: undefined\n    }\n  };\n\n  /**\n   * The `dataObject` is an object containing all the information used by Popper.js.\n   * This object is passed to modifiers and to the `onCreate` and `onUpdate` callbacks.\n   * @name dataObject\n   * @property {Object} data.instance The Popper.js instance\n   * @property {String} data.placement Placement applied to popper\n   * @property {String} data.originalPlacement Placement originally defined on init\n   * @property {Boolean} data.flipped True if popper has been flipped by flip modifier\n   * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper\n   * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier\n   * @property {Object} data.styles Any CSS property defined here will be applied to the popper. It expects the JavaScript nomenclature (eg. `marginBottom`)\n   * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow. It expects the JavaScript nomenclature (eg. `marginBottom`)\n   * @property {Object} data.boundaries Offsets of the popper boundaries\n   * @property {Object} data.offsets The measurements of popper, reference and arrow elements\n   * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values\n   * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values\n   * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0\n   */\n\n  /**\n   * Default options provided to Popper.js constructor.<br />\n   * These can be overridden using the `options` argument of Popper.js.<br />\n   * To override an option, simply pass an object with the same\n   * structure of the `options` object, as the 3rd argument. For example:\n   * ```\n   * new Popper(ref, pop, {\n   *   modifiers: {\n   *     preventOverflow: { enabled: false }\n   *   }\n   * })\n   * ```\n   * @type {Object}\n   * @static\n   * @memberof Popper\n   */\n  var Defaults = {\n    /**\n     * Popper's placement.\n     * @prop {Popper.placements} placement='bottom'\n     */\n    placement: 'bottom',\n\n    /**\n     * Set this to true if you want popper to position it self in 'fixed' mode\n     * @prop {Boolean} positionFixed=false\n     */\n    positionFixed: false,\n\n    /**\n     * Whether events (resize, scroll) are initially enabled.\n     * @prop {Boolean} eventsEnabled=true\n     */\n    eventsEnabled: true,\n\n    /**\n     * Set to true if you want to automatically remove the popper when\n     * you call the `destroy` method.\n     * @prop {Boolean} removeOnDestroy=false\n     */\n    removeOnDestroy: false,\n\n    /**\n     * Callback called when the popper is created.<br />\n     * By default, it is set to no-op.<br />\n     * Access Popper.js instance with `data.instance`.\n     * @prop {onCreate}\n     */\n    onCreate: function onCreate() {},\n\n    /**\n     * Callback called when the popper is updated. This callback is not called\n     * on the initialization/creation of the popper, but only on subsequent\n     * updates.<br />\n     * By default, it is set to no-op.<br />\n     * Access Popper.js instance with `data.instance`.\n     * @prop {onUpdate}\n     */\n    onUpdate: function onUpdate() {},\n\n    /**\n     * List of modifiers used to modify the offsets before they are applied to the popper.\n     * They provide most of the functionalities of Popper.js.\n     * @prop {modifiers}\n     */\n    modifiers: modifiers\n  };\n\n  /**\n   * @callback onCreate\n   * @param {dataObject} data\n   */\n\n  /**\n   * @callback onUpdate\n   * @param {dataObject} data\n   */\n\n  // Utils\n  // Methods\n  var Popper = function () {\n    /**\n     * Creates a new Popper.js instance.\n     * @class Popper\n     * @param {HTMLElement|referenceObject} reference - The reference element used to position the popper\n     * @param {HTMLElement} popper - The HTML element used as the popper\n     * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)\n     * @return {Object} instance - The generated Popper.js instance\n     */\n    function Popper(reference, popper) {\n      var _this = this;\n\n      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n      classCallCheck(this, Popper);\n\n      this.scheduleUpdate = function () {\n        return requestAnimationFrame(_this.update);\n      };\n\n      // make update() debounced, so that it only runs at most once-per-tick\n      this.update = debounce(this.update.bind(this));\n\n      // with {} we create a new object with the options inside it\n      this.options = _extends({}, Popper.Defaults, options);\n\n      // init state\n      this.state = {\n        isDestroyed: false,\n        isCreated: false,\n        scrollParents: []\n      };\n\n      // get reference and popper elements (allow jQuery wrappers)\n      this.reference = reference && reference.jquery ? reference[0] : reference;\n      this.popper = popper && popper.jquery ? popper[0] : popper;\n\n      // Deep merge modifiers options\n      this.options.modifiers = {};\n      Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {\n        _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});\n      });\n\n      // Refactoring modifiers' list (Object => Array)\n      this.modifiers = Object.keys(this.options.modifiers).map(function (name) {\n        return _extends({\n          name: name\n        }, _this.options.modifiers[name]);\n      })\n      // sort the modifiers by order\n      .sort(function (a, b) {\n        return a.order - b.order;\n      });\n\n      // modifiers have the ability to execute arbitrary code when Popper.js get inited\n      // such code is executed in the same order of its modifier\n      // they could add new properties to their options configuration\n      // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!\n      this.modifiers.forEach(function (modifierOptions) {\n        if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {\n          modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);\n        }\n      });\n\n      // fire the first update to position the popper in the right place\n      this.update();\n\n      var eventsEnabled = this.options.eventsEnabled;\n      if (eventsEnabled) {\n        // setup event listeners, they will take care of update the position in specific situations\n        this.enableEventListeners();\n      }\n\n      this.state.eventsEnabled = eventsEnabled;\n    }\n\n    // We can't use class properties because they don't get listed in the\n    // class prototype and break stuff like Sinon stubs\n\n\n    createClass(Popper, [{\n      key: 'update',\n      value: function update$$1() {\n        return update.call(this);\n      }\n    }, {\n      key: 'destroy',\n      value: function destroy$$1() {\n        return destroy.call(this);\n      }\n    }, {\n      key: 'enableEventListeners',\n      value: function enableEventListeners$$1() {\n        return enableEventListeners.call(this);\n      }\n    }, {\n      key: 'disableEventListeners',\n      value: function disableEventListeners$$1() {\n        return disableEventListeners.call(this);\n      }\n\n      /**\n       * Schedules an update. It will run on the next UI update available.\n       * @method scheduleUpdate\n       * @memberof Popper\n       */\n\n\n      /**\n       * Collection of utilities useful when writing custom modifiers.\n       * Starting from version 1.7, this method is available only if you\n       * include `popper-utils.js` before `popper.js`.\n       *\n       * **DEPRECATION**: This way to access PopperUtils is deprecated\n       * and will be removed in v2! Use the PopperUtils module directly instead.\n       * Due to the high instability of the methods contained in Utils, we can't\n       * guarantee them to follow semver. Use them at your own risk!\n       * @static\n       * @private\n       * @type {Object}\n       * @deprecated since version 1.8\n       * @member Utils\n       * @memberof Popper\n       */\n\n    }]);\n    return Popper;\n  }();\n\n  /**\n   * The `referenceObject` is an object that provides an interface compatible with Popper.js\n   * and lets you use it as replacement of a real DOM node.<br />\n   * You can use this method to position a popper relatively to a set of coordinates\n   * in case you don't have a DOM node to use as reference.\n   *\n   * ```\n   * new Popper(referenceObject, popperNode);\n   * ```\n   *\n   * NB: This feature isn't supported in Internet Explorer 10.\n   * @name referenceObject\n   * @property {Function} data.getBoundingClientRect\n   * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.\n   * @property {number} data.clientWidth\n   * An ES6 getter that will return the width of the virtual reference element.\n   * @property {number} data.clientHeight\n   * An ES6 getter that will return the height of the virtual reference element.\n   */\n\n\n  Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;\n  Popper.placements = placements;\n  Popper.Defaults = Defaults;\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$4 = 'dropdown';\n  var VERSION$4 = '4.3.1';\n  var DATA_KEY$4 = 'bs.dropdown';\n  var EVENT_KEY$4 = \".\" + DATA_KEY$4;\n  var DATA_API_KEY$4 = '.data-api';\n  var JQUERY_NO_CONFLICT$4 = $.fn[NAME$4];\n  var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n  var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key\n\n  var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key\n\n  var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key\n\n  var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key\n\n  var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)\n\n  var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + \"|\" + ARROW_DOWN_KEYCODE + \"|\" + ESCAPE_KEYCODE);\n  var Event$4 = {\n    HIDE: \"hide\" + EVENT_KEY$4,\n    HIDDEN: \"hidden\" + EVENT_KEY$4,\n    SHOW: \"show\" + EVENT_KEY$4,\n    SHOWN: \"shown\" + EVENT_KEY$4,\n    CLICK: \"click\" + EVENT_KEY$4,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$4 + DATA_API_KEY$4,\n    KEYDOWN_DATA_API: \"keydown\" + EVENT_KEY$4 + DATA_API_KEY$4,\n    KEYUP_DATA_API: \"keyup\" + EVENT_KEY$4 + DATA_API_KEY$4\n  };\n  var ClassName$4 = {\n    DISABLED: 'disabled',\n    SHOW: 'show',\n    DROPUP: 'dropup',\n    DROPRIGHT: 'dropright',\n    DROPLEFT: 'dropleft',\n    MENURIGHT: 'dropdown-menu-right',\n    MENULEFT: 'dropdown-menu-left',\n    POSITION_STATIC: 'position-static'\n  };\n  var Selector$4 = {\n    DATA_TOGGLE: '[data-toggle=\"dropdown\"]',\n    FORM_CHILD: '.dropdown form',\n    MENU: '.dropdown-menu',\n    NAVBAR_NAV: '.navbar-nav',\n    VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n  };\n  var AttachmentMap = {\n    TOP: 'top-start',\n    TOPEND: 'top-end',\n    BOTTOM: 'bottom-start',\n    BOTTOMEND: 'bottom-end',\n    RIGHT: 'right-start',\n    RIGHTEND: 'right-end',\n    LEFT: 'left-start',\n    LEFTEND: 'left-end'\n  };\n  var Default$2 = {\n    offset: 0,\n    flip: true,\n    boundary: 'scrollParent',\n    reference: 'toggle',\n    display: 'dynamic'\n  };\n  var DefaultType$2 = {\n    offset: '(number|string|function)',\n    flip: 'boolean',\n    boundary: '(string|element)',\n    reference: '(string|element)',\n    display: 'string'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Dropdown =\n  /*#__PURE__*/\n  function () {\n    function Dropdown(element, config) {\n      this._element = element;\n      this._popper = null;\n      this._config = this._getConfig(config);\n      this._menu = this._getMenuElement();\n      this._inNavbar = this._detectNavbar();\n\n      this._addEventListeners();\n    } // Getters\n\n\n    var _proto = Dropdown.prototype;\n\n    // Public\n    _proto.toggle = function toggle() {\n      if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED)) {\n        return;\n      }\n\n      var parent = Dropdown._getParentFromElement(this._element);\n\n      var isActive = $(this._menu).hasClass(ClassName$4.SHOW);\n\n      Dropdown._clearMenus();\n\n      if (isActive) {\n        return;\n      }\n\n      var relatedTarget = {\n        relatedTarget: this._element\n      };\n      var showEvent = $.Event(Event$4.SHOW, relatedTarget);\n      $(parent).trigger(showEvent);\n\n      if (showEvent.isDefaultPrevented()) {\n        return;\n      } // Disable totally Popper.js for Dropdown in Navbar\n\n\n      if (!this._inNavbar) {\n        /**\n         * Check for Popper dependency\n         * Popper - https://popper.js.org\n         */\n        if (typeof Popper === 'undefined') {\n          throw new TypeError('Bootstrap\\'s dropdowns require Popper.js (https://popper.js.org/)');\n        }\n\n        var referenceElement = this._element;\n\n        if (this._config.reference === 'parent') {\n          referenceElement = parent;\n        } else if (Util.isElement(this._config.reference)) {\n          referenceElement = this._config.reference; // Check if it's jQuery element\n\n          if (typeof this._config.reference.jquery !== 'undefined') {\n            referenceElement = this._config.reference[0];\n          }\n        } // If boundary is not `scrollParent`, then set position to `static`\n        // to allow the menu to \"escape\" the scroll parent's boundaries\n        // https://github.com/twbs/bootstrap/issues/24251\n\n\n        if (this._config.boundary !== 'scrollParent') {\n          $(parent).addClass(ClassName$4.POSITION_STATIC);\n        }\n\n        this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig());\n      } // If this is a touch-enabled device we add extra\n      // empty mouseover listeners to the body's immediate children;\n      // only needed because of broken event delegation on iOS\n      // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n\n      if ('ontouchstart' in document.documentElement && $(parent).closest(Selector$4.NAVBAR_NAV).length === 0) {\n        $(document.body).children().on('mouseover', null, $.noop);\n      }\n\n      this._element.focus();\n\n      this._element.setAttribute('aria-expanded', true);\n\n      $(this._menu).toggleClass(ClassName$4.SHOW);\n      $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget));\n    };\n\n    _proto.show = function show() {\n      if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || $(this._menu).hasClass(ClassName$4.SHOW)) {\n        return;\n      }\n\n      var relatedTarget = {\n        relatedTarget: this._element\n      };\n      var showEvent = $.Event(Event$4.SHOW, relatedTarget);\n\n      var parent = Dropdown._getParentFromElement(this._element);\n\n      $(parent).trigger(showEvent);\n\n      if (showEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      $(this._menu).toggleClass(ClassName$4.SHOW);\n      $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget));\n    };\n\n    _proto.hide = function hide() {\n      if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || !$(this._menu).hasClass(ClassName$4.SHOW)) {\n        return;\n      }\n\n      var relatedTarget = {\n        relatedTarget: this._element\n      };\n      var hideEvent = $.Event(Event$4.HIDE, relatedTarget);\n\n      var parent = Dropdown._getParentFromElement(this._element);\n\n      $(parent).trigger(hideEvent);\n\n      if (hideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      $(this._menu).toggleClass(ClassName$4.SHOW);\n      $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$4);\n      $(this._element).off(EVENT_KEY$4);\n      this._element = null;\n      this._menu = null;\n\n      if (this._popper !== null) {\n        this._popper.destroy();\n\n        this._popper = null;\n      }\n    };\n\n    _proto.update = function update() {\n      this._inNavbar = this._detectNavbar();\n\n      if (this._popper !== null) {\n        this._popper.scheduleUpdate();\n      }\n    } // Private\n    ;\n\n    _proto._addEventListeners = function _addEventListeners() {\n      var _this = this;\n\n      $(this._element).on(Event$4.CLICK, function (event) {\n        event.preventDefault();\n        event.stopPropagation();\n\n        _this.toggle();\n      });\n    };\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, this.constructor.Default, $(this._element).data(), config);\n      Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType);\n      return config;\n    };\n\n    _proto._getMenuElement = function _getMenuElement() {\n      if (!this._menu) {\n        var parent = Dropdown._getParentFromElement(this._element);\n\n        if (parent) {\n          this._menu = parent.querySelector(Selector$4.MENU);\n        }\n      }\n\n      return this._menu;\n    };\n\n    _proto._getPlacement = function _getPlacement() {\n      var $parentDropdown = $(this._element.parentNode);\n      var placement = AttachmentMap.BOTTOM; // Handle dropup\n\n      if ($parentDropdown.hasClass(ClassName$4.DROPUP)) {\n        placement = AttachmentMap.TOP;\n\n        if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {\n          placement = AttachmentMap.TOPEND;\n        }\n      } else if ($parentDropdown.hasClass(ClassName$4.DROPRIGHT)) {\n        placement = AttachmentMap.RIGHT;\n      } else if ($parentDropdown.hasClass(ClassName$4.DROPLEFT)) {\n        placement = AttachmentMap.LEFT;\n      } else if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {\n        placement = AttachmentMap.BOTTOMEND;\n      }\n\n      return placement;\n    };\n\n    _proto._detectNavbar = function _detectNavbar() {\n      return $(this._element).closest('.navbar').length > 0;\n    };\n\n    _proto._getOffset = function _getOffset() {\n      var _this2 = this;\n\n      var offset = {};\n\n      if (typeof this._config.offset === 'function') {\n        offset.fn = function (data) {\n          data.offsets = _objectSpread({}, data.offsets, _this2._config.offset(data.offsets, _this2._element) || {});\n          return data;\n        };\n      } else {\n        offset.offset = this._config.offset;\n      }\n\n      return offset;\n    };\n\n    _proto._getPopperConfig = function _getPopperConfig() {\n      var popperConfig = {\n        placement: this._getPlacement(),\n        modifiers: {\n          offset: this._getOffset(),\n          flip: {\n            enabled: this._config.flip\n          },\n          preventOverflow: {\n            boundariesElement: this._config.boundary\n          }\n        } // Disable Popper.js if we have a static display\n\n      };\n\n      if (this._config.display === 'static') {\n        popperConfig.modifiers.applyStyle = {\n          enabled: false\n        };\n      }\n\n      return popperConfig;\n    } // Static\n    ;\n\n    Dropdown._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$4);\n\n        var _config = typeof config === 'object' ? config : null;\n\n        if (!data) {\n          data = new Dropdown(this, _config);\n          $(this).data(DATA_KEY$4, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    Dropdown._clearMenus = function _clearMenus(event) {\n      if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {\n        return;\n      }\n\n      var toggles = [].slice.call(document.querySelectorAll(Selector$4.DATA_TOGGLE));\n\n      for (var i = 0, len = toggles.length; i < len; i++) {\n        var parent = Dropdown._getParentFromElement(toggles[i]);\n\n        var context = $(toggles[i]).data(DATA_KEY$4);\n        var relatedTarget = {\n          relatedTarget: toggles[i]\n        };\n\n        if (event && event.type === 'click') {\n          relatedTarget.clickEvent = event;\n        }\n\n        if (!context) {\n          continue;\n        }\n\n        var dropdownMenu = context._menu;\n\n        if (!$(parent).hasClass(ClassName$4.SHOW)) {\n          continue;\n        }\n\n        if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) {\n          continue;\n        }\n\n        var hideEvent = $.Event(Event$4.HIDE, relatedTarget);\n        $(parent).trigger(hideEvent);\n\n        if (hideEvent.isDefaultPrevented()) {\n          continue;\n        } // If this is a touch-enabled device we remove the extra\n        // empty mouseover listeners we added for iOS support\n\n\n        if ('ontouchstart' in document.documentElement) {\n          $(document.body).children().off('mouseover', null, $.noop);\n        }\n\n        toggles[i].setAttribute('aria-expanded', 'false');\n        $(dropdownMenu).removeClass(ClassName$4.SHOW);\n        $(parent).removeClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));\n      }\n    };\n\n    Dropdown._getParentFromElement = function _getParentFromElement(element) {\n      var parent;\n      var selector = Util.getSelectorFromElement(element);\n\n      if (selector) {\n        parent = document.querySelector(selector);\n      }\n\n      return parent || element.parentNode;\n    } // eslint-disable-next-line complexity\n    ;\n\n    Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {\n      // If not input/textarea:\n      //  - And not a key in REGEXP_KEYDOWN => not a dropdown command\n      // If input/textarea:\n      //  - If space key => not a dropdown command\n      //  - If key is other than escape\n      //    - If key is not up or down => not a dropdown command\n      //    - If trigger inside the menu => not a dropdown command\n      if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector$4.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {\n        return;\n      }\n\n      event.preventDefault();\n      event.stopPropagation();\n\n      if (this.disabled || $(this).hasClass(ClassName$4.DISABLED)) {\n        return;\n      }\n\n      var parent = Dropdown._getParentFromElement(this);\n\n      var isActive = $(parent).hasClass(ClassName$4.SHOW);\n\n      if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {\n        if (event.which === ESCAPE_KEYCODE) {\n          var toggle = parent.querySelector(Selector$4.DATA_TOGGLE);\n          $(toggle).trigger('focus');\n        }\n\n        $(this).trigger('click');\n        return;\n      }\n\n      var items = [].slice.call(parent.querySelectorAll(Selector$4.VISIBLE_ITEMS));\n\n      if (items.length === 0) {\n        return;\n      }\n\n      var index = items.indexOf(event.target);\n\n      if (event.which === ARROW_UP_KEYCODE && index > 0) {\n        // Up\n        index--;\n      }\n\n      if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {\n        // Down\n        index++;\n      }\n\n      if (index < 0) {\n        index = 0;\n      }\n\n      items[index].focus();\n    };\n\n    _createClass(Dropdown, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$4;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$2;\n      }\n    }, {\n      key: \"DefaultType\",\n      get: function get() {\n        return DefaultType$2;\n      }\n    }]);\n\n    return Dropdown;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$4.KEYDOWN_DATA_API, Selector$4.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event$4.KEYDOWN_DATA_API, Selector$4.MENU, Dropdown._dataApiKeydownHandler).on(Event$4.CLICK_DATA_API + \" \" + Event$4.KEYUP_DATA_API, Dropdown._clearMenus).on(Event$4.CLICK_DATA_API, Selector$4.DATA_TOGGLE, function (event) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    Dropdown._jQueryInterface.call($(this), 'toggle');\n  }).on(Event$4.CLICK_DATA_API, Selector$4.FORM_CHILD, function (e) {\n    e.stopPropagation();\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$4] = Dropdown._jQueryInterface;\n  $.fn[NAME$4].Constructor = Dropdown;\n\n  $.fn[NAME$4].noConflict = function () {\n    $.fn[NAME$4] = JQUERY_NO_CONFLICT$4;\n    return Dropdown._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$5 = 'modal';\n  var VERSION$5 = '4.3.1';\n  var DATA_KEY$5 = 'bs.modal';\n  var EVENT_KEY$5 = \".\" + DATA_KEY$5;\n  var DATA_API_KEY$5 = '.data-api';\n  var JQUERY_NO_CONFLICT$5 = $.fn[NAME$5];\n  var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n  var Default$3 = {\n    backdrop: true,\n    keyboard: true,\n    focus: true,\n    show: true\n  };\n  var DefaultType$3 = {\n    backdrop: '(boolean|string)',\n    keyboard: 'boolean',\n    focus: 'boolean',\n    show: 'boolean'\n  };\n  var Event$5 = {\n    HIDE: \"hide\" + EVENT_KEY$5,\n    HIDDEN: \"hidden\" + EVENT_KEY$5,\n    SHOW: \"show\" + EVENT_KEY$5,\n    SHOWN: \"shown\" + EVENT_KEY$5,\n    FOCUSIN: \"focusin\" + EVENT_KEY$5,\n    RESIZE: \"resize\" + EVENT_KEY$5,\n    CLICK_DISMISS: \"click.dismiss\" + EVENT_KEY$5,\n    KEYDOWN_DISMISS: \"keydown.dismiss\" + EVENT_KEY$5,\n    MOUSEUP_DISMISS: \"mouseup.dismiss\" + EVENT_KEY$5,\n    MOUSEDOWN_DISMISS: \"mousedown.dismiss\" + EVENT_KEY$5,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$5 + DATA_API_KEY$5\n  };\n  var ClassName$5 = {\n    SCROLLABLE: 'modal-dialog-scrollable',\n    SCROLLBAR_MEASURER: 'modal-scrollbar-measure',\n    BACKDROP: 'modal-backdrop',\n    OPEN: 'modal-open',\n    FADE: 'fade',\n    SHOW: 'show'\n  };\n  var Selector$5 = {\n    DIALOG: '.modal-dialog',\n    MODAL_BODY: '.modal-body',\n    DATA_TOGGLE: '[data-toggle=\"modal\"]',\n    DATA_DISMISS: '[data-dismiss=\"modal\"]',\n    FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',\n    STICKY_CONTENT: '.sticky-top'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Modal =\n  /*#__PURE__*/\n  function () {\n    function Modal(element, config) {\n      this._config = this._getConfig(config);\n      this._element = element;\n      this._dialog = element.querySelector(Selector$5.DIALOG);\n      this._backdrop = null;\n      this._isShown = false;\n      this._isBodyOverflowing = false;\n      this._ignoreBackdropClick = false;\n      this._isTransitioning = false;\n      this._scrollbarWidth = 0;\n    } // Getters\n\n\n    var _proto = Modal.prototype;\n\n    // Public\n    _proto.toggle = function toggle(relatedTarget) {\n      return this._isShown ? this.hide() : this.show(relatedTarget);\n    };\n\n    _proto.show = function show(relatedTarget) {\n      var _this = this;\n\n      if (this._isShown || this._isTransitioning) {\n        return;\n      }\n\n      if ($(this._element).hasClass(ClassName$5.FADE)) {\n        this._isTransitioning = true;\n      }\n\n      var showEvent = $.Event(Event$5.SHOW, {\n        relatedTarget: relatedTarget\n      });\n      $(this._element).trigger(showEvent);\n\n      if (this._isShown || showEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      this._isShown = true;\n\n      this._checkScrollbar();\n\n      this._setScrollbar();\n\n      this._adjustDialog();\n\n      this._setEscapeEvent();\n\n      this._setResizeEvent();\n\n      $(this._element).on(Event$5.CLICK_DISMISS, Selector$5.DATA_DISMISS, function (event) {\n        return _this.hide(event);\n      });\n      $(this._dialog).on(Event$5.MOUSEDOWN_DISMISS, function () {\n        $(_this._element).one(Event$5.MOUSEUP_DISMISS, function (event) {\n          if ($(event.target).is(_this._element)) {\n            _this._ignoreBackdropClick = true;\n          }\n        });\n      });\n\n      this._showBackdrop(function () {\n        return _this._showElement(relatedTarget);\n      });\n    };\n\n    _proto.hide = function hide(event) {\n      var _this2 = this;\n\n      if (event) {\n        event.preventDefault();\n      }\n\n      if (!this._isShown || this._isTransitioning) {\n        return;\n      }\n\n      var hideEvent = $.Event(Event$5.HIDE);\n      $(this._element).trigger(hideEvent);\n\n      if (!this._isShown || hideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      this._isShown = false;\n      var transition = $(this._element).hasClass(ClassName$5.FADE);\n\n      if (transition) {\n        this._isTransitioning = true;\n      }\n\n      this._setEscapeEvent();\n\n      this._setResizeEvent();\n\n      $(document).off(Event$5.FOCUSIN);\n      $(this._element).removeClass(ClassName$5.SHOW);\n      $(this._element).off(Event$5.CLICK_DISMISS);\n      $(this._dialog).off(Event$5.MOUSEDOWN_DISMISS);\n\n      if (transition) {\n        var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n        $(this._element).one(Util.TRANSITION_END, function (event) {\n          return _this2._hideModal(event);\n        }).emulateTransitionEnd(transitionDuration);\n      } else {\n        this._hideModal();\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      [window, this._element, this._dialog].forEach(function (htmlElement) {\n        return $(htmlElement).off(EVENT_KEY$5);\n      });\n      /**\n       * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API`\n       * Do not move `document` in `htmlElements` array\n       * It will remove `Event.CLICK_DATA_API` event that should remain\n       */\n\n      $(document).off(Event$5.FOCUSIN);\n      $.removeData(this._element, DATA_KEY$5);\n      this._config = null;\n      this._element = null;\n      this._dialog = null;\n      this._backdrop = null;\n      this._isShown = null;\n      this._isBodyOverflowing = null;\n      this._ignoreBackdropClick = null;\n      this._isTransitioning = null;\n      this._scrollbarWidth = null;\n    };\n\n    _proto.handleUpdate = function handleUpdate() {\n      this._adjustDialog();\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default$3, config);\n      Util.typeCheckConfig(NAME$5, config, DefaultType$3);\n      return config;\n    };\n\n    _proto._showElement = function _showElement(relatedTarget) {\n      var _this3 = this;\n\n      var transition = $(this._element).hasClass(ClassName$5.FADE);\n\n      if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n        // Don't move modal's DOM position\n        document.body.appendChild(this._element);\n      }\n\n      this._element.style.display = 'block';\n\n      this._element.removeAttribute('aria-hidden');\n\n      this._element.setAttribute('aria-modal', true);\n\n      if ($(this._dialog).hasClass(ClassName$5.SCROLLABLE)) {\n        this._dialog.querySelector(Selector$5.MODAL_BODY).scrollTop = 0;\n      } else {\n        this._element.scrollTop = 0;\n      }\n\n      if (transition) {\n        Util.reflow(this._element);\n      }\n\n      $(this._element).addClass(ClassName$5.SHOW);\n\n      if (this._config.focus) {\n        this._enforceFocus();\n      }\n\n      var shownEvent = $.Event(Event$5.SHOWN, {\n        relatedTarget: relatedTarget\n      });\n\n      var transitionComplete = function transitionComplete() {\n        if (_this3._config.focus) {\n          _this3._element.focus();\n        }\n\n        _this3._isTransitioning = false;\n        $(_this3._element).trigger(shownEvent);\n      };\n\n      if (transition) {\n        var transitionDuration = Util.getTransitionDurationFromElement(this._dialog);\n        $(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration);\n      } else {\n        transitionComplete();\n      }\n    };\n\n    _proto._enforceFocus = function _enforceFocus() {\n      var _this4 = this;\n\n      $(document).off(Event$5.FOCUSIN) // Guard against infinite focus loop\n      .on(Event$5.FOCUSIN, function (event) {\n        if (document !== event.target && _this4._element !== event.target && $(_this4._element).has(event.target).length === 0) {\n          _this4._element.focus();\n        }\n      });\n    };\n\n    _proto._setEscapeEvent = function _setEscapeEvent() {\n      var _this5 = this;\n\n      if (this._isShown && this._config.keyboard) {\n        $(this._element).on(Event$5.KEYDOWN_DISMISS, function (event) {\n          if (event.which === ESCAPE_KEYCODE$1) {\n            event.preventDefault();\n\n            _this5.hide();\n          }\n        });\n      } else if (!this._isShown) {\n        $(this._element).off(Event$5.KEYDOWN_DISMISS);\n      }\n    };\n\n    _proto._setResizeEvent = function _setResizeEvent() {\n      var _this6 = this;\n\n      if (this._isShown) {\n        $(window).on(Event$5.RESIZE, function (event) {\n          return _this6.handleUpdate(event);\n        });\n      } else {\n        $(window).off(Event$5.RESIZE);\n      }\n    };\n\n    _proto._hideModal = function _hideModal() {\n      var _this7 = this;\n\n      this._element.style.display = 'none';\n\n      this._element.setAttribute('aria-hidden', true);\n\n      this._element.removeAttribute('aria-modal');\n\n      this._isTransitioning = false;\n\n      this._showBackdrop(function () {\n        $(document.body).removeClass(ClassName$5.OPEN);\n\n        _this7._resetAdjustments();\n\n        _this7._resetScrollbar();\n\n        $(_this7._element).trigger(Event$5.HIDDEN);\n      });\n    };\n\n    _proto._removeBackdrop = function _removeBackdrop() {\n      if (this._backdrop) {\n        $(this._backdrop).remove();\n        this._backdrop = null;\n      }\n    };\n\n    _proto._showBackdrop = function _showBackdrop(callback) {\n      var _this8 = this;\n\n      var animate = $(this._element).hasClass(ClassName$5.FADE) ? ClassName$5.FADE : '';\n\n      if (this._isShown && this._config.backdrop) {\n        this._backdrop = document.createElement('div');\n        this._backdrop.className = ClassName$5.BACKDROP;\n\n        if (animate) {\n          this._backdrop.classList.add(animate);\n        }\n\n        $(this._backdrop).appendTo(document.body);\n        $(this._element).on(Event$5.CLICK_DISMISS, function (event) {\n          if (_this8._ignoreBackdropClick) {\n            _this8._ignoreBackdropClick = false;\n            return;\n          }\n\n          if (event.target !== event.currentTarget) {\n            return;\n          }\n\n          if (_this8._config.backdrop === 'static') {\n            _this8._element.focus();\n          } else {\n            _this8.hide();\n          }\n        });\n\n        if (animate) {\n          Util.reflow(this._backdrop);\n        }\n\n        $(this._backdrop).addClass(ClassName$5.SHOW);\n\n        if (!callback) {\n          return;\n        }\n\n        if (!animate) {\n          callback();\n          return;\n        }\n\n        var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n        $(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration);\n      } else if (!this._isShown && this._backdrop) {\n        $(this._backdrop).removeClass(ClassName$5.SHOW);\n\n        var callbackRemove = function callbackRemove() {\n          _this8._removeBackdrop();\n\n          if (callback) {\n            callback();\n          }\n        };\n\n        if ($(this._element).hasClass(ClassName$5.FADE)) {\n          var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n\n          $(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration);\n        } else {\n          callbackRemove();\n        }\n      } else if (callback) {\n        callback();\n      }\n    } // ----------------------------------------------------------------------\n    // the following methods are used to handle overflowing modals\n    // todo (fat): these should probably be refactored out of modal.js\n    // ----------------------------------------------------------------------\n    ;\n\n    _proto._adjustDialog = function _adjustDialog() {\n      var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n\n      if (!this._isBodyOverflowing && isModalOverflowing) {\n        this._element.style.paddingLeft = this._scrollbarWidth + \"px\";\n      }\n\n      if (this._isBodyOverflowing && !isModalOverflowing) {\n        this._element.style.paddingRight = this._scrollbarWidth + \"px\";\n      }\n    };\n\n    _proto._resetAdjustments = function _resetAdjustments() {\n      this._element.style.paddingLeft = '';\n      this._element.style.paddingRight = '';\n    };\n\n    _proto._checkScrollbar = function _checkScrollbar() {\n      var rect = document.body.getBoundingClientRect();\n      this._isBodyOverflowing = rect.left + rect.right < window.innerWidth;\n      this._scrollbarWidth = this._getScrollbarWidth();\n    };\n\n    _proto._setScrollbar = function _setScrollbar() {\n      var _this9 = this;\n\n      if (this._isBodyOverflowing) {\n        // Note: DOMNode.style.paddingRight returns the actual value or '' if not set\n        //   while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set\n        var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));\n        var stickyContent = [].slice.call(document.querySelectorAll(Selector$5.STICKY_CONTENT)); // Adjust fixed content padding\n\n        $(fixedContent).each(function (index, element) {\n          var actualPadding = element.style.paddingRight;\n          var calculatedPadding = $(element).css('padding-right');\n          $(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + \"px\");\n        }); // Adjust sticky content margin\n\n        $(stickyContent).each(function (index, element) {\n          var actualMargin = element.style.marginRight;\n          var calculatedMargin = $(element).css('margin-right');\n          $(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + \"px\");\n        }); // Adjust body padding\n\n        var actualPadding = document.body.style.paddingRight;\n        var calculatedPadding = $(document.body).css('padding-right');\n        $(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + \"px\");\n      }\n\n      $(document.body).addClass(ClassName$5.OPEN);\n    };\n\n    _proto._resetScrollbar = function _resetScrollbar() {\n      // Restore fixed content padding\n      var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));\n      $(fixedContent).each(function (index, element) {\n        var padding = $(element).data('padding-right');\n        $(element).removeData('padding-right');\n        element.style.paddingRight = padding ? padding : '';\n      }); // Restore sticky content\n\n      var elements = [].slice.call(document.querySelectorAll(\"\" + Selector$5.STICKY_CONTENT));\n      $(elements).each(function (index, element) {\n        var margin = $(element).data('margin-right');\n\n        if (typeof margin !== 'undefined') {\n          $(element).css('margin-right', margin).removeData('margin-right');\n        }\n      }); // Restore body padding\n\n      var padding = $(document.body).data('padding-right');\n      $(document.body).removeData('padding-right');\n      document.body.style.paddingRight = padding ? padding : '';\n    };\n\n    _proto._getScrollbarWidth = function _getScrollbarWidth() {\n      // thx d.walsh\n      var scrollDiv = document.createElement('div');\n      scrollDiv.className = ClassName$5.SCROLLBAR_MEASURER;\n      document.body.appendChild(scrollDiv);\n      var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;\n      document.body.removeChild(scrollDiv);\n      return scrollbarWidth;\n    } // Static\n    ;\n\n    Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$5);\n\n        var _config = _objectSpread({}, Default$3, $(this).data(), typeof config === 'object' && config ? config : {});\n\n        if (!data) {\n          data = new Modal(this, _config);\n          $(this).data(DATA_KEY$5, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config](relatedTarget);\n        } else if (_config.show) {\n          data.show(relatedTarget);\n        }\n      });\n    };\n\n    _createClass(Modal, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$5;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$3;\n      }\n    }]);\n\n    return Modal;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$5.CLICK_DATA_API, Selector$5.DATA_TOGGLE, function (event) {\n    var _this10 = this;\n\n    var target;\n    var selector = Util.getSelectorFromElement(this);\n\n    if (selector) {\n      target = document.querySelector(selector);\n    }\n\n    var config = $(target).data(DATA_KEY$5) ? 'toggle' : _objectSpread({}, $(target).data(), $(this).data());\n\n    if (this.tagName === 'A' || this.tagName === 'AREA') {\n      event.preventDefault();\n    }\n\n    var $target = $(target).one(Event$5.SHOW, function (showEvent) {\n      if (showEvent.isDefaultPrevented()) {\n        // Only register focus restorer if modal will actually get shown\n        return;\n      }\n\n      $target.one(Event$5.HIDDEN, function () {\n        if ($(_this10).is(':visible')) {\n          _this10.focus();\n        }\n      });\n    });\n\n    Modal._jQueryInterface.call($(target), config, this);\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$5] = Modal._jQueryInterface;\n  $.fn[NAME$5].Constructor = Modal;\n\n  $.fn[NAME$5].noConflict = function () {\n    $.fn[NAME$5] = JQUERY_NO_CONFLICT$5;\n    return Modal._jQueryInterface;\n  };\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.3.1): tools/sanitizer.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n  var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href'];\n  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\n  var DefaultWhitelist = {\n    // Global attributes allowed on any supplied element below.\n    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n    a: ['target', 'href', 'title', 'rel'],\n    area: [],\n    b: [],\n    br: [],\n    col: [],\n    code: [],\n    div: [],\n    em: [],\n    hr: [],\n    h1: [],\n    h2: [],\n    h3: [],\n    h4: [],\n    h5: [],\n    h6: [],\n    i: [],\n    img: ['src', 'alt', 'title', 'width', 'height'],\n    li: [],\n    ol: [],\n    p: [],\n    pre: [],\n    s: [],\n    small: [],\n    span: [],\n    sub: [],\n    sup: [],\n    strong: [],\n    u: [],\n    ul: []\n    /**\n     * A pattern that recognizes a commonly useful subset of URLs that are safe.\n     *\n     * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\n     */\n\n  };\n  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;\n  /**\n   * A pattern that matches safe data URLs. Only matches image, video and audio types.\n   *\n   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\n   */\n\n  var DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;\n\n  function allowedAttribute(attr, allowedAttributeList) {\n    var attrName = attr.nodeName.toLowerCase();\n\n    if (allowedAttributeList.indexOf(attrName) !== -1) {\n      if (uriAttrs.indexOf(attrName) !== -1) {\n        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN));\n      }\n\n      return true;\n    }\n\n    var regExp = allowedAttributeList.filter(function (attrRegex) {\n      return attrRegex instanceof RegExp;\n    }); // Check if a regular expression validates the attribute.\n\n    for (var i = 0, l = regExp.length; i < l; i++) {\n      if (attrName.match(regExp[i])) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {\n    if (unsafeHtml.length === 0) {\n      return unsafeHtml;\n    }\n\n    if (sanitizeFn && typeof sanitizeFn === 'function') {\n      return sanitizeFn(unsafeHtml);\n    }\n\n    var domParser = new window.DOMParser();\n    var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');\n    var whitelistKeys = Object.keys(whiteList);\n    var elements = [].slice.call(createdDocument.body.querySelectorAll('*'));\n\n    var _loop = function _loop(i, len) {\n      var el = elements[i];\n      var elName = el.nodeName.toLowerCase();\n\n      if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {\n        el.parentNode.removeChild(el);\n        return \"continue\";\n      }\n\n      var attributeList = [].slice.call(el.attributes);\n      var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);\n      attributeList.forEach(function (attr) {\n        if (!allowedAttribute(attr, whitelistedAttributes)) {\n          el.removeAttribute(attr.nodeName);\n        }\n      });\n    };\n\n    for (var i = 0, len = elements.length; i < len; i++) {\n      var _ret = _loop(i, len);\n\n      if (_ret === \"continue\") continue;\n    }\n\n    return createdDocument.body.innerHTML;\n  }\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$6 = 'tooltip';\n  var VERSION$6 = '4.3.1';\n  var DATA_KEY$6 = 'bs.tooltip';\n  var EVENT_KEY$6 = \".\" + DATA_KEY$6;\n  var JQUERY_NO_CONFLICT$6 = $.fn[NAME$6];\n  var CLASS_PREFIX = 'bs-tooltip';\n  var BSCLS_PREFIX_REGEX = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX + \"\\\\S+\", 'g');\n  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];\n  var DefaultType$4 = {\n    animation: 'boolean',\n    template: 'string',\n    title: '(string|element|function)',\n    trigger: 'string',\n    delay: '(number|object)',\n    html: 'boolean',\n    selector: '(string|boolean)',\n    placement: '(string|function)',\n    offset: '(number|string|function)',\n    container: '(string|element|boolean)',\n    fallbackPlacement: '(string|array)',\n    boundary: '(string|element)',\n    sanitize: 'boolean',\n    sanitizeFn: '(null|function)',\n    whiteList: 'object'\n  };\n  var AttachmentMap$1 = {\n    AUTO: 'auto',\n    TOP: 'top',\n    RIGHT: 'right',\n    BOTTOM: 'bottom',\n    LEFT: 'left'\n  };\n  var Default$4 = {\n    animation: true,\n    template: '<div class=\"tooltip\" role=\"tooltip\">' + '<div class=\"arrow\"></div>' + '<div class=\"tooltip-inner\"></div></div>',\n    trigger: 'hover focus',\n    title: '',\n    delay: 0,\n    html: false,\n    selector: false,\n    placement: 'top',\n    offset: 0,\n    container: false,\n    fallbackPlacement: 'flip',\n    boundary: 'scrollParent',\n    sanitize: true,\n    sanitizeFn: null,\n    whiteList: DefaultWhitelist\n  };\n  var HoverState = {\n    SHOW: 'show',\n    OUT: 'out'\n  };\n  var Event$6 = {\n    HIDE: \"hide\" + EVENT_KEY$6,\n    HIDDEN: \"hidden\" + EVENT_KEY$6,\n    SHOW: \"show\" + EVENT_KEY$6,\n    SHOWN: \"shown\" + EVENT_KEY$6,\n    INSERTED: \"inserted\" + EVENT_KEY$6,\n    CLICK: \"click\" + EVENT_KEY$6,\n    FOCUSIN: \"focusin\" + EVENT_KEY$6,\n    FOCUSOUT: \"focusout\" + EVENT_KEY$6,\n    MOUSEENTER: \"mouseenter\" + EVENT_KEY$6,\n    MOUSELEAVE: \"mouseleave\" + EVENT_KEY$6\n  };\n  var ClassName$6 = {\n    FADE: 'fade',\n    SHOW: 'show'\n  };\n  var Selector$6 = {\n    TOOLTIP: '.tooltip',\n    TOOLTIP_INNER: '.tooltip-inner',\n    ARROW: '.arrow'\n  };\n  var Trigger = {\n    HOVER: 'hover',\n    FOCUS: 'focus',\n    CLICK: 'click',\n    MANUAL: 'manual'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Tooltip =\n  /*#__PURE__*/\n  function () {\n    function Tooltip(element, config) {\n      /**\n       * Check for Popper dependency\n       * Popper - https://popper.js.org\n       */\n      if (typeof Popper === 'undefined') {\n        throw new TypeError('Bootstrap\\'s tooltips require Popper.js (https://popper.js.org/)');\n      } // private\n\n\n      this._isEnabled = true;\n      this._timeout = 0;\n      this._hoverState = '';\n      this._activeTrigger = {};\n      this._popper = null; // Protected\n\n      this.element = element;\n      this.config = this._getConfig(config);\n      this.tip = null;\n\n      this._setListeners();\n    } // Getters\n\n\n    var _proto = Tooltip.prototype;\n\n    // Public\n    _proto.enable = function enable() {\n      this._isEnabled = true;\n    };\n\n    _proto.disable = function disable() {\n      this._isEnabled = false;\n    };\n\n    _proto.toggleEnabled = function toggleEnabled() {\n      this._isEnabled = !this._isEnabled;\n    };\n\n    _proto.toggle = function toggle(event) {\n      if (!this._isEnabled) {\n        return;\n      }\n\n      if (event) {\n        var dataKey = this.constructor.DATA_KEY;\n        var context = $(event.currentTarget).data(dataKey);\n\n        if (!context) {\n          context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n          $(event.currentTarget).data(dataKey, context);\n        }\n\n        context._activeTrigger.click = !context._activeTrigger.click;\n\n        if (context._isWithActiveTrigger()) {\n          context._enter(null, context);\n        } else {\n          context._leave(null, context);\n        }\n      } else {\n        if ($(this.getTipElement()).hasClass(ClassName$6.SHOW)) {\n          this._leave(null, this);\n\n          return;\n        }\n\n        this._enter(null, this);\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      clearTimeout(this._timeout);\n      $.removeData(this.element, this.constructor.DATA_KEY);\n      $(this.element).off(this.constructor.EVENT_KEY);\n      $(this.element).closest('.modal').off('hide.bs.modal');\n\n      if (this.tip) {\n        $(this.tip).remove();\n      }\n\n      this._isEnabled = null;\n      this._timeout = null;\n      this._hoverState = null;\n      this._activeTrigger = null;\n\n      if (this._popper !== null) {\n        this._popper.destroy();\n      }\n\n      this._popper = null;\n      this.element = null;\n      this.config = null;\n      this.tip = null;\n    };\n\n    _proto.show = function show() {\n      var _this = this;\n\n      if ($(this.element).css('display') === 'none') {\n        throw new Error('Please use show on visible elements');\n      }\n\n      var showEvent = $.Event(this.constructor.Event.SHOW);\n\n      if (this.isWithContent() && this._isEnabled) {\n        $(this.element).trigger(showEvent);\n        var shadowRoot = Util.findShadowRoot(this.element);\n        var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element);\n\n        if (showEvent.isDefaultPrevented() || !isInTheDom) {\n          return;\n        }\n\n        var tip = this.getTipElement();\n        var tipId = Util.getUID(this.constructor.NAME);\n        tip.setAttribute('id', tipId);\n        this.element.setAttribute('aria-describedby', tipId);\n        this.setContent();\n\n        if (this.config.animation) {\n          $(tip).addClass(ClassName$6.FADE);\n        }\n\n        var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;\n\n        var attachment = this._getAttachment(placement);\n\n        this.addAttachmentClass(attachment);\n\n        var container = this._getContainer();\n\n        $(tip).data(this.constructor.DATA_KEY, this);\n\n        if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {\n          $(tip).appendTo(container);\n        }\n\n        $(this.element).trigger(this.constructor.Event.INSERTED);\n        this._popper = new Popper(this.element, tip, {\n          placement: attachment,\n          modifiers: {\n            offset: this._getOffset(),\n            flip: {\n              behavior: this.config.fallbackPlacement\n            },\n            arrow: {\n              element: Selector$6.ARROW\n            },\n            preventOverflow: {\n              boundariesElement: this.config.boundary\n            }\n          },\n          onCreate: function onCreate(data) {\n            if (data.originalPlacement !== data.placement) {\n              _this._handlePopperPlacementChange(data);\n            }\n          },\n          onUpdate: function onUpdate(data) {\n            return _this._handlePopperPlacementChange(data);\n          }\n        });\n        $(tip).addClass(ClassName$6.SHOW); // If this is a touch-enabled device we add extra\n        // empty mouseover listeners to the body's immediate children;\n        // only needed because of broken event delegation on iOS\n        // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n        if ('ontouchstart' in document.documentElement) {\n          $(document.body).children().on('mouseover', null, $.noop);\n        }\n\n        var complete = function complete() {\n          if (_this.config.animation) {\n            _this._fixTransition();\n          }\n\n          var prevHoverState = _this._hoverState;\n          _this._hoverState = null;\n          $(_this.element).trigger(_this.constructor.Event.SHOWN);\n\n          if (prevHoverState === HoverState.OUT) {\n            _this._leave(null, _this);\n          }\n        };\n\n        if ($(this.tip).hasClass(ClassName$6.FADE)) {\n          var transitionDuration = Util.getTransitionDurationFromElement(this.tip);\n          $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n        } else {\n          complete();\n        }\n      }\n    };\n\n    _proto.hide = function hide(callback) {\n      var _this2 = this;\n\n      var tip = this.getTipElement();\n      var hideEvent = $.Event(this.constructor.Event.HIDE);\n\n      var complete = function complete() {\n        if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {\n          tip.parentNode.removeChild(tip);\n        }\n\n        _this2._cleanTipClass();\n\n        _this2.element.removeAttribute('aria-describedby');\n\n        $(_this2.element).trigger(_this2.constructor.Event.HIDDEN);\n\n        if (_this2._popper !== null) {\n          _this2._popper.destroy();\n        }\n\n        if (callback) {\n          callback();\n        }\n      };\n\n      $(this.element).trigger(hideEvent);\n\n      if (hideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      $(tip).removeClass(ClassName$6.SHOW); // If this is a touch-enabled device we remove the extra\n      // empty mouseover listeners we added for iOS support\n\n      if ('ontouchstart' in document.documentElement) {\n        $(document.body).children().off('mouseover', null, $.noop);\n      }\n\n      this._activeTrigger[Trigger.CLICK] = false;\n      this._activeTrigger[Trigger.FOCUS] = false;\n      this._activeTrigger[Trigger.HOVER] = false;\n\n      if ($(this.tip).hasClass(ClassName$6.FADE)) {\n        var transitionDuration = Util.getTransitionDurationFromElement(tip);\n        $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      } else {\n        complete();\n      }\n\n      this._hoverState = '';\n    };\n\n    _proto.update = function update() {\n      if (this._popper !== null) {\n        this._popper.scheduleUpdate();\n      }\n    } // Protected\n    ;\n\n    _proto.isWithContent = function isWithContent() {\n      return Boolean(this.getTitle());\n    };\n\n    _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n      $(this.getTipElement()).addClass(CLASS_PREFIX + \"-\" + attachment);\n    };\n\n    _proto.getTipElement = function getTipElement() {\n      this.tip = this.tip || $(this.config.template)[0];\n      return this.tip;\n    };\n\n    _proto.setContent = function setContent() {\n      var tip = this.getTipElement();\n      this.setElementContent($(tip.querySelectorAll(Selector$6.TOOLTIP_INNER)), this.getTitle());\n      $(tip).removeClass(ClassName$6.FADE + \" \" + ClassName$6.SHOW);\n    };\n\n    _proto.setElementContent = function setElementContent($element, content) {\n      if (typeof content === 'object' && (content.nodeType || content.jquery)) {\n        // Content is a DOM node or a jQuery\n        if (this.config.html) {\n          if (!$(content).parent().is($element)) {\n            $element.empty().append(content);\n          }\n        } else {\n          $element.text($(content).text());\n        }\n\n        return;\n      }\n\n      if (this.config.html) {\n        if (this.config.sanitize) {\n          content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn);\n        }\n\n        $element.html(content);\n      } else {\n        $element.text(content);\n      }\n    };\n\n    _proto.getTitle = function getTitle() {\n      var title = this.element.getAttribute('data-original-title');\n\n      if (!title) {\n        title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;\n      }\n\n      return title;\n    } // Private\n    ;\n\n    _proto._getOffset = function _getOffset() {\n      var _this3 = this;\n\n      var offset = {};\n\n      if (typeof this.config.offset === 'function') {\n        offset.fn = function (data) {\n          data.offsets = _objectSpread({}, data.offsets, _this3.config.offset(data.offsets, _this3.element) || {});\n          return data;\n        };\n      } else {\n        offset.offset = this.config.offset;\n      }\n\n      return offset;\n    };\n\n    _proto._getContainer = function _getContainer() {\n      if (this.config.container === false) {\n        return document.body;\n      }\n\n      if (Util.isElement(this.config.container)) {\n        return $(this.config.container);\n      }\n\n      return $(document).find(this.config.container);\n    };\n\n    _proto._getAttachment = function _getAttachment(placement) {\n      return AttachmentMap$1[placement.toUpperCase()];\n    };\n\n    _proto._setListeners = function _setListeners() {\n      var _this4 = this;\n\n      var triggers = this.config.trigger.split(' ');\n      triggers.forEach(function (trigger) {\n        if (trigger === 'click') {\n          $(_this4.element).on(_this4.constructor.Event.CLICK, _this4.config.selector, function (event) {\n            return _this4.toggle(event);\n          });\n        } else if (trigger !== Trigger.MANUAL) {\n          var eventIn = trigger === Trigger.HOVER ? _this4.constructor.Event.MOUSEENTER : _this4.constructor.Event.FOCUSIN;\n          var eventOut = trigger === Trigger.HOVER ? _this4.constructor.Event.MOUSELEAVE : _this4.constructor.Event.FOCUSOUT;\n          $(_this4.element).on(eventIn, _this4.config.selector, function (event) {\n            return _this4._enter(event);\n          }).on(eventOut, _this4.config.selector, function (event) {\n            return _this4._leave(event);\n          });\n        }\n      });\n      $(this.element).closest('.modal').on('hide.bs.modal', function () {\n        if (_this4.element) {\n          _this4.hide();\n        }\n      });\n\n      if (this.config.selector) {\n        this.config = _objectSpread({}, this.config, {\n          trigger: 'manual',\n          selector: ''\n        });\n      } else {\n        this._fixTitle();\n      }\n    };\n\n    _proto._fixTitle = function _fixTitle() {\n      var titleType = typeof this.element.getAttribute('data-original-title');\n\n      if (this.element.getAttribute('title') || titleType !== 'string') {\n        this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');\n        this.element.setAttribute('title', '');\n      }\n    };\n\n    _proto._enter = function _enter(event, context) {\n      var dataKey = this.constructor.DATA_KEY;\n      context = context || $(event.currentTarget).data(dataKey);\n\n      if (!context) {\n        context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n        $(event.currentTarget).data(dataKey, context);\n      }\n\n      if (event) {\n        context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;\n      }\n\n      if ($(context.getTipElement()).hasClass(ClassName$6.SHOW) || context._hoverState === HoverState.SHOW) {\n        context._hoverState = HoverState.SHOW;\n        return;\n      }\n\n      clearTimeout(context._timeout);\n      context._hoverState = HoverState.SHOW;\n\n      if (!context.config.delay || !context.config.delay.show) {\n        context.show();\n        return;\n      }\n\n      context._timeout = setTimeout(function () {\n        if (context._hoverState === HoverState.SHOW) {\n          context.show();\n        }\n      }, context.config.delay.show);\n    };\n\n    _proto._leave = function _leave(event, context) {\n      var dataKey = this.constructor.DATA_KEY;\n      context = context || $(event.currentTarget).data(dataKey);\n\n      if (!context) {\n        context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n        $(event.currentTarget).data(dataKey, context);\n      }\n\n      if (event) {\n        context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;\n      }\n\n      if (context._isWithActiveTrigger()) {\n        return;\n      }\n\n      clearTimeout(context._timeout);\n      context._hoverState = HoverState.OUT;\n\n      if (!context.config.delay || !context.config.delay.hide) {\n        context.hide();\n        return;\n      }\n\n      context._timeout = setTimeout(function () {\n        if (context._hoverState === HoverState.OUT) {\n          context.hide();\n        }\n      }, context.config.delay.hide);\n    };\n\n    _proto._isWithActiveTrigger = function _isWithActiveTrigger() {\n      for (var trigger in this._activeTrigger) {\n        if (this._activeTrigger[trigger]) {\n          return true;\n        }\n      }\n\n      return false;\n    };\n\n    _proto._getConfig = function _getConfig(config) {\n      var dataAttributes = $(this.element).data();\n      Object.keys(dataAttributes).forEach(function (dataAttr) {\n        if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {\n          delete dataAttributes[dataAttr];\n        }\n      });\n      config = _objectSpread({}, this.constructor.Default, dataAttributes, typeof config === 'object' && config ? config : {});\n\n      if (typeof config.delay === 'number') {\n        config.delay = {\n          show: config.delay,\n          hide: config.delay\n        };\n      }\n\n      if (typeof config.title === 'number') {\n        config.title = config.title.toString();\n      }\n\n      if (typeof config.content === 'number') {\n        config.content = config.content.toString();\n      }\n\n      Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType);\n\n      if (config.sanitize) {\n        config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn);\n      }\n\n      return config;\n    };\n\n    _proto._getDelegateConfig = function _getDelegateConfig() {\n      var config = {};\n\n      if (this.config) {\n        for (var key in this.config) {\n          if (this.constructor.Default[key] !== this.config[key]) {\n            config[key] = this.config[key];\n          }\n        }\n      }\n\n      return config;\n    };\n\n    _proto._cleanTipClass = function _cleanTipClass() {\n      var $tip = $(this.getTipElement());\n      var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);\n\n      if (tabClass !== null && tabClass.length) {\n        $tip.removeClass(tabClass.join(''));\n      }\n    };\n\n    _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {\n      var popperInstance = popperData.instance;\n      this.tip = popperInstance.popper;\n\n      this._cleanTipClass();\n\n      this.addAttachmentClass(this._getAttachment(popperData.placement));\n    };\n\n    _proto._fixTransition = function _fixTransition() {\n      var tip = this.getTipElement();\n      var initConfigAnimation = this.config.animation;\n\n      if (tip.getAttribute('x-placement') !== null) {\n        return;\n      }\n\n      $(tip).removeClass(ClassName$6.FADE);\n      this.config.animation = false;\n      this.hide();\n      this.show();\n      this.config.animation = initConfigAnimation;\n    } // Static\n    ;\n\n    Tooltip._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$6);\n\n        var _config = typeof config === 'object' && config;\n\n        if (!data && /dispose|hide/.test(config)) {\n          return;\n        }\n\n        if (!data) {\n          data = new Tooltip(this, _config);\n          $(this).data(DATA_KEY$6, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Tooltip, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$6;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$4;\n      }\n    }, {\n      key: \"NAME\",\n      get: function get() {\n        return NAME$6;\n      }\n    }, {\n      key: \"DATA_KEY\",\n      get: function get() {\n        return DATA_KEY$6;\n      }\n    }, {\n      key: \"Event\",\n      get: function get() {\n        return Event$6;\n      }\n    }, {\n      key: \"EVENT_KEY\",\n      get: function get() {\n        return EVENT_KEY$6;\n      }\n    }, {\n      key: \"DefaultType\",\n      get: function get() {\n        return DefaultType$4;\n      }\n    }]);\n\n    return Tooltip;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n\n  $.fn[NAME$6] = Tooltip._jQueryInterface;\n  $.fn[NAME$6].Constructor = Tooltip;\n\n  $.fn[NAME$6].noConflict = function () {\n    $.fn[NAME$6] = JQUERY_NO_CONFLICT$6;\n    return Tooltip._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$7 = 'popover';\n  var VERSION$7 = '4.3.1';\n  var DATA_KEY$7 = 'bs.popover';\n  var EVENT_KEY$7 = \".\" + DATA_KEY$7;\n  var JQUERY_NO_CONFLICT$7 = $.fn[NAME$7];\n  var CLASS_PREFIX$1 = 'bs-popover';\n  var BSCLS_PREFIX_REGEX$1 = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX$1 + \"\\\\S+\", 'g');\n\n  var Default$5 = _objectSpread({}, Tooltip.Default, {\n    placement: 'right',\n    trigger: 'click',\n    content: '',\n    template: '<div class=\"popover\" role=\"tooltip\">' + '<div class=\"arrow\"></div>' + '<h3 class=\"popover-header\"></h3>' + '<div class=\"popover-body\"></div></div>'\n  });\n\n  var DefaultType$5 = _objectSpread({}, Tooltip.DefaultType, {\n    content: '(string|element|function)'\n  });\n\n  var ClassName$7 = {\n    FADE: 'fade',\n    SHOW: 'show'\n  };\n  var Selector$7 = {\n    TITLE: '.popover-header',\n    CONTENT: '.popover-body'\n  };\n  var Event$7 = {\n    HIDE: \"hide\" + EVENT_KEY$7,\n    HIDDEN: \"hidden\" + EVENT_KEY$7,\n    SHOW: \"show\" + EVENT_KEY$7,\n    SHOWN: \"shown\" + EVENT_KEY$7,\n    INSERTED: \"inserted\" + EVENT_KEY$7,\n    CLICK: \"click\" + EVENT_KEY$7,\n    FOCUSIN: \"focusin\" + EVENT_KEY$7,\n    FOCUSOUT: \"focusout\" + EVENT_KEY$7,\n    MOUSEENTER: \"mouseenter\" + EVENT_KEY$7,\n    MOUSELEAVE: \"mouseleave\" + EVENT_KEY$7\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Popover =\n  /*#__PURE__*/\n  function (_Tooltip) {\n    _inheritsLoose(Popover, _Tooltip);\n\n    function Popover() {\n      return _Tooltip.apply(this, arguments) || this;\n    }\n\n    var _proto = Popover.prototype;\n\n    // Overrides\n    _proto.isWithContent = function isWithContent() {\n      return this.getTitle() || this._getContent();\n    };\n\n    _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n      $(this.getTipElement()).addClass(CLASS_PREFIX$1 + \"-\" + attachment);\n    };\n\n    _proto.getTipElement = function getTipElement() {\n      this.tip = this.tip || $(this.config.template)[0];\n      return this.tip;\n    };\n\n    _proto.setContent = function setContent() {\n      var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events\n\n      this.setElementContent($tip.find(Selector$7.TITLE), this.getTitle());\n\n      var content = this._getContent();\n\n      if (typeof content === 'function') {\n        content = content.call(this.element);\n      }\n\n      this.setElementContent($tip.find(Selector$7.CONTENT), content);\n      $tip.removeClass(ClassName$7.FADE + \" \" + ClassName$7.SHOW);\n    } // Private\n    ;\n\n    _proto._getContent = function _getContent() {\n      return this.element.getAttribute('data-content') || this.config.content;\n    };\n\n    _proto._cleanTipClass = function _cleanTipClass() {\n      var $tip = $(this.getTipElement());\n      var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1);\n\n      if (tabClass !== null && tabClass.length > 0) {\n        $tip.removeClass(tabClass.join(''));\n      }\n    } // Static\n    ;\n\n    Popover._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$7);\n\n        var _config = typeof config === 'object' ? config : null;\n\n        if (!data && /dispose|hide/.test(config)) {\n          return;\n        }\n\n        if (!data) {\n          data = new Popover(this, _config);\n          $(this).data(DATA_KEY$7, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Popover, null, [{\n      key: \"VERSION\",\n      // Getters\n      get: function get() {\n        return VERSION$7;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$5;\n      }\n    }, {\n      key: \"NAME\",\n      get: function get() {\n        return NAME$7;\n      }\n    }, {\n      key: \"DATA_KEY\",\n      get: function get() {\n        return DATA_KEY$7;\n      }\n    }, {\n      key: \"Event\",\n      get: function get() {\n        return Event$7;\n      }\n    }, {\n      key: \"EVENT_KEY\",\n      get: function get() {\n        return EVENT_KEY$7;\n      }\n    }, {\n      key: \"DefaultType\",\n      get: function get() {\n        return DefaultType$5;\n      }\n    }]);\n\n    return Popover;\n  }(Tooltip);\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n\n  $.fn[NAME$7] = Popover._jQueryInterface;\n  $.fn[NAME$7].Constructor = Popover;\n\n  $.fn[NAME$7].noConflict = function () {\n    $.fn[NAME$7] = JQUERY_NO_CONFLICT$7;\n    return Popover._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$8 = 'scrollspy';\n  var VERSION$8 = '4.3.1';\n  var DATA_KEY$8 = 'bs.scrollspy';\n  var EVENT_KEY$8 = \".\" + DATA_KEY$8;\n  var DATA_API_KEY$6 = '.data-api';\n  var JQUERY_NO_CONFLICT$8 = $.fn[NAME$8];\n  var Default$6 = {\n    offset: 10,\n    method: 'auto',\n    target: ''\n  };\n  var DefaultType$6 = {\n    offset: 'number',\n    method: 'string',\n    target: '(string|element)'\n  };\n  var Event$8 = {\n    ACTIVATE: \"activate\" + EVENT_KEY$8,\n    SCROLL: \"scroll\" + EVENT_KEY$8,\n    LOAD_DATA_API: \"load\" + EVENT_KEY$8 + DATA_API_KEY$6\n  };\n  var ClassName$8 = {\n    DROPDOWN_ITEM: 'dropdown-item',\n    DROPDOWN_MENU: 'dropdown-menu',\n    ACTIVE: 'active'\n  };\n  var Selector$8 = {\n    DATA_SPY: '[data-spy=\"scroll\"]',\n    ACTIVE: '.active',\n    NAV_LIST_GROUP: '.nav, .list-group',\n    NAV_LINKS: '.nav-link',\n    NAV_ITEMS: '.nav-item',\n    LIST_ITEMS: '.list-group-item',\n    DROPDOWN: '.dropdown',\n    DROPDOWN_ITEMS: '.dropdown-item',\n    DROPDOWN_TOGGLE: '.dropdown-toggle'\n  };\n  var OffsetMethod = {\n    OFFSET: 'offset',\n    POSITION: 'position'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var ScrollSpy =\n  /*#__PURE__*/\n  function () {\n    function ScrollSpy(element, config) {\n      var _this = this;\n\n      this._element = element;\n      this._scrollElement = element.tagName === 'BODY' ? window : element;\n      this._config = this._getConfig(config);\n      this._selector = this._config.target + \" \" + Selector$8.NAV_LINKS + \",\" + (this._config.target + \" \" + Selector$8.LIST_ITEMS + \",\") + (this._config.target + \" \" + Selector$8.DROPDOWN_ITEMS);\n      this._offsets = [];\n      this._targets = [];\n      this._activeTarget = null;\n      this._scrollHeight = 0;\n      $(this._scrollElement).on(Event$8.SCROLL, function (event) {\n        return _this._process(event);\n      });\n      this.refresh();\n\n      this._process();\n    } // Getters\n\n\n    var _proto = ScrollSpy.prototype;\n\n    // Public\n    _proto.refresh = function refresh() {\n      var _this2 = this;\n\n      var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;\n      var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;\n      var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;\n      this._offsets = [];\n      this._targets = [];\n      this._scrollHeight = this._getScrollHeight();\n      var targets = [].slice.call(document.querySelectorAll(this._selector));\n      targets.map(function (element) {\n        var target;\n        var targetSelector = Util.getSelectorFromElement(element);\n\n        if (targetSelector) {\n          target = document.querySelector(targetSelector);\n        }\n\n        if (target) {\n          var targetBCR = target.getBoundingClientRect();\n\n          if (targetBCR.width || targetBCR.height) {\n            // TODO (fat): remove sketch reliance on jQuery position/offset\n            return [$(target)[offsetMethod]().top + offsetBase, targetSelector];\n          }\n        }\n\n        return null;\n      }).filter(function (item) {\n        return item;\n      }).sort(function (a, b) {\n        return a[0] - b[0];\n      }).forEach(function (item) {\n        _this2._offsets.push(item[0]);\n\n        _this2._targets.push(item[1]);\n      });\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$8);\n      $(this._scrollElement).off(EVENT_KEY$8);\n      this._element = null;\n      this._scrollElement = null;\n      this._config = null;\n      this._selector = null;\n      this._offsets = null;\n      this._targets = null;\n      this._activeTarget = null;\n      this._scrollHeight = null;\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default$6, typeof config === 'object' && config ? config : {});\n\n      if (typeof config.target !== 'string') {\n        var id = $(config.target).attr('id');\n\n        if (!id) {\n          id = Util.getUID(NAME$8);\n          $(config.target).attr('id', id);\n        }\n\n        config.target = \"#\" + id;\n      }\n\n      Util.typeCheckConfig(NAME$8, config, DefaultType$6);\n      return config;\n    };\n\n    _proto._getScrollTop = function _getScrollTop() {\n      return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;\n    };\n\n    _proto._getScrollHeight = function _getScrollHeight() {\n      return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);\n    };\n\n    _proto._getOffsetHeight = function _getOffsetHeight() {\n      return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;\n    };\n\n    _proto._process = function _process() {\n      var scrollTop = this._getScrollTop() + this._config.offset;\n\n      var scrollHeight = this._getScrollHeight();\n\n      var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();\n\n      if (this._scrollHeight !== scrollHeight) {\n        this.refresh();\n      }\n\n      if (scrollTop >= maxScroll) {\n        var target = this._targets[this._targets.length - 1];\n\n        if (this._activeTarget !== target) {\n          this._activate(target);\n        }\n\n        return;\n      }\n\n      if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n        this._activeTarget = null;\n\n        this._clear();\n\n        return;\n      }\n\n      var offsetLength = this._offsets.length;\n\n      for (var i = offsetLength; i--;) {\n        var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);\n\n        if (isActiveTarget) {\n          this._activate(this._targets[i]);\n        }\n      }\n    };\n\n    _proto._activate = function _activate(target) {\n      this._activeTarget = target;\n\n      this._clear();\n\n      var queries = this._selector.split(',').map(function (selector) {\n        return selector + \"[data-target=\\\"\" + target + \"\\\"],\" + selector + \"[href=\\\"\" + target + \"\\\"]\";\n      });\n\n      var $link = $([].slice.call(document.querySelectorAll(queries.join(','))));\n\n      if ($link.hasClass(ClassName$8.DROPDOWN_ITEM)) {\n        $link.closest(Selector$8.DROPDOWN).find(Selector$8.DROPDOWN_TOGGLE).addClass(ClassName$8.ACTIVE);\n        $link.addClass(ClassName$8.ACTIVE);\n      } else {\n        // Set triggered link as active\n        $link.addClass(ClassName$8.ACTIVE); // Set triggered links parents as active\n        // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n\n        $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_LINKS + \", \" + Selector$8.LIST_ITEMS).addClass(ClassName$8.ACTIVE); // Handle special case when .nav-link is inside .nav-item\n\n        $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_ITEMS).children(Selector$8.NAV_LINKS).addClass(ClassName$8.ACTIVE);\n      }\n\n      $(this._scrollElement).trigger(Event$8.ACTIVATE, {\n        relatedTarget: target\n      });\n    };\n\n    _proto._clear = function _clear() {\n      [].slice.call(document.querySelectorAll(this._selector)).filter(function (node) {\n        return node.classList.contains(ClassName$8.ACTIVE);\n      }).forEach(function (node) {\n        return node.classList.remove(ClassName$8.ACTIVE);\n      });\n    } // Static\n    ;\n\n    ScrollSpy._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$8);\n\n        var _config = typeof config === 'object' && config;\n\n        if (!data) {\n          data = new ScrollSpy(this, _config);\n          $(this).data(DATA_KEY$8, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(ScrollSpy, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$8;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$6;\n      }\n    }]);\n\n    return ScrollSpy;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(window).on(Event$8.LOAD_DATA_API, function () {\n    var scrollSpys = [].slice.call(document.querySelectorAll(Selector$8.DATA_SPY));\n    var scrollSpysLength = scrollSpys.length;\n\n    for (var i = scrollSpysLength; i--;) {\n      var $spy = $(scrollSpys[i]);\n\n      ScrollSpy._jQueryInterface.call($spy, $spy.data());\n    }\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$8] = ScrollSpy._jQueryInterface;\n  $.fn[NAME$8].Constructor = ScrollSpy;\n\n  $.fn[NAME$8].noConflict = function () {\n    $.fn[NAME$8] = JQUERY_NO_CONFLICT$8;\n    return ScrollSpy._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$9 = 'tab';\n  var VERSION$9 = '4.3.1';\n  var DATA_KEY$9 = 'bs.tab';\n  var EVENT_KEY$9 = \".\" + DATA_KEY$9;\n  var DATA_API_KEY$7 = '.data-api';\n  var JQUERY_NO_CONFLICT$9 = $.fn[NAME$9];\n  var Event$9 = {\n    HIDE: \"hide\" + EVENT_KEY$9,\n    HIDDEN: \"hidden\" + EVENT_KEY$9,\n    SHOW: \"show\" + EVENT_KEY$9,\n    SHOWN: \"shown\" + EVENT_KEY$9,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$9 + DATA_API_KEY$7\n  };\n  var ClassName$9 = {\n    DROPDOWN_MENU: 'dropdown-menu',\n    ACTIVE: 'active',\n    DISABLED: 'disabled',\n    FADE: 'fade',\n    SHOW: 'show'\n  };\n  var Selector$9 = {\n    DROPDOWN: '.dropdown',\n    NAV_LIST_GROUP: '.nav, .list-group',\n    ACTIVE: '.active',\n    ACTIVE_UL: '> li > .active',\n    DATA_TOGGLE: '[data-toggle=\"tab\"], [data-toggle=\"pill\"], [data-toggle=\"list\"]',\n    DROPDOWN_TOGGLE: '.dropdown-toggle',\n    DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Tab =\n  /*#__PURE__*/\n  function () {\n    function Tab(element) {\n      this._element = element;\n    } // Getters\n\n\n    var _proto = Tab.prototype;\n\n    // Public\n    _proto.show = function show() {\n      var _this = this;\n\n      if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $(this._element).hasClass(ClassName$9.ACTIVE) || $(this._element).hasClass(ClassName$9.DISABLED)) {\n        return;\n      }\n\n      var target;\n      var previous;\n      var listElement = $(this._element).closest(Selector$9.NAV_LIST_GROUP)[0];\n      var selector = Util.getSelectorFromElement(this._element);\n\n      if (listElement) {\n        var itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector$9.ACTIVE_UL : Selector$9.ACTIVE;\n        previous = $.makeArray($(listElement).find(itemSelector));\n        previous = previous[previous.length - 1];\n      }\n\n      var hideEvent = $.Event(Event$9.HIDE, {\n        relatedTarget: this._element\n      });\n      var showEvent = $.Event(Event$9.SHOW, {\n        relatedTarget: previous\n      });\n\n      if (previous) {\n        $(previous).trigger(hideEvent);\n      }\n\n      $(this._element).trigger(showEvent);\n\n      if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      if (selector) {\n        target = document.querySelector(selector);\n      }\n\n      this._activate(this._element, listElement);\n\n      var complete = function complete() {\n        var hiddenEvent = $.Event(Event$9.HIDDEN, {\n          relatedTarget: _this._element\n        });\n        var shownEvent = $.Event(Event$9.SHOWN, {\n          relatedTarget: previous\n        });\n        $(previous).trigger(hiddenEvent);\n        $(_this._element).trigger(shownEvent);\n      };\n\n      if (target) {\n        this._activate(target, target.parentNode, complete);\n      } else {\n        complete();\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$9);\n      this._element = null;\n    } // Private\n    ;\n\n    _proto._activate = function _activate(element, container, callback) {\n      var _this2 = this;\n\n      var activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? $(container).find(Selector$9.ACTIVE_UL) : $(container).children(Selector$9.ACTIVE);\n      var active = activeElements[0];\n      var isTransitioning = callback && active && $(active).hasClass(ClassName$9.FADE);\n\n      var complete = function complete() {\n        return _this2._transitionComplete(element, active, callback);\n      };\n\n      if (active && isTransitioning) {\n        var transitionDuration = Util.getTransitionDurationFromElement(active);\n        $(active).removeClass(ClassName$9.SHOW).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      } else {\n        complete();\n      }\n    };\n\n    _proto._transitionComplete = function _transitionComplete(element, active, callback) {\n      if (active) {\n        $(active).removeClass(ClassName$9.ACTIVE);\n        var dropdownChild = $(active.parentNode).find(Selector$9.DROPDOWN_ACTIVE_CHILD)[0];\n\n        if (dropdownChild) {\n          $(dropdownChild).removeClass(ClassName$9.ACTIVE);\n        }\n\n        if (active.getAttribute('role') === 'tab') {\n          active.setAttribute('aria-selected', false);\n        }\n      }\n\n      $(element).addClass(ClassName$9.ACTIVE);\n\n      if (element.getAttribute('role') === 'tab') {\n        element.setAttribute('aria-selected', true);\n      }\n\n      Util.reflow(element);\n\n      if (element.classList.contains(ClassName$9.FADE)) {\n        element.classList.add(ClassName$9.SHOW);\n      }\n\n      if (element.parentNode && $(element.parentNode).hasClass(ClassName$9.DROPDOWN_MENU)) {\n        var dropdownElement = $(element).closest(Selector$9.DROPDOWN)[0];\n\n        if (dropdownElement) {\n          var dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(Selector$9.DROPDOWN_TOGGLE));\n          $(dropdownToggleList).addClass(ClassName$9.ACTIVE);\n        }\n\n        element.setAttribute('aria-expanded', true);\n      }\n\n      if (callback) {\n        callback();\n      }\n    } // Static\n    ;\n\n    Tab._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var $this = $(this);\n        var data = $this.data(DATA_KEY$9);\n\n        if (!data) {\n          data = new Tab(this);\n          $this.data(DATA_KEY$9, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Tab, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$9;\n      }\n    }]);\n\n    return Tab;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$9.CLICK_DATA_API, Selector$9.DATA_TOGGLE, function (event) {\n    event.preventDefault();\n\n    Tab._jQueryInterface.call($(this), 'show');\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$9] = Tab._jQueryInterface;\n  $.fn[NAME$9].Constructor = Tab;\n\n  $.fn[NAME$9].noConflict = function () {\n    $.fn[NAME$9] = JQUERY_NO_CONFLICT$9;\n    return Tab._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$a = 'toast';\n  var VERSION$a = '4.3.1';\n  var DATA_KEY$a = 'bs.toast';\n  var EVENT_KEY$a = \".\" + DATA_KEY$a;\n  var JQUERY_NO_CONFLICT$a = $.fn[NAME$a];\n  var Event$a = {\n    CLICK_DISMISS: \"click.dismiss\" + EVENT_KEY$a,\n    HIDE: \"hide\" + EVENT_KEY$a,\n    HIDDEN: \"hidden\" + EVENT_KEY$a,\n    SHOW: \"show\" + EVENT_KEY$a,\n    SHOWN: \"shown\" + EVENT_KEY$a\n  };\n  var ClassName$a = {\n    FADE: 'fade',\n    HIDE: 'hide',\n    SHOW: 'show',\n    SHOWING: 'showing'\n  };\n  var DefaultType$7 = {\n    animation: 'boolean',\n    autohide: 'boolean',\n    delay: 'number'\n  };\n  var Default$7 = {\n    animation: true,\n    autohide: true,\n    delay: 500\n  };\n  var Selector$a = {\n    DATA_DISMISS: '[data-dismiss=\"toast\"]'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Toast =\n  /*#__PURE__*/\n  function () {\n    function Toast(element, config) {\n      this._element = element;\n      this._config = this._getConfig(config);\n      this._timeout = null;\n\n      this._setListeners();\n    } // Getters\n\n\n    var _proto = Toast.prototype;\n\n    // Public\n    _proto.show = function show() {\n      var _this = this;\n\n      $(this._element).trigger(Event$a.SHOW);\n\n      if (this._config.animation) {\n        this._element.classList.add(ClassName$a.FADE);\n      }\n\n      var complete = function complete() {\n        _this._element.classList.remove(ClassName$a.SHOWING);\n\n        _this._element.classList.add(ClassName$a.SHOW);\n\n        $(_this._element).trigger(Event$a.SHOWN);\n\n        if (_this._config.autohide) {\n          _this.hide();\n        }\n      };\n\n      this._element.classList.remove(ClassName$a.HIDE);\n\n      this._element.classList.add(ClassName$a.SHOWING);\n\n      if (this._config.animation) {\n        var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n        $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      } else {\n        complete();\n      }\n    };\n\n    _proto.hide = function hide(withoutTimeout) {\n      var _this2 = this;\n\n      if (!this._element.classList.contains(ClassName$a.SHOW)) {\n        return;\n      }\n\n      $(this._element).trigger(Event$a.HIDE);\n\n      if (withoutTimeout) {\n        this._close();\n      } else {\n        this._timeout = setTimeout(function () {\n          _this2._close();\n        }, this._config.delay);\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      clearTimeout(this._timeout);\n      this._timeout = null;\n\n      if (this._element.classList.contains(ClassName$a.SHOW)) {\n        this._element.classList.remove(ClassName$a.SHOW);\n      }\n\n      $(this._element).off(Event$a.CLICK_DISMISS);\n      $.removeData(this._element, DATA_KEY$a);\n      this._element = null;\n      this._config = null;\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default$7, $(this._element).data(), typeof config === 'object' && config ? config : {});\n      Util.typeCheckConfig(NAME$a, config, this.constructor.DefaultType);\n      return config;\n    };\n\n    _proto._setListeners = function _setListeners() {\n      var _this3 = this;\n\n      $(this._element).on(Event$a.CLICK_DISMISS, Selector$a.DATA_DISMISS, function () {\n        return _this3.hide(true);\n      });\n    };\n\n    _proto._close = function _close() {\n      var _this4 = this;\n\n      var complete = function complete() {\n        _this4._element.classList.add(ClassName$a.HIDE);\n\n        $(_this4._element).trigger(Event$a.HIDDEN);\n      };\n\n      this._element.classList.remove(ClassName$a.SHOW);\n\n      if (this._config.animation) {\n        var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n        $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      } else {\n        complete();\n      }\n    } // Static\n    ;\n\n    Toast._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var $element = $(this);\n        var data = $element.data(DATA_KEY$a);\n\n        var _config = typeof config === 'object' && config;\n\n        if (!data) {\n          data = new Toast(this, _config);\n          $element.data(DATA_KEY$a, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config](this);\n        }\n      });\n    };\n\n    _createClass(Toast, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$a;\n      }\n    }, {\n      key: \"DefaultType\",\n      get: function get() {\n        return DefaultType$7;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$7;\n      }\n    }]);\n\n    return Toast;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n\n  $.fn[NAME$a] = Toast._jQueryInterface;\n  $.fn[NAME$a].Constructor = Toast;\n\n  $.fn[NAME$a].noConflict = function () {\n    $.fn[NAME$a] = JQUERY_NO_CONFLICT$a;\n    return Toast._jQueryInterface;\n  };\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.3.1): index.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  (function () {\n    if (typeof $ === 'undefined') {\n      throw new TypeError('Bootstrap\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\'s JavaScript.');\n    }\n\n    var version = $.fn.jquery.split(' ')[0].split('.');\n    var minMajor = 1;\n    var ltMajor = 2;\n    var minMinor = 9;\n    var minPatch = 1;\n    var maxMajor = 4;\n\n    if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {\n      throw new Error('Bootstrap\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');\n    }\n  })();\n\n  exports.Util = Util;\n  exports.Alert = Alert;\n  exports.Button = Button;\n  exports.Carousel = Carousel;\n  exports.Collapse = Collapse;\n  exports.Dropdown = Dropdown;\n  exports.Modal = Modal;\n  exports.Popover = Popover;\n  exports.Scrollspy = ScrollSpy;\n  exports.Tab = Tab;\n  exports.Toast = Toast;\n  exports.Tooltip = Tooltip;\n\n  Object.defineProperty(exports, '__esModule', { value: true });\n\n}));\n//# sourceMappingURL=bootstrap.bundle.js.map\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/bootstrap/dist/js/bootstrap.js",
    "content": "/*!\n  * Bootstrap v4.3.1 (https://getbootstrap.com/)\n  * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n  */\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery'), require('popper.js')) :\n  typeof define === 'function' && define.amd ? define(['exports', 'jquery', 'popper.js'], factory) :\n  (global = global || self, factory(global.bootstrap = {}, global.jQuery, global.Popper));\n}(this, function (exports, $, Popper) { 'use strict';\n\n  $ = $ && $.hasOwnProperty('default') ? $['default'] : $;\n  Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper;\n\n  function _defineProperties(target, props) {\n    for (var i = 0; i < props.length; i++) {\n      var descriptor = props[i];\n      descriptor.enumerable = descriptor.enumerable || false;\n      descriptor.configurable = true;\n      if (\"value\" in descriptor) descriptor.writable = true;\n      Object.defineProperty(target, descriptor.key, descriptor);\n    }\n  }\n\n  function _createClass(Constructor, protoProps, staticProps) {\n    if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n    if (staticProps) _defineProperties(Constructor, staticProps);\n    return Constructor;\n  }\n\n  function _defineProperty(obj, key, value) {\n    if (key in obj) {\n      Object.defineProperty(obj, key, {\n        value: value,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      });\n    } else {\n      obj[key] = value;\n    }\n\n    return obj;\n  }\n\n  function _objectSpread(target) {\n    for (var i = 1; i < arguments.length; i++) {\n      var source = arguments[i] != null ? arguments[i] : {};\n      var ownKeys = Object.keys(source);\n\n      if (typeof Object.getOwnPropertySymbols === 'function') {\n        ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {\n          return Object.getOwnPropertyDescriptor(source, sym).enumerable;\n        }));\n      }\n\n      ownKeys.forEach(function (key) {\n        _defineProperty(target, key, source[key]);\n      });\n    }\n\n    return target;\n  }\n\n  function _inheritsLoose(subClass, superClass) {\n    subClass.prototype = Object.create(superClass.prototype);\n    subClass.prototype.constructor = subClass;\n    subClass.__proto__ = superClass;\n  }\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.3.1): util.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n  /**\n   * ------------------------------------------------------------------------\n   * Private TransitionEnd Helpers\n   * ------------------------------------------------------------------------\n   */\n\n  var TRANSITION_END = 'transitionend';\n  var MAX_UID = 1000000;\n  var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)\n\n  function toType(obj) {\n    return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase();\n  }\n\n  function getSpecialTransitionEndEvent() {\n    return {\n      bindType: TRANSITION_END,\n      delegateType: TRANSITION_END,\n      handle: function handle(event) {\n        if ($(event.target).is(this)) {\n          return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params\n        }\n\n        return undefined; // eslint-disable-line no-undefined\n      }\n    };\n  }\n\n  function transitionEndEmulator(duration) {\n    var _this = this;\n\n    var called = false;\n    $(this).one(Util.TRANSITION_END, function () {\n      called = true;\n    });\n    setTimeout(function () {\n      if (!called) {\n        Util.triggerTransitionEnd(_this);\n      }\n    }, duration);\n    return this;\n  }\n\n  function setTransitionEndSupport() {\n    $.fn.emulateTransitionEnd = transitionEndEmulator;\n    $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();\n  }\n  /**\n   * --------------------------------------------------------------------------\n   * Public Util Api\n   * --------------------------------------------------------------------------\n   */\n\n\n  var Util = {\n    TRANSITION_END: 'bsTransitionEnd',\n    getUID: function getUID(prefix) {\n      do {\n        // eslint-disable-next-line no-bitwise\n        prefix += ~~(Math.random() * MAX_UID); // \"~~\" acts like a faster Math.floor() here\n      } while (document.getElementById(prefix));\n\n      return prefix;\n    },\n    getSelectorFromElement: function getSelectorFromElement(element) {\n      var selector = element.getAttribute('data-target');\n\n      if (!selector || selector === '#') {\n        var hrefAttr = element.getAttribute('href');\n        selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '';\n      }\n\n      try {\n        return document.querySelector(selector) ? selector : null;\n      } catch (err) {\n        return null;\n      }\n    },\n    getTransitionDurationFromElement: function getTransitionDurationFromElement(element) {\n      if (!element) {\n        return 0;\n      } // Get transition-duration of the element\n\n\n      var transitionDuration = $(element).css('transition-duration');\n      var transitionDelay = $(element).css('transition-delay');\n      var floatTransitionDuration = parseFloat(transitionDuration);\n      var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found\n\n      if (!floatTransitionDuration && !floatTransitionDelay) {\n        return 0;\n      } // If multiple durations are defined, take the first\n\n\n      transitionDuration = transitionDuration.split(',')[0];\n      transitionDelay = transitionDelay.split(',')[0];\n      return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;\n    },\n    reflow: function reflow(element) {\n      return element.offsetHeight;\n    },\n    triggerTransitionEnd: function triggerTransitionEnd(element) {\n      $(element).trigger(TRANSITION_END);\n    },\n    // TODO: Remove in v5\n    supportsTransitionEnd: function supportsTransitionEnd() {\n      return Boolean(TRANSITION_END);\n    },\n    isElement: function isElement(obj) {\n      return (obj[0] || obj).nodeType;\n    },\n    typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {\n      for (var property in configTypes) {\n        if (Object.prototype.hasOwnProperty.call(configTypes, property)) {\n          var expectedTypes = configTypes[property];\n          var value = config[property];\n          var valueType = value && Util.isElement(value) ? 'element' : toType(value);\n\n          if (!new RegExp(expectedTypes).test(valueType)) {\n            throw new Error(componentName.toUpperCase() + \": \" + (\"Option \\\"\" + property + \"\\\" provided type \\\"\" + valueType + \"\\\" \") + (\"but expected type \\\"\" + expectedTypes + \"\\\".\"));\n          }\n        }\n      }\n    },\n    findShadowRoot: function findShadowRoot(element) {\n      if (!document.documentElement.attachShadow) {\n        return null;\n      } // Can find the shadow root otherwise it'll return the document\n\n\n      if (typeof element.getRootNode === 'function') {\n        var root = element.getRootNode();\n        return root instanceof ShadowRoot ? root : null;\n      }\n\n      if (element instanceof ShadowRoot) {\n        return element;\n      } // when we don't find a shadow root\n\n\n      if (!element.parentNode) {\n        return null;\n      }\n\n      return Util.findShadowRoot(element.parentNode);\n    }\n  };\n  setTransitionEndSupport();\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME = 'alert';\n  var VERSION = '4.3.1';\n  var DATA_KEY = 'bs.alert';\n  var EVENT_KEY = \".\" + DATA_KEY;\n  var DATA_API_KEY = '.data-api';\n  var JQUERY_NO_CONFLICT = $.fn[NAME];\n  var Selector = {\n    DISMISS: '[data-dismiss=\"alert\"]'\n  };\n  var Event = {\n    CLOSE: \"close\" + EVENT_KEY,\n    CLOSED: \"closed\" + EVENT_KEY,\n    CLICK_DATA_API: \"click\" + EVENT_KEY + DATA_API_KEY\n  };\n  var ClassName = {\n    ALERT: 'alert',\n    FADE: 'fade',\n    SHOW: 'show'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Alert =\n  /*#__PURE__*/\n  function () {\n    function Alert(element) {\n      this._element = element;\n    } // Getters\n\n\n    var _proto = Alert.prototype;\n\n    // Public\n    _proto.close = function close(element) {\n      var rootElement = this._element;\n\n      if (element) {\n        rootElement = this._getRootElement(element);\n      }\n\n      var customEvent = this._triggerCloseEvent(rootElement);\n\n      if (customEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      this._removeElement(rootElement);\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY);\n      this._element = null;\n    } // Private\n    ;\n\n    _proto._getRootElement = function _getRootElement(element) {\n      var selector = Util.getSelectorFromElement(element);\n      var parent = false;\n\n      if (selector) {\n        parent = document.querySelector(selector);\n      }\n\n      if (!parent) {\n        parent = $(element).closest(\".\" + ClassName.ALERT)[0];\n      }\n\n      return parent;\n    };\n\n    _proto._triggerCloseEvent = function _triggerCloseEvent(element) {\n      var closeEvent = $.Event(Event.CLOSE);\n      $(element).trigger(closeEvent);\n      return closeEvent;\n    };\n\n    _proto._removeElement = function _removeElement(element) {\n      var _this = this;\n\n      $(element).removeClass(ClassName.SHOW);\n\n      if (!$(element).hasClass(ClassName.FADE)) {\n        this._destroyElement(element);\n\n        return;\n      }\n\n      var transitionDuration = Util.getTransitionDurationFromElement(element);\n      $(element).one(Util.TRANSITION_END, function (event) {\n        return _this._destroyElement(element, event);\n      }).emulateTransitionEnd(transitionDuration);\n    };\n\n    _proto._destroyElement = function _destroyElement(element) {\n      $(element).detach().trigger(Event.CLOSED).remove();\n    } // Static\n    ;\n\n    Alert._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var $element = $(this);\n        var data = $element.data(DATA_KEY);\n\n        if (!data) {\n          data = new Alert(this);\n          $element.data(DATA_KEY, data);\n        }\n\n        if (config === 'close') {\n          data[config](this);\n        }\n      });\n    };\n\n    Alert._handleDismiss = function _handleDismiss(alertInstance) {\n      return function (event) {\n        if (event) {\n          event.preventDefault();\n        }\n\n        alertInstance.close(this);\n      };\n    };\n\n    _createClass(Alert, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION;\n      }\n    }]);\n\n    return Alert;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME] = Alert._jQueryInterface;\n  $.fn[NAME].Constructor = Alert;\n\n  $.fn[NAME].noConflict = function () {\n    $.fn[NAME] = JQUERY_NO_CONFLICT;\n    return Alert._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$1 = 'button';\n  var VERSION$1 = '4.3.1';\n  var DATA_KEY$1 = 'bs.button';\n  var EVENT_KEY$1 = \".\" + DATA_KEY$1;\n  var DATA_API_KEY$1 = '.data-api';\n  var JQUERY_NO_CONFLICT$1 = $.fn[NAME$1];\n  var ClassName$1 = {\n    ACTIVE: 'active',\n    BUTTON: 'btn',\n    FOCUS: 'focus'\n  };\n  var Selector$1 = {\n    DATA_TOGGLE_CARROT: '[data-toggle^=\"button\"]',\n    DATA_TOGGLE: '[data-toggle=\"buttons\"]',\n    INPUT: 'input:not([type=\"hidden\"])',\n    ACTIVE: '.active',\n    BUTTON: '.btn'\n  };\n  var Event$1 = {\n    CLICK_DATA_API: \"click\" + EVENT_KEY$1 + DATA_API_KEY$1,\n    FOCUS_BLUR_DATA_API: \"focus\" + EVENT_KEY$1 + DATA_API_KEY$1 + \" \" + (\"blur\" + EVENT_KEY$1 + DATA_API_KEY$1)\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Button =\n  /*#__PURE__*/\n  function () {\n    function Button(element) {\n      this._element = element;\n    } // Getters\n\n\n    var _proto = Button.prototype;\n\n    // Public\n    _proto.toggle = function toggle() {\n      var triggerChangeEvent = true;\n      var addAriaPressed = true;\n      var rootElement = $(this._element).closest(Selector$1.DATA_TOGGLE)[0];\n\n      if (rootElement) {\n        var input = this._element.querySelector(Selector$1.INPUT);\n\n        if (input) {\n          if (input.type === 'radio') {\n            if (input.checked && this._element.classList.contains(ClassName$1.ACTIVE)) {\n              triggerChangeEvent = false;\n            } else {\n              var activeElement = rootElement.querySelector(Selector$1.ACTIVE);\n\n              if (activeElement) {\n                $(activeElement).removeClass(ClassName$1.ACTIVE);\n              }\n            }\n          }\n\n          if (triggerChangeEvent) {\n            if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) {\n              return;\n            }\n\n            input.checked = !this._element.classList.contains(ClassName$1.ACTIVE);\n            $(input).trigger('change');\n          }\n\n          input.focus();\n          addAriaPressed = false;\n        }\n      }\n\n      if (addAriaPressed) {\n        this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName$1.ACTIVE));\n      }\n\n      if (triggerChangeEvent) {\n        $(this._element).toggleClass(ClassName$1.ACTIVE);\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$1);\n      this._element = null;\n    } // Static\n    ;\n\n    Button._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$1);\n\n        if (!data) {\n          data = new Button(this);\n          $(this).data(DATA_KEY$1, data);\n        }\n\n        if (config === 'toggle') {\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Button, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$1;\n      }\n    }]);\n\n    return Button;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$1.CLICK_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {\n    event.preventDefault();\n    var button = event.target;\n\n    if (!$(button).hasClass(ClassName$1.BUTTON)) {\n      button = $(button).closest(Selector$1.BUTTON);\n    }\n\n    Button._jQueryInterface.call($(button), 'toggle');\n  }).on(Event$1.FOCUS_BLUR_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {\n    var button = $(event.target).closest(Selector$1.BUTTON)[0];\n    $(button).toggleClass(ClassName$1.FOCUS, /^focus(in)?$/.test(event.type));\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$1] = Button._jQueryInterface;\n  $.fn[NAME$1].Constructor = Button;\n\n  $.fn[NAME$1].noConflict = function () {\n    $.fn[NAME$1] = JQUERY_NO_CONFLICT$1;\n    return Button._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$2 = 'carousel';\n  var VERSION$2 = '4.3.1';\n  var DATA_KEY$2 = 'bs.carousel';\n  var EVENT_KEY$2 = \".\" + DATA_KEY$2;\n  var DATA_API_KEY$2 = '.data-api';\n  var JQUERY_NO_CONFLICT$2 = $.fn[NAME$2];\n  var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key\n\n  var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key\n\n  var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\n  var SWIPE_THRESHOLD = 40;\n  var Default = {\n    interval: 5000,\n    keyboard: true,\n    slide: false,\n    pause: 'hover',\n    wrap: true,\n    touch: true\n  };\n  var DefaultType = {\n    interval: '(number|boolean)',\n    keyboard: 'boolean',\n    slide: '(boolean|string)',\n    pause: '(string|boolean)',\n    wrap: 'boolean',\n    touch: 'boolean'\n  };\n  var Direction = {\n    NEXT: 'next',\n    PREV: 'prev',\n    LEFT: 'left',\n    RIGHT: 'right'\n  };\n  var Event$2 = {\n    SLIDE: \"slide\" + EVENT_KEY$2,\n    SLID: \"slid\" + EVENT_KEY$2,\n    KEYDOWN: \"keydown\" + EVENT_KEY$2,\n    MOUSEENTER: \"mouseenter\" + EVENT_KEY$2,\n    MOUSELEAVE: \"mouseleave\" + EVENT_KEY$2,\n    TOUCHSTART: \"touchstart\" + EVENT_KEY$2,\n    TOUCHMOVE: \"touchmove\" + EVENT_KEY$2,\n    TOUCHEND: \"touchend\" + EVENT_KEY$2,\n    POINTERDOWN: \"pointerdown\" + EVENT_KEY$2,\n    POINTERUP: \"pointerup\" + EVENT_KEY$2,\n    DRAG_START: \"dragstart\" + EVENT_KEY$2,\n    LOAD_DATA_API: \"load\" + EVENT_KEY$2 + DATA_API_KEY$2,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$2 + DATA_API_KEY$2\n  };\n  var ClassName$2 = {\n    CAROUSEL: 'carousel',\n    ACTIVE: 'active',\n    SLIDE: 'slide',\n    RIGHT: 'carousel-item-right',\n    LEFT: 'carousel-item-left',\n    NEXT: 'carousel-item-next',\n    PREV: 'carousel-item-prev',\n    ITEM: 'carousel-item',\n    POINTER_EVENT: 'pointer-event'\n  };\n  var Selector$2 = {\n    ACTIVE: '.active',\n    ACTIVE_ITEM: '.active.carousel-item',\n    ITEM: '.carousel-item',\n    ITEM_IMG: '.carousel-item img',\n    NEXT_PREV: '.carousel-item-next, .carousel-item-prev',\n    INDICATORS: '.carousel-indicators',\n    DATA_SLIDE: '[data-slide], [data-slide-to]',\n    DATA_RIDE: '[data-ride=\"carousel\"]'\n  };\n  var PointerType = {\n    TOUCH: 'touch',\n    PEN: 'pen'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Carousel =\n  /*#__PURE__*/\n  function () {\n    function Carousel(element, config) {\n      this._items = null;\n      this._interval = null;\n      this._activeElement = null;\n      this._isPaused = false;\n      this._isSliding = false;\n      this.touchTimeout = null;\n      this.touchStartX = 0;\n      this.touchDeltaX = 0;\n      this._config = this._getConfig(config);\n      this._element = element;\n      this._indicatorsElement = this._element.querySelector(Selector$2.INDICATORS);\n      this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;\n      this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent);\n\n      this._addEventListeners();\n    } // Getters\n\n\n    var _proto = Carousel.prototype;\n\n    // Public\n    _proto.next = function next() {\n      if (!this._isSliding) {\n        this._slide(Direction.NEXT);\n      }\n    };\n\n    _proto.nextWhenVisible = function nextWhenVisible() {\n      // Don't call next when the page isn't visible\n      // or the carousel or its parent isn't visible\n      if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') {\n        this.next();\n      }\n    };\n\n    _proto.prev = function prev() {\n      if (!this._isSliding) {\n        this._slide(Direction.PREV);\n      }\n    };\n\n    _proto.pause = function pause(event) {\n      if (!event) {\n        this._isPaused = true;\n      }\n\n      if (this._element.querySelector(Selector$2.NEXT_PREV)) {\n        Util.triggerTransitionEnd(this._element);\n        this.cycle(true);\n      }\n\n      clearInterval(this._interval);\n      this._interval = null;\n    };\n\n    _proto.cycle = function cycle(event) {\n      if (!event) {\n        this._isPaused = false;\n      }\n\n      if (this._interval) {\n        clearInterval(this._interval);\n        this._interval = null;\n      }\n\n      if (this._config.interval && !this._isPaused) {\n        this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);\n      }\n    };\n\n    _proto.to = function to(index) {\n      var _this = this;\n\n      this._activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);\n\n      var activeIndex = this._getItemIndex(this._activeElement);\n\n      if (index > this._items.length - 1 || index < 0) {\n        return;\n      }\n\n      if (this._isSliding) {\n        $(this._element).one(Event$2.SLID, function () {\n          return _this.to(index);\n        });\n        return;\n      }\n\n      if (activeIndex === index) {\n        this.pause();\n        this.cycle();\n        return;\n      }\n\n      var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;\n\n      this._slide(direction, this._items[index]);\n    };\n\n    _proto.dispose = function dispose() {\n      $(this._element).off(EVENT_KEY$2);\n      $.removeData(this._element, DATA_KEY$2);\n      this._items = null;\n      this._config = null;\n      this._element = null;\n      this._interval = null;\n      this._isPaused = null;\n      this._isSliding = null;\n      this._activeElement = null;\n      this._indicatorsElement = null;\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default, config);\n      Util.typeCheckConfig(NAME$2, config, DefaultType);\n      return config;\n    };\n\n    _proto._handleSwipe = function _handleSwipe() {\n      var absDeltax = Math.abs(this.touchDeltaX);\n\n      if (absDeltax <= SWIPE_THRESHOLD) {\n        return;\n      }\n\n      var direction = absDeltax / this.touchDeltaX; // swipe left\n\n      if (direction > 0) {\n        this.prev();\n      } // swipe right\n\n\n      if (direction < 0) {\n        this.next();\n      }\n    };\n\n    _proto._addEventListeners = function _addEventListeners() {\n      var _this2 = this;\n\n      if (this._config.keyboard) {\n        $(this._element).on(Event$2.KEYDOWN, function (event) {\n          return _this2._keydown(event);\n        });\n      }\n\n      if (this._config.pause === 'hover') {\n        $(this._element).on(Event$2.MOUSEENTER, function (event) {\n          return _this2.pause(event);\n        }).on(Event$2.MOUSELEAVE, function (event) {\n          return _this2.cycle(event);\n        });\n      }\n\n      if (this._config.touch) {\n        this._addTouchEventListeners();\n      }\n    };\n\n    _proto._addTouchEventListeners = function _addTouchEventListeners() {\n      var _this3 = this;\n\n      if (!this._touchSupported) {\n        return;\n      }\n\n      var start = function start(event) {\n        if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n          _this3.touchStartX = event.originalEvent.clientX;\n        } else if (!_this3._pointerEvent) {\n          _this3.touchStartX = event.originalEvent.touches[0].clientX;\n        }\n      };\n\n      var move = function move(event) {\n        // ensure swiping with one touch and not pinching\n        if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {\n          _this3.touchDeltaX = 0;\n        } else {\n          _this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX;\n        }\n      };\n\n      var end = function end(event) {\n        if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n          _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX;\n        }\n\n        _this3._handleSwipe();\n\n        if (_this3._config.pause === 'hover') {\n          // If it's a touch-enabled device, mouseenter/leave are fired as\n          // part of the mouse compatibility events on first tap - the carousel\n          // would stop cycling until user tapped out of it;\n          // here, we listen for touchend, explicitly pause the carousel\n          // (as if it's the second time we tap on it, mouseenter compat event\n          // is NOT fired) and after a timeout (to allow for mouse compatibility\n          // events to fire) we explicitly restart cycling\n          _this3.pause();\n\n          if (_this3.touchTimeout) {\n            clearTimeout(_this3.touchTimeout);\n          }\n\n          _this3.touchTimeout = setTimeout(function (event) {\n            return _this3.cycle(event);\n          }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval);\n        }\n      };\n\n      $(this._element.querySelectorAll(Selector$2.ITEM_IMG)).on(Event$2.DRAG_START, function (e) {\n        return e.preventDefault();\n      });\n\n      if (this._pointerEvent) {\n        $(this._element).on(Event$2.POINTERDOWN, function (event) {\n          return start(event);\n        });\n        $(this._element).on(Event$2.POINTERUP, function (event) {\n          return end(event);\n        });\n\n        this._element.classList.add(ClassName$2.POINTER_EVENT);\n      } else {\n        $(this._element).on(Event$2.TOUCHSTART, function (event) {\n          return start(event);\n        });\n        $(this._element).on(Event$2.TOUCHMOVE, function (event) {\n          return move(event);\n        });\n        $(this._element).on(Event$2.TOUCHEND, function (event) {\n          return end(event);\n        });\n      }\n    };\n\n    _proto._keydown = function _keydown(event) {\n      if (/input|textarea/i.test(event.target.tagName)) {\n        return;\n      }\n\n      switch (event.which) {\n        case ARROW_LEFT_KEYCODE:\n          event.preventDefault();\n          this.prev();\n          break;\n\n        case ARROW_RIGHT_KEYCODE:\n          event.preventDefault();\n          this.next();\n          break;\n\n        default:\n      }\n    };\n\n    _proto._getItemIndex = function _getItemIndex(element) {\n      this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector$2.ITEM)) : [];\n      return this._items.indexOf(element);\n    };\n\n    _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {\n      var isNextDirection = direction === Direction.NEXT;\n      var isPrevDirection = direction === Direction.PREV;\n\n      var activeIndex = this._getItemIndex(activeElement);\n\n      var lastItemIndex = this._items.length - 1;\n      var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;\n\n      if (isGoingToWrap && !this._config.wrap) {\n        return activeElement;\n      }\n\n      var delta = direction === Direction.PREV ? -1 : 1;\n      var itemIndex = (activeIndex + delta) % this._items.length;\n      return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];\n    };\n\n    _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {\n      var targetIndex = this._getItemIndex(relatedTarget);\n\n      var fromIndex = this._getItemIndex(this._element.querySelector(Selector$2.ACTIVE_ITEM));\n\n      var slideEvent = $.Event(Event$2.SLIDE, {\n        relatedTarget: relatedTarget,\n        direction: eventDirectionName,\n        from: fromIndex,\n        to: targetIndex\n      });\n      $(this._element).trigger(slideEvent);\n      return slideEvent;\n    };\n\n    _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {\n      if (this._indicatorsElement) {\n        var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector$2.ACTIVE));\n        $(indicators).removeClass(ClassName$2.ACTIVE);\n\n        var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];\n\n        if (nextIndicator) {\n          $(nextIndicator).addClass(ClassName$2.ACTIVE);\n        }\n      }\n    };\n\n    _proto._slide = function _slide(direction, element) {\n      var _this4 = this;\n\n      var activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);\n\n      var activeElementIndex = this._getItemIndex(activeElement);\n\n      var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);\n\n      var nextElementIndex = this._getItemIndex(nextElement);\n\n      var isCycling = Boolean(this._interval);\n      var directionalClassName;\n      var orderClassName;\n      var eventDirectionName;\n\n      if (direction === Direction.NEXT) {\n        directionalClassName = ClassName$2.LEFT;\n        orderClassName = ClassName$2.NEXT;\n        eventDirectionName = Direction.LEFT;\n      } else {\n        directionalClassName = ClassName$2.RIGHT;\n        orderClassName = ClassName$2.PREV;\n        eventDirectionName = Direction.RIGHT;\n      }\n\n      if (nextElement && $(nextElement).hasClass(ClassName$2.ACTIVE)) {\n        this._isSliding = false;\n        return;\n      }\n\n      var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);\n\n      if (slideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      if (!activeElement || !nextElement) {\n        // Some weirdness is happening, so we bail\n        return;\n      }\n\n      this._isSliding = true;\n\n      if (isCycling) {\n        this.pause();\n      }\n\n      this._setActiveIndicatorElement(nextElement);\n\n      var slidEvent = $.Event(Event$2.SLID, {\n        relatedTarget: nextElement,\n        direction: eventDirectionName,\n        from: activeElementIndex,\n        to: nextElementIndex\n      });\n\n      if ($(this._element).hasClass(ClassName$2.SLIDE)) {\n        $(nextElement).addClass(orderClassName);\n        Util.reflow(nextElement);\n        $(activeElement).addClass(directionalClassName);\n        $(nextElement).addClass(directionalClassName);\n        var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10);\n\n        if (nextElementInterval) {\n          this._config.defaultInterval = this._config.defaultInterval || this._config.interval;\n          this._config.interval = nextElementInterval;\n        } else {\n          this._config.interval = this._config.defaultInterval || this._config.interval;\n        }\n\n        var transitionDuration = Util.getTransitionDurationFromElement(activeElement);\n        $(activeElement).one(Util.TRANSITION_END, function () {\n          $(nextElement).removeClass(directionalClassName + \" \" + orderClassName).addClass(ClassName$2.ACTIVE);\n          $(activeElement).removeClass(ClassName$2.ACTIVE + \" \" + orderClassName + \" \" + directionalClassName);\n          _this4._isSliding = false;\n          setTimeout(function () {\n            return $(_this4._element).trigger(slidEvent);\n          }, 0);\n        }).emulateTransitionEnd(transitionDuration);\n      } else {\n        $(activeElement).removeClass(ClassName$2.ACTIVE);\n        $(nextElement).addClass(ClassName$2.ACTIVE);\n        this._isSliding = false;\n        $(this._element).trigger(slidEvent);\n      }\n\n      if (isCycling) {\n        this.cycle();\n      }\n    } // Static\n    ;\n\n    Carousel._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$2);\n\n        var _config = _objectSpread({}, Default, $(this).data());\n\n        if (typeof config === 'object') {\n          _config = _objectSpread({}, _config, config);\n        }\n\n        var action = typeof config === 'string' ? config : _config.slide;\n\n        if (!data) {\n          data = new Carousel(this, _config);\n          $(this).data(DATA_KEY$2, data);\n        }\n\n        if (typeof config === 'number') {\n          data.to(config);\n        } else if (typeof action === 'string') {\n          if (typeof data[action] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + action + \"\\\"\");\n          }\n\n          data[action]();\n        } else if (_config.interval && _config.ride) {\n          data.pause();\n          data.cycle();\n        }\n      });\n    };\n\n    Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {\n      var selector = Util.getSelectorFromElement(this);\n\n      if (!selector) {\n        return;\n      }\n\n      var target = $(selector)[0];\n\n      if (!target || !$(target).hasClass(ClassName$2.CAROUSEL)) {\n        return;\n      }\n\n      var config = _objectSpread({}, $(target).data(), $(this).data());\n\n      var slideIndex = this.getAttribute('data-slide-to');\n\n      if (slideIndex) {\n        config.interval = false;\n      }\n\n      Carousel._jQueryInterface.call($(target), config);\n\n      if (slideIndex) {\n        $(target).data(DATA_KEY$2).to(slideIndex);\n      }\n\n      event.preventDefault();\n    };\n\n    _createClass(Carousel, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$2;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default;\n      }\n    }]);\n\n    return Carousel;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$2.CLICK_DATA_API, Selector$2.DATA_SLIDE, Carousel._dataApiClickHandler);\n  $(window).on(Event$2.LOAD_DATA_API, function () {\n    var carousels = [].slice.call(document.querySelectorAll(Selector$2.DATA_RIDE));\n\n    for (var i = 0, len = carousels.length; i < len; i++) {\n      var $carousel = $(carousels[i]);\n\n      Carousel._jQueryInterface.call($carousel, $carousel.data());\n    }\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$2] = Carousel._jQueryInterface;\n  $.fn[NAME$2].Constructor = Carousel;\n\n  $.fn[NAME$2].noConflict = function () {\n    $.fn[NAME$2] = JQUERY_NO_CONFLICT$2;\n    return Carousel._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$3 = 'collapse';\n  var VERSION$3 = '4.3.1';\n  var DATA_KEY$3 = 'bs.collapse';\n  var EVENT_KEY$3 = \".\" + DATA_KEY$3;\n  var DATA_API_KEY$3 = '.data-api';\n  var JQUERY_NO_CONFLICT$3 = $.fn[NAME$3];\n  var Default$1 = {\n    toggle: true,\n    parent: ''\n  };\n  var DefaultType$1 = {\n    toggle: 'boolean',\n    parent: '(string|element)'\n  };\n  var Event$3 = {\n    SHOW: \"show\" + EVENT_KEY$3,\n    SHOWN: \"shown\" + EVENT_KEY$3,\n    HIDE: \"hide\" + EVENT_KEY$3,\n    HIDDEN: \"hidden\" + EVENT_KEY$3,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$3 + DATA_API_KEY$3\n  };\n  var ClassName$3 = {\n    SHOW: 'show',\n    COLLAPSE: 'collapse',\n    COLLAPSING: 'collapsing',\n    COLLAPSED: 'collapsed'\n  };\n  var Dimension = {\n    WIDTH: 'width',\n    HEIGHT: 'height'\n  };\n  var Selector$3 = {\n    ACTIVES: '.show, .collapsing',\n    DATA_TOGGLE: '[data-toggle=\"collapse\"]'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Collapse =\n  /*#__PURE__*/\n  function () {\n    function Collapse(element, config) {\n      this._isTransitioning = false;\n      this._element = element;\n      this._config = this._getConfig(config);\n      this._triggerArray = [].slice.call(document.querySelectorAll(\"[data-toggle=\\\"collapse\\\"][href=\\\"#\" + element.id + \"\\\"],\" + (\"[data-toggle=\\\"collapse\\\"][data-target=\\\"#\" + element.id + \"\\\"]\")));\n      var toggleList = [].slice.call(document.querySelectorAll(Selector$3.DATA_TOGGLE));\n\n      for (var i = 0, len = toggleList.length; i < len; i++) {\n        var elem = toggleList[i];\n        var selector = Util.getSelectorFromElement(elem);\n        var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {\n          return foundElem === element;\n        });\n\n        if (selector !== null && filterElement.length > 0) {\n          this._selector = selector;\n\n          this._triggerArray.push(elem);\n        }\n      }\n\n      this._parent = this._config.parent ? this._getParent() : null;\n\n      if (!this._config.parent) {\n        this._addAriaAndCollapsedClass(this._element, this._triggerArray);\n      }\n\n      if (this._config.toggle) {\n        this.toggle();\n      }\n    } // Getters\n\n\n    var _proto = Collapse.prototype;\n\n    // Public\n    _proto.toggle = function toggle() {\n      if ($(this._element).hasClass(ClassName$3.SHOW)) {\n        this.hide();\n      } else {\n        this.show();\n      }\n    };\n\n    _proto.show = function show() {\n      var _this = this;\n\n      if (this._isTransitioning || $(this._element).hasClass(ClassName$3.SHOW)) {\n        return;\n      }\n\n      var actives;\n      var activesData;\n\n      if (this._parent) {\n        actives = [].slice.call(this._parent.querySelectorAll(Selector$3.ACTIVES)).filter(function (elem) {\n          if (typeof _this._config.parent === 'string') {\n            return elem.getAttribute('data-parent') === _this._config.parent;\n          }\n\n          return elem.classList.contains(ClassName$3.COLLAPSE);\n        });\n\n        if (actives.length === 0) {\n          actives = null;\n        }\n      }\n\n      if (actives) {\n        activesData = $(actives).not(this._selector).data(DATA_KEY$3);\n\n        if (activesData && activesData._isTransitioning) {\n          return;\n        }\n      }\n\n      var startEvent = $.Event(Event$3.SHOW);\n      $(this._element).trigger(startEvent);\n\n      if (startEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      if (actives) {\n        Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide');\n\n        if (!activesData) {\n          $(actives).data(DATA_KEY$3, null);\n        }\n      }\n\n      var dimension = this._getDimension();\n\n      $(this._element).removeClass(ClassName$3.COLLAPSE).addClass(ClassName$3.COLLAPSING);\n      this._element.style[dimension] = 0;\n\n      if (this._triggerArray.length) {\n        $(this._triggerArray).removeClass(ClassName$3.COLLAPSED).attr('aria-expanded', true);\n      }\n\n      this.setTransitioning(true);\n\n      var complete = function complete() {\n        $(_this._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).addClass(ClassName$3.SHOW);\n        _this._element.style[dimension] = '';\n\n        _this.setTransitioning(false);\n\n        $(_this._element).trigger(Event$3.SHOWN);\n      };\n\n      var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n      var scrollSize = \"scroll\" + capitalizedDimension;\n      var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n      $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      this._element.style[dimension] = this._element[scrollSize] + \"px\";\n    };\n\n    _proto.hide = function hide() {\n      var _this2 = this;\n\n      if (this._isTransitioning || !$(this._element).hasClass(ClassName$3.SHOW)) {\n        return;\n      }\n\n      var startEvent = $.Event(Event$3.HIDE);\n      $(this._element).trigger(startEvent);\n\n      if (startEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      var dimension = this._getDimension();\n\n      this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + \"px\";\n      Util.reflow(this._element);\n      $(this._element).addClass(ClassName$3.COLLAPSING).removeClass(ClassName$3.COLLAPSE).removeClass(ClassName$3.SHOW);\n      var triggerArrayLength = this._triggerArray.length;\n\n      if (triggerArrayLength > 0) {\n        for (var i = 0; i < triggerArrayLength; i++) {\n          var trigger = this._triggerArray[i];\n          var selector = Util.getSelectorFromElement(trigger);\n\n          if (selector !== null) {\n            var $elem = $([].slice.call(document.querySelectorAll(selector)));\n\n            if (!$elem.hasClass(ClassName$3.SHOW)) {\n              $(trigger).addClass(ClassName$3.COLLAPSED).attr('aria-expanded', false);\n            }\n          }\n        }\n      }\n\n      this.setTransitioning(true);\n\n      var complete = function complete() {\n        _this2.setTransitioning(false);\n\n        $(_this2._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).trigger(Event$3.HIDDEN);\n      };\n\n      this._element.style[dimension] = '';\n      var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n      $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n    };\n\n    _proto.setTransitioning = function setTransitioning(isTransitioning) {\n      this._isTransitioning = isTransitioning;\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$3);\n      this._config = null;\n      this._parent = null;\n      this._element = null;\n      this._triggerArray = null;\n      this._isTransitioning = null;\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default$1, config);\n      config.toggle = Boolean(config.toggle); // Coerce string values\n\n      Util.typeCheckConfig(NAME$3, config, DefaultType$1);\n      return config;\n    };\n\n    _proto._getDimension = function _getDimension() {\n      var hasWidth = $(this._element).hasClass(Dimension.WIDTH);\n      return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;\n    };\n\n    _proto._getParent = function _getParent() {\n      var _this3 = this;\n\n      var parent;\n\n      if (Util.isElement(this._config.parent)) {\n        parent = this._config.parent; // It's a jQuery object\n\n        if (typeof this._config.parent.jquery !== 'undefined') {\n          parent = this._config.parent[0];\n        }\n      } else {\n        parent = document.querySelector(this._config.parent);\n      }\n\n      var selector = \"[data-toggle=\\\"collapse\\\"][data-parent=\\\"\" + this._config.parent + \"\\\"]\";\n      var children = [].slice.call(parent.querySelectorAll(selector));\n      $(children).each(function (i, element) {\n        _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);\n      });\n      return parent;\n    };\n\n    _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {\n      var isOpen = $(element).hasClass(ClassName$3.SHOW);\n\n      if (triggerArray.length) {\n        $(triggerArray).toggleClass(ClassName$3.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);\n      }\n    } // Static\n    ;\n\n    Collapse._getTargetFromElement = function _getTargetFromElement(element) {\n      var selector = Util.getSelectorFromElement(element);\n      return selector ? document.querySelector(selector) : null;\n    };\n\n    Collapse._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var $this = $(this);\n        var data = $this.data(DATA_KEY$3);\n\n        var _config = _objectSpread({}, Default$1, $this.data(), typeof config === 'object' && config ? config : {});\n\n        if (!data && _config.toggle && /show|hide/.test(config)) {\n          _config.toggle = false;\n        }\n\n        if (!data) {\n          data = new Collapse(this, _config);\n          $this.data(DATA_KEY$3, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Collapse, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$3;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$1;\n      }\n    }]);\n\n    return Collapse;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$3.CLICK_DATA_API, Selector$3.DATA_TOGGLE, function (event) {\n    // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n    if (event.currentTarget.tagName === 'A') {\n      event.preventDefault();\n    }\n\n    var $trigger = $(this);\n    var selector = Util.getSelectorFromElement(this);\n    var selectors = [].slice.call(document.querySelectorAll(selector));\n    $(selectors).each(function () {\n      var $target = $(this);\n      var data = $target.data(DATA_KEY$3);\n      var config = data ? 'toggle' : $trigger.data();\n\n      Collapse._jQueryInterface.call($target, config);\n    });\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$3] = Collapse._jQueryInterface;\n  $.fn[NAME$3].Constructor = Collapse;\n\n  $.fn[NAME$3].noConflict = function () {\n    $.fn[NAME$3] = JQUERY_NO_CONFLICT$3;\n    return Collapse._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$4 = 'dropdown';\n  var VERSION$4 = '4.3.1';\n  var DATA_KEY$4 = 'bs.dropdown';\n  var EVENT_KEY$4 = \".\" + DATA_KEY$4;\n  var DATA_API_KEY$4 = '.data-api';\n  var JQUERY_NO_CONFLICT$4 = $.fn[NAME$4];\n  var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n  var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key\n\n  var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key\n\n  var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key\n\n  var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key\n\n  var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)\n\n  var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + \"|\" + ARROW_DOWN_KEYCODE + \"|\" + ESCAPE_KEYCODE);\n  var Event$4 = {\n    HIDE: \"hide\" + EVENT_KEY$4,\n    HIDDEN: \"hidden\" + EVENT_KEY$4,\n    SHOW: \"show\" + EVENT_KEY$4,\n    SHOWN: \"shown\" + EVENT_KEY$4,\n    CLICK: \"click\" + EVENT_KEY$4,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$4 + DATA_API_KEY$4,\n    KEYDOWN_DATA_API: \"keydown\" + EVENT_KEY$4 + DATA_API_KEY$4,\n    KEYUP_DATA_API: \"keyup\" + EVENT_KEY$4 + DATA_API_KEY$4\n  };\n  var ClassName$4 = {\n    DISABLED: 'disabled',\n    SHOW: 'show',\n    DROPUP: 'dropup',\n    DROPRIGHT: 'dropright',\n    DROPLEFT: 'dropleft',\n    MENURIGHT: 'dropdown-menu-right',\n    MENULEFT: 'dropdown-menu-left',\n    POSITION_STATIC: 'position-static'\n  };\n  var Selector$4 = {\n    DATA_TOGGLE: '[data-toggle=\"dropdown\"]',\n    FORM_CHILD: '.dropdown form',\n    MENU: '.dropdown-menu',\n    NAVBAR_NAV: '.navbar-nav',\n    VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n  };\n  var AttachmentMap = {\n    TOP: 'top-start',\n    TOPEND: 'top-end',\n    BOTTOM: 'bottom-start',\n    BOTTOMEND: 'bottom-end',\n    RIGHT: 'right-start',\n    RIGHTEND: 'right-end',\n    LEFT: 'left-start',\n    LEFTEND: 'left-end'\n  };\n  var Default$2 = {\n    offset: 0,\n    flip: true,\n    boundary: 'scrollParent',\n    reference: 'toggle',\n    display: 'dynamic'\n  };\n  var DefaultType$2 = {\n    offset: '(number|string|function)',\n    flip: 'boolean',\n    boundary: '(string|element)',\n    reference: '(string|element)',\n    display: 'string'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Dropdown =\n  /*#__PURE__*/\n  function () {\n    function Dropdown(element, config) {\n      this._element = element;\n      this._popper = null;\n      this._config = this._getConfig(config);\n      this._menu = this._getMenuElement();\n      this._inNavbar = this._detectNavbar();\n\n      this._addEventListeners();\n    } // Getters\n\n\n    var _proto = Dropdown.prototype;\n\n    // Public\n    _proto.toggle = function toggle() {\n      if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED)) {\n        return;\n      }\n\n      var parent = Dropdown._getParentFromElement(this._element);\n\n      var isActive = $(this._menu).hasClass(ClassName$4.SHOW);\n\n      Dropdown._clearMenus();\n\n      if (isActive) {\n        return;\n      }\n\n      var relatedTarget = {\n        relatedTarget: this._element\n      };\n      var showEvent = $.Event(Event$4.SHOW, relatedTarget);\n      $(parent).trigger(showEvent);\n\n      if (showEvent.isDefaultPrevented()) {\n        return;\n      } // Disable totally Popper.js for Dropdown in Navbar\n\n\n      if (!this._inNavbar) {\n        /**\n         * Check for Popper dependency\n         * Popper - https://popper.js.org\n         */\n        if (typeof Popper === 'undefined') {\n          throw new TypeError('Bootstrap\\'s dropdowns require Popper.js (https://popper.js.org/)');\n        }\n\n        var referenceElement = this._element;\n\n        if (this._config.reference === 'parent') {\n          referenceElement = parent;\n        } else if (Util.isElement(this._config.reference)) {\n          referenceElement = this._config.reference; // Check if it's jQuery element\n\n          if (typeof this._config.reference.jquery !== 'undefined') {\n            referenceElement = this._config.reference[0];\n          }\n        } // If boundary is not `scrollParent`, then set position to `static`\n        // to allow the menu to \"escape\" the scroll parent's boundaries\n        // https://github.com/twbs/bootstrap/issues/24251\n\n\n        if (this._config.boundary !== 'scrollParent') {\n          $(parent).addClass(ClassName$4.POSITION_STATIC);\n        }\n\n        this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig());\n      } // If this is a touch-enabled device we add extra\n      // empty mouseover listeners to the body's immediate children;\n      // only needed because of broken event delegation on iOS\n      // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n\n      if ('ontouchstart' in document.documentElement && $(parent).closest(Selector$4.NAVBAR_NAV).length === 0) {\n        $(document.body).children().on('mouseover', null, $.noop);\n      }\n\n      this._element.focus();\n\n      this._element.setAttribute('aria-expanded', true);\n\n      $(this._menu).toggleClass(ClassName$4.SHOW);\n      $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget));\n    };\n\n    _proto.show = function show() {\n      if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || $(this._menu).hasClass(ClassName$4.SHOW)) {\n        return;\n      }\n\n      var relatedTarget = {\n        relatedTarget: this._element\n      };\n      var showEvent = $.Event(Event$4.SHOW, relatedTarget);\n\n      var parent = Dropdown._getParentFromElement(this._element);\n\n      $(parent).trigger(showEvent);\n\n      if (showEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      $(this._menu).toggleClass(ClassName$4.SHOW);\n      $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget));\n    };\n\n    _proto.hide = function hide() {\n      if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || !$(this._menu).hasClass(ClassName$4.SHOW)) {\n        return;\n      }\n\n      var relatedTarget = {\n        relatedTarget: this._element\n      };\n      var hideEvent = $.Event(Event$4.HIDE, relatedTarget);\n\n      var parent = Dropdown._getParentFromElement(this._element);\n\n      $(parent).trigger(hideEvent);\n\n      if (hideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      $(this._menu).toggleClass(ClassName$4.SHOW);\n      $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$4);\n      $(this._element).off(EVENT_KEY$4);\n      this._element = null;\n      this._menu = null;\n\n      if (this._popper !== null) {\n        this._popper.destroy();\n\n        this._popper = null;\n      }\n    };\n\n    _proto.update = function update() {\n      this._inNavbar = this._detectNavbar();\n\n      if (this._popper !== null) {\n        this._popper.scheduleUpdate();\n      }\n    } // Private\n    ;\n\n    _proto._addEventListeners = function _addEventListeners() {\n      var _this = this;\n\n      $(this._element).on(Event$4.CLICK, function (event) {\n        event.preventDefault();\n        event.stopPropagation();\n\n        _this.toggle();\n      });\n    };\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, this.constructor.Default, $(this._element).data(), config);\n      Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType);\n      return config;\n    };\n\n    _proto._getMenuElement = function _getMenuElement() {\n      if (!this._menu) {\n        var parent = Dropdown._getParentFromElement(this._element);\n\n        if (parent) {\n          this._menu = parent.querySelector(Selector$4.MENU);\n        }\n      }\n\n      return this._menu;\n    };\n\n    _proto._getPlacement = function _getPlacement() {\n      var $parentDropdown = $(this._element.parentNode);\n      var placement = AttachmentMap.BOTTOM; // Handle dropup\n\n      if ($parentDropdown.hasClass(ClassName$4.DROPUP)) {\n        placement = AttachmentMap.TOP;\n\n        if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {\n          placement = AttachmentMap.TOPEND;\n        }\n      } else if ($parentDropdown.hasClass(ClassName$4.DROPRIGHT)) {\n        placement = AttachmentMap.RIGHT;\n      } else if ($parentDropdown.hasClass(ClassName$4.DROPLEFT)) {\n        placement = AttachmentMap.LEFT;\n      } else if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {\n        placement = AttachmentMap.BOTTOMEND;\n      }\n\n      return placement;\n    };\n\n    _proto._detectNavbar = function _detectNavbar() {\n      return $(this._element).closest('.navbar').length > 0;\n    };\n\n    _proto._getOffset = function _getOffset() {\n      var _this2 = this;\n\n      var offset = {};\n\n      if (typeof this._config.offset === 'function') {\n        offset.fn = function (data) {\n          data.offsets = _objectSpread({}, data.offsets, _this2._config.offset(data.offsets, _this2._element) || {});\n          return data;\n        };\n      } else {\n        offset.offset = this._config.offset;\n      }\n\n      return offset;\n    };\n\n    _proto._getPopperConfig = function _getPopperConfig() {\n      var popperConfig = {\n        placement: this._getPlacement(),\n        modifiers: {\n          offset: this._getOffset(),\n          flip: {\n            enabled: this._config.flip\n          },\n          preventOverflow: {\n            boundariesElement: this._config.boundary\n          }\n        } // Disable Popper.js if we have a static display\n\n      };\n\n      if (this._config.display === 'static') {\n        popperConfig.modifiers.applyStyle = {\n          enabled: false\n        };\n      }\n\n      return popperConfig;\n    } // Static\n    ;\n\n    Dropdown._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$4);\n\n        var _config = typeof config === 'object' ? config : null;\n\n        if (!data) {\n          data = new Dropdown(this, _config);\n          $(this).data(DATA_KEY$4, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    Dropdown._clearMenus = function _clearMenus(event) {\n      if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {\n        return;\n      }\n\n      var toggles = [].slice.call(document.querySelectorAll(Selector$4.DATA_TOGGLE));\n\n      for (var i = 0, len = toggles.length; i < len; i++) {\n        var parent = Dropdown._getParentFromElement(toggles[i]);\n\n        var context = $(toggles[i]).data(DATA_KEY$4);\n        var relatedTarget = {\n          relatedTarget: toggles[i]\n        };\n\n        if (event && event.type === 'click') {\n          relatedTarget.clickEvent = event;\n        }\n\n        if (!context) {\n          continue;\n        }\n\n        var dropdownMenu = context._menu;\n\n        if (!$(parent).hasClass(ClassName$4.SHOW)) {\n          continue;\n        }\n\n        if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) {\n          continue;\n        }\n\n        var hideEvent = $.Event(Event$4.HIDE, relatedTarget);\n        $(parent).trigger(hideEvent);\n\n        if (hideEvent.isDefaultPrevented()) {\n          continue;\n        } // If this is a touch-enabled device we remove the extra\n        // empty mouseover listeners we added for iOS support\n\n\n        if ('ontouchstart' in document.documentElement) {\n          $(document.body).children().off('mouseover', null, $.noop);\n        }\n\n        toggles[i].setAttribute('aria-expanded', 'false');\n        $(dropdownMenu).removeClass(ClassName$4.SHOW);\n        $(parent).removeClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));\n      }\n    };\n\n    Dropdown._getParentFromElement = function _getParentFromElement(element) {\n      var parent;\n      var selector = Util.getSelectorFromElement(element);\n\n      if (selector) {\n        parent = document.querySelector(selector);\n      }\n\n      return parent || element.parentNode;\n    } // eslint-disable-next-line complexity\n    ;\n\n    Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {\n      // If not input/textarea:\n      //  - And not a key in REGEXP_KEYDOWN => not a dropdown command\n      // If input/textarea:\n      //  - If space key => not a dropdown command\n      //  - If key is other than escape\n      //    - If key is not up or down => not a dropdown command\n      //    - If trigger inside the menu => not a dropdown command\n      if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector$4.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {\n        return;\n      }\n\n      event.preventDefault();\n      event.stopPropagation();\n\n      if (this.disabled || $(this).hasClass(ClassName$4.DISABLED)) {\n        return;\n      }\n\n      var parent = Dropdown._getParentFromElement(this);\n\n      var isActive = $(parent).hasClass(ClassName$4.SHOW);\n\n      if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {\n        if (event.which === ESCAPE_KEYCODE) {\n          var toggle = parent.querySelector(Selector$4.DATA_TOGGLE);\n          $(toggle).trigger('focus');\n        }\n\n        $(this).trigger('click');\n        return;\n      }\n\n      var items = [].slice.call(parent.querySelectorAll(Selector$4.VISIBLE_ITEMS));\n\n      if (items.length === 0) {\n        return;\n      }\n\n      var index = items.indexOf(event.target);\n\n      if (event.which === ARROW_UP_KEYCODE && index > 0) {\n        // Up\n        index--;\n      }\n\n      if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {\n        // Down\n        index++;\n      }\n\n      if (index < 0) {\n        index = 0;\n      }\n\n      items[index].focus();\n    };\n\n    _createClass(Dropdown, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$4;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$2;\n      }\n    }, {\n      key: \"DefaultType\",\n      get: function get() {\n        return DefaultType$2;\n      }\n    }]);\n\n    return Dropdown;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$4.KEYDOWN_DATA_API, Selector$4.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event$4.KEYDOWN_DATA_API, Selector$4.MENU, Dropdown._dataApiKeydownHandler).on(Event$4.CLICK_DATA_API + \" \" + Event$4.KEYUP_DATA_API, Dropdown._clearMenus).on(Event$4.CLICK_DATA_API, Selector$4.DATA_TOGGLE, function (event) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    Dropdown._jQueryInterface.call($(this), 'toggle');\n  }).on(Event$4.CLICK_DATA_API, Selector$4.FORM_CHILD, function (e) {\n    e.stopPropagation();\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$4] = Dropdown._jQueryInterface;\n  $.fn[NAME$4].Constructor = Dropdown;\n\n  $.fn[NAME$4].noConflict = function () {\n    $.fn[NAME$4] = JQUERY_NO_CONFLICT$4;\n    return Dropdown._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$5 = 'modal';\n  var VERSION$5 = '4.3.1';\n  var DATA_KEY$5 = 'bs.modal';\n  var EVENT_KEY$5 = \".\" + DATA_KEY$5;\n  var DATA_API_KEY$5 = '.data-api';\n  var JQUERY_NO_CONFLICT$5 = $.fn[NAME$5];\n  var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n  var Default$3 = {\n    backdrop: true,\n    keyboard: true,\n    focus: true,\n    show: true\n  };\n  var DefaultType$3 = {\n    backdrop: '(boolean|string)',\n    keyboard: 'boolean',\n    focus: 'boolean',\n    show: 'boolean'\n  };\n  var Event$5 = {\n    HIDE: \"hide\" + EVENT_KEY$5,\n    HIDDEN: \"hidden\" + EVENT_KEY$5,\n    SHOW: \"show\" + EVENT_KEY$5,\n    SHOWN: \"shown\" + EVENT_KEY$5,\n    FOCUSIN: \"focusin\" + EVENT_KEY$5,\n    RESIZE: \"resize\" + EVENT_KEY$5,\n    CLICK_DISMISS: \"click.dismiss\" + EVENT_KEY$5,\n    KEYDOWN_DISMISS: \"keydown.dismiss\" + EVENT_KEY$5,\n    MOUSEUP_DISMISS: \"mouseup.dismiss\" + EVENT_KEY$5,\n    MOUSEDOWN_DISMISS: \"mousedown.dismiss\" + EVENT_KEY$5,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$5 + DATA_API_KEY$5\n  };\n  var ClassName$5 = {\n    SCROLLABLE: 'modal-dialog-scrollable',\n    SCROLLBAR_MEASURER: 'modal-scrollbar-measure',\n    BACKDROP: 'modal-backdrop',\n    OPEN: 'modal-open',\n    FADE: 'fade',\n    SHOW: 'show'\n  };\n  var Selector$5 = {\n    DIALOG: '.modal-dialog',\n    MODAL_BODY: '.modal-body',\n    DATA_TOGGLE: '[data-toggle=\"modal\"]',\n    DATA_DISMISS: '[data-dismiss=\"modal\"]',\n    FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',\n    STICKY_CONTENT: '.sticky-top'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Modal =\n  /*#__PURE__*/\n  function () {\n    function Modal(element, config) {\n      this._config = this._getConfig(config);\n      this._element = element;\n      this._dialog = element.querySelector(Selector$5.DIALOG);\n      this._backdrop = null;\n      this._isShown = false;\n      this._isBodyOverflowing = false;\n      this._ignoreBackdropClick = false;\n      this._isTransitioning = false;\n      this._scrollbarWidth = 0;\n    } // Getters\n\n\n    var _proto = Modal.prototype;\n\n    // Public\n    _proto.toggle = function toggle(relatedTarget) {\n      return this._isShown ? this.hide() : this.show(relatedTarget);\n    };\n\n    _proto.show = function show(relatedTarget) {\n      var _this = this;\n\n      if (this._isShown || this._isTransitioning) {\n        return;\n      }\n\n      if ($(this._element).hasClass(ClassName$5.FADE)) {\n        this._isTransitioning = true;\n      }\n\n      var showEvent = $.Event(Event$5.SHOW, {\n        relatedTarget: relatedTarget\n      });\n      $(this._element).trigger(showEvent);\n\n      if (this._isShown || showEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      this._isShown = true;\n\n      this._checkScrollbar();\n\n      this._setScrollbar();\n\n      this._adjustDialog();\n\n      this._setEscapeEvent();\n\n      this._setResizeEvent();\n\n      $(this._element).on(Event$5.CLICK_DISMISS, Selector$5.DATA_DISMISS, function (event) {\n        return _this.hide(event);\n      });\n      $(this._dialog).on(Event$5.MOUSEDOWN_DISMISS, function () {\n        $(_this._element).one(Event$5.MOUSEUP_DISMISS, function (event) {\n          if ($(event.target).is(_this._element)) {\n            _this._ignoreBackdropClick = true;\n          }\n        });\n      });\n\n      this._showBackdrop(function () {\n        return _this._showElement(relatedTarget);\n      });\n    };\n\n    _proto.hide = function hide(event) {\n      var _this2 = this;\n\n      if (event) {\n        event.preventDefault();\n      }\n\n      if (!this._isShown || this._isTransitioning) {\n        return;\n      }\n\n      var hideEvent = $.Event(Event$5.HIDE);\n      $(this._element).trigger(hideEvent);\n\n      if (!this._isShown || hideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      this._isShown = false;\n      var transition = $(this._element).hasClass(ClassName$5.FADE);\n\n      if (transition) {\n        this._isTransitioning = true;\n      }\n\n      this._setEscapeEvent();\n\n      this._setResizeEvent();\n\n      $(document).off(Event$5.FOCUSIN);\n      $(this._element).removeClass(ClassName$5.SHOW);\n      $(this._element).off(Event$5.CLICK_DISMISS);\n      $(this._dialog).off(Event$5.MOUSEDOWN_DISMISS);\n\n      if (transition) {\n        var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n        $(this._element).one(Util.TRANSITION_END, function (event) {\n          return _this2._hideModal(event);\n        }).emulateTransitionEnd(transitionDuration);\n      } else {\n        this._hideModal();\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      [window, this._element, this._dialog].forEach(function (htmlElement) {\n        return $(htmlElement).off(EVENT_KEY$5);\n      });\n      /**\n       * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API`\n       * Do not move `document` in `htmlElements` array\n       * It will remove `Event.CLICK_DATA_API` event that should remain\n       */\n\n      $(document).off(Event$5.FOCUSIN);\n      $.removeData(this._element, DATA_KEY$5);\n      this._config = null;\n      this._element = null;\n      this._dialog = null;\n      this._backdrop = null;\n      this._isShown = null;\n      this._isBodyOverflowing = null;\n      this._ignoreBackdropClick = null;\n      this._isTransitioning = null;\n      this._scrollbarWidth = null;\n    };\n\n    _proto.handleUpdate = function handleUpdate() {\n      this._adjustDialog();\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default$3, config);\n      Util.typeCheckConfig(NAME$5, config, DefaultType$3);\n      return config;\n    };\n\n    _proto._showElement = function _showElement(relatedTarget) {\n      var _this3 = this;\n\n      var transition = $(this._element).hasClass(ClassName$5.FADE);\n\n      if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n        // Don't move modal's DOM position\n        document.body.appendChild(this._element);\n      }\n\n      this._element.style.display = 'block';\n\n      this._element.removeAttribute('aria-hidden');\n\n      this._element.setAttribute('aria-modal', true);\n\n      if ($(this._dialog).hasClass(ClassName$5.SCROLLABLE)) {\n        this._dialog.querySelector(Selector$5.MODAL_BODY).scrollTop = 0;\n      } else {\n        this._element.scrollTop = 0;\n      }\n\n      if (transition) {\n        Util.reflow(this._element);\n      }\n\n      $(this._element).addClass(ClassName$5.SHOW);\n\n      if (this._config.focus) {\n        this._enforceFocus();\n      }\n\n      var shownEvent = $.Event(Event$5.SHOWN, {\n        relatedTarget: relatedTarget\n      });\n\n      var transitionComplete = function transitionComplete() {\n        if (_this3._config.focus) {\n          _this3._element.focus();\n        }\n\n        _this3._isTransitioning = false;\n        $(_this3._element).trigger(shownEvent);\n      };\n\n      if (transition) {\n        var transitionDuration = Util.getTransitionDurationFromElement(this._dialog);\n        $(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration);\n      } else {\n        transitionComplete();\n      }\n    };\n\n    _proto._enforceFocus = function _enforceFocus() {\n      var _this4 = this;\n\n      $(document).off(Event$5.FOCUSIN) // Guard against infinite focus loop\n      .on(Event$5.FOCUSIN, function (event) {\n        if (document !== event.target && _this4._element !== event.target && $(_this4._element).has(event.target).length === 0) {\n          _this4._element.focus();\n        }\n      });\n    };\n\n    _proto._setEscapeEvent = function _setEscapeEvent() {\n      var _this5 = this;\n\n      if (this._isShown && this._config.keyboard) {\n        $(this._element).on(Event$5.KEYDOWN_DISMISS, function (event) {\n          if (event.which === ESCAPE_KEYCODE$1) {\n            event.preventDefault();\n\n            _this5.hide();\n          }\n        });\n      } else if (!this._isShown) {\n        $(this._element).off(Event$5.KEYDOWN_DISMISS);\n      }\n    };\n\n    _proto._setResizeEvent = function _setResizeEvent() {\n      var _this6 = this;\n\n      if (this._isShown) {\n        $(window).on(Event$5.RESIZE, function (event) {\n          return _this6.handleUpdate(event);\n        });\n      } else {\n        $(window).off(Event$5.RESIZE);\n      }\n    };\n\n    _proto._hideModal = function _hideModal() {\n      var _this7 = this;\n\n      this._element.style.display = 'none';\n\n      this._element.setAttribute('aria-hidden', true);\n\n      this._element.removeAttribute('aria-modal');\n\n      this._isTransitioning = false;\n\n      this._showBackdrop(function () {\n        $(document.body).removeClass(ClassName$5.OPEN);\n\n        _this7._resetAdjustments();\n\n        _this7._resetScrollbar();\n\n        $(_this7._element).trigger(Event$5.HIDDEN);\n      });\n    };\n\n    _proto._removeBackdrop = function _removeBackdrop() {\n      if (this._backdrop) {\n        $(this._backdrop).remove();\n        this._backdrop = null;\n      }\n    };\n\n    _proto._showBackdrop = function _showBackdrop(callback) {\n      var _this8 = this;\n\n      var animate = $(this._element).hasClass(ClassName$5.FADE) ? ClassName$5.FADE : '';\n\n      if (this._isShown && this._config.backdrop) {\n        this._backdrop = document.createElement('div');\n        this._backdrop.className = ClassName$5.BACKDROP;\n\n        if (animate) {\n          this._backdrop.classList.add(animate);\n        }\n\n        $(this._backdrop).appendTo(document.body);\n        $(this._element).on(Event$5.CLICK_DISMISS, function (event) {\n          if (_this8._ignoreBackdropClick) {\n            _this8._ignoreBackdropClick = false;\n            return;\n          }\n\n          if (event.target !== event.currentTarget) {\n            return;\n          }\n\n          if (_this8._config.backdrop === 'static') {\n            _this8._element.focus();\n          } else {\n            _this8.hide();\n          }\n        });\n\n        if (animate) {\n          Util.reflow(this._backdrop);\n        }\n\n        $(this._backdrop).addClass(ClassName$5.SHOW);\n\n        if (!callback) {\n          return;\n        }\n\n        if (!animate) {\n          callback();\n          return;\n        }\n\n        var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n        $(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration);\n      } else if (!this._isShown && this._backdrop) {\n        $(this._backdrop).removeClass(ClassName$5.SHOW);\n\n        var callbackRemove = function callbackRemove() {\n          _this8._removeBackdrop();\n\n          if (callback) {\n            callback();\n          }\n        };\n\n        if ($(this._element).hasClass(ClassName$5.FADE)) {\n          var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n\n          $(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration);\n        } else {\n          callbackRemove();\n        }\n      } else if (callback) {\n        callback();\n      }\n    } // ----------------------------------------------------------------------\n    // the following methods are used to handle overflowing modals\n    // todo (fat): these should probably be refactored out of modal.js\n    // ----------------------------------------------------------------------\n    ;\n\n    _proto._adjustDialog = function _adjustDialog() {\n      var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n\n      if (!this._isBodyOverflowing && isModalOverflowing) {\n        this._element.style.paddingLeft = this._scrollbarWidth + \"px\";\n      }\n\n      if (this._isBodyOverflowing && !isModalOverflowing) {\n        this._element.style.paddingRight = this._scrollbarWidth + \"px\";\n      }\n    };\n\n    _proto._resetAdjustments = function _resetAdjustments() {\n      this._element.style.paddingLeft = '';\n      this._element.style.paddingRight = '';\n    };\n\n    _proto._checkScrollbar = function _checkScrollbar() {\n      var rect = document.body.getBoundingClientRect();\n      this._isBodyOverflowing = rect.left + rect.right < window.innerWidth;\n      this._scrollbarWidth = this._getScrollbarWidth();\n    };\n\n    _proto._setScrollbar = function _setScrollbar() {\n      var _this9 = this;\n\n      if (this._isBodyOverflowing) {\n        // Note: DOMNode.style.paddingRight returns the actual value or '' if not set\n        //   while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set\n        var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));\n        var stickyContent = [].slice.call(document.querySelectorAll(Selector$5.STICKY_CONTENT)); // Adjust fixed content padding\n\n        $(fixedContent).each(function (index, element) {\n          var actualPadding = element.style.paddingRight;\n          var calculatedPadding = $(element).css('padding-right');\n          $(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + \"px\");\n        }); // Adjust sticky content margin\n\n        $(stickyContent).each(function (index, element) {\n          var actualMargin = element.style.marginRight;\n          var calculatedMargin = $(element).css('margin-right');\n          $(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + \"px\");\n        }); // Adjust body padding\n\n        var actualPadding = document.body.style.paddingRight;\n        var calculatedPadding = $(document.body).css('padding-right');\n        $(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + \"px\");\n      }\n\n      $(document.body).addClass(ClassName$5.OPEN);\n    };\n\n    _proto._resetScrollbar = function _resetScrollbar() {\n      // Restore fixed content padding\n      var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));\n      $(fixedContent).each(function (index, element) {\n        var padding = $(element).data('padding-right');\n        $(element).removeData('padding-right');\n        element.style.paddingRight = padding ? padding : '';\n      }); // Restore sticky content\n\n      var elements = [].slice.call(document.querySelectorAll(\"\" + Selector$5.STICKY_CONTENT));\n      $(elements).each(function (index, element) {\n        var margin = $(element).data('margin-right');\n\n        if (typeof margin !== 'undefined') {\n          $(element).css('margin-right', margin).removeData('margin-right');\n        }\n      }); // Restore body padding\n\n      var padding = $(document.body).data('padding-right');\n      $(document.body).removeData('padding-right');\n      document.body.style.paddingRight = padding ? padding : '';\n    };\n\n    _proto._getScrollbarWidth = function _getScrollbarWidth() {\n      // thx d.walsh\n      var scrollDiv = document.createElement('div');\n      scrollDiv.className = ClassName$5.SCROLLBAR_MEASURER;\n      document.body.appendChild(scrollDiv);\n      var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;\n      document.body.removeChild(scrollDiv);\n      return scrollbarWidth;\n    } // Static\n    ;\n\n    Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$5);\n\n        var _config = _objectSpread({}, Default$3, $(this).data(), typeof config === 'object' && config ? config : {});\n\n        if (!data) {\n          data = new Modal(this, _config);\n          $(this).data(DATA_KEY$5, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config](relatedTarget);\n        } else if (_config.show) {\n          data.show(relatedTarget);\n        }\n      });\n    };\n\n    _createClass(Modal, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$5;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$3;\n      }\n    }]);\n\n    return Modal;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$5.CLICK_DATA_API, Selector$5.DATA_TOGGLE, function (event) {\n    var _this10 = this;\n\n    var target;\n    var selector = Util.getSelectorFromElement(this);\n\n    if (selector) {\n      target = document.querySelector(selector);\n    }\n\n    var config = $(target).data(DATA_KEY$5) ? 'toggle' : _objectSpread({}, $(target).data(), $(this).data());\n\n    if (this.tagName === 'A' || this.tagName === 'AREA') {\n      event.preventDefault();\n    }\n\n    var $target = $(target).one(Event$5.SHOW, function (showEvent) {\n      if (showEvent.isDefaultPrevented()) {\n        // Only register focus restorer if modal will actually get shown\n        return;\n      }\n\n      $target.one(Event$5.HIDDEN, function () {\n        if ($(_this10).is(':visible')) {\n          _this10.focus();\n        }\n      });\n    });\n\n    Modal._jQueryInterface.call($(target), config, this);\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$5] = Modal._jQueryInterface;\n  $.fn[NAME$5].Constructor = Modal;\n\n  $.fn[NAME$5].noConflict = function () {\n    $.fn[NAME$5] = JQUERY_NO_CONFLICT$5;\n    return Modal._jQueryInterface;\n  };\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.3.1): tools/sanitizer.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n  var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href'];\n  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\n  var DefaultWhitelist = {\n    // Global attributes allowed on any supplied element below.\n    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n    a: ['target', 'href', 'title', 'rel'],\n    area: [],\n    b: [],\n    br: [],\n    col: [],\n    code: [],\n    div: [],\n    em: [],\n    hr: [],\n    h1: [],\n    h2: [],\n    h3: [],\n    h4: [],\n    h5: [],\n    h6: [],\n    i: [],\n    img: ['src', 'alt', 'title', 'width', 'height'],\n    li: [],\n    ol: [],\n    p: [],\n    pre: [],\n    s: [],\n    small: [],\n    span: [],\n    sub: [],\n    sup: [],\n    strong: [],\n    u: [],\n    ul: []\n    /**\n     * A pattern that recognizes a commonly useful subset of URLs that are safe.\n     *\n     * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\n     */\n\n  };\n  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;\n  /**\n   * A pattern that matches safe data URLs. Only matches image, video and audio types.\n   *\n   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\n   */\n\n  var DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;\n\n  function allowedAttribute(attr, allowedAttributeList) {\n    var attrName = attr.nodeName.toLowerCase();\n\n    if (allowedAttributeList.indexOf(attrName) !== -1) {\n      if (uriAttrs.indexOf(attrName) !== -1) {\n        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN));\n      }\n\n      return true;\n    }\n\n    var regExp = allowedAttributeList.filter(function (attrRegex) {\n      return attrRegex instanceof RegExp;\n    }); // Check if a regular expression validates the attribute.\n\n    for (var i = 0, l = regExp.length; i < l; i++) {\n      if (attrName.match(regExp[i])) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {\n    if (unsafeHtml.length === 0) {\n      return unsafeHtml;\n    }\n\n    if (sanitizeFn && typeof sanitizeFn === 'function') {\n      return sanitizeFn(unsafeHtml);\n    }\n\n    var domParser = new window.DOMParser();\n    var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');\n    var whitelistKeys = Object.keys(whiteList);\n    var elements = [].slice.call(createdDocument.body.querySelectorAll('*'));\n\n    var _loop = function _loop(i, len) {\n      var el = elements[i];\n      var elName = el.nodeName.toLowerCase();\n\n      if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {\n        el.parentNode.removeChild(el);\n        return \"continue\";\n      }\n\n      var attributeList = [].slice.call(el.attributes);\n      var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);\n      attributeList.forEach(function (attr) {\n        if (!allowedAttribute(attr, whitelistedAttributes)) {\n          el.removeAttribute(attr.nodeName);\n        }\n      });\n    };\n\n    for (var i = 0, len = elements.length; i < len; i++) {\n      var _ret = _loop(i, len);\n\n      if (_ret === \"continue\") continue;\n    }\n\n    return createdDocument.body.innerHTML;\n  }\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$6 = 'tooltip';\n  var VERSION$6 = '4.3.1';\n  var DATA_KEY$6 = 'bs.tooltip';\n  var EVENT_KEY$6 = \".\" + DATA_KEY$6;\n  var JQUERY_NO_CONFLICT$6 = $.fn[NAME$6];\n  var CLASS_PREFIX = 'bs-tooltip';\n  var BSCLS_PREFIX_REGEX = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX + \"\\\\S+\", 'g');\n  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];\n  var DefaultType$4 = {\n    animation: 'boolean',\n    template: 'string',\n    title: '(string|element|function)',\n    trigger: 'string',\n    delay: '(number|object)',\n    html: 'boolean',\n    selector: '(string|boolean)',\n    placement: '(string|function)',\n    offset: '(number|string|function)',\n    container: '(string|element|boolean)',\n    fallbackPlacement: '(string|array)',\n    boundary: '(string|element)',\n    sanitize: 'boolean',\n    sanitizeFn: '(null|function)',\n    whiteList: 'object'\n  };\n  var AttachmentMap$1 = {\n    AUTO: 'auto',\n    TOP: 'top',\n    RIGHT: 'right',\n    BOTTOM: 'bottom',\n    LEFT: 'left'\n  };\n  var Default$4 = {\n    animation: true,\n    template: '<div class=\"tooltip\" role=\"tooltip\">' + '<div class=\"arrow\"></div>' + '<div class=\"tooltip-inner\"></div></div>',\n    trigger: 'hover focus',\n    title: '',\n    delay: 0,\n    html: false,\n    selector: false,\n    placement: 'top',\n    offset: 0,\n    container: false,\n    fallbackPlacement: 'flip',\n    boundary: 'scrollParent',\n    sanitize: true,\n    sanitizeFn: null,\n    whiteList: DefaultWhitelist\n  };\n  var HoverState = {\n    SHOW: 'show',\n    OUT: 'out'\n  };\n  var Event$6 = {\n    HIDE: \"hide\" + EVENT_KEY$6,\n    HIDDEN: \"hidden\" + EVENT_KEY$6,\n    SHOW: \"show\" + EVENT_KEY$6,\n    SHOWN: \"shown\" + EVENT_KEY$6,\n    INSERTED: \"inserted\" + EVENT_KEY$6,\n    CLICK: \"click\" + EVENT_KEY$6,\n    FOCUSIN: \"focusin\" + EVENT_KEY$6,\n    FOCUSOUT: \"focusout\" + EVENT_KEY$6,\n    MOUSEENTER: \"mouseenter\" + EVENT_KEY$6,\n    MOUSELEAVE: \"mouseleave\" + EVENT_KEY$6\n  };\n  var ClassName$6 = {\n    FADE: 'fade',\n    SHOW: 'show'\n  };\n  var Selector$6 = {\n    TOOLTIP: '.tooltip',\n    TOOLTIP_INNER: '.tooltip-inner',\n    ARROW: '.arrow'\n  };\n  var Trigger = {\n    HOVER: 'hover',\n    FOCUS: 'focus',\n    CLICK: 'click',\n    MANUAL: 'manual'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Tooltip =\n  /*#__PURE__*/\n  function () {\n    function Tooltip(element, config) {\n      /**\n       * Check for Popper dependency\n       * Popper - https://popper.js.org\n       */\n      if (typeof Popper === 'undefined') {\n        throw new TypeError('Bootstrap\\'s tooltips require Popper.js (https://popper.js.org/)');\n      } // private\n\n\n      this._isEnabled = true;\n      this._timeout = 0;\n      this._hoverState = '';\n      this._activeTrigger = {};\n      this._popper = null; // Protected\n\n      this.element = element;\n      this.config = this._getConfig(config);\n      this.tip = null;\n\n      this._setListeners();\n    } // Getters\n\n\n    var _proto = Tooltip.prototype;\n\n    // Public\n    _proto.enable = function enable() {\n      this._isEnabled = true;\n    };\n\n    _proto.disable = function disable() {\n      this._isEnabled = false;\n    };\n\n    _proto.toggleEnabled = function toggleEnabled() {\n      this._isEnabled = !this._isEnabled;\n    };\n\n    _proto.toggle = function toggle(event) {\n      if (!this._isEnabled) {\n        return;\n      }\n\n      if (event) {\n        var dataKey = this.constructor.DATA_KEY;\n        var context = $(event.currentTarget).data(dataKey);\n\n        if (!context) {\n          context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n          $(event.currentTarget).data(dataKey, context);\n        }\n\n        context._activeTrigger.click = !context._activeTrigger.click;\n\n        if (context._isWithActiveTrigger()) {\n          context._enter(null, context);\n        } else {\n          context._leave(null, context);\n        }\n      } else {\n        if ($(this.getTipElement()).hasClass(ClassName$6.SHOW)) {\n          this._leave(null, this);\n\n          return;\n        }\n\n        this._enter(null, this);\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      clearTimeout(this._timeout);\n      $.removeData(this.element, this.constructor.DATA_KEY);\n      $(this.element).off(this.constructor.EVENT_KEY);\n      $(this.element).closest('.modal').off('hide.bs.modal');\n\n      if (this.tip) {\n        $(this.tip).remove();\n      }\n\n      this._isEnabled = null;\n      this._timeout = null;\n      this._hoverState = null;\n      this._activeTrigger = null;\n\n      if (this._popper !== null) {\n        this._popper.destroy();\n      }\n\n      this._popper = null;\n      this.element = null;\n      this.config = null;\n      this.tip = null;\n    };\n\n    _proto.show = function show() {\n      var _this = this;\n\n      if ($(this.element).css('display') === 'none') {\n        throw new Error('Please use show on visible elements');\n      }\n\n      var showEvent = $.Event(this.constructor.Event.SHOW);\n\n      if (this.isWithContent() && this._isEnabled) {\n        $(this.element).trigger(showEvent);\n        var shadowRoot = Util.findShadowRoot(this.element);\n        var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element);\n\n        if (showEvent.isDefaultPrevented() || !isInTheDom) {\n          return;\n        }\n\n        var tip = this.getTipElement();\n        var tipId = Util.getUID(this.constructor.NAME);\n        tip.setAttribute('id', tipId);\n        this.element.setAttribute('aria-describedby', tipId);\n        this.setContent();\n\n        if (this.config.animation) {\n          $(tip).addClass(ClassName$6.FADE);\n        }\n\n        var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;\n\n        var attachment = this._getAttachment(placement);\n\n        this.addAttachmentClass(attachment);\n\n        var container = this._getContainer();\n\n        $(tip).data(this.constructor.DATA_KEY, this);\n\n        if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {\n          $(tip).appendTo(container);\n        }\n\n        $(this.element).trigger(this.constructor.Event.INSERTED);\n        this._popper = new Popper(this.element, tip, {\n          placement: attachment,\n          modifiers: {\n            offset: this._getOffset(),\n            flip: {\n              behavior: this.config.fallbackPlacement\n            },\n            arrow: {\n              element: Selector$6.ARROW\n            },\n            preventOverflow: {\n              boundariesElement: this.config.boundary\n            }\n          },\n          onCreate: function onCreate(data) {\n            if (data.originalPlacement !== data.placement) {\n              _this._handlePopperPlacementChange(data);\n            }\n          },\n          onUpdate: function onUpdate(data) {\n            return _this._handlePopperPlacementChange(data);\n          }\n        });\n        $(tip).addClass(ClassName$6.SHOW); // If this is a touch-enabled device we add extra\n        // empty mouseover listeners to the body's immediate children;\n        // only needed because of broken event delegation on iOS\n        // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n        if ('ontouchstart' in document.documentElement) {\n          $(document.body).children().on('mouseover', null, $.noop);\n        }\n\n        var complete = function complete() {\n          if (_this.config.animation) {\n            _this._fixTransition();\n          }\n\n          var prevHoverState = _this._hoverState;\n          _this._hoverState = null;\n          $(_this.element).trigger(_this.constructor.Event.SHOWN);\n\n          if (prevHoverState === HoverState.OUT) {\n            _this._leave(null, _this);\n          }\n        };\n\n        if ($(this.tip).hasClass(ClassName$6.FADE)) {\n          var transitionDuration = Util.getTransitionDurationFromElement(this.tip);\n          $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n        } else {\n          complete();\n        }\n      }\n    };\n\n    _proto.hide = function hide(callback) {\n      var _this2 = this;\n\n      var tip = this.getTipElement();\n      var hideEvent = $.Event(this.constructor.Event.HIDE);\n\n      var complete = function complete() {\n        if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {\n          tip.parentNode.removeChild(tip);\n        }\n\n        _this2._cleanTipClass();\n\n        _this2.element.removeAttribute('aria-describedby');\n\n        $(_this2.element).trigger(_this2.constructor.Event.HIDDEN);\n\n        if (_this2._popper !== null) {\n          _this2._popper.destroy();\n        }\n\n        if (callback) {\n          callback();\n        }\n      };\n\n      $(this.element).trigger(hideEvent);\n\n      if (hideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      $(tip).removeClass(ClassName$6.SHOW); // If this is a touch-enabled device we remove the extra\n      // empty mouseover listeners we added for iOS support\n\n      if ('ontouchstart' in document.documentElement) {\n        $(document.body).children().off('mouseover', null, $.noop);\n      }\n\n      this._activeTrigger[Trigger.CLICK] = false;\n      this._activeTrigger[Trigger.FOCUS] = false;\n      this._activeTrigger[Trigger.HOVER] = false;\n\n      if ($(this.tip).hasClass(ClassName$6.FADE)) {\n        var transitionDuration = Util.getTransitionDurationFromElement(tip);\n        $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      } else {\n        complete();\n      }\n\n      this._hoverState = '';\n    };\n\n    _proto.update = function update() {\n      if (this._popper !== null) {\n        this._popper.scheduleUpdate();\n      }\n    } // Protected\n    ;\n\n    _proto.isWithContent = function isWithContent() {\n      return Boolean(this.getTitle());\n    };\n\n    _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n      $(this.getTipElement()).addClass(CLASS_PREFIX + \"-\" + attachment);\n    };\n\n    _proto.getTipElement = function getTipElement() {\n      this.tip = this.tip || $(this.config.template)[0];\n      return this.tip;\n    };\n\n    _proto.setContent = function setContent() {\n      var tip = this.getTipElement();\n      this.setElementContent($(tip.querySelectorAll(Selector$6.TOOLTIP_INNER)), this.getTitle());\n      $(tip).removeClass(ClassName$6.FADE + \" \" + ClassName$6.SHOW);\n    };\n\n    _proto.setElementContent = function setElementContent($element, content) {\n      if (typeof content === 'object' && (content.nodeType || content.jquery)) {\n        // Content is a DOM node or a jQuery\n        if (this.config.html) {\n          if (!$(content).parent().is($element)) {\n            $element.empty().append(content);\n          }\n        } else {\n          $element.text($(content).text());\n        }\n\n        return;\n      }\n\n      if (this.config.html) {\n        if (this.config.sanitize) {\n          content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn);\n        }\n\n        $element.html(content);\n      } else {\n        $element.text(content);\n      }\n    };\n\n    _proto.getTitle = function getTitle() {\n      var title = this.element.getAttribute('data-original-title');\n\n      if (!title) {\n        title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;\n      }\n\n      return title;\n    } // Private\n    ;\n\n    _proto._getOffset = function _getOffset() {\n      var _this3 = this;\n\n      var offset = {};\n\n      if (typeof this.config.offset === 'function') {\n        offset.fn = function (data) {\n          data.offsets = _objectSpread({}, data.offsets, _this3.config.offset(data.offsets, _this3.element) || {});\n          return data;\n        };\n      } else {\n        offset.offset = this.config.offset;\n      }\n\n      return offset;\n    };\n\n    _proto._getContainer = function _getContainer() {\n      if (this.config.container === false) {\n        return document.body;\n      }\n\n      if (Util.isElement(this.config.container)) {\n        return $(this.config.container);\n      }\n\n      return $(document).find(this.config.container);\n    };\n\n    _proto._getAttachment = function _getAttachment(placement) {\n      return AttachmentMap$1[placement.toUpperCase()];\n    };\n\n    _proto._setListeners = function _setListeners() {\n      var _this4 = this;\n\n      var triggers = this.config.trigger.split(' ');\n      triggers.forEach(function (trigger) {\n        if (trigger === 'click') {\n          $(_this4.element).on(_this4.constructor.Event.CLICK, _this4.config.selector, function (event) {\n            return _this4.toggle(event);\n          });\n        } else if (trigger !== Trigger.MANUAL) {\n          var eventIn = trigger === Trigger.HOVER ? _this4.constructor.Event.MOUSEENTER : _this4.constructor.Event.FOCUSIN;\n          var eventOut = trigger === Trigger.HOVER ? _this4.constructor.Event.MOUSELEAVE : _this4.constructor.Event.FOCUSOUT;\n          $(_this4.element).on(eventIn, _this4.config.selector, function (event) {\n            return _this4._enter(event);\n          }).on(eventOut, _this4.config.selector, function (event) {\n            return _this4._leave(event);\n          });\n        }\n      });\n      $(this.element).closest('.modal').on('hide.bs.modal', function () {\n        if (_this4.element) {\n          _this4.hide();\n        }\n      });\n\n      if (this.config.selector) {\n        this.config = _objectSpread({}, this.config, {\n          trigger: 'manual',\n          selector: ''\n        });\n      } else {\n        this._fixTitle();\n      }\n    };\n\n    _proto._fixTitle = function _fixTitle() {\n      var titleType = typeof this.element.getAttribute('data-original-title');\n\n      if (this.element.getAttribute('title') || titleType !== 'string') {\n        this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');\n        this.element.setAttribute('title', '');\n      }\n    };\n\n    _proto._enter = function _enter(event, context) {\n      var dataKey = this.constructor.DATA_KEY;\n      context = context || $(event.currentTarget).data(dataKey);\n\n      if (!context) {\n        context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n        $(event.currentTarget).data(dataKey, context);\n      }\n\n      if (event) {\n        context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;\n      }\n\n      if ($(context.getTipElement()).hasClass(ClassName$6.SHOW) || context._hoverState === HoverState.SHOW) {\n        context._hoverState = HoverState.SHOW;\n        return;\n      }\n\n      clearTimeout(context._timeout);\n      context._hoverState = HoverState.SHOW;\n\n      if (!context.config.delay || !context.config.delay.show) {\n        context.show();\n        return;\n      }\n\n      context._timeout = setTimeout(function () {\n        if (context._hoverState === HoverState.SHOW) {\n          context.show();\n        }\n      }, context.config.delay.show);\n    };\n\n    _proto._leave = function _leave(event, context) {\n      var dataKey = this.constructor.DATA_KEY;\n      context = context || $(event.currentTarget).data(dataKey);\n\n      if (!context) {\n        context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n        $(event.currentTarget).data(dataKey, context);\n      }\n\n      if (event) {\n        context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;\n      }\n\n      if (context._isWithActiveTrigger()) {\n        return;\n      }\n\n      clearTimeout(context._timeout);\n      context._hoverState = HoverState.OUT;\n\n      if (!context.config.delay || !context.config.delay.hide) {\n        context.hide();\n        return;\n      }\n\n      context._timeout = setTimeout(function () {\n        if (context._hoverState === HoverState.OUT) {\n          context.hide();\n        }\n      }, context.config.delay.hide);\n    };\n\n    _proto._isWithActiveTrigger = function _isWithActiveTrigger() {\n      for (var trigger in this._activeTrigger) {\n        if (this._activeTrigger[trigger]) {\n          return true;\n        }\n      }\n\n      return false;\n    };\n\n    _proto._getConfig = function _getConfig(config) {\n      var dataAttributes = $(this.element).data();\n      Object.keys(dataAttributes).forEach(function (dataAttr) {\n        if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {\n          delete dataAttributes[dataAttr];\n        }\n      });\n      config = _objectSpread({}, this.constructor.Default, dataAttributes, typeof config === 'object' && config ? config : {});\n\n      if (typeof config.delay === 'number') {\n        config.delay = {\n          show: config.delay,\n          hide: config.delay\n        };\n      }\n\n      if (typeof config.title === 'number') {\n        config.title = config.title.toString();\n      }\n\n      if (typeof config.content === 'number') {\n        config.content = config.content.toString();\n      }\n\n      Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType);\n\n      if (config.sanitize) {\n        config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn);\n      }\n\n      return config;\n    };\n\n    _proto._getDelegateConfig = function _getDelegateConfig() {\n      var config = {};\n\n      if (this.config) {\n        for (var key in this.config) {\n          if (this.constructor.Default[key] !== this.config[key]) {\n            config[key] = this.config[key];\n          }\n        }\n      }\n\n      return config;\n    };\n\n    _proto._cleanTipClass = function _cleanTipClass() {\n      var $tip = $(this.getTipElement());\n      var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);\n\n      if (tabClass !== null && tabClass.length) {\n        $tip.removeClass(tabClass.join(''));\n      }\n    };\n\n    _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {\n      var popperInstance = popperData.instance;\n      this.tip = popperInstance.popper;\n\n      this._cleanTipClass();\n\n      this.addAttachmentClass(this._getAttachment(popperData.placement));\n    };\n\n    _proto._fixTransition = function _fixTransition() {\n      var tip = this.getTipElement();\n      var initConfigAnimation = this.config.animation;\n\n      if (tip.getAttribute('x-placement') !== null) {\n        return;\n      }\n\n      $(tip).removeClass(ClassName$6.FADE);\n      this.config.animation = false;\n      this.hide();\n      this.show();\n      this.config.animation = initConfigAnimation;\n    } // Static\n    ;\n\n    Tooltip._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$6);\n\n        var _config = typeof config === 'object' && config;\n\n        if (!data && /dispose|hide/.test(config)) {\n          return;\n        }\n\n        if (!data) {\n          data = new Tooltip(this, _config);\n          $(this).data(DATA_KEY$6, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Tooltip, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$6;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$4;\n      }\n    }, {\n      key: \"NAME\",\n      get: function get() {\n        return NAME$6;\n      }\n    }, {\n      key: \"DATA_KEY\",\n      get: function get() {\n        return DATA_KEY$6;\n      }\n    }, {\n      key: \"Event\",\n      get: function get() {\n        return Event$6;\n      }\n    }, {\n      key: \"EVENT_KEY\",\n      get: function get() {\n        return EVENT_KEY$6;\n      }\n    }, {\n      key: \"DefaultType\",\n      get: function get() {\n        return DefaultType$4;\n      }\n    }]);\n\n    return Tooltip;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n\n  $.fn[NAME$6] = Tooltip._jQueryInterface;\n  $.fn[NAME$6].Constructor = Tooltip;\n\n  $.fn[NAME$6].noConflict = function () {\n    $.fn[NAME$6] = JQUERY_NO_CONFLICT$6;\n    return Tooltip._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$7 = 'popover';\n  var VERSION$7 = '4.3.1';\n  var DATA_KEY$7 = 'bs.popover';\n  var EVENT_KEY$7 = \".\" + DATA_KEY$7;\n  var JQUERY_NO_CONFLICT$7 = $.fn[NAME$7];\n  var CLASS_PREFIX$1 = 'bs-popover';\n  var BSCLS_PREFIX_REGEX$1 = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX$1 + \"\\\\S+\", 'g');\n\n  var Default$5 = _objectSpread({}, Tooltip.Default, {\n    placement: 'right',\n    trigger: 'click',\n    content: '',\n    template: '<div class=\"popover\" role=\"tooltip\">' + '<div class=\"arrow\"></div>' + '<h3 class=\"popover-header\"></h3>' + '<div class=\"popover-body\"></div></div>'\n  });\n\n  var DefaultType$5 = _objectSpread({}, Tooltip.DefaultType, {\n    content: '(string|element|function)'\n  });\n\n  var ClassName$7 = {\n    FADE: 'fade',\n    SHOW: 'show'\n  };\n  var Selector$7 = {\n    TITLE: '.popover-header',\n    CONTENT: '.popover-body'\n  };\n  var Event$7 = {\n    HIDE: \"hide\" + EVENT_KEY$7,\n    HIDDEN: \"hidden\" + EVENT_KEY$7,\n    SHOW: \"show\" + EVENT_KEY$7,\n    SHOWN: \"shown\" + EVENT_KEY$7,\n    INSERTED: \"inserted\" + EVENT_KEY$7,\n    CLICK: \"click\" + EVENT_KEY$7,\n    FOCUSIN: \"focusin\" + EVENT_KEY$7,\n    FOCUSOUT: \"focusout\" + EVENT_KEY$7,\n    MOUSEENTER: \"mouseenter\" + EVENT_KEY$7,\n    MOUSELEAVE: \"mouseleave\" + EVENT_KEY$7\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Popover =\n  /*#__PURE__*/\n  function (_Tooltip) {\n    _inheritsLoose(Popover, _Tooltip);\n\n    function Popover() {\n      return _Tooltip.apply(this, arguments) || this;\n    }\n\n    var _proto = Popover.prototype;\n\n    // Overrides\n    _proto.isWithContent = function isWithContent() {\n      return this.getTitle() || this._getContent();\n    };\n\n    _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n      $(this.getTipElement()).addClass(CLASS_PREFIX$1 + \"-\" + attachment);\n    };\n\n    _proto.getTipElement = function getTipElement() {\n      this.tip = this.tip || $(this.config.template)[0];\n      return this.tip;\n    };\n\n    _proto.setContent = function setContent() {\n      var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events\n\n      this.setElementContent($tip.find(Selector$7.TITLE), this.getTitle());\n\n      var content = this._getContent();\n\n      if (typeof content === 'function') {\n        content = content.call(this.element);\n      }\n\n      this.setElementContent($tip.find(Selector$7.CONTENT), content);\n      $tip.removeClass(ClassName$7.FADE + \" \" + ClassName$7.SHOW);\n    } // Private\n    ;\n\n    _proto._getContent = function _getContent() {\n      return this.element.getAttribute('data-content') || this.config.content;\n    };\n\n    _proto._cleanTipClass = function _cleanTipClass() {\n      var $tip = $(this.getTipElement());\n      var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1);\n\n      if (tabClass !== null && tabClass.length > 0) {\n        $tip.removeClass(tabClass.join(''));\n      }\n    } // Static\n    ;\n\n    Popover._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$7);\n\n        var _config = typeof config === 'object' ? config : null;\n\n        if (!data && /dispose|hide/.test(config)) {\n          return;\n        }\n\n        if (!data) {\n          data = new Popover(this, _config);\n          $(this).data(DATA_KEY$7, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Popover, null, [{\n      key: \"VERSION\",\n      // Getters\n      get: function get() {\n        return VERSION$7;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$5;\n      }\n    }, {\n      key: \"NAME\",\n      get: function get() {\n        return NAME$7;\n      }\n    }, {\n      key: \"DATA_KEY\",\n      get: function get() {\n        return DATA_KEY$7;\n      }\n    }, {\n      key: \"Event\",\n      get: function get() {\n        return Event$7;\n      }\n    }, {\n      key: \"EVENT_KEY\",\n      get: function get() {\n        return EVENT_KEY$7;\n      }\n    }, {\n      key: \"DefaultType\",\n      get: function get() {\n        return DefaultType$5;\n      }\n    }]);\n\n    return Popover;\n  }(Tooltip);\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n\n  $.fn[NAME$7] = Popover._jQueryInterface;\n  $.fn[NAME$7].Constructor = Popover;\n\n  $.fn[NAME$7].noConflict = function () {\n    $.fn[NAME$7] = JQUERY_NO_CONFLICT$7;\n    return Popover._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$8 = 'scrollspy';\n  var VERSION$8 = '4.3.1';\n  var DATA_KEY$8 = 'bs.scrollspy';\n  var EVENT_KEY$8 = \".\" + DATA_KEY$8;\n  var DATA_API_KEY$6 = '.data-api';\n  var JQUERY_NO_CONFLICT$8 = $.fn[NAME$8];\n  var Default$6 = {\n    offset: 10,\n    method: 'auto',\n    target: ''\n  };\n  var DefaultType$6 = {\n    offset: 'number',\n    method: 'string',\n    target: '(string|element)'\n  };\n  var Event$8 = {\n    ACTIVATE: \"activate\" + EVENT_KEY$8,\n    SCROLL: \"scroll\" + EVENT_KEY$8,\n    LOAD_DATA_API: \"load\" + EVENT_KEY$8 + DATA_API_KEY$6\n  };\n  var ClassName$8 = {\n    DROPDOWN_ITEM: 'dropdown-item',\n    DROPDOWN_MENU: 'dropdown-menu',\n    ACTIVE: 'active'\n  };\n  var Selector$8 = {\n    DATA_SPY: '[data-spy=\"scroll\"]',\n    ACTIVE: '.active',\n    NAV_LIST_GROUP: '.nav, .list-group',\n    NAV_LINKS: '.nav-link',\n    NAV_ITEMS: '.nav-item',\n    LIST_ITEMS: '.list-group-item',\n    DROPDOWN: '.dropdown',\n    DROPDOWN_ITEMS: '.dropdown-item',\n    DROPDOWN_TOGGLE: '.dropdown-toggle'\n  };\n  var OffsetMethod = {\n    OFFSET: 'offset',\n    POSITION: 'position'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var ScrollSpy =\n  /*#__PURE__*/\n  function () {\n    function ScrollSpy(element, config) {\n      var _this = this;\n\n      this._element = element;\n      this._scrollElement = element.tagName === 'BODY' ? window : element;\n      this._config = this._getConfig(config);\n      this._selector = this._config.target + \" \" + Selector$8.NAV_LINKS + \",\" + (this._config.target + \" \" + Selector$8.LIST_ITEMS + \",\") + (this._config.target + \" \" + Selector$8.DROPDOWN_ITEMS);\n      this._offsets = [];\n      this._targets = [];\n      this._activeTarget = null;\n      this._scrollHeight = 0;\n      $(this._scrollElement).on(Event$8.SCROLL, function (event) {\n        return _this._process(event);\n      });\n      this.refresh();\n\n      this._process();\n    } // Getters\n\n\n    var _proto = ScrollSpy.prototype;\n\n    // Public\n    _proto.refresh = function refresh() {\n      var _this2 = this;\n\n      var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;\n      var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;\n      var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;\n      this._offsets = [];\n      this._targets = [];\n      this._scrollHeight = this._getScrollHeight();\n      var targets = [].slice.call(document.querySelectorAll(this._selector));\n      targets.map(function (element) {\n        var target;\n        var targetSelector = Util.getSelectorFromElement(element);\n\n        if (targetSelector) {\n          target = document.querySelector(targetSelector);\n        }\n\n        if (target) {\n          var targetBCR = target.getBoundingClientRect();\n\n          if (targetBCR.width || targetBCR.height) {\n            // TODO (fat): remove sketch reliance on jQuery position/offset\n            return [$(target)[offsetMethod]().top + offsetBase, targetSelector];\n          }\n        }\n\n        return null;\n      }).filter(function (item) {\n        return item;\n      }).sort(function (a, b) {\n        return a[0] - b[0];\n      }).forEach(function (item) {\n        _this2._offsets.push(item[0]);\n\n        _this2._targets.push(item[1]);\n      });\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$8);\n      $(this._scrollElement).off(EVENT_KEY$8);\n      this._element = null;\n      this._scrollElement = null;\n      this._config = null;\n      this._selector = null;\n      this._offsets = null;\n      this._targets = null;\n      this._activeTarget = null;\n      this._scrollHeight = null;\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default$6, typeof config === 'object' && config ? config : {});\n\n      if (typeof config.target !== 'string') {\n        var id = $(config.target).attr('id');\n\n        if (!id) {\n          id = Util.getUID(NAME$8);\n          $(config.target).attr('id', id);\n        }\n\n        config.target = \"#\" + id;\n      }\n\n      Util.typeCheckConfig(NAME$8, config, DefaultType$6);\n      return config;\n    };\n\n    _proto._getScrollTop = function _getScrollTop() {\n      return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;\n    };\n\n    _proto._getScrollHeight = function _getScrollHeight() {\n      return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);\n    };\n\n    _proto._getOffsetHeight = function _getOffsetHeight() {\n      return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;\n    };\n\n    _proto._process = function _process() {\n      var scrollTop = this._getScrollTop() + this._config.offset;\n\n      var scrollHeight = this._getScrollHeight();\n\n      var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();\n\n      if (this._scrollHeight !== scrollHeight) {\n        this.refresh();\n      }\n\n      if (scrollTop >= maxScroll) {\n        var target = this._targets[this._targets.length - 1];\n\n        if (this._activeTarget !== target) {\n          this._activate(target);\n        }\n\n        return;\n      }\n\n      if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n        this._activeTarget = null;\n\n        this._clear();\n\n        return;\n      }\n\n      var offsetLength = this._offsets.length;\n\n      for (var i = offsetLength; i--;) {\n        var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);\n\n        if (isActiveTarget) {\n          this._activate(this._targets[i]);\n        }\n      }\n    };\n\n    _proto._activate = function _activate(target) {\n      this._activeTarget = target;\n\n      this._clear();\n\n      var queries = this._selector.split(',').map(function (selector) {\n        return selector + \"[data-target=\\\"\" + target + \"\\\"],\" + selector + \"[href=\\\"\" + target + \"\\\"]\";\n      });\n\n      var $link = $([].slice.call(document.querySelectorAll(queries.join(','))));\n\n      if ($link.hasClass(ClassName$8.DROPDOWN_ITEM)) {\n        $link.closest(Selector$8.DROPDOWN).find(Selector$8.DROPDOWN_TOGGLE).addClass(ClassName$8.ACTIVE);\n        $link.addClass(ClassName$8.ACTIVE);\n      } else {\n        // Set triggered link as active\n        $link.addClass(ClassName$8.ACTIVE); // Set triggered links parents as active\n        // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n\n        $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_LINKS + \", \" + Selector$8.LIST_ITEMS).addClass(ClassName$8.ACTIVE); // Handle special case when .nav-link is inside .nav-item\n\n        $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_ITEMS).children(Selector$8.NAV_LINKS).addClass(ClassName$8.ACTIVE);\n      }\n\n      $(this._scrollElement).trigger(Event$8.ACTIVATE, {\n        relatedTarget: target\n      });\n    };\n\n    _proto._clear = function _clear() {\n      [].slice.call(document.querySelectorAll(this._selector)).filter(function (node) {\n        return node.classList.contains(ClassName$8.ACTIVE);\n      }).forEach(function (node) {\n        return node.classList.remove(ClassName$8.ACTIVE);\n      });\n    } // Static\n    ;\n\n    ScrollSpy._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var data = $(this).data(DATA_KEY$8);\n\n        var _config = typeof config === 'object' && config;\n\n        if (!data) {\n          data = new ScrollSpy(this, _config);\n          $(this).data(DATA_KEY$8, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(ScrollSpy, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$8;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$6;\n      }\n    }]);\n\n    return ScrollSpy;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(window).on(Event$8.LOAD_DATA_API, function () {\n    var scrollSpys = [].slice.call(document.querySelectorAll(Selector$8.DATA_SPY));\n    var scrollSpysLength = scrollSpys.length;\n\n    for (var i = scrollSpysLength; i--;) {\n      var $spy = $(scrollSpys[i]);\n\n      ScrollSpy._jQueryInterface.call($spy, $spy.data());\n    }\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$8] = ScrollSpy._jQueryInterface;\n  $.fn[NAME$8].Constructor = ScrollSpy;\n\n  $.fn[NAME$8].noConflict = function () {\n    $.fn[NAME$8] = JQUERY_NO_CONFLICT$8;\n    return ScrollSpy._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$9 = 'tab';\n  var VERSION$9 = '4.3.1';\n  var DATA_KEY$9 = 'bs.tab';\n  var EVENT_KEY$9 = \".\" + DATA_KEY$9;\n  var DATA_API_KEY$7 = '.data-api';\n  var JQUERY_NO_CONFLICT$9 = $.fn[NAME$9];\n  var Event$9 = {\n    HIDE: \"hide\" + EVENT_KEY$9,\n    HIDDEN: \"hidden\" + EVENT_KEY$9,\n    SHOW: \"show\" + EVENT_KEY$9,\n    SHOWN: \"shown\" + EVENT_KEY$9,\n    CLICK_DATA_API: \"click\" + EVENT_KEY$9 + DATA_API_KEY$7\n  };\n  var ClassName$9 = {\n    DROPDOWN_MENU: 'dropdown-menu',\n    ACTIVE: 'active',\n    DISABLED: 'disabled',\n    FADE: 'fade',\n    SHOW: 'show'\n  };\n  var Selector$9 = {\n    DROPDOWN: '.dropdown',\n    NAV_LIST_GROUP: '.nav, .list-group',\n    ACTIVE: '.active',\n    ACTIVE_UL: '> li > .active',\n    DATA_TOGGLE: '[data-toggle=\"tab\"], [data-toggle=\"pill\"], [data-toggle=\"list\"]',\n    DROPDOWN_TOGGLE: '.dropdown-toggle',\n    DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Tab =\n  /*#__PURE__*/\n  function () {\n    function Tab(element) {\n      this._element = element;\n    } // Getters\n\n\n    var _proto = Tab.prototype;\n\n    // Public\n    _proto.show = function show() {\n      var _this = this;\n\n      if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $(this._element).hasClass(ClassName$9.ACTIVE) || $(this._element).hasClass(ClassName$9.DISABLED)) {\n        return;\n      }\n\n      var target;\n      var previous;\n      var listElement = $(this._element).closest(Selector$9.NAV_LIST_GROUP)[0];\n      var selector = Util.getSelectorFromElement(this._element);\n\n      if (listElement) {\n        var itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector$9.ACTIVE_UL : Selector$9.ACTIVE;\n        previous = $.makeArray($(listElement).find(itemSelector));\n        previous = previous[previous.length - 1];\n      }\n\n      var hideEvent = $.Event(Event$9.HIDE, {\n        relatedTarget: this._element\n      });\n      var showEvent = $.Event(Event$9.SHOW, {\n        relatedTarget: previous\n      });\n\n      if (previous) {\n        $(previous).trigger(hideEvent);\n      }\n\n      $(this._element).trigger(showEvent);\n\n      if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {\n        return;\n      }\n\n      if (selector) {\n        target = document.querySelector(selector);\n      }\n\n      this._activate(this._element, listElement);\n\n      var complete = function complete() {\n        var hiddenEvent = $.Event(Event$9.HIDDEN, {\n          relatedTarget: _this._element\n        });\n        var shownEvent = $.Event(Event$9.SHOWN, {\n          relatedTarget: previous\n        });\n        $(previous).trigger(hiddenEvent);\n        $(_this._element).trigger(shownEvent);\n      };\n\n      if (target) {\n        this._activate(target, target.parentNode, complete);\n      } else {\n        complete();\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      $.removeData(this._element, DATA_KEY$9);\n      this._element = null;\n    } // Private\n    ;\n\n    _proto._activate = function _activate(element, container, callback) {\n      var _this2 = this;\n\n      var activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? $(container).find(Selector$9.ACTIVE_UL) : $(container).children(Selector$9.ACTIVE);\n      var active = activeElements[0];\n      var isTransitioning = callback && active && $(active).hasClass(ClassName$9.FADE);\n\n      var complete = function complete() {\n        return _this2._transitionComplete(element, active, callback);\n      };\n\n      if (active && isTransitioning) {\n        var transitionDuration = Util.getTransitionDurationFromElement(active);\n        $(active).removeClass(ClassName$9.SHOW).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      } else {\n        complete();\n      }\n    };\n\n    _proto._transitionComplete = function _transitionComplete(element, active, callback) {\n      if (active) {\n        $(active).removeClass(ClassName$9.ACTIVE);\n        var dropdownChild = $(active.parentNode).find(Selector$9.DROPDOWN_ACTIVE_CHILD)[0];\n\n        if (dropdownChild) {\n          $(dropdownChild).removeClass(ClassName$9.ACTIVE);\n        }\n\n        if (active.getAttribute('role') === 'tab') {\n          active.setAttribute('aria-selected', false);\n        }\n      }\n\n      $(element).addClass(ClassName$9.ACTIVE);\n\n      if (element.getAttribute('role') === 'tab') {\n        element.setAttribute('aria-selected', true);\n      }\n\n      Util.reflow(element);\n\n      if (element.classList.contains(ClassName$9.FADE)) {\n        element.classList.add(ClassName$9.SHOW);\n      }\n\n      if (element.parentNode && $(element.parentNode).hasClass(ClassName$9.DROPDOWN_MENU)) {\n        var dropdownElement = $(element).closest(Selector$9.DROPDOWN)[0];\n\n        if (dropdownElement) {\n          var dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(Selector$9.DROPDOWN_TOGGLE));\n          $(dropdownToggleList).addClass(ClassName$9.ACTIVE);\n        }\n\n        element.setAttribute('aria-expanded', true);\n      }\n\n      if (callback) {\n        callback();\n      }\n    } // Static\n    ;\n\n    Tab._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var $this = $(this);\n        var data = $this.data(DATA_KEY$9);\n\n        if (!data) {\n          data = new Tab(this);\n          $this.data(DATA_KEY$9, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config]();\n        }\n      });\n    };\n\n    _createClass(Tab, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$9;\n      }\n    }]);\n\n    return Tab;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * Data Api implementation\n   * ------------------------------------------------------------------------\n   */\n\n\n  $(document).on(Event$9.CLICK_DATA_API, Selector$9.DATA_TOGGLE, function (event) {\n    event.preventDefault();\n\n    Tab._jQueryInterface.call($(this), 'show');\n  });\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n  $.fn[NAME$9] = Tab._jQueryInterface;\n  $.fn[NAME$9].Constructor = Tab;\n\n  $.fn[NAME$9].noConflict = function () {\n    $.fn[NAME$9] = JQUERY_NO_CONFLICT$9;\n    return Tab._jQueryInterface;\n  };\n\n  /**\n   * ------------------------------------------------------------------------\n   * Constants\n   * ------------------------------------------------------------------------\n   */\n\n  var NAME$a = 'toast';\n  var VERSION$a = '4.3.1';\n  var DATA_KEY$a = 'bs.toast';\n  var EVENT_KEY$a = \".\" + DATA_KEY$a;\n  var JQUERY_NO_CONFLICT$a = $.fn[NAME$a];\n  var Event$a = {\n    CLICK_DISMISS: \"click.dismiss\" + EVENT_KEY$a,\n    HIDE: \"hide\" + EVENT_KEY$a,\n    HIDDEN: \"hidden\" + EVENT_KEY$a,\n    SHOW: \"show\" + EVENT_KEY$a,\n    SHOWN: \"shown\" + EVENT_KEY$a\n  };\n  var ClassName$a = {\n    FADE: 'fade',\n    HIDE: 'hide',\n    SHOW: 'show',\n    SHOWING: 'showing'\n  };\n  var DefaultType$7 = {\n    animation: 'boolean',\n    autohide: 'boolean',\n    delay: 'number'\n  };\n  var Default$7 = {\n    animation: true,\n    autohide: true,\n    delay: 500\n  };\n  var Selector$a = {\n    DATA_DISMISS: '[data-dismiss=\"toast\"]'\n    /**\n     * ------------------------------------------------------------------------\n     * Class Definition\n     * ------------------------------------------------------------------------\n     */\n\n  };\n\n  var Toast =\n  /*#__PURE__*/\n  function () {\n    function Toast(element, config) {\n      this._element = element;\n      this._config = this._getConfig(config);\n      this._timeout = null;\n\n      this._setListeners();\n    } // Getters\n\n\n    var _proto = Toast.prototype;\n\n    // Public\n    _proto.show = function show() {\n      var _this = this;\n\n      $(this._element).trigger(Event$a.SHOW);\n\n      if (this._config.animation) {\n        this._element.classList.add(ClassName$a.FADE);\n      }\n\n      var complete = function complete() {\n        _this._element.classList.remove(ClassName$a.SHOWING);\n\n        _this._element.classList.add(ClassName$a.SHOW);\n\n        $(_this._element).trigger(Event$a.SHOWN);\n\n        if (_this._config.autohide) {\n          _this.hide();\n        }\n      };\n\n      this._element.classList.remove(ClassName$a.HIDE);\n\n      this._element.classList.add(ClassName$a.SHOWING);\n\n      if (this._config.animation) {\n        var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n        $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      } else {\n        complete();\n      }\n    };\n\n    _proto.hide = function hide(withoutTimeout) {\n      var _this2 = this;\n\n      if (!this._element.classList.contains(ClassName$a.SHOW)) {\n        return;\n      }\n\n      $(this._element).trigger(Event$a.HIDE);\n\n      if (withoutTimeout) {\n        this._close();\n      } else {\n        this._timeout = setTimeout(function () {\n          _this2._close();\n        }, this._config.delay);\n      }\n    };\n\n    _proto.dispose = function dispose() {\n      clearTimeout(this._timeout);\n      this._timeout = null;\n\n      if (this._element.classList.contains(ClassName$a.SHOW)) {\n        this._element.classList.remove(ClassName$a.SHOW);\n      }\n\n      $(this._element).off(Event$a.CLICK_DISMISS);\n      $.removeData(this._element, DATA_KEY$a);\n      this._element = null;\n      this._config = null;\n    } // Private\n    ;\n\n    _proto._getConfig = function _getConfig(config) {\n      config = _objectSpread({}, Default$7, $(this._element).data(), typeof config === 'object' && config ? config : {});\n      Util.typeCheckConfig(NAME$a, config, this.constructor.DefaultType);\n      return config;\n    };\n\n    _proto._setListeners = function _setListeners() {\n      var _this3 = this;\n\n      $(this._element).on(Event$a.CLICK_DISMISS, Selector$a.DATA_DISMISS, function () {\n        return _this3.hide(true);\n      });\n    };\n\n    _proto._close = function _close() {\n      var _this4 = this;\n\n      var complete = function complete() {\n        _this4._element.classList.add(ClassName$a.HIDE);\n\n        $(_this4._element).trigger(Event$a.HIDDEN);\n      };\n\n      this._element.classList.remove(ClassName$a.SHOW);\n\n      if (this._config.animation) {\n        var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n        $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n      } else {\n        complete();\n      }\n    } // Static\n    ;\n\n    Toast._jQueryInterface = function _jQueryInterface(config) {\n      return this.each(function () {\n        var $element = $(this);\n        var data = $element.data(DATA_KEY$a);\n\n        var _config = typeof config === 'object' && config;\n\n        if (!data) {\n          data = new Toast(this, _config);\n          $element.data(DATA_KEY$a, data);\n        }\n\n        if (typeof config === 'string') {\n          if (typeof data[config] === 'undefined') {\n            throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n          }\n\n          data[config](this);\n        }\n      });\n    };\n\n    _createClass(Toast, null, [{\n      key: \"VERSION\",\n      get: function get() {\n        return VERSION$a;\n      }\n    }, {\n      key: \"DefaultType\",\n      get: function get() {\n        return DefaultType$7;\n      }\n    }, {\n      key: \"Default\",\n      get: function get() {\n        return Default$7;\n      }\n    }]);\n\n    return Toast;\n  }();\n  /**\n   * ------------------------------------------------------------------------\n   * jQuery\n   * ------------------------------------------------------------------------\n   */\n\n\n  $.fn[NAME$a] = Toast._jQueryInterface;\n  $.fn[NAME$a].Constructor = Toast;\n\n  $.fn[NAME$a].noConflict = function () {\n    $.fn[NAME$a] = JQUERY_NO_CONFLICT$a;\n    return Toast._jQueryInterface;\n  };\n\n  /**\n   * --------------------------------------------------------------------------\n   * Bootstrap (v4.3.1): index.js\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * --------------------------------------------------------------------------\n   */\n\n  (function () {\n    if (typeof $ === 'undefined') {\n      throw new TypeError('Bootstrap\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\'s JavaScript.');\n    }\n\n    var version = $.fn.jquery.split(' ')[0].split('.');\n    var minMajor = 1;\n    var ltMajor = 2;\n    var minMinor = 9;\n    var minPatch = 1;\n    var maxMajor = 4;\n\n    if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {\n      throw new Error('Bootstrap\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');\n    }\n  })();\n\n  exports.Util = Util;\n  exports.Alert = Alert;\n  exports.Button = Button;\n  exports.Carousel = Carousel;\n  exports.Collapse = Collapse;\n  exports.Dropdown = Dropdown;\n  exports.Modal = Modal;\n  exports.Popover = Popover;\n  exports.Scrollspy = ScrollSpy;\n  exports.Tab = Tab;\n  exports.Toast = Toast;\n  exports.Tooltip = Tooltip;\n\n  Object.defineProperty(exports, '__esModule', { value: true });\n\n}));\n//# sourceMappingURL=bootstrap.js.map\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/jquery/LICENSE.txt",
    "content": "Copyright JS Foundation and other contributors, https://js.foundation/\n\nThis software consists of voluntary contributions made by many\nindividuals. For exact contribution history, see the revision history\navailable at https://github.com/jquery/jquery\n\nThe following license applies to all parts of this software except as\ndocumented below:\n\n====\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n====\n\nAll files located in the node_modules and external directories are\nexternally maintained libraries used by this software which have their\nown licenses; we recommend you read them, as their terms may differ from\nthe terms above.\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/jquery/dist/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v3.5.1\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2020-05-04T22:49Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n      // Support: Chrome <=57, Firefox <=52\n      // In some browsers, typeof returns \"function\" for HTML <object> elements\n      // (i.e., `typeof document.createElement( \"object\" ) === \"function\"`).\n      // We don't want to classify *any* DOM node as a function.\n      return typeof obj === \"function\" && typeof obj.nodeType !== \"number\";\n  };\n\n\nvar isWindow = function isWindow( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t};\n\n\nvar document = window.document;\n\n\n\n\tvar preservedScriptAttributes = {\n\t\ttype: true,\n\t\tsrc: true,\n\t\tnonce: true,\n\t\tnoModule: true\n\t};\n\n\tfunction DOMEval( code, node, doc ) {\n\t\tdoc = doc || document;\n\n\t\tvar i, val,\n\t\t\tscript = doc.createElement( \"script\" );\n\n\t\tscript.text = code;\n\t\tif ( node ) {\n\t\t\tfor ( i in preservedScriptAttributes ) {\n\n\t\t\t\t// Support: Firefox 64+, Edge 18+\n\t\t\t\t// Some browsers don't support the \"nonce\" property on scripts.\n\t\t\t\t// On the other hand, just using `getAttribute` is not enough as\n\t\t\t\t// the `nonce` attribute is reset to an empty string whenever it\n\t\t\t\t// becomes browsing-context connected.\n\t\t\t\t// See https://github.com/whatwg/html/issues/2369\n\t\t\t\t// See https://html.spec.whatwg.org/#nonce-attributes\n\t\t\t\t// The `node.getAttribute` check was added for the sake of\n\t\t\t\t// `jQuery.globalEval` so that it can fake a nonce-containing node\n\t\t\t\t// via an object.\n\t\t\t\tval = node[ i ] || node.getAttribute && node.getAttribute( i );\n\t\t\t\tif ( val ) {\n\t\t\t\t\tscript.setAttribute( i, val );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n\t}\n\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\t// Support: Android <=2.3 only (functionish RegExp)\n\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n/* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\nvar\n\tversion = \"3.5.1\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teven: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn ( i + 1 ) % 2;\n\t\t} ) );\n\t},\n\n\todd: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn i % 2;\n\t\t} ) );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a provided context; falls back to the global one\n\t// if not specified.\n\tglobalEval: function( code, options, doc ) {\n\t\tDOMEval( code, { nonce: options && options.nonce }, doc );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t// push.apply(_, arraylike) throws on ancient WebKit\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn flat( ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\nfunction( _i, name ) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: real iOS 8.2 only (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( isFunction( obj ) || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.3.5\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://js.foundation/\n *\n * Date: 2020-03-14\n */\n( function( window ) {\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// Instance methods\n\thasOwn = ( {} ).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpushNative = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\n\t// Use a stripped-down indexOf as it's faster than native\n\t// https://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[ i ] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|\" +\n\t\t\"ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram\n\tidentifier = \"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\t\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\n\t\t// \"Attribute values must be CSS identifiers [capture 5]\n\t\t// or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" +\n\t\twhitespace + \"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" +\n\t\twhitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace +\n\t\t\"*\" ),\n\trdescend = new RegExp( whitespace + \"|>\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" +\n\t\t\twhitespace + \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" +\n\t\t\twhitespace + \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace +\n\t\t\t\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" + whitespace +\n\t\t\t\"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trhtml = /HTML$/i,\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\n\t// CSS escapes\n\t// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace + \"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\", \"g\" ),\n\tfunescape = function( escape, nonHex ) {\n\t\tvar high = \"0x\" + escape.slice( 1 ) - 0x10000;\n\n\t\treturn nonHex ?\n\n\t\t\t// Strip the backslash prefix from a non-hex escape sequence\n\t\t\tnonHex :\n\n\t\t\t// Replace a hexadecimal escape sequence with the encoded Unicode code point\n\t\t\t// Support: IE <=11+\n\t\t\t// For values outside the Basic Multilingual Plane (BMP), manually construct a\n\t\t\t// surrogate pair\n\t\t\thigh < 0 ?\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// CSS string/identifier serialization\n\t// https://drafts.csswg.org/cssom/#common-serializing-idioms\n\trcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n\tfcssescape = function( ch, asCodePoint ) {\n\t\tif ( asCodePoint ) {\n\n\t\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\t\tif ( ch === \"\\0\" ) {\n\t\t\t\treturn \"\\uFFFD\";\n\t\t\t}\n\n\t\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\t\treturn ch.slice( 0, -1 ) + \"\\\\\" +\n\t\t\t\tch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t\t}\n\n\t\t// Other potentially-special ASCII characters get backslash-escaped\n\t\treturn \"\\\\\" + ch;\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && elem.nodeName.toLowerCase() === \"fieldset\";\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t( arr = slice.call( preferredDoc.childNodes ) ),\n\t\tpreferredDoc.childNodes\n\t);\n\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\t// eslint-disable-next-line no-unused-expressions\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpushNative.apply( target, slice.call( els ) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( ( target[ j++ ] = els[ i++ ] ) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\t\tsetDocument( context );\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( ( m = match[ 1 ] ) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( ( elem = context.getElementById( m ) ) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && ( elem = newContext.getElementById( m ) ) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[ 2 ] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&\n\n\t\t\t\t// Support: IE 8 only\n\t\t\t\t// Exclude object elements\n\t\t\t\t( nodeType !== 1 || context.nodeName.toLowerCase() !== \"object\" ) ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// The technique has to be used as well when a leading combinator is used\n\t\t\t\t// as such selectors are not recognized by querySelectorAll.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 &&\n\t\t\t\t\t( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\n\t\t\t\t\t// We can use :scope instead of the ID hack if the browser\n\t\t\t\t\t// supports it & if we're not changing the context.\n\t\t\t\t\tif ( newContext !== context || !support.scope ) {\n\n\t\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\t\tif ( ( nid = context.getAttribute( \"id\" ) ) ) {\n\t\t\t\t\t\t\tnid = nid.replace( rcssescape, fcssescape );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.setAttribute( \"id\", ( nid = expando ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[ i ] = ( nid ? \"#\" + nid : \":scope\" ) + \" \" +\n\t\t\t\t\t\t\ttoSelector( groups[ i ] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn ( cache[ key + \" \" ] = value );\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created element and returns a boolean result\n */\nfunction assert( fn ) {\n\tvar el = document.createElement( \"fieldset\" );\n\n\ttry {\n\t\treturn !!fn( el );\n\t} catch ( e ) {\n\t\treturn false;\n\t} finally {\n\n\t\t// Remove from its parent by default\n\t\tif ( el.parentNode ) {\n\t\t\tel.parentNode.removeChild( el );\n\t\t}\n\n\t\t// release memory in IE\n\t\tel = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split( \"|\" ),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[ i ] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\ta.sourceIndex - b.sourceIndex;\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( ( cur = cur.nextSibling ) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn ( name === \"input\" || name === \"button\" ) && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\t/* jshint -W018 */\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction( function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction( function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ ( j = matchIndexes[ i ] ) ] ) {\n\t\t\t\t\tseed[ j ] = !( matches[ j ] = seed[ j ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\tvar namespace = elem.namespaceURI,\n\t\tdocElem = ( elem.ownerDocument || elem ).documentElement;\n\n\t// Support: IE <=8\n\t// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes\n\t// https://bugs.jquery.com/ticket/4833\n\treturn !rhtml.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, subWindow,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( preferredDoc != document &&\n\t\t( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {\n\n\t\t// Support: IE 11, Edge\n\t\tif ( subWindow.addEventListener ) {\n\t\t\tsubWindow.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( subWindow.attachEvent ) {\n\t\t\tsubWindow.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t// Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,\n\t// Safari 4 - 5 only, Opera <=11.6 - 12.x only\n\t// IE/Edge & older browsers don't support the :scope pseudo-class.\n\t// Support: Safari 6.0 only\n\t// Safari 6.0 supports :scope but it's an alias of :root there.\n\tsupport.scope = assert( function( el ) {\n\t\tdocElem.appendChild( el ).appendChild( document.createElement( \"div\" ) );\n\t\treturn typeof el.querySelectorAll !== \"undefined\" &&\n\t\t\t!el.querySelectorAll( \":scope fieldset div\" ).length;\n\t} );\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert( function( el ) {\n\t\tel.className = \"i\";\n\t\treturn !el.getAttribute( \"className\" );\n\t} );\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert( function( el ) {\n\t\tel.appendChild( document.createComment( \"\" ) );\n\t\treturn !el.getElementsByTagName( \"*\" ).length;\n\t} );\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programmatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert( function( el ) {\n\t\tdocElem.appendChild( el ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t} );\n\n\t// ID filter and find\n\tif ( support.getById ) {\n\t\tExpr.filter[ \"ID\" ] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"id\" ) === attrId;\n\t\t\t};\n\t\t};\n\t\tExpr.find[ \"ID\" ] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t};\n\t} else {\n\t\tExpr.filter[ \"ID\" ] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode( \"id\" );\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\n\t\t// Support: IE 6 - 7 only\n\t\t// getElementById is not reliable as a find shortcut\n\t\tExpr.find[ \"ID\" ] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar node, i, elems,\n\t\t\t\t\telem = context.getElementById( id );\n\n\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t// Verify the id attribute\n\t\t\t\t\tnode = elem.getAttributeNode( \"id\" );\n\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall back on getElementsByName\n\t\t\t\t\telems = context.getElementsByName( id );\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile ( ( elem = elems[ i++ ] ) ) {\n\t\t\t\t\t\tnode = elem.getAttributeNode( \"id\" );\n\t\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn [];\n\t\t\t}\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[ \"TAG\" ] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[ \"CLASS\" ] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See https://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {\n\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert( function( el ) {\n\n\t\t\tvar input;\n\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// https://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( el ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( el.querySelectorAll( \"[msallowcapture^='']\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !el.querySelectorAll( \"[selected]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"~=\" );\n\t\t\t}\n\n\t\t\t// Support: IE 11+, Edge 15 - 18+\n\t\t\t// IE 11/Edge don't find elements on a `[name='']` query in some cases.\n\t\t\t// Adding a temporary attribute to the document before the selection works\n\t\t\t// around the issue.\n\t\t\t// Interestingly, IE 10 & older don't seem to have the issue.\n\t\t\tinput = document.createElement( \"input\" );\n\t\t\tinput.setAttribute( \"name\", \"\" );\n\t\t\tel.appendChild( input );\n\t\t\tif ( !el.querySelectorAll( \"[name='']\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*name\" + whitespace + \"*=\" +\n\t\t\t\t\twhitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !el.querySelectorAll( \":checked\" ).length ) {\n\t\t\t\trbuggyQSA.push( \":checked\" );\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibling-combinator selector` fails\n\t\t\tif ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push( \".#.+[+~]\" );\n\t\t\t}\n\n\t\t\t// Support: Firefox <=3.6 - 5 only\n\t\t\t// Old Firefox doesn't throw on a badly-escaped identifier.\n\t\t\tel.querySelectorAll( \"\\\\\\f\" );\n\t\t\trbuggyQSA.push( \"[\\\\r\\\\n\\\\f]\" );\n\t\t} );\n\n\t\tassert( function( el ) {\n\t\t\tel.innerHTML = \"<a href='' disabled='disabled'></a>\" +\n\t\t\t\t\"<select disabled='disabled'><option/></select>\";\n\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement( \"input\" );\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tel.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( el.querySelectorAll( \"[name=d]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( el.querySelectorAll( \":enabled\" ).length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\tdocElem.appendChild( el ).disabled = true;\n\t\t\tif ( el.querySelectorAll( \":disabled\" ).length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: Opera 10 - 11 only\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tel.querySelectorAll( \"*,:x\" );\n\t\t\trbuggyQSA.push( \",.*:\" );\n\t\t} );\n\t}\n\n\tif ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector ) ) ) ) {\n\n\t\tassert( function( el ) {\n\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( el, \"*\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( el, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t} );\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( \"|\" ) );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( \"|\" ) );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t) );\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( ( b = b.parentNode ) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tcompare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif ( a == document || a.ownerDocument == preferredDoc &&\n\t\t\t\tcontains( preferredDoc, a ) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif ( b == document || b.ownerDocument == preferredDoc &&\n\t\t\t\tcontains( preferredDoc, b ) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t/* eslint-disable eqeqeq */\n\t\t\treturn a == document ? -1 :\n\t\t\t\tb == document ? 1 :\n\t\t\t\t/* eslint-enable eqeqeq */\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( ( cur = cur.parentNode ) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( ( cur = cur.parentNode ) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[ i ] === bp[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[ i ], bp[ i ] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t/* eslint-disable eqeqeq */\n\t\t\tap[ i ] == preferredDoc ? -1 :\n\t\t\tbp[ i ] == preferredDoc ? 1 :\n\t\t\t/* eslint-enable eqeqeq */\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\tsetDocument( elem );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\n\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t// fragment in IE 9\n\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\n\t// Set document vars if needed\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( ( context.ownerDocument || context ) != document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\n\t// Set document vars if needed\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( ( elem.ownerDocument || elem ) != document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t( val = elem.getAttributeNode( name ) ) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.escape = function( sel ) {\n\treturn ( sel + \"\" ).replace( rcssescape, fcssescape );\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( ( node = elem[ i++ ] ) ) {\n\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[ 1 ] = match[ 1 ].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[ 3 ] = ( match[ 3 ] || match[ 4 ] ||\n\t\t\t\tmatch[ 5 ] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[ 2 ] === \"~=\" ) {\n\t\t\t\tmatch[ 3 ] = \" \" + match[ 3 ] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[ 1 ] = match[ 1 ].toLowerCase();\n\n\t\t\tif ( match[ 1 ].slice( 0, 3 ) === \"nth\" ) {\n\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[ 3 ] ) {\n\t\t\t\t\tSizzle.error( match[ 0 ] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[ 4 ] = +( match[ 4 ] ?\n\t\t\t\t\tmatch[ 5 ] + ( match[ 6 ] || 1 ) :\n\t\t\t\t\t2 * ( match[ 3 ] === \"even\" || match[ 3 ] === \"odd\" ) );\n\t\t\t\tmatch[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === \"odd\" );\n\n\t\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[ 3 ] ) {\n\t\t\t\tSizzle.error( match[ 0 ] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[ 6 ] && match[ 2 ];\n\n\t\t\tif ( matchExpr[ \"CHILD\" ].test( match[ 0 ] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[ 3 ] ) {\n\t\t\t\tmatch[ 2 ] = match[ 4 ] || match[ 5 ] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t( excess = tokenize( unquoted, true ) ) &&\n\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t( excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length ) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[ 0 ] = match[ 0 ].slice( 0, excess );\n\t\t\t\tmatch[ 2 ] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() {\n\t\t\t\t\treturn true;\n\t\t\t\t} :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t( pattern = new RegExp( \"(^|\" + whitespace +\n\t\t\t\t\t\")\" + className + \"(\" + whitespace + \"|$)\" ) ) && classCache(\n\t\t\t\t\t\tclassName, function( elem ) {\n\t\t\t\t\t\t\treturn pattern.test(\n\t\t\t\t\t\t\t\ttypeof elem.className === \"string\" && elem.className ||\n\t\t\t\t\t\t\t\ttypeof elem.getAttribute !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\telem.getAttribute( \"class\" ) ||\n\t\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\t/* eslint-disable max-len */\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t\t/* eslint-enable max-len */\n\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, _argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( ( node = node[ dir ] ) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || ( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || ( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction( function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[ i ] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} ) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction( function( selector ) {\n\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction( function( seed, matches, _context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\t\t\t\t\tseed[ i ] = !( matches[ i ] = elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} ) :\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tinput[ 0 ] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[ 0 ] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t} ),\n\n\t\t\"has\": markFunction( function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t} ),\n\n\t\t\"contains\": markFunction( function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t} ),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test( lang || \"\" ) ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( ( elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute( \"xml:lang\" ) || elem.getAttribute( \"lang\" ) ) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t} ),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement &&\n\t\t\t\t( !document.hasFocus || document.hasFocus() ) &&\n\t\t\t\t!!( elem.type || elem.href || ~elem.tabIndex );\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": createDisabledPseudo( false ),\n\t\t\"disabled\": createDisabledPseudo( true ),\n\n\t\t\"checked\": function( elem ) {\n\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn ( nodeName === \"input\" && !!elem.checked ) ||\n\t\t\t\t( nodeName === \"option\" && !!elem.selected );\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[ \"empty\" ]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( ( attr = elem.getAttribute( \"type\" ) ) == null ||\n\t\t\t\t\tattr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo( function() {\n\t\t\treturn [ 0 ];\n\t\t} ),\n\n\t\t\"last\": createPositionalPseudo( function( _matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t} ),\n\n\t\t\"eq\": createPositionalPseudo( function( _matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t} ),\n\n\t\t\"even\": createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"odd\": createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"lt\": createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ?\n\t\t\t\targument + length :\n\t\t\t\targument > length ?\n\t\t\t\t\tlength :\n\t\t\t\t\targument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"gt\": createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} )\n\t}\n};\n\nExpr.pseudos[ \"nth\" ] = Expr.pseudos[ \"eq\" ];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || ( match = rcomma.exec( soFar ) ) ) {\n\t\t\tif ( match ) {\n\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[ 0 ].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( ( tokens = [] ) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( ( match = rcombinators.exec( soFar ) ) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[ 0 ].replace( rtrim, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||\n\t\t\t\t( match = preFilters[ type ]( match ) ) ) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[ i ].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || ( elem[ expando ] = {} );\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] ||\n\t\t\t\t\t\t\t( outerCache[ elem.uniqueID ] = {} );\n\n\t\t\t\t\t\tif ( skip && skip === elem.nodeName.toLowerCase() ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( ( oldCache = uniqueCache[ key ] ) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn ( newCache[ 2 ] = oldCache[ 2 ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[ i ]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[ 0 ];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[ i ], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction( function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts(\n\t\t\t\tselector || \"*\",\n\t\t\t\tcontext.nodeType ? [ context ] : context,\n\t\t\t\t[]\n\t\t\t),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( ( elem = temp[ i ] ) ) {\n\t\t\t\t\tmatcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) ) {\n\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( ( matcherIn[ i ] = elem ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, ( matcherOut = [] ), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) &&\n\t\t\t\t\t\t( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {\n\n\t\t\t\t\t\tseed[ temp ] = !( results[ temp ] = elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t} );\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[ 0 ].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[ \" \" ],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t( checkContext = context ).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {\n\t\t\tmatchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[ j ].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\n\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\ttokens\n\t\t\t\t\t\t.slice( 0, i - 1 )\n\t\t\t\t\t\t.concat( { value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" } )\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[ \"TAG\" ]( \"*\", outermost ),\n\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\n\t\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\toutermostContext = context == document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\n\t\t\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( !context && elem.ownerDocument != document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( ( matcher = elementMatchers[ j++ ] ) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( ( elem = !matcher && elem ) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( ( matcher = setMatchers[ j++ ] ) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !( unmatched[ i ] || setMatched[ i ] ) ) {\n\t\t\t\t\t\t\t\tsetMatched[ i ] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[ i ] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache(\n\t\t\tselector,\n\t\t\tmatcherFromGroupMatchers( elementMatchers, setMatchers )\n\t\t);\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( ( selector = compiled.selector || selector ) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[ 0 ] = match[ 0 ].slice( 0 );\n\t\tif ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === \"ID\" &&\n\t\t\tcontext.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {\n\n\t\t\tcontext = ( Expr.find[ \"ID\" ]( token.matches[ 0 ]\n\t\t\t\t.replace( runescape, funescape ), context ) || [] )[ 0 ];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[ \"needsContext\" ].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[ i ];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ ( type = token.type ) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ( find = Expr.find[ type ] ) ) {\n\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( ( seed = find(\n\t\t\t\t\ttoken.matches[ 0 ].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext\n\t\t\t\t) ) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split( \"\" ).sort( sortOrder ).join( \"\" ) === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert( function( el ) {\n\n\t// Should return 1, but returns 4 (following)\n\treturn el.compareDocumentPosition( document.createElement( \"fieldset\" ) ) & 1;\n} );\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert( function( el ) {\n\tel.innerHTML = \"<a href='#'></a>\";\n\treturn el.firstChild.getAttribute( \"href\" ) === \"#\";\n} ) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t} );\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert( function( el ) {\n\tel.innerHTML = \"<input/>\";\n\tel.firstChild.setAttribute( \"value\", \"\" );\n\treturn el.firstChild.getAttribute( \"value\" ) === \"\";\n} ) ) {\n\taddHandle( \"value\", function( elem, _name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t} );\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert( function( el ) {\n\treturn el.getAttribute( \"disabled\" ) == null;\n} ) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t( val = elem.getAttributeNode( name ) ) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\t\tnull;\n\t\t}\n\t} );\n}\n\nreturn Sizzle;\n\n} )( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\n\n// Deprecated\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\njQuery.escapeSelector = Sizzle.escape;\n\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n\n\nfunction nodeName( elem, name ) {\n\n  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\n};\nvar rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\tif ( elem.contentDocument != null &&\n\n\t\t\t// Support: IE 11+\n\t\t\t// <object> elements with no `data` attribute has an object\n\t\t\t// `contentDocument` with a `null` prototype.\n\t\t\tgetProto( elem.contentDocument ) ) {\n\n\t\t\treturn elem.contentDocument;\n\t\t}\n\n\t\t// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only\n\t\t// Treat the template element as a regular one in browsers that\n\t\t// don't support it.\n\t\tif ( nodeName( elem, \"template\" ) ) {\n\t\t\telem = elem.content || elem;\n\t\t}\n\n\t\treturn jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && isFunction( ( method = value.promise ) ) ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && isFunction( ( method = value.then ) ) ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\n\t\t// Support: Android 4.0 only\n\t\t// Strict mode functions invoked without .call/.apply get global-object context\n\t\treject.apply( undefined, [ value ] );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\t\"catch\": function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( _i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( isFunction( then ) ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.stackTrace );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the stack, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getStackHook ) {\n\t\t\t\t\t\t\t\t\tprocess.stackTrace = jQuery.Deferred.getStackHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onProgress ) ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onFulfilled ) ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onRejected ) ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the master Deferred\n\t\t\tmaster = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tmaster.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( master.state() === \"pending\" ||\n\t\t\t\tisFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n\t\t\t\treturn master.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), master.reject );\n\t\t}\n\n\t\treturn master.promise();\n\t}\n} );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\njQuery.Deferred.exceptionHook = function( error, stack ) {\n\n\t// Support: IE 8 - 9 only\n\t// Console exists when dev tools are open, which can happen at any time\n\tif ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n\t}\n};\n\n\n\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n\n\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\nif ( document.readyState === \"complete\" ||\n\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, _key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\tvalue :\n\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n};\n\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/,\n\trdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( _all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase; used by the css and data modules\n// Support: IE <=9 - 11, Edge 12 - 15\n// Microsoft forgot to hump their vendor prefix (#9572)\nfunction camelCase( string ) {\n\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n}\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11 only\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar documentElement = document.documentElement;\n\n\n\n\tvar isAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem );\n\t\t},\n\t\tcomposed = { composed: true };\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only\n\t// Check attachment across shadow DOM boundaries when possible (gh-3504)\n\t// Support: iOS 10.0-10.2 only\n\t// Early iOS 10 versions support `attachShadow` but not `getRootNode`,\n\t// leading to errors. We need to check for `getRootNode`.\n\tif ( documentElement.getRootNode ) {\n\t\tisAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem ) ||\n\t\t\t\telem.getRootNode( composed ) === elem.ownerDocument;\n\t\t};\n\t}\nvar isHiddenWithinTree = function( elem, el ) {\n\n\t\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\n\t\t// Inline style trumps all\n\t\treturn elem.style.display === \"none\" ||\n\t\t\telem.style.display === \"\" &&\n\n\t\t\t// Otherwise, check computed style\n\t\t\t// Support: Firefox <=43 - 45\n\t\t\t// Disconnected elements can have computed display: none, so first confirm that elem is\n\t\t\t// in the document.\n\t\t\tisAttached( elem ) &&\n\n\t\t\tjQuery.css( elem, \"display\" ) === \"none\";\n\t};\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = elem.nodeType &&\n\t\t\t( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i );\n\nvar rscriptType = ( /^$|^module$|\\/(?:java|ecma)script/i );\n\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0 - 4.3 only\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Android <=4.1 only\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE <=11 only\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n\n\t// Support: IE <=9 only\n\t// IE <=9 replaces <option> tags with their contents when inserted outside of\n\t// the select element.\n\tdiv.innerHTML = \"<option></option>\";\n\tsupport.option = !!div.lastChild;\n} )();\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// Support: IE <=9 only\nif ( !support.option ) {\n\twrapMap.optgroup = wrapMap.option = [ 1, \"<select multiple='multiple'>\", \"</select>\" ];\n}\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, attached, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tattached = isAttached( elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( attached ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 - 11+\n// focus() and blur() are asynchronous, except when they are no-op.\n// So expect focus to be synchronous when the element is already active,\n// and blur to be synchronous when the element is not already active.\n// (focus and blur are always synchronous in other supported browsers,\n// this just defines when we can count on it).\nfunction expectSync( elem, type ) {\n\treturn ( elem === safeActiveElement() ) === ( type === \"focus\" );\n}\n\n// Support: IE <=9 only\n// Accessing document.activeElement can throw unexpectedly\n// https://bugs.jquery.com/ticket/13393\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Only attach events to objects that accept data\n\t\tif ( !acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = Object.create( null );\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\n\t\t\t// Make a writable jQuery.Event from the native event object\n\t\t\tevent = jQuery.event.fix( nativeEvent ),\n\n\t\t\thandlers = (\n\t\t\t\t\tdataPriv.get( this, \"events\" ) || Object.create( null )\n\t\t\t\t)[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// If the event is namespaced, then each handler is only invoked if it is\n\t\t\t\t// specially universal or its namespaces are a superset of the event's.\n\t\t\t\tif ( !event.rnamespace || handleObj.namespace === false ||\n\t\t\t\t\tevent.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG <use> instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\n\t\t\t// Utilize native event to ensure correct state for checkable inputs\n\t\t\tsetup: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Claim the first handler\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\t// dataPriv.set( el, \"click\", ... )\n\t\t\t\t\tleverageNative( el, \"click\", returnTrue );\n\t\t\t\t}\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\ttrigger: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Force setup before triggering a click\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\tleverageNative( el, \"click\" );\n\t\t\t\t}\n\n\t\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, suppress native .click() on links\n\t\t\t// Also prevent it if we're currently inside a leveraged native-event stack\n\t\t\t_default: function( event ) {\n\t\t\t\tvar target = event.target;\n\t\t\t\treturn rcheckableType.test( target.type ) &&\n\t\t\t\t\ttarget.click && nodeName( target, \"input\" ) &&\n\t\t\t\t\tdataPriv.get( target, \"click\" ) ||\n\t\t\t\t\tnodeName( target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Ensure the presence of an event listener that handles manually-triggered\n// synthetic events by interrupting progress until reinvoked in response to\n// *native* events that it fires directly, ensuring that state changes have\n// already occurred before other listeners are invoked.\nfunction leverageNative( el, type, expectSync ) {\n\n\t// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add\n\tif ( !expectSync ) {\n\t\tif ( dataPriv.get( el, type ) === undefined ) {\n\t\t\tjQuery.event.add( el, type, returnTrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// Register the controller as a special universal handler for all event namespaces\n\tdataPriv.set( el, type, false );\n\tjQuery.event.add( el, type, {\n\t\tnamespace: false,\n\t\thandler: function( event ) {\n\t\t\tvar notAsync, result,\n\t\t\t\tsaved = dataPriv.get( this, type );\n\n\t\t\tif ( ( event.isTrigger & 1 ) && this[ type ] ) {\n\n\t\t\t\t// Interrupt processing of the outer synthetic .trigger()ed event\n\t\t\t\t// Saved data should be false in such cases, but might be a leftover capture object\n\t\t\t\t// from an async native handler (gh-4350)\n\t\t\t\tif ( !saved.length ) {\n\n\t\t\t\t\t// Store arguments for use when handling the inner native event\n\t\t\t\t\t// There will always be at least one argument (an event object), so this array\n\t\t\t\t\t// will not be confused with a leftover capture object.\n\t\t\t\t\tsaved = slice.call( arguments );\n\t\t\t\t\tdataPriv.set( this, type, saved );\n\n\t\t\t\t\t// Trigger the native event and capture its result\n\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t// focus() and blur() are asynchronous\n\t\t\t\t\tnotAsync = expectSync( this, type );\n\t\t\t\t\tthis[ type ]();\n\t\t\t\t\tresult = dataPriv.get( this, type );\n\t\t\t\t\tif ( saved !== result || notAsync ) {\n\t\t\t\t\t\tdataPriv.set( this, type, false );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = {};\n\t\t\t\t\t}\n\t\t\t\t\tif ( saved !== result ) {\n\n\t\t\t\t\t\t// Cancel the outer synthetic event\n\t\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\treturn result.value;\n\t\t\t\t\t}\n\n\t\t\t\t// If this is an inner synthetic event for an event with a bubbling surrogate\n\t\t\t\t// (focus or blur), assume that the surrogate already propagated from triggering the\n\t\t\t\t// native event and prevent that from happening again here.\n\t\t\t\t// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the\n\t\t\t\t// bubbling surrogate propagates *after* the non-bubbling base), but that seems\n\t\t\t\t// less bad than duplication.\n\t\t\t\t} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\n\t\t\t// If this is a native event triggered above, everything is now in order\n\t\t\t// Fire an inner synthetic event with the original arguments\n\t\t\t} else if ( saved.length ) {\n\n\t\t\t\t// ...and capture the result\n\t\t\t\tdataPriv.set( this, type, {\n\t\t\t\t\tvalue: jQuery.event.trigger(\n\n\t\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t\t// Extend with the prototype to reset the above stopImmediatePropagation()\n\t\t\t\t\t\tjQuery.extend( saved[ 0 ], jQuery.Event.prototype ),\n\t\t\t\t\t\tsaved.slice( 1 ),\n\t\t\t\t\t\tthis\n\t\t\t\t\t)\n\t\t\t\t} );\n\n\t\t\t\t// Abort handling of the native event\n\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t}\n\t\t}\n\t} );\n}\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcode: true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\n\twhich: function( event ) {\n\t\tvar button = event.button;\n\n\t\t// Add which for key events\n\t\tif ( event.which == null && rkeyEvent.test( event.type ) ) {\n\t\t\treturn event.charCode != null ? event.charCode : event.keyCode;\n\t\t}\n\n\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\tif ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {\n\t\t\tif ( button & 1 ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif ( button & 2 ) {\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\t\tif ( button & 4 ) {\n\t\t\t\treturn 2;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn event.which;\n\t}\n}, jQuery.event.addProp );\n\njQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( type, delegateType ) {\n\tjQuery.event.special[ type ] = {\n\n\t\t// Utilize native event if possible so blur/focus sequence is correct\n\t\tsetup: function() {\n\n\t\t\t// Claim the first handler\n\t\t\t// dataPriv.set( this, \"focus\", ... )\n\t\t\t// dataPriv.set( this, \"blur\", ... )\n\t\t\tleverageNative( this, type, expectSync );\n\n\t\t\t// Return false to allow normal processing in the caller\n\t\t\treturn false;\n\t\t},\n\t\ttrigger: function() {\n\n\t\t\t// Force setup before trigger\n\t\t\tleverageNative( this, type );\n\n\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\treturn true;\n\t\t},\n\n\t\tdelegateType: delegateType\n\t};\n} );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t// Support: IE <=10 - 11, Edge 12 - 13 only\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( elem ).children( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.get( src );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdataPriv.remove( dest, \"handle events\" );\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = flat( args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( valueIsFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase()  !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl && !node.noModule ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src, {\n\t\t\t\t\t\t\t\t\tnonce: node.nonce || node.getAttribute( \"nonce\" )\n\t\t\t\t\t\t\t\t}, doc );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), node, doc );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && isAttached( node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html;\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = isAttached( elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar swap = function( elem, options, callback ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.call( elem );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar rboxStyle = new RegExp( cssExpand.join( \"|\" ), \"i\" );\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer.style.cssText = \"position:absolute;left:-11111px;width:60px;\" +\n\t\t\t\"margin-top:1px;padding:0;border:0\";\n\t\tdiv.style.cssText =\n\t\t\t\"position:relative;display:block;box-sizing:border-box;overflow:scroll;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"width:60%;top:1%\";\n\t\tdocumentElement.appendChild( container ).appendChild( div );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;\n\n\t\t// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.right = \"60%\";\n\t\tpixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;\n\n\t\t// Support: IE 9 - 11 only\n\t\t// Detect misreporting of content dimensions for box-sizing:border-box elements\n\t\tboxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;\n\n\t\t// Support: IE 9 only\n\t\t// Detect overflow:scroll screwiness (gh-3699)\n\t\t// Support: Chrome <=64\n\t\t// Don't get tricked when zoom affects offsetWidth (gh-4029)\n\t\tdiv.style.position = \"absolute\";\n\t\tscrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tfunction roundPixelMeasures( measure ) {\n\t\treturn Math.round( parseFloat( measure ) );\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,\n\t\treliableTrDimensionsVal, reliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tjQuery.extend( support, {\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelBoxStyles: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelBoxStylesVal;\n\t\t},\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\tscrollboxSize: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn scrollboxSizeVal;\n\t\t},\n\n\t\t// Support: IE 9 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Behavior in IE 9 is more subtle than in newer versions & it passes\n\t\t// some versions of this test; make sure not to make it pass there!\n\t\treliableTrDimensions: function() {\n\t\t\tvar table, tr, trChild, trStyle;\n\t\t\tif ( reliableTrDimensionsVal == null ) {\n\t\t\t\ttable = document.createElement( \"table\" );\n\t\t\t\ttr = document.createElement( \"tr\" );\n\t\t\t\ttrChild = document.createElement( \"div\" );\n\n\t\t\t\ttable.style.cssText = \"position:absolute;left:-11111px\";\n\t\t\t\ttr.style.height = \"1px\";\n\t\t\t\ttrChild.style.height = \"9px\";\n\n\t\t\t\tdocumentElement\n\t\t\t\t\t.appendChild( table )\n\t\t\t\t\t.appendChild( tr )\n\t\t\t\t\t.appendChild( trChild );\n\n\t\t\t\ttrStyle = window.getComputedStyle( tr );\n\t\t\t\treliableTrDimensionsVal = parseInt( trStyle.height ) > 3;\n\n\t\t\t\tdocumentElement.removeChild( table );\n\t\t\t}\n\t\t\treturn reliableTrDimensionsVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t//   .css('filter') (IE 9 only, #12537)\n\t//   .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !isAttached( elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style,\n\tvendorProps = {};\n\n// Return a vendor-prefixed property or undefined\nfunction vendorPropName( name ) {\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a potentially-mapped jQuery.cssProps or vendor prefixed property\nfunction finalPropName( name ) {\n\tvar final = jQuery.cssProps[ name ] || vendorProps[ name ];\n\n\tif ( final ) {\n\t\treturn final;\n\t}\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\treturn vendorProps[ name ] = vendorPropName( name ) || name;\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t};\n\nfunction setPositiveNumber( _elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\tif ( box === \"margin\" ) {\n\t\t\tdelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\n\t\t// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter\n\t\t// Use an explicit zero to avoid NaN (gh-3964)\n\t\t) ) || 0;\n\t}\n\n\treturn delta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\n\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).\n\t\t// Fake content-box until we know it's needed to know the true value.\n\t\tboxSizingNeeded = !support.boxSizingReliable() || extra,\n\t\tisBorderBox = boxSizingNeeded &&\n\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox,\n\n\t\tval = curCSS( elem, dimension, styles ),\n\t\toffsetProp = \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );\n\n\t// Support: Firefox <=54\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\n\t// Support: IE 9 - 11 only\n\t// Use offsetWidth/offsetHeight for when box sizing is unreliable.\n\t// In those cases, the computed value can be trusted to be border-box.\n\tif ( ( !support.boxSizingReliable() && isBorderBox ||\n\n\t\t// Support: IE 10 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Interestingly, in some cases IE 9 doesn't suffer from this issue.\n\t\t!support.reliableTrDimensions() && nodeName( elem, \"tr\" ) ||\n\n\t\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t\t// This happens for inline elements with no explicit setting (gh-3571)\n\t\tval === \"auto\" ||\n\n\t\t// Support: Android <=4.1 - 4.3 only\n\t\t// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)\n\t\t!parseFloat( val ) && jQuery.css( elem, \"display\", false, styles ) === \"inline\" ) &&\n\n\t\t// Make sure the element is visible & connected\n\t\telem.getClientRects().length ) {\n\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t\t// Where available, offsetWidth/offsetHeight approximate border box dimensions.\n\t\t// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the\n\t\t// retrieved value as a content box dimension.\n\t\tvalueIsBorderBox = offsetProp in elem;\n\t\tif ( valueIsBorderBox ) {\n\t\t\tval = elem[ offsetProp ];\n\t\t}\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"gridArea\": true,\n\t\t\"gridColumn\": true,\n\t\t\"gridColumnEnd\": true,\n\t\t\"gridColumnStart\": true,\n\t\t\"gridRow\": true,\n\t\t\"gridRowEnd\": true,\n\t\t\"gridRowStart\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\t// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append\n\t\t\t// \"px\" to a few hardcoded values.\n\t\t\tif ( type === \"number\" && !isCustomProp ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( _i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t\t} ) :\n\t\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\n\t\t\t\t// Only read styles.position if the test has a chance to fail\n\t\t\t\t// to avoid forcing a reflow.\n\t\t\t\tscrollboxSizeBuggy = !support.scrollboxSize() &&\n\t\t\t\t\tstyles.position === \"absolute\",\n\n\t\t\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)\n\t\t\t\tboxSizingNeeded = scrollboxSizeBuggy || extra,\n\t\t\t\tisBorderBox = boxSizingNeeded &&\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra ?\n\t\t\t\t\tboxModelAdjustment(\n\t\t\t\t\t\telem,\n\t\t\t\t\t\tdimension,\n\t\t\t\t\t\textra,\n\t\t\t\t\t\tisBorderBox,\n\t\t\t\t\t\tstyles\n\t\t\t\t\t) :\n\t\t\t\t\t0;\n\n\t\t\t// Account for unreliable border-box dimensions by comparing offset* to computed and\n\t\t\t// faking a content-box to get border and padding (gh-3699)\n\t\t\tif ( isBorderBox && scrollboxSizeBuggy ) {\n\t\t\t\tsubtract -= Math.ceil(\n\t\t\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\t\t\tparseFloat( styles[ dimension ] ) -\n\t\t\t\t\tboxModelAdjustment( elem, dimension, \"border\", false, styles ) -\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 && (\n\t\t\t\t\tjQuery.cssHooks[ tween.prop ] ||\n\t\t\t\t\ttween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, jQuery.fx.interval );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11, Edge 12 - 15\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY and Edge just mirrors\n\t\t// the overflowX value there.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t/* eslint-disable no-loop-func */\n\n\t\t\tanim.done( function() {\n\n\t\t\t/* eslint-enable no-loop-func */\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3 only\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tisFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !isFunction( easing ) && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( _i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( _i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisValidValue = type === \"string\" || Array.isArray( value );\n\n\t\tif ( typeof stateVal === \"boolean\" && isValidValue ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( isValidValue ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = classesToArray( value );\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = (\n\t\t\t\t\tdataPriv.get( cur, \"events\" ) || Object.create( null )\n\t\t\t\t)[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\n\t\t\t\t// Handle: regular nodes (via `this.ownerDocument`), window\n\t\t\t\t// (via `this.document`) & document (via `this`).\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = { guid: Date.now() };\n\nvar rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\tif ( a == null ) {\n\t\treturn \"\";\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} )\n\t\t.filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} )\n\t\t.map( function( _i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\toriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() + \" \" ] =\n\t\t\t\t\t\t\t\t\t( responseHeaders[ match[ 1 ].toLowerCase() + \" \" ] || [] )\n\t\t\t\t\t\t\t\t\t\t.concat( match[ 2 ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() + \" \" ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match.join( \", \" );\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11, Edge 12 - 15\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11 only\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce.guid++ ) +\n\t\t\t\t\tuncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Use a noop converter for missing script\n\t\t\tif ( !isSuccess && jQuery.inArray( \"script\", s.dataTypes ) > -1 ) {\n\t\t\t\ts.converters[ \"text script\" ] = function() {};\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( _i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\njQuery.ajaxPrefilter( function( s ) {\n\tvar i;\n\tfor ( i in s.headers ) {\n\t\tif ( i.toLowerCase() === \"content-type\" ) {\n\t\t\ts.contentType = s.headers[ i ] || \"\";\n\t\t}\n\t}\n} );\n\n\njQuery._evalUrl = function( url, options, doc ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\n\t\t// Only evaluate the response if it is successful (gh-4126)\n\t\t// dataFilter is not invoked for failure responses, so using it instead\n\t\t// of the default converter is kludgy but it works.\n\t\tconverters: {\n\t\t\t\"text script\": function() {}\n\t\t},\n\t\tdataFilter: function( response ) {\n\t\t\tjQuery.globalEval( response, options, doc );\n\t\t}\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE <=9 only\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.ontimeout =\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\"  ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t\t// Support: IE 9 only\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\njQuery.ajaxPrefilter( function( s ) {\n\tif ( s.crossDomain ) {\n\t\ts.contents.script = false;\n\t}\n} );\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain or forced-by-attrs requests\n\tif ( s.crossDomain || s.scriptAttrs ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"<script>\" )\n\t\t\t\t\t.attr( s.scriptAttrs || {} )\n\t\t\t\t\t.prop( { charset: s.scriptCharset, src: s.url } )\n\t\t\t\t\t.on( \"load error\", callback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup( {\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce.guid++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n} );\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" &&\n\t\t\t\t( s.contentType || \"\" )\n\t\t\t\t\t.indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n\t\t\t\trjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[ \"script json\" ] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// Force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always( function() {\n\n\t\t\t// If previous value didn't exist - remove it\n\t\t\tif ( overwritten === undefined ) {\n\t\t\t\tjQuery( window ).removeProp( callbackName );\n\n\t\t\t// Otherwise restore preexisting value\n\t\t\t} else {\n\t\t\t\twindow[ callbackName ] = overwritten;\n\t\t\t}\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\n\t\t\t\t// Make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// Save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t} );\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n} );\n\n\n\n\n// Support: Safari 8 only\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\nsupport.createHTMLDocument = ( function() {\n\tvar body = document.implementation.createHTMLDocument( \"\" ).body;\n\tbody.innerHTML = \"<form></form><form></form>\";\n\treturn body.childNodes.length === 2;\n} )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( typeof data !== \"string\" ) {\n\t\treturn [];\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\n\tvar base, parsed, scripts;\n\n\tif ( !context ) {\n\n\t\t// Stop scripts or inline event handlers from being executed immediately\n\t\t// by using document.implementation\n\t\tif ( support.createHTMLDocument ) {\n\t\t\tcontext = document.implementation.createHTMLDocument( \"\" );\n\n\t\t\t// Set the base href for the created document\n\t\t\t// so any parsed elements with URLs\n\t\t\t// are based on the document's URL (gh-2965)\n\t\t\tbase = context.createElement( \"base\" );\n\t\t\tbase.href = document.location.href;\n\t\t\tcontext.head.appendChild( base );\n\t\t} else {\n\t\t\tcontext = document;\n\t\t}\n\t}\n\n\tparsed = rsingleTag.exec( data );\n\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf( \" \" );\n\n\tif ( off > -1 ) {\n\t\tselector = stripAndCollapse( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax( {\n\t\t\turl: url,\n\n\t\t\t// If \"type\" variable is undefined, then \"GET\" method will be used.\n\t\t\t// Make value of this field explicit since\n\t\t\t// user can override it through ajaxSetup method\n\t\t\ttype: type || \"GET\",\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t} ).done( function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t// If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n\t\t// but they are ignored because response was set above.\n\t\t// If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n\t\t} ).always( callback && function( jqXHR, status ) {\n\t\t\tself.each( function() {\n\t\t\t\tcallback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t\t} );\n\t\t} );\n\t}\n\n\treturn this;\n};\n\n\n\n\njQuery.expr.pseudos.animated = function( elem ) {\n\treturn jQuery.grep( jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t} ).length;\n};\n\n\n\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tif ( typeof props.top === \"number\" ) {\n\t\t\t\tprops.top += \"px\";\n\t\t\t}\n\t\t\tif ( typeof props.left === \"number\" ) {\n\t\t\t\tprops.left += \"px\";\n\t\t\t}\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\n\t// offset() relates an element's border box to the document origin\n\toffset: function( options ) {\n\n\t\t// Preserve chaining for setter\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar rect, win,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !elem ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Return zeros for disconnected and hidden (display: none) elements (gh-2310)\n\t\t// Support: IE <=11 only\n\t\t// Running getBoundingClientRect on a\n\t\t// disconnected node in IE throws an error\n\t\tif ( !elem.getClientRects().length ) {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t\t// Get document-relative position by adding viewport scroll to viewport-relative gBCR\n\t\trect = elem.getBoundingClientRect();\n\t\twin = elem.ownerDocument.defaultView;\n\t\treturn {\n\t\t\ttop: rect.top + win.pageYOffset,\n\t\t\tleft: rect.left + win.pageXOffset\n\t\t};\n\t},\n\n\t// position() relates an element's margin box to its offset parent's padding box\n\t// This corresponds to the behavior of CSS absolute positioning\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset, doc,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// position:fixed elements are offset from the viewport, which itself always has zero offset\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume position:fixed implies availability of getBoundingClientRect\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\toffset = this.offset();\n\n\t\t\t// Account for the *real* offset parent, which can be the document or its root element\n\t\t\t// when a statically positioned element is identified\n\t\t\tdoc = elem.ownerDocument;\n\t\t\toffsetParent = elem.offsetParent || doc.documentElement;\n\t\t\twhile ( offsetParent &&\n\t\t\t\t( offsetParent === doc.body || offsetParent === doc.documentElement ) &&\n\t\t\t\tjQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\n\t\t\t\toffsetParent = offsetParent.parentNode;\n\t\t\t}\n\t\t\tif ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {\n\n\t\t\t\t// Incorporate borders into its offset, since they are outside its content origin\n\t\t\t\tparentOffset = jQuery( offsetParent ).offset();\n\t\t\t\tparentOffset.top += jQuery.css( offsetParent, \"borderTopWidth\", true );\n\t\t\t\tparentOffset.left += jQuery.css( offsetParent, \"borderLeftWidth\", true );\n\t\t\t}\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t//    documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\n\t\t\t// Coalesce documents and windows\n\t\t\tvar win;\n\t\t\tif ( isWindow( elem ) ) {\n\t\t\t\twin = elem;\n\t\t\t} else if ( elem.nodeType === 9 ) {\n\t\t\t\twin = elem.defaultView;\n\t\t\t}\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari <=7 - 9.1, Chrome <=37 - 49\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( _i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name },\n\t\tfunction( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( isWindow( elem ) ) {\n\n\t\t\t\t\t// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)\n\t\t\t\t\treturn funcName.indexOf( \"outer\" ) === 0 ?\n\t\t\t\t\t\telem[ \"inner\" + name ] :\n\t\t\t\t\t\telem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable );\n\t\t};\n\t} );\n} );\n\n\njQuery.each( [\n\t\"ajaxStart\",\n\t\"ajaxStop\",\n\t\"ajaxComplete\",\n\t\"ajaxError\",\n\t\"ajaxSuccess\",\n\t\"ajaxSend\"\n], function( _i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n} );\n\n\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t},\n\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\njQuery.each( ( \"blur focus focusin focusout resize scroll click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup contextmenu\" ).split( \" \" ),\n\tfunction( _i, name ) {\n\n\t\t// Handle event binding\n\t\tjQuery.fn[ name ] = function( data, fn ) {\n\t\t\treturn arguments.length > 0 ?\n\t\t\t\tthis.on( name, null, data, fn ) :\n\t\t\t\tthis.trigger( name );\n\t\t};\n\t} );\n\n\n\n\n// Support: Android <=4.0 only\n// Make sure we trim BOM and NBSP\nvar rtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;\n\n// Bind a function to a context, optionally partially applying any\n// arguments.\n// jQuery.proxy is deprecated to promote standards (specifically Function#bind)\n// However, it is not slated for removal any time soon\njQuery.proxy = function( fn, context ) {\n\tvar tmp, args, proxy;\n\n\tif ( typeof context === \"string\" ) {\n\t\ttmp = fn[ context ];\n\t\tcontext = fn;\n\t\tfn = tmp;\n\t}\n\n\t// Quick check to determine if target is callable, in the spec\n\t// this throws a TypeError, but we will just return undefined.\n\tif ( !isFunction( fn ) ) {\n\t\treturn undefined;\n\t}\n\n\t// Simulated bind\n\targs = slice.call( arguments, 2 );\n\tproxy = function() {\n\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t};\n\n\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\treturn proxy;\n};\n\njQuery.holdReady = function( hold ) {\n\tif ( hold ) {\n\t\tjQuery.readyWait++;\n\t} else {\n\t\tjQuery.ready( true );\n\t}\n};\njQuery.isArray = Array.isArray;\njQuery.parseJSON = JSON.parse;\njQuery.nodeName = nodeName;\njQuery.isFunction = isFunction;\njQuery.isWindow = isWindow;\njQuery.camelCase = camelCase;\njQuery.type = toType;\n\njQuery.now = Date.now;\n\njQuery.isNumeric = function( obj ) {\n\n\t// As of jQuery 3.0, isNumeric is limited to\n\t// strings and numbers (primitives or objects)\n\t// that can be coerced to finite numbers (gh-2662)\n\tvar type = jQuery.type( obj );\n\treturn ( type === \"number\" || type === \"string\" ) &&\n\n\t\t// parseFloat NaNs numeric-cast false positives (\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t!isNaN( obj - parseFloat( obj ) );\n};\n\njQuery.trim = function( text ) {\n\treturn text == null ?\n\t\t\"\" :\n\t\t( text + \"\" ).replace( rtrim, \"\" );\n};\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t} );\n}\n\n\n\n\nvar\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( typeof noGlobal === \"undefined\" ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n} );\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/jquery-validation/LICENSE.md",
    "content": "The MIT License (MIT)\n=====================\n\nCopyright Jörn Zaefferer\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/jquery-validation/dist/additional-methods.js",
    "content": "/*!\n * jQuery Validation Plugin v1.17.0\n *\n * https://jqueryvalidation.org/\n *\n * Copyright (c) 2017 Jörn Zaefferer\n * Released under the MIT license\n */\n(function( factory ) {\n\tif ( typeof define === \"function\" && define.amd ) {\n\t\tdefine( [\"jquery\", \"./jquery.validate\"], factory );\n\t} else if (typeof module === \"object\" && module.exports) {\n\t\tmodule.exports = factory( require( \"jquery\" ) );\n\t} else {\n\t\tfactory( jQuery );\n\t}\n}(function( $ ) {\n\n( function() {\n\n\tfunction stripHtml( value ) {\n\n\t\t// Remove html tags and space chars\n\t\treturn value.replace( /<.[^<>]*?>/g, \" \" ).replace( /&nbsp;|&#160;/gi, \" \" )\n\n\t\t// Remove punctuation\n\t\t.replace( /[.(),;:!?%#$'\\\"_+=\\/\\-“”’]*/g, \"\" );\n\t}\n\n\t$.validator.addMethod( \"maxWords\", function( value, element, params ) {\n\t\treturn this.optional( element ) || stripHtml( value ).match( /\\b\\w+\\b/g ).length <= params;\n\t}, $.validator.format( \"Please enter {0} words or less.\" ) );\n\n\t$.validator.addMethod( \"minWords\", function( value, element, params ) {\n\t\treturn this.optional( element ) || stripHtml( value ).match( /\\b\\w+\\b/g ).length >= params;\n\t}, $.validator.format( \"Please enter at least {0} words.\" ) );\n\n\t$.validator.addMethod( \"rangeWords\", function( value, element, params ) {\n\t\tvar valueStripped = stripHtml( value ),\n\t\t\tregex = /\\b\\w+\\b/g;\n\t\treturn this.optional( element ) || valueStripped.match( regex ).length >= params[ 0 ] && valueStripped.match( regex ).length <= params[ 1 ];\n\t}, $.validator.format( \"Please enter between {0} and {1} words.\" ) );\n\n}() );\n\n// Accept a value from a file input based on a required mimetype\n$.validator.addMethod( \"accept\", function( value, element, param ) {\n\n\t// Split mime on commas in case we have multiple types we can accept\n\tvar typeParam = typeof param === \"string\" ? param.replace( /\\s/g, \"\" ) : \"image/*\",\n\t\toptionalValue = this.optional( element ),\n\t\ti, file, regex;\n\n\t// Element is optional\n\tif ( optionalValue ) {\n\t\treturn optionalValue;\n\t}\n\n\tif ( $( element ).attr( \"type\" ) === \"file\" ) {\n\n\t\t// Escape string to be used in the regex\n\t\t// see: https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex\n\t\t// Escape also \"/*\" as \"/.*\" as a wildcard\n\t\ttypeParam = typeParam\n\t\t\t\t.replace( /[\\-\\[\\]\\/\\{\\}\\(\\)\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\" )\n\t\t\t\t.replace( /,/g, \"|\" )\n\t\t\t\t.replace( /\\/\\*/g, \"/.*\" );\n\n\t\t// Check if the element has a FileList before checking each file\n\t\tif ( element.files && element.files.length ) {\n\t\t\tregex = new RegExp( \".?(\" + typeParam + \")$\", \"i\" );\n\t\t\tfor ( i = 0; i < element.files.length; i++ ) {\n\t\t\t\tfile = element.files[ i ];\n\n\t\t\t\t// Grab the mimetype from the loaded file, verify it matches\n\t\t\t\tif ( !file.type.match( regex ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Either return true because we've validated each file, or because the\n\t// browser does not support element.files and the FileList feature\n\treturn true;\n}, $.validator.format( \"Please enter a value with a valid mimetype.\" ) );\n\n$.validator.addMethod( \"alphanumeric\", function( value, element ) {\n\treturn this.optional( element ) || /^\\w+$/i.test( value );\n}, \"Letters, numbers, and underscores only please\" );\n\n/*\n * Dutch bank account numbers (not 'giro' numbers) have 9 digits\n * and pass the '11 check'.\n * We accept the notation with spaces, as that is common.\n * acceptable: 123456789 or 12 34 56 789\n */\n$.validator.addMethod( \"bankaccountNL\", function( value, element ) {\n\tif ( this.optional( element ) ) {\n\t\treturn true;\n\t}\n\tif ( !( /^[0-9]{9}|([0-9]{2} ){3}[0-9]{3}$/.test( value ) ) ) {\n\t\treturn false;\n\t}\n\n\t// Now '11 check'\n\tvar account = value.replace( / /g, \"\" ), // Remove spaces\n\t\tsum = 0,\n\t\tlen = account.length,\n\t\tpos, factor, digit;\n\tfor ( pos = 0; pos < len; pos++ ) {\n\t\tfactor = len - pos;\n\t\tdigit = account.substring( pos, pos + 1 );\n\t\tsum = sum + factor * digit;\n\t}\n\treturn sum % 11 === 0;\n}, \"Please specify a valid bank account number\" );\n\n$.validator.addMethod( \"bankorgiroaccountNL\", function( value, element ) {\n\treturn this.optional( element ) ||\n\t\t\t( $.validator.methods.bankaccountNL.call( this, value, element ) ) ||\n\t\t\t( $.validator.methods.giroaccountNL.call( this, value, element ) );\n}, \"Please specify a valid bank or giro account number\" );\n\n/**\n * BIC is the business identifier code (ISO 9362). This BIC check is not a guarantee for authenticity.\n *\n * BIC pattern: BBBBCCLLbbb (8 or 11 characters long; bbb is optional)\n *\n * Validation is case-insensitive. Please make sure to normalize input yourself.\n *\n * BIC definition in detail:\n * - First 4 characters - bank code (only letters)\n * - Next 2 characters - ISO 3166-1 alpha-2 country code (only letters)\n * - Next 2 characters - location code (letters and digits)\n *   a. shall not start with '0' or '1'\n *   b. second character must be a letter ('O' is not allowed) or digit ('0' for test (therefore not allowed), '1' denoting passive participant, '2' typically reverse-billing)\n * - Last 3 characters - branch code, optional (shall not start with 'X' except in case of 'XXX' for primary office) (letters and digits)\n */\n$.validator.addMethod( \"bic\", function( value, element ) {\n    return this.optional( element ) || /^([A-Z]{6}[A-Z2-9][A-NP-Z1-9])(X{3}|[A-WY-Z0-9][A-Z0-9]{2})?$/.test( value.toUpperCase() );\n}, \"Please specify a valid BIC code\" );\n\n/*\n * Código de identificación fiscal ( CIF ) is the tax identification code for Spanish legal entities\n * Further rules can be found in Spanish on http://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal\n *\n * Spanish CIF structure:\n *\n * [ T ][ P ][ P ][ N ][ N ][ N ][ N ][ N ][ C ]\n *\n * Where:\n *\n * T: 1 character. Kind of Organization Letter: [ABCDEFGHJKLMNPQRSUVW]\n * P: 2 characters. Province.\n * N: 5 characters. Secuencial Number within the province.\n * C: 1 character. Control Digit: [0-9A-J].\n *\n * [ T ]: Kind of Organizations. Possible values:\n *\n *   A. Corporations\n *   B. LLCs\n *   C. General partnerships\n *   D. Companies limited partnerships\n *   E. Communities of goods\n *   F. Cooperative Societies\n *   G. Associations\n *   H. Communities of homeowners in horizontal property regime\n *   J. Civil Societies\n *   K. Old format\n *   L. Old format\n *   M. Old format\n *   N. Nonresident entities\n *   P. Local authorities\n *   Q. Autonomous bodies, state or not, and the like, and congregations and religious institutions\n *   R. Congregations and religious institutions (since 2008 ORDER EHA/451/2008)\n *   S. Organs of State Administration and regions\n *   V. Agrarian Transformation\n *   W. Permanent establishments of non-resident in Spain\n *\n * [ C ]: Control Digit. It can be a number or a letter depending on T value:\n * [ T ]  -->  [ C ]\n * ------    ----------\n *   A         Number\n *   B         Number\n *   E         Number\n *   H         Number\n *   K         Letter\n *   P         Letter\n *   Q         Letter\n *   S         Letter\n *\n */\n$.validator.addMethod( \"cifES\", function( value, element ) {\n\t\"use strict\";\n\n\tif ( this.optional( element ) ) {\n\t\treturn true;\n\t}\n\n\tvar cifRegEx = new RegExp( /^([ABCDEFGHJKLMNPQRSUVW])(\\d{7})([0-9A-J])$/gi );\n\tvar letter  = value.substring( 0, 1 ), // [ T ]\n\t\tnumber  = value.substring( 1, 8 ), // [ P ][ P ][ N ][ N ][ N ][ N ][ N ]\n\t\tcontrol = value.substring( 8, 9 ), // [ C ]\n\t\tall_sum = 0,\n\t\teven_sum = 0,\n\t\todd_sum = 0,\n\t\ti, n,\n\t\tcontrol_digit,\n\t\tcontrol_letter;\n\n\tfunction isOdd( n ) {\n\t\treturn n % 2 === 0;\n\t}\n\n\t// Quick format test\n\tif ( value.length !== 9 || !cifRegEx.test( value ) ) {\n\t\treturn false;\n\t}\n\n\tfor ( i = 0; i < number.length; i++ ) {\n\t\tn = parseInt( number[ i ], 10 );\n\n\t\t// Odd positions\n\t\tif ( isOdd( i ) ) {\n\n\t\t\t// Odd positions are multiplied first.\n\t\t\tn *= 2;\n\n\t\t\t// If the multiplication is bigger than 10 we need to adjust\n\t\t\todd_sum += n < 10 ? n : n - 9;\n\n\t\t// Even positions\n\t\t// Just sum them\n\t\t} else {\n\t\t\teven_sum += n;\n\t\t}\n\t}\n\n\tall_sum = even_sum + odd_sum;\n\tcontrol_digit = ( 10 - ( all_sum ).toString().substr( -1 ) ).toString();\n\tcontrol_digit = parseInt( control_digit, 10 ) > 9 ? \"0\" : control_digit;\n\tcontrol_letter = \"JABCDEFGHI\".substr( control_digit, 1 ).toString();\n\n\t// Control must be a digit\n\tif ( letter.match( /[ABEH]/ ) ) {\n\t\treturn control === control_digit;\n\n\t// Control must be a letter\n\t} else if ( letter.match( /[KPQS]/ ) ) {\n\t\treturn control === control_letter;\n\t}\n\n\t// Can be either\n\treturn control === control_digit || control === control_letter;\n\n}, \"Please specify a valid CIF number.\" );\n\n/*\n * Brazillian CPF number (Cadastrado de Pessoas Físicas) is the equivalent of a Brazilian tax registration number.\n * CPF numbers have 11 digits in total: 9 numbers followed by 2 check numbers that are being used for validation.\n */\n$.validator.addMethod( \"cpfBR\", function( value ) {\n\n\t// Removing special characters from value\n\tvalue = value.replace( /([~!@#$%^&*()_+=`{}\\[\\]\\-|\\\\:;'<>,.\\/? ])+/g, \"\" );\n\n\t// Checking value to have 11 digits only\n\tif ( value.length !== 11 ) {\n\t\treturn false;\n\t}\n\n\tvar sum = 0,\n\t\tfirstCN, secondCN, checkResult, i;\n\n\tfirstCN = parseInt( value.substring( 9, 10 ), 10 );\n\tsecondCN = parseInt( value.substring( 10, 11 ), 10 );\n\n\tcheckResult = function( sum, cn ) {\n\t\tvar result = ( sum * 10 ) % 11;\n\t\tif ( ( result === 10 ) || ( result === 11 ) ) {\n\t\t\tresult = 0;\n\t\t}\n\t\treturn ( result === cn );\n\t};\n\n\t// Checking for dump data\n\tif ( value === \"\" ||\n\t\tvalue === \"00000000000\" ||\n\t\tvalue === \"11111111111\" ||\n\t\tvalue === \"22222222222\" ||\n\t\tvalue === \"33333333333\" ||\n\t\tvalue === \"44444444444\" ||\n\t\tvalue === \"55555555555\" ||\n\t\tvalue === \"66666666666\" ||\n\t\tvalue === \"77777777777\" ||\n\t\tvalue === \"88888888888\" ||\n\t\tvalue === \"99999999999\"\n\t) {\n\t\treturn false;\n\t}\n\n\t// Step 1 - using first Check Number:\n\tfor ( i = 1; i <= 9; i++ ) {\n\t\tsum = sum + parseInt( value.substring( i - 1, i ), 10 ) * ( 11 - i );\n\t}\n\n\t// If first Check Number (CN) is valid, move to Step 2 - using second Check Number:\n\tif ( checkResult( sum, firstCN ) ) {\n\t\tsum = 0;\n\t\tfor ( i = 1; i <= 10; i++ ) {\n\t\t\tsum = sum + parseInt( value.substring( i - 1, i ), 10 ) * ( 12 - i );\n\t\t}\n\t\treturn checkResult( sum, secondCN );\n\t}\n\treturn false;\n\n}, \"Please specify a valid CPF number\" );\n\n// https://jqueryvalidation.org/creditcard-method/\n// based on https://en.wikipedia.org/wiki/Luhn_algorithm\n$.validator.addMethod( \"creditcard\", function( value, element ) {\n\tif ( this.optional( element ) ) {\n\t\treturn \"dependency-mismatch\";\n\t}\n\n\t// Accept only spaces, digits and dashes\n\tif ( /[^0-9 \\-]+/.test( value ) ) {\n\t\treturn false;\n\t}\n\n\tvar nCheck = 0,\n\t\tnDigit = 0,\n\t\tbEven = false,\n\t\tn, cDigit;\n\n\tvalue = value.replace( /\\D/g, \"\" );\n\n\t// Basing min and max length on\n\t// https://developer.ean.com/general_info/Valid_Credit_Card_Types\n\tif ( value.length < 13 || value.length > 19 ) {\n\t\treturn false;\n\t}\n\n\tfor ( n = value.length - 1; n >= 0; n-- ) {\n\t\tcDigit = value.charAt( n );\n\t\tnDigit = parseInt( cDigit, 10 );\n\t\tif ( bEven ) {\n\t\t\tif ( ( nDigit *= 2 ) > 9 ) {\n\t\t\t\tnDigit -= 9;\n\t\t\t}\n\t\t}\n\n\t\tnCheck += nDigit;\n\t\tbEven = !bEven;\n\t}\n\n\treturn ( nCheck % 10 ) === 0;\n}, \"Please enter a valid credit card number.\" );\n\n/* NOTICE: Modified version of Castle.Components.Validator.CreditCardValidator\n * Redistributed under the the Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0\n * Valid Types: mastercard, visa, amex, dinersclub, enroute, discover, jcb, unknown, all (overrides all other settings)\n */\n$.validator.addMethod( \"creditcardtypes\", function( value, element, param ) {\n\tif ( /[^0-9\\-]+/.test( value ) ) {\n\t\treturn false;\n\t}\n\n\tvalue = value.replace( /\\D/g, \"\" );\n\n\tvar validTypes = 0x0000;\n\n\tif ( param.mastercard ) {\n\t\tvalidTypes |= 0x0001;\n\t}\n\tif ( param.visa ) {\n\t\tvalidTypes |= 0x0002;\n\t}\n\tif ( param.amex ) {\n\t\tvalidTypes |= 0x0004;\n\t}\n\tif ( param.dinersclub ) {\n\t\tvalidTypes |= 0x0008;\n\t}\n\tif ( param.enroute ) {\n\t\tvalidTypes |= 0x0010;\n\t}\n\tif ( param.discover ) {\n\t\tvalidTypes |= 0x0020;\n\t}\n\tif ( param.jcb ) {\n\t\tvalidTypes |= 0x0040;\n\t}\n\tif ( param.unknown ) {\n\t\tvalidTypes |= 0x0080;\n\t}\n\tif ( param.all ) {\n\t\tvalidTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;\n\t}\n\tif ( validTypes & 0x0001 && /^(5[12345])/.test( value ) ) { // Mastercard\n\t\treturn value.length === 16;\n\t}\n\tif ( validTypes & 0x0002 && /^(4)/.test( value ) ) { // Visa\n\t\treturn value.length === 16;\n\t}\n\tif ( validTypes & 0x0004 && /^(3[47])/.test( value ) ) { // Amex\n\t\treturn value.length === 15;\n\t}\n\tif ( validTypes & 0x0008 && /^(3(0[012345]|[68]))/.test( value ) ) { // Dinersclub\n\t\treturn value.length === 14;\n\t}\n\tif ( validTypes & 0x0010 && /^(2(014|149))/.test( value ) ) { // Enroute\n\t\treturn value.length === 15;\n\t}\n\tif ( validTypes & 0x0020 && /^(6011)/.test( value ) ) { // Discover\n\t\treturn value.length === 16;\n\t}\n\tif ( validTypes & 0x0040 && /^(3)/.test( value ) ) { // Jcb\n\t\treturn value.length === 16;\n\t}\n\tif ( validTypes & 0x0040 && /^(2131|1800)/.test( value ) ) { // Jcb\n\t\treturn value.length === 15;\n\t}\n\tif ( validTypes & 0x0080 ) { // Unknown\n\t\treturn true;\n\t}\n\treturn false;\n}, \"Please enter a valid credit card number.\" );\n\n/**\n * Validates currencies with any given symbols by @jameslouiz\n * Symbols can be optional or required. Symbols required by default\n *\n * Usage examples:\n *  currency: [\"£\", false] - Use false for soft currency validation\n *  currency: [\"$\", false]\n *  currency: [\"RM\", false] - also works with text based symbols such as \"RM\" - Malaysia Ringgit etc\n *\n *  <input class=\"currencyInput\" name=\"currencyInput\">\n *\n * Soft symbol checking\n *  currencyInput: {\n *     currency: [\"$\", false]\n *  }\n *\n * Strict symbol checking (default)\n *  currencyInput: {\n *     currency: \"$\"\n *     //OR\n *     currency: [\"$\", true]\n *  }\n *\n * Multiple Symbols\n *  currencyInput: {\n *     currency: \"$,£,¢\"\n *  }\n */\n$.validator.addMethod( \"currency\", function( value, element, param ) {\n    var isParamString = typeof param === \"string\",\n        symbol = isParamString ? param : param[ 0 ],\n        soft = isParamString ? true : param[ 1 ],\n        regex;\n\n    symbol = symbol.replace( /,/g, \"\" );\n    symbol = soft ? symbol + \"]\" : symbol + \"]?\";\n    regex = \"^[\" + symbol + \"([1-9]{1}[0-9]{0,2}(\\\\,[0-9]{3})*(\\\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\\\.[0-9]{0,2})?|0(\\\\.[0-9]{0,2})?|(\\\\.[0-9]{1,2})?)$\";\n    regex = new RegExp( regex );\n    return this.optional( element ) || regex.test( value );\n\n}, \"Please specify a valid currency\" );\n\n$.validator.addMethod( \"dateFA\", function( value, element ) {\n\treturn this.optional( element ) || /^[1-4]\\d{3}\\/((0?[1-6]\\/((3[0-1])|([1-2][0-9])|(0?[1-9])))|((1[0-2]|(0?[7-9]))\\/(30|([1-2][0-9])|(0?[1-9]))))$/.test( value );\n}, $.validator.messages.date );\n\n/**\n * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.\n *\n * @example $.validator.methods.date(\"01/01/1900\")\n * @result true\n *\n * @example $.validator.methods.date(\"01/13/1990\")\n * @result false\n *\n * @example $.validator.methods.date(\"01.01.1900\")\n * @result false\n *\n * @example <input name=\"pippo\" class=\"{dateITA:true}\" />\n * @desc Declares an optional input element whose value must be a valid date.\n *\n * @name $.validator.methods.dateITA\n * @type Boolean\n * @cat Plugins/Validate/Methods\n */\n$.validator.addMethod( \"dateITA\", function( value, element ) {\n\tvar check = false,\n\t\tre = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/,\n\t\tadata, gg, mm, aaaa, xdata;\n\tif ( re.test( value ) ) {\n\t\tadata = value.split( \"/\" );\n\t\tgg = parseInt( adata[ 0 ], 10 );\n\t\tmm = parseInt( adata[ 1 ], 10 );\n\t\taaaa = parseInt( adata[ 2 ], 10 );\n\t\txdata = new Date( Date.UTC( aaaa, mm - 1, gg, 12, 0, 0, 0 ) );\n\t\tif ( ( xdata.getUTCFullYear() === aaaa ) && ( xdata.getUTCMonth() === mm - 1 ) && ( xdata.getUTCDate() === gg ) ) {\n\t\t\tcheck = true;\n\t\t} else {\n\t\t\tcheck = false;\n\t\t}\n\t} else {\n\t\tcheck = false;\n\t}\n\treturn this.optional( element ) || check;\n}, $.validator.messages.date );\n\n$.validator.addMethod( \"dateNL\", function( value, element ) {\n\treturn this.optional( element ) || /^(0?[1-9]|[12]\\d|3[01])[\\.\\/\\-](0?[1-9]|1[012])[\\.\\/\\-]([12]\\d)?(\\d\\d)$/.test( value );\n}, $.validator.messages.date );\n\n// Older \"accept\" file extension method. Old docs: http://docs.jquery.com/Plugins/Validation/Methods/accept\n$.validator.addMethod( \"extension\", function( value, element, param ) {\n\tparam = typeof param === \"string\" ? param.replace( /,/g, \"|\" ) : \"png|jpe?g|gif\";\n\treturn this.optional( element ) || value.match( new RegExp( \"\\\\.(\" + param + \")$\", \"i\" ) );\n}, $.validator.format( \"Please enter a value with a valid extension.\" ) );\n\n/**\n * Dutch giro account numbers (not bank numbers) have max 7 digits\n */\n$.validator.addMethod( \"giroaccountNL\", function( value, element ) {\n\treturn this.optional( element ) || /^[0-9]{1,7}$/.test( value );\n}, \"Please specify a valid giro account number\" );\n\n/**\n * IBAN is the international bank account number.\n * It has a country - specific format, that is checked here too\n *\n * Validation is case-insensitive. Please make sure to normalize input yourself.\n */\n$.validator.addMethod( \"iban\", function( value, element ) {\n\n\t// Some quick simple tests to prevent needless work\n\tif ( this.optional( element ) ) {\n\t\treturn true;\n\t}\n\n\t// Remove spaces and to upper case\n\tvar iban = value.replace( / /g, \"\" ).toUpperCase(),\n\t\tibancheckdigits = \"\",\n\t\tleadingZeroes = true,\n\t\tcRest = \"\",\n\t\tcOperator = \"\",\n\t\tcountrycode, ibancheck, charAt, cChar, bbanpattern, bbancountrypatterns, ibanregexp, i, p;\n\n\t// Check for IBAN code length.\n\t// It contains:\n\t// country code ISO 3166-1 - two letters,\n\t// two check digits,\n\t// Basic Bank Account Number (BBAN) - up to 30 chars\n\tvar minimalIBANlength = 5;\n\tif ( iban.length < minimalIBANlength ) {\n\t\treturn false;\n\t}\n\n\t// Check the country code and find the country specific format\n\tcountrycode = iban.substring( 0, 2 );\n\tbbancountrypatterns = {\n\t\t\"AL\": \"\\\\d{8}[\\\\dA-Z]{16}\",\n\t\t\"AD\": \"\\\\d{8}[\\\\dA-Z]{12}\",\n\t\t\"AT\": \"\\\\d{16}\",\n\t\t\"AZ\": \"[\\\\dA-Z]{4}\\\\d{20}\",\n\t\t\"BE\": \"\\\\d{12}\",\n\t\t\"BH\": \"[A-Z]{4}[\\\\dA-Z]{14}\",\n\t\t\"BA\": \"\\\\d{16}\",\n\t\t\"BR\": \"\\\\d{23}[A-Z][\\\\dA-Z]\",\n\t\t\"BG\": \"[A-Z]{4}\\\\d{6}[\\\\dA-Z]{8}\",\n\t\t\"CR\": \"\\\\d{17}\",\n\t\t\"HR\": \"\\\\d{17}\",\n\t\t\"CY\": \"\\\\d{8}[\\\\dA-Z]{16}\",\n\t\t\"CZ\": \"\\\\d{20}\",\n\t\t\"DK\": \"\\\\d{14}\",\n\t\t\"DO\": \"[A-Z]{4}\\\\d{20}\",\n\t\t\"EE\": \"\\\\d{16}\",\n\t\t\"FO\": \"\\\\d{14}\",\n\t\t\"FI\": \"\\\\d{14}\",\n\t\t\"FR\": \"\\\\d{10}[\\\\dA-Z]{11}\\\\d{2}\",\n\t\t\"GE\": \"[\\\\dA-Z]{2}\\\\d{16}\",\n\t\t\"DE\": \"\\\\d{18}\",\n\t\t\"GI\": \"[A-Z]{4}[\\\\dA-Z]{15}\",\n\t\t\"GR\": \"\\\\d{7}[\\\\dA-Z]{16}\",\n\t\t\"GL\": \"\\\\d{14}\",\n\t\t\"GT\": \"[\\\\dA-Z]{4}[\\\\dA-Z]{20}\",\n\t\t\"HU\": \"\\\\d{24}\",\n\t\t\"IS\": \"\\\\d{22}\",\n\t\t\"IE\": \"[\\\\dA-Z]{4}\\\\d{14}\",\n\t\t\"IL\": \"\\\\d{19}\",\n\t\t\"IT\": \"[A-Z]\\\\d{10}[\\\\dA-Z]{12}\",\n\t\t\"KZ\": \"\\\\d{3}[\\\\dA-Z]{13}\",\n\t\t\"KW\": \"[A-Z]{4}[\\\\dA-Z]{22}\",\n\t\t\"LV\": \"[A-Z]{4}[\\\\dA-Z]{13}\",\n\t\t\"LB\": \"\\\\d{4}[\\\\dA-Z]{20}\",\n\t\t\"LI\": \"\\\\d{5}[\\\\dA-Z]{12}\",\n\t\t\"LT\": \"\\\\d{16}\",\n\t\t\"LU\": \"\\\\d{3}[\\\\dA-Z]{13}\",\n\t\t\"MK\": \"\\\\d{3}[\\\\dA-Z]{10}\\\\d{2}\",\n\t\t\"MT\": \"[A-Z]{4}\\\\d{5}[\\\\dA-Z]{18}\",\n\t\t\"MR\": \"\\\\d{23}\",\n\t\t\"MU\": \"[A-Z]{4}\\\\d{19}[A-Z]{3}\",\n\t\t\"MC\": \"\\\\d{10}[\\\\dA-Z]{11}\\\\d{2}\",\n\t\t\"MD\": \"[\\\\dA-Z]{2}\\\\d{18}\",\n\t\t\"ME\": \"\\\\d{18}\",\n\t\t\"NL\": \"[A-Z]{4}\\\\d{10}\",\n\t\t\"NO\": \"\\\\d{11}\",\n\t\t\"PK\": \"[\\\\dA-Z]{4}\\\\d{16}\",\n\t\t\"PS\": \"[\\\\dA-Z]{4}\\\\d{21}\",\n\t\t\"PL\": \"\\\\d{24}\",\n\t\t\"PT\": \"\\\\d{21}\",\n\t\t\"RO\": \"[A-Z]{4}[\\\\dA-Z]{16}\",\n\t\t\"SM\": \"[A-Z]\\\\d{10}[\\\\dA-Z]{12}\",\n\t\t\"SA\": \"\\\\d{2}[\\\\dA-Z]{18}\",\n\t\t\"RS\": \"\\\\d{18}\",\n\t\t\"SK\": \"\\\\d{20}\",\n\t\t\"SI\": \"\\\\d{15}\",\n\t\t\"ES\": \"\\\\d{20}\",\n\t\t\"SE\": \"\\\\d{20}\",\n\t\t\"CH\": \"\\\\d{5}[\\\\dA-Z]{12}\",\n\t\t\"TN\": \"\\\\d{20}\",\n\t\t\"TR\": \"\\\\d{5}[\\\\dA-Z]{17}\",\n\t\t\"AE\": \"\\\\d{3}\\\\d{16}\",\n\t\t\"GB\": \"[A-Z]{4}\\\\d{14}\",\n\t\t\"VG\": \"[\\\\dA-Z]{4}\\\\d{16}\"\n\t};\n\n\tbbanpattern = bbancountrypatterns[ countrycode ];\n\n\t// As new countries will start using IBAN in the\n\t// future, we only check if the countrycode is known.\n\t// This prevents false negatives, while almost all\n\t// false positives introduced by this, will be caught\n\t// by the checksum validation below anyway.\n\t// Strict checking should return FALSE for unknown\n\t// countries.\n\tif ( typeof bbanpattern !== \"undefined\" ) {\n\t\tibanregexp = new RegExp( \"^[A-Z]{2}\\\\d{2}\" + bbanpattern + \"$\", \"\" );\n\t\tif ( !( ibanregexp.test( iban ) ) ) {\n\t\t\treturn false; // Invalid country specific format\n\t\t}\n\t}\n\n\t// Now check the checksum, first convert to digits\n\tibancheck = iban.substring( 4, iban.length ) + iban.substring( 0, 4 );\n\tfor ( i = 0; i < ibancheck.length; i++ ) {\n\t\tcharAt = ibancheck.charAt( i );\n\t\tif ( charAt !== \"0\" ) {\n\t\t\tleadingZeroes = false;\n\t\t}\n\t\tif ( !leadingZeroes ) {\n\t\t\tibancheckdigits += \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\".indexOf( charAt );\n\t\t}\n\t}\n\n\t// Calculate the result of: ibancheckdigits % 97\n\tfor ( p = 0; p < ibancheckdigits.length; p++ ) {\n\t\tcChar = ibancheckdigits.charAt( p );\n\t\tcOperator = \"\" + cRest + \"\" + cChar;\n\t\tcRest = cOperator % 97;\n\t}\n\treturn cRest === 1;\n}, \"Please specify a valid IBAN\" );\n\n$.validator.addMethod( \"integer\", function( value, element ) {\n\treturn this.optional( element ) || /^-?\\d+$/.test( value );\n}, \"A positive or negative non-decimal number please\" );\n\n$.validator.addMethod( \"ipv4\", function( value, element ) {\n\treturn this.optional( element ) || /^(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$/i.test( value );\n}, \"Please enter a valid IP v4 address.\" );\n\n$.validator.addMethod( \"ipv6\", function( value, element ) {\n\treturn this.optional( element ) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test( value );\n}, \"Please enter a valid IP v6 address.\" );\n\n$.validator.addMethod( \"lettersonly\", function( value, element ) {\n\treturn this.optional( element ) || /^[a-z]+$/i.test( value );\n}, \"Letters only please\" );\n\n$.validator.addMethod( \"letterswithbasicpunc\", function( value, element ) {\n\treturn this.optional( element ) || /^[a-z\\-.,()'\"\\s]+$/i.test( value );\n}, \"Letters or punctuation only please\" );\n\n$.validator.addMethod( \"mobileNL\", function( value, element ) {\n\treturn this.optional( element ) || /^((\\+|00(\\s|\\s?\\-\\s?)?)31(\\s|\\s?\\-\\s?)?(\\(0\\)[\\-\\s]?)?|0)6((\\s|\\s?\\-\\s?)?[0-9]){8}$/.test( value );\n}, \"Please specify a valid mobile number\" );\n\n/* For UK phone functions, do the following server side processing:\n * Compare original input with this RegEx pattern:\n * ^\\(?(?:(?:00\\)?[\\s\\-]?\\(?|\\+)(44)\\)?[\\s\\-]?\\(?(?:0\\)?[\\s\\-]?\\(?)?|0)([1-9]\\d{1,4}\\)?[\\s\\d\\-]+)$\n * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'\n * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.\n * A number of very detailed GB telephone number RegEx patterns can also be found at:\n * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers\n */\n$.validator.addMethod( \"mobileUK\", function( phone_number, element ) {\n\tphone_number = phone_number.replace( /\\(|\\)|\\s+|-/g, \"\" );\n\treturn this.optional( element ) || phone_number.length > 9 &&\n\t\tphone_number.match( /^(?:(?:(?:00\\s?|\\+)44\\s?|0)7(?:[1345789]\\d{2}|624)\\s?\\d{3}\\s?\\d{3})$/ );\n}, \"Please specify a valid mobile number\" );\n\n$.validator.addMethod( \"netmask\", function( value, element ) {\n    return this.optional( element ) || /^(254|252|248|240|224|192|128)\\.0\\.0\\.0|255\\.(254|252|248|240|224|192|128|0)\\.0\\.0|255\\.255\\.(254|252|248|240|224|192|128|0)\\.0|255\\.255\\.255\\.(254|252|248|240|224|192|128|0)/i.test( value );\n}, \"Please enter a valid netmask.\" );\n\n/*\n * The NIE (Número de Identificación de Extranjero) is a Spanish tax identification number assigned by the Spanish\n * authorities to any foreigner.\n *\n * The NIE is the equivalent of a Spaniards Número de Identificación Fiscal (NIF) which serves as a fiscal\n * identification number. The CIF number (Certificado de Identificación Fiscal) is equivalent to the NIF, but applies to\n * companies rather than individuals. The NIE consists of an 'X' or 'Y' followed by 7 or 8 digits then another letter.\n */\n$.validator.addMethod( \"nieES\", function( value, element ) {\n\t\"use strict\";\n\n\tif ( this.optional( element ) ) {\n\t\treturn true;\n\t}\n\n\tvar nieRegEx = new RegExp( /^[MXYZ]{1}[0-9]{7,8}[TRWAGMYFPDXBNJZSQVHLCKET]{1}$/gi );\n\tvar validChars = \"TRWAGMYFPDXBNJZSQVHLCKET\",\n\t\tletter = value.substr( value.length - 1 ).toUpperCase(),\n\t\tnumber;\n\n\tvalue = value.toString().toUpperCase();\n\n\t// Quick format test\n\tif ( value.length > 10 || value.length < 9 || !nieRegEx.test( value ) ) {\n\t\treturn false;\n\t}\n\n\t// X means same number\n\t// Y means number + 10000000\n\t// Z means number + 20000000\n\tvalue = value.replace( /^[X]/, \"0\" )\n\t\t.replace( /^[Y]/, \"1\" )\n\t\t.replace( /^[Z]/, \"2\" );\n\n\tnumber = value.length === 9 ? value.substr( 0, 8 ) : value.substr( 0, 9 );\n\n\treturn validChars.charAt( parseInt( number, 10 ) % 23 ) === letter;\n\n}, \"Please specify a valid NIE number.\" );\n\n/*\n * The Número de Identificación Fiscal ( NIF ) is the way tax identification used in Spain for individuals\n */\n$.validator.addMethod( \"nifES\", function( value, element ) {\n\t\"use strict\";\n\n\tif ( this.optional( element ) ) {\n\t\treturn true;\n\t}\n\n\tvalue = value.toUpperCase();\n\n\t// Basic format test\n\tif ( !value.match( \"((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)\" ) ) {\n\t\treturn false;\n\t}\n\n\t// Test NIF\n\tif ( /^[0-9]{8}[A-Z]{1}$/.test( value ) ) {\n\t\treturn ( \"TRWAGMYFPDXBNJZSQVHLCKE\".charAt( value.substring( 8, 0 ) % 23 ) === value.charAt( 8 ) );\n\t}\n\n\t// Test specials NIF (starts with K, L or M)\n\tif ( /^[KLM]{1}/.test( value ) ) {\n\t\treturn ( value[ 8 ] === \"TRWAGMYFPDXBNJZSQVHLCKE\".charAt( value.substring( 8, 1 ) % 23 ) );\n\t}\n\n\treturn false;\n\n}, \"Please specify a valid NIF number.\" );\n\n/*\n * Numer identyfikacji podatkowej ( NIP ) is the way tax identification used in Poland for companies\n */\n$.validator.addMethod( \"nipPL\", function( value ) {\n\t\"use strict\";\n\n\tvalue = value.replace( /[^0-9]/g, \"\" );\n\n\tif ( value.length !== 10 ) {\n\t\treturn false;\n\t}\n\n\tvar arrSteps = [ 6, 5, 7, 2, 3, 4, 5, 6, 7 ];\n\tvar intSum = 0;\n\tfor ( var i = 0; i < 9; i++ ) {\n\t\tintSum += arrSteps[ i ] * value[ i ];\n\t}\n\tvar int2 = intSum % 11;\n\tvar intControlNr = ( int2 === 10 ) ? 0 : int2;\n\n\treturn ( intControlNr === parseInt( value[ 9 ], 10 ) );\n}, \"Please specify a valid NIP number.\" );\n\n$.validator.addMethod( \"notEqualTo\", function( value, element, param ) {\n\treturn this.optional( element ) || !$.validator.methods.equalTo.call( this, value, element, param );\n}, \"Please enter a different value, values must not be the same.\" );\n\n$.validator.addMethod( \"nowhitespace\", function( value, element ) {\n\treturn this.optional( element ) || /^\\S+$/i.test( value );\n}, \"No white space please\" );\n\n/**\n* Return true if the field value matches the given format RegExp\n*\n* @example $.validator.methods.pattern(\"AR1004\",element,/^AR\\d{4}$/)\n* @result true\n*\n* @example $.validator.methods.pattern(\"BR1004\",element,/^AR\\d{4}$/)\n* @result false\n*\n* @name $.validator.methods.pattern\n* @type Boolean\n* @cat Plugins/Validate/Methods\n*/\n$.validator.addMethod( \"pattern\", function( value, element, param ) {\n\tif ( this.optional( element ) ) {\n\t\treturn true;\n\t}\n\tif ( typeof param === \"string\" ) {\n\t\tparam = new RegExp( \"^(?:\" + param + \")$\" );\n\t}\n\treturn param.test( value );\n}, \"Invalid format.\" );\n\n/**\n * Dutch phone numbers have 10 digits (or 11 and start with +31).\n */\n$.validator.addMethod( \"phoneNL\", function( value, element ) {\n\treturn this.optional( element ) || /^((\\+|00(\\s|\\s?\\-\\s?)?)31(\\s|\\s?\\-\\s?)?(\\(0\\)[\\-\\s]?)?|0)[1-9]((\\s|\\s?\\-\\s?)?[0-9]){8}$/.test( value );\n}, \"Please specify a valid phone number.\" );\n\n/* For UK phone functions, do the following server side processing:\n * Compare original input with this RegEx pattern:\n * ^\\(?(?:(?:00\\)?[\\s\\-]?\\(?|\\+)(44)\\)?[\\s\\-]?\\(?(?:0\\)?[\\s\\-]?\\(?)?|0)([1-9]\\d{1,4}\\)?[\\s\\d\\-]+)$\n * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'\n * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.\n * A number of very detailed GB telephone number RegEx patterns can also be found at:\n * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers\n */\n\n// Matches UK landline + mobile, accepting only 01-3 for landline or 07 for mobile to exclude many premium numbers\n$.validator.addMethod( \"phonesUK\", function( phone_number, element ) {\n\tphone_number = phone_number.replace( /\\(|\\)|\\s+|-/g, \"\" );\n\treturn this.optional( element ) || phone_number.length > 9 &&\n\t\tphone_number.match( /^(?:(?:(?:00\\s?|\\+)44\\s?|0)(?:1\\d{8,9}|[23]\\d{9}|7(?:[1345789]\\d{8}|624\\d{6})))$/ );\n}, \"Please specify a valid uk phone number\" );\n\n/* For UK phone functions, do the following server side processing:\n * Compare original input with this RegEx pattern:\n * ^\\(?(?:(?:00\\)?[\\s\\-]?\\(?|\\+)(44)\\)?[\\s\\-]?\\(?(?:0\\)?[\\s\\-]?\\(?)?|0)([1-9]\\d{1,4}\\)?[\\s\\d\\-]+)$\n * Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'\n * Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.\n * A number of very detailed GB telephone number RegEx patterns can also be found at:\n * http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers\n */\n$.validator.addMethod( \"phoneUK\", function( phone_number, element ) {\n\tphone_number = phone_number.replace( /\\(|\\)|\\s+|-/g, \"\" );\n\treturn this.optional( element ) || phone_number.length > 9 &&\n\t\tphone_number.match( /^(?:(?:(?:00\\s?|\\+)44\\s?)|(?:\\(?0))(?:\\d{2}\\)?\\s?\\d{4}\\s?\\d{4}|\\d{3}\\)?\\s?\\d{3}\\s?\\d{3,4}|\\d{4}\\)?\\s?(?:\\d{5}|\\d{3}\\s?\\d{3})|\\d{5}\\)?\\s?\\d{4,5})$/ );\n}, \"Please specify a valid phone number\" );\n\n/**\n * Matches US phone number format\n *\n * where the area code may not start with 1 and the prefix may not start with 1\n * allows '-' or ' ' as a separator and allows parens around area code\n * some people may want to put a '1' in front of their number\n *\n * 1(212)-999-2345 or\n * 212 999 2344 or\n * 212-999-0983\n *\n * but not\n * 111-123-5434\n * and not\n * 212 123 4567\n */\n$.validator.addMethod( \"phoneUS\", function( phone_number, element ) {\n\tphone_number = phone_number.replace( /\\s+/g, \"\" );\n\treturn this.optional( element ) || phone_number.length > 9 &&\n\t\tphone_number.match( /^(\\+?1-?)?(\\([2-9]([02-9]\\d|1[02-9])\\)|[2-9]([02-9]\\d|1[02-9]))-?[2-9]([02-9]\\d|1[02-9])-?\\d{4}$/ );\n}, \"Please specify a valid phone number\" );\n\n/*\n* Valida CEPs do brasileiros:\n*\n* Formatos aceitos:\n* 99999-999\n* 99.999-999\n* 99999999\n*/\n$.validator.addMethod( \"postalcodeBR\", function( cep_value, element ) {\n\treturn this.optional( element ) || /^\\d{2}.\\d{3}-\\d{3}?$|^\\d{5}-?\\d{3}?$/.test( cep_value );\n}, \"Informe um CEP válido.\" );\n\n/**\n * Matches a valid Canadian Postal Code\n *\n * @example jQuery.validator.methods.postalCodeCA( \"H0H 0H0\", element )\n * @result true\n *\n * @example jQuery.validator.methods.postalCodeCA( \"H0H0H0\", element )\n * @result false\n *\n * @name jQuery.validator.methods.postalCodeCA\n * @type Boolean\n * @cat Plugins/Validate/Methods\n */\n$.validator.addMethod( \"postalCodeCA\", function( value, element ) {\n\treturn this.optional( element ) || /^[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJKLMNPRSTVWXYZ] *\\d[ABCEGHJKLMNPRSTVWXYZ]\\d$/i.test( value );\n}, \"Please specify a valid postal code\" );\n\n/* Matches Italian postcode (CAP) */\n$.validator.addMethod( \"postalcodeIT\", function( value, element ) {\n\treturn this.optional( element ) || /^\\d{5}$/.test( value );\n}, \"Please specify a valid postal code\" );\n\n$.validator.addMethod( \"postalcodeNL\", function( value, element ) {\n\treturn this.optional( element ) || /^[1-9][0-9]{3}\\s?[a-zA-Z]{2}$/.test( value );\n}, \"Please specify a valid postal code\" );\n\n// Matches UK postcode. Does not match to UK Channel Islands that have their own postcodes (non standard UK)\n$.validator.addMethod( \"postcodeUK\", function( value, element ) {\n\treturn this.optional( element ) || /^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\\s?(0AA))$/i.test( value );\n}, \"Please specify a valid UK postcode\" );\n\n/*\n * Lets you say \"at least X inputs that match selector Y must be filled.\"\n *\n * The end result is that neither of these inputs:\n *\n *\t<input class=\"productinfo\" name=\"partnumber\">\n *\t<input class=\"productinfo\" name=\"description\">\n *\n *\t...will validate unless at least one of them is filled.\n *\n * partnumber:\t{require_from_group: [1,\".productinfo\"]},\n * description: {require_from_group: [1,\".productinfo\"]}\n *\n * options[0]: number of fields that must be filled in the group\n * options[1]: CSS selector that defines the group of conditionally required fields\n */\n$.validator.addMethod( \"require_from_group\", function( value, element, options ) {\n\tvar $fields = $( options[ 1 ], element.form ),\n\t\t$fieldsFirst = $fields.eq( 0 ),\n\t\tvalidator = $fieldsFirst.data( \"valid_req_grp\" ) ? $fieldsFirst.data( \"valid_req_grp\" ) : $.extend( {}, this ),\n\t\tisValid = $fields.filter( function() {\n\t\t\treturn validator.elementValue( this );\n\t\t} ).length >= options[ 0 ];\n\n\t// Store the cloned validator for future validation\n\t$fieldsFirst.data( \"valid_req_grp\", validator );\n\n\t// If element isn't being validated, run each require_from_group field's validation rules\n\tif ( !$( element ).data( \"being_validated\" ) ) {\n\t\t$fields.data( \"being_validated\", true );\n\t\t$fields.each( function() {\n\t\t\tvalidator.element( this );\n\t\t} );\n\t\t$fields.data( \"being_validated\", false );\n\t}\n\treturn isValid;\n}, $.validator.format( \"Please fill at least {0} of these fields.\" ) );\n\n/*\n * Lets you say \"either at least X inputs that match selector Y must be filled,\n * OR they must all be skipped (left blank).\"\n *\n * The end result, is that none of these inputs:\n *\n *\t<input class=\"productinfo\" name=\"partnumber\">\n *\t<input class=\"productinfo\" name=\"description\">\n *\t<input class=\"productinfo\" name=\"color\">\n *\n *\t...will validate unless either at least two of them are filled,\n *\tOR none of them are.\n *\n * partnumber:\t{skip_or_fill_minimum: [2,\".productinfo\"]},\n * description: {skip_or_fill_minimum: [2,\".productinfo\"]},\n * color:\t\t{skip_or_fill_minimum: [2,\".productinfo\"]}\n *\n * options[0]: number of fields that must be filled in the group\n * options[1]: CSS selector that defines the group of conditionally required fields\n *\n */\n$.validator.addMethod( \"skip_or_fill_minimum\", function( value, element, options ) {\n\tvar $fields = $( options[ 1 ], element.form ),\n\t\t$fieldsFirst = $fields.eq( 0 ),\n\t\tvalidator = $fieldsFirst.data( \"valid_skip\" ) ? $fieldsFirst.data( \"valid_skip\" ) : $.extend( {}, this ),\n\t\tnumberFilled = $fields.filter( function() {\n\t\t\treturn validator.elementValue( this );\n\t\t} ).length,\n\t\tisValid = numberFilled === 0 || numberFilled >= options[ 0 ];\n\n\t// Store the cloned validator for future validation\n\t$fieldsFirst.data( \"valid_skip\", validator );\n\n\t// If element isn't being validated, run each skip_or_fill_minimum field's validation rules\n\tif ( !$( element ).data( \"being_validated\" ) ) {\n\t\t$fields.data( \"being_validated\", true );\n\t\t$fields.each( function() {\n\t\t\tvalidator.element( this );\n\t\t} );\n\t\t$fields.data( \"being_validated\", false );\n\t}\n\treturn isValid;\n}, $.validator.format( \"Please either skip these fields or fill at least {0} of them.\" ) );\n\n/* Validates US States and/or Territories by @jdforsythe\n * Can be case insensitive or require capitalization - default is case insensitive\n * Can include US Territories or not - default does not\n * Can include US Military postal abbreviations (AA, AE, AP) - default does not\n *\n * Note: \"States\" always includes DC (District of Colombia)\n *\n * Usage examples:\n *\n *  This is the default - case insensitive, no territories, no military zones\n *  stateInput: {\n *     caseSensitive: false,\n *     includeTerritories: false,\n *     includeMilitary: false\n *  }\n *\n *  Only allow capital letters, no territories, no military zones\n *  stateInput: {\n *     caseSensitive: false\n *  }\n *\n *  Case insensitive, include territories but not military zones\n *  stateInput: {\n *     includeTerritories: true\n *  }\n *\n *  Only allow capital letters, include territories and military zones\n *  stateInput: {\n *     caseSensitive: true,\n *     includeTerritories: true,\n *     includeMilitary: true\n *  }\n *\n */\n$.validator.addMethod( \"stateUS\", function( value, element, options ) {\n\tvar isDefault = typeof options === \"undefined\",\n\t\tcaseSensitive = ( isDefault || typeof options.caseSensitive === \"undefined\" ) ? false : options.caseSensitive,\n\t\tincludeTerritories = ( isDefault || typeof options.includeTerritories === \"undefined\" ) ? false : options.includeTerritories,\n\t\tincludeMilitary = ( isDefault || typeof options.includeMilitary === \"undefined\" ) ? false : options.includeMilitary,\n\t\tregex;\n\n\tif ( !includeTerritories && !includeMilitary ) {\n\t\tregex = \"^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$\";\n\t} else if ( includeTerritories && includeMilitary ) {\n\t\tregex = \"^(A[AEKLPRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$\";\n\t} else if ( includeTerritories ) {\n\t\tregex = \"^(A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$\";\n\t} else {\n\t\tregex = \"^(A[AEKLPRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$\";\n\t}\n\n\tregex = caseSensitive ? new RegExp( regex ) : new RegExp( regex, \"i\" );\n\treturn this.optional( element ) || regex.test( value );\n}, \"Please specify a valid state\" );\n\n// TODO check if value starts with <, otherwise don't try stripping anything\n$.validator.addMethod( \"strippedminlength\", function( value, element, param ) {\n\treturn $( value ).text().length >= param;\n}, $.validator.format( \"Please enter at least {0} characters\" ) );\n\n$.validator.addMethod( \"time\", function( value, element ) {\n\treturn this.optional( element ) || /^([01]\\d|2[0-3]|[0-9])(:[0-5]\\d){1,2}$/.test( value );\n}, \"Please enter a valid time, between 00:00 and 23:59\" );\n\n$.validator.addMethod( \"time12h\", function( value, element ) {\n\treturn this.optional( element ) || /^((0?[1-9]|1[012])(:[0-5]\\d){1,2}(\\ ?[AP]M))$/i.test( value );\n}, \"Please enter a valid time in 12-hour am/pm format\" );\n\n// Same as url, but TLD is optional\n$.validator.addMethod( \"url2\", function( value, element ) {\n\treturn this.optional( element ) || /^(https?|ftp):\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.test( value );\n}, $.validator.messages.url );\n\n/**\n * Return true, if the value is a valid vehicle identification number (VIN).\n *\n * Works with all kind of text inputs.\n *\n * @example <input type=\"text\" size=\"20\" name=\"VehicleID\" class=\"{required:true,vinUS:true}\" />\n * @desc Declares a required input element whose value must be a valid vehicle identification number.\n *\n * @name $.validator.methods.vinUS\n * @type Boolean\n * @cat Plugins/Validate/Methods\n */\n$.validator.addMethod( \"vinUS\", function( v ) {\n\tif ( v.length !== 17 ) {\n\t\treturn false;\n\t}\n\n\tvar LL = [ \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"J\", \"K\", \"L\", \"M\", \"N\", \"P\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\" ],\n\t\tVL = [ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9 ],\n\t\tFL = [ 8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2 ],\n\t\trs = 0,\n\t\ti, n, d, f, cd, cdv;\n\n\tfor ( i = 0; i < 17; i++ ) {\n\t\tf = FL[ i ];\n\t\td = v.slice( i, i + 1 );\n\t\tif ( i === 8 ) {\n\t\t\tcdv = d;\n\t\t}\n\t\tif ( !isNaN( d ) ) {\n\t\t\td *= f;\n\t\t} else {\n\t\t\tfor ( n = 0; n < LL.length; n++ ) {\n\t\t\t\tif ( d.toUpperCase() === LL[ n ] ) {\n\t\t\t\t\td = VL[ n ];\n\t\t\t\t\td *= f;\n\t\t\t\t\tif ( isNaN( cdv ) && n === 8 ) {\n\t\t\t\t\t\tcdv = LL[ n ];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trs += d;\n\t}\n\tcd = rs % 11;\n\tif ( cd === 10 ) {\n\t\tcd = \"X\";\n\t}\n\tif ( cd === cdv ) {\n\t\treturn true;\n\t}\n\treturn false;\n}, \"The specified vehicle identification number (VIN) is invalid.\" );\n\n$.validator.addMethod( \"zipcodeUS\", function( value, element ) {\n\treturn this.optional( element ) || /^\\d{5}(-\\d{4})?$/.test( value );\n}, \"The specified US ZIP Code is invalid\" );\n\n$.validator.addMethod( \"ziprange\", function( value, element ) {\n\treturn this.optional( element ) || /^90[2-5]\\d\\{2\\}-\\d{4}$/.test( value );\n}, \"Your ZIP-code must be in the range 902xx-xxxx to 905xx-xxxx\" );\nreturn $;\n}));"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/jquery-validation/dist/jquery.validate.js",
    "content": "/*!\n * jQuery Validation Plugin v1.17.0\n *\n * https://jqueryvalidation.org/\n *\n * Copyright (c) 2017 Jörn Zaefferer\n * Released under the MIT license\n */\n(function( factory ) {\n\tif ( typeof define === \"function\" && define.amd ) {\n\t\tdefine( [\"jquery\"], factory );\n\t} else if (typeof module === \"object\" && module.exports) {\n\t\tmodule.exports = factory( require( \"jquery\" ) );\n\t} else {\n\t\tfactory( jQuery );\n\t}\n}(function( $ ) {\n\n$.extend( $.fn, {\n\n\t// https://jqueryvalidation.org/validate/\n\tvalidate: function( options ) {\n\n\t\t// If nothing is selected, return nothing; can't chain anyway\n\t\tif ( !this.length ) {\n\t\t\tif ( options && options.debug && window.console ) {\n\t\t\t\tconsole.warn( \"Nothing selected, can't validate, returning nothing.\" );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if a validator for this form was already created\n\t\tvar validator = $.data( this[ 0 ], \"validator\" );\n\t\tif ( validator ) {\n\t\t\treturn validator;\n\t\t}\n\n\t\t// Add novalidate tag if HTML5.\n\t\tthis.attr( \"novalidate\", \"novalidate\" );\n\n\t\tvalidator = new $.validator( options, this[ 0 ] );\n\t\t$.data( this[ 0 ], \"validator\", validator );\n\n\t\tif ( validator.settings.onsubmit ) {\n\n\t\t\tthis.on( \"click.validate\", \":submit\", function( event ) {\n\n\t\t\t\t// Track the used submit button to properly handle scripted\n\t\t\t\t// submits later.\n\t\t\t\tvalidator.submitButton = event.currentTarget;\n\n\t\t\t\t// Allow suppressing validation by adding a cancel class to the submit button\n\t\t\t\tif ( $( this ).hasClass( \"cancel\" ) ) {\n\t\t\t\t\tvalidator.cancelSubmit = true;\n\t\t\t\t}\n\n\t\t\t\t// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button\n\t\t\t\tif ( $( this ).attr( \"formnovalidate\" ) !== undefined ) {\n\t\t\t\t\tvalidator.cancelSubmit = true;\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\t// Validate the form on submit\n\t\t\tthis.on( \"submit.validate\", function( event ) {\n\t\t\t\tif ( validator.settings.debug ) {\n\n\t\t\t\t\t// Prevent form submit to be able to see console output\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t\tfunction handle() {\n\t\t\t\t\tvar hidden, result;\n\n\t\t\t\t\t// Insert a hidden input as a replacement for the missing submit button\n\t\t\t\t\t// The hidden input is inserted in two cases:\n\t\t\t\t\t//   - A user defined a `submitHandler`\n\t\t\t\t\t//   - There was a pending request due to `remote` method and `stopRequest()`\n\t\t\t\t\t//     was called to submit the form in case it's valid\n\t\t\t\t\tif ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {\n\t\t\t\t\t\thidden = $( \"<input type='hidden'/>\" )\n\t\t\t\t\t\t\t.attr( \"name\", validator.submitButton.name )\n\t\t\t\t\t\t\t.val( $( validator.submitButton ).val() )\n\t\t\t\t\t\t\t.appendTo( validator.currentForm );\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( validator.settings.submitHandler ) {\n\t\t\t\t\t\tresult = validator.settings.submitHandler.call( validator, validator.currentForm, event );\n\t\t\t\t\t\tif ( hidden ) {\n\n\t\t\t\t\t\t\t// And clean up afterwards; thanks to no-block-scope, hidden can be referenced\n\t\t\t\t\t\t\thidden.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( result !== undefined ) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// Prevent submit for invalid forms or custom submit handlers\n\t\t\t\tif ( validator.cancelSubmit ) {\n\t\t\t\t\tvalidator.cancelSubmit = false;\n\t\t\t\t\treturn handle();\n\t\t\t\t}\n\t\t\t\tif ( validator.form() ) {\n\t\t\t\t\tif ( validator.pendingRequest ) {\n\t\t\t\t\t\tvalidator.formSubmitted = true;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn handle();\n\t\t\t\t} else {\n\t\t\t\t\tvalidator.focusInvalid();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn validator;\n\t},\n\n\t// https://jqueryvalidation.org/valid/\n\tvalid: function() {\n\t\tvar valid, validator, errorList;\n\n\t\tif ( $( this[ 0 ] ).is( \"form\" ) ) {\n\t\t\tvalid = this.validate().form();\n\t\t} else {\n\t\t\terrorList = [];\n\t\t\tvalid = true;\n\t\t\tvalidator = $( this[ 0 ].form ).validate();\n\t\t\tthis.each( function() {\n\t\t\t\tvalid = validator.element( this ) && valid;\n\t\t\t\tif ( !valid ) {\n\t\t\t\t\terrorList = errorList.concat( validator.errorList );\n\t\t\t\t}\n\t\t\t} );\n\t\t\tvalidator.errorList = errorList;\n\t\t}\n\t\treturn valid;\n\t},\n\n\t// https://jqueryvalidation.org/rules/\n\trules: function( command, argument ) {\n\t\tvar element = this[ 0 ],\n\t\t\tsettings, staticRules, existingRules, data, param, filtered;\n\n\t\t// If nothing is selected, return empty object; can't chain anyway\n\t\tif ( element == null ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !element.form && element.hasAttribute( \"contenteditable\" ) ) {\n\t\t\telement.form = this.closest( \"form\" )[ 0 ];\n\t\t\telement.name = this.attr( \"name\" );\n\t\t}\n\n\t\tif ( element.form == null ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( command ) {\n\t\t\tsettings = $.data( element.form, \"validator\" ).settings;\n\t\t\tstaticRules = settings.rules;\n\t\t\texistingRules = $.validator.staticRules( element );\n\t\t\tswitch ( command ) {\n\t\t\tcase \"add\":\n\t\t\t\t$.extend( existingRules, $.validator.normalizeRule( argument ) );\n\n\t\t\t\t// Remove messages from rules, but allow them to be set separately\n\t\t\t\tdelete existingRules.messages;\n\t\t\t\tstaticRules[ element.name ] = existingRules;\n\t\t\t\tif ( argument.messages ) {\n\t\t\t\t\tsettings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"remove\":\n\t\t\t\tif ( !argument ) {\n\t\t\t\t\tdelete staticRules[ element.name ];\n\t\t\t\t\treturn existingRules;\n\t\t\t\t}\n\t\t\t\tfiltered = {};\n\t\t\t\t$.each( argument.split( /\\s/ ), function( index, method ) {\n\t\t\t\t\tfiltered[ method ] = existingRules[ method ];\n\t\t\t\t\tdelete existingRules[ method ];\n\t\t\t\t} );\n\t\t\t\treturn filtered;\n\t\t\t}\n\t\t}\n\n\t\tdata = $.validator.normalizeRules(\n\t\t$.extend(\n\t\t\t{},\n\t\t\t$.validator.classRules( element ),\n\t\t\t$.validator.attributeRules( element ),\n\t\t\t$.validator.dataRules( element ),\n\t\t\t$.validator.staticRules( element )\n\t\t), element );\n\n\t\t// Make sure required is at front\n\t\tif ( data.required ) {\n\t\t\tparam = data.required;\n\t\t\tdelete data.required;\n\t\t\tdata = $.extend( { required: param }, data );\n\t\t}\n\n\t\t// Make sure remote is at back\n\t\tif ( data.remote ) {\n\t\t\tparam = data.remote;\n\t\t\tdelete data.remote;\n\t\t\tdata = $.extend( data, { remote: param } );\n\t\t}\n\n\t\treturn data;\n\t}\n} );\n\n// Custom selectors\n$.extend( $.expr.pseudos || $.expr[ \":\" ], {\t\t// '|| $.expr[ \":\" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support\n\n\t// https://jqueryvalidation.org/blank-selector/\n\tblank: function( a ) {\n\t\treturn !$.trim( \"\" + $( a ).val() );\n\t},\n\n\t// https://jqueryvalidation.org/filled-selector/\n\tfilled: function( a ) {\n\t\tvar val = $( a ).val();\n\t\treturn val !== null && !!$.trim( \"\" + val );\n\t},\n\n\t// https://jqueryvalidation.org/unchecked-selector/\n\tunchecked: function( a ) {\n\t\treturn !$( a ).prop( \"checked\" );\n\t}\n} );\n\n// Constructor for validator\n$.validator = function( options, form ) {\n\tthis.settings = $.extend( true, {}, $.validator.defaults, options );\n\tthis.currentForm = form;\n\tthis.init();\n};\n\n// https://jqueryvalidation.org/jQuery.validator.format/\n$.validator.format = function( source, params ) {\n\tif ( arguments.length === 1 ) {\n\t\treturn function() {\n\t\t\tvar args = $.makeArray( arguments );\n\t\t\targs.unshift( source );\n\t\t\treturn $.validator.format.apply( this, args );\n\t\t};\n\t}\n\tif ( params === undefined ) {\n\t\treturn source;\n\t}\n\tif ( arguments.length > 2 && params.constructor !== Array  ) {\n\t\tparams = $.makeArray( arguments ).slice( 1 );\n\t}\n\tif ( params.constructor !== Array ) {\n\t\tparams = [ params ];\n\t}\n\t$.each( params, function( i, n ) {\n\t\tsource = source.replace( new RegExp( \"\\\\{\" + i + \"\\\\}\", \"g\" ), function() {\n\t\t\treturn n;\n\t\t} );\n\t} );\n\treturn source;\n};\n\n$.extend( $.validator, {\n\n\tdefaults: {\n\t\tmessages: {},\n\t\tgroups: {},\n\t\trules: {},\n\t\terrorClass: \"error\",\n\t\tpendingClass: \"pending\",\n\t\tvalidClass: \"valid\",\n\t\terrorElement: \"label\",\n\t\tfocusCleanup: false,\n\t\tfocusInvalid: true,\n\t\terrorContainer: $( [] ),\n\t\terrorLabelContainer: $( [] ),\n\t\tonsubmit: true,\n\t\tignore: \":hidden\",\n\t\tignoreTitle: false,\n\t\tonfocusin: function( element ) {\n\t\t\tthis.lastActive = element;\n\n\t\t\t// Hide error label and remove error class on focus if enabled\n\t\t\tif ( this.settings.focusCleanup ) {\n\t\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t\tthis.hideThese( this.errorsFor( element ) );\n\t\t\t}\n\t\t},\n\t\tonfocusout: function( element ) {\n\t\t\tif ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {\n\t\t\t\tthis.element( element );\n\t\t\t}\n\t\t},\n\t\tonkeyup: function( element, event ) {\n\n\t\t\t// Avoid revalidate the field when pressing one of the following keys\n\t\t\t// Shift       => 16\n\t\t\t// Ctrl        => 17\n\t\t\t// Alt         => 18\n\t\t\t// Caps lock   => 20\n\t\t\t// End         => 35\n\t\t\t// Home        => 36\n\t\t\t// Left arrow  => 37\n\t\t\t// Up arrow    => 38\n\t\t\t// Right arrow => 39\n\t\t\t// Down arrow  => 40\n\t\t\t// Insert      => 45\n\t\t\t// Num lock    => 144\n\t\t\t// AltGr key   => 225\n\t\t\tvar excludedKeys = [\n\t\t\t\t16, 17, 18, 20, 35, 36, 37,\n\t\t\t\t38, 39, 40, 45, 144, 225\n\t\t\t];\n\n\t\t\tif ( event.which === 9 && this.elementValue( element ) === \"\" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {\n\t\t\t\treturn;\n\t\t\t} else if ( element.name in this.submitted || element.name in this.invalid ) {\n\t\t\t\tthis.element( element );\n\t\t\t}\n\t\t},\n\t\tonclick: function( element ) {\n\n\t\t\t// Click on selects, radiobuttons and checkboxes\n\t\t\tif ( element.name in this.submitted ) {\n\t\t\t\tthis.element( element );\n\n\t\t\t// Or option elements, check parent select in that case\n\t\t\t} else if ( element.parentNode.name in this.submitted ) {\n\t\t\t\tthis.element( element.parentNode );\n\t\t\t}\n\t\t},\n\t\thighlight: function( element, errorClass, validClass ) {\n\t\t\tif ( element.type === \"radio\" ) {\n\t\t\t\tthis.findByName( element.name ).addClass( errorClass ).removeClass( validClass );\n\t\t\t} else {\n\t\t\t\t$( element ).addClass( errorClass ).removeClass( validClass );\n\t\t\t}\n\t\t},\n\t\tunhighlight: function( element, errorClass, validClass ) {\n\t\t\tif ( element.type === \"radio\" ) {\n\t\t\t\tthis.findByName( element.name ).removeClass( errorClass ).addClass( validClass );\n\t\t\t} else {\n\t\t\t\t$( element ).removeClass( errorClass ).addClass( validClass );\n\t\t\t}\n\t\t}\n\t},\n\n\t// https://jqueryvalidation.org/jQuery.validator.setDefaults/\n\tsetDefaults: function( settings ) {\n\t\t$.extend( $.validator.defaults, settings );\n\t},\n\n\tmessages: {\n\t\trequired: \"This field is required.\",\n\t\tremote: \"Please fix this field.\",\n\t\temail: \"Please enter a valid email address.\",\n\t\turl: \"Please enter a valid URL.\",\n\t\tdate: \"Please enter a valid date.\",\n\t\tdateISO: \"Please enter a valid date (ISO).\",\n\t\tnumber: \"Please enter a valid number.\",\n\t\tdigits: \"Please enter only digits.\",\n\t\tequalTo: \"Please enter the same value again.\",\n\t\tmaxlength: $.validator.format( \"Please enter no more than {0} characters.\" ),\n\t\tminlength: $.validator.format( \"Please enter at least {0} characters.\" ),\n\t\trangelength: $.validator.format( \"Please enter a value between {0} and {1} characters long.\" ),\n\t\trange: $.validator.format( \"Please enter a value between {0} and {1}.\" ),\n\t\tmax: $.validator.format( \"Please enter a value less than or equal to {0}.\" ),\n\t\tmin: $.validator.format( \"Please enter a value greater than or equal to {0}.\" ),\n\t\tstep: $.validator.format( \"Please enter a multiple of {0}.\" )\n\t},\n\n\tautoCreateRanges: false,\n\n\tprototype: {\n\n\t\tinit: function() {\n\t\t\tthis.labelContainer = $( this.settings.errorLabelContainer );\n\t\t\tthis.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );\n\t\t\tthis.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );\n\t\t\tthis.submitted = {};\n\t\t\tthis.valueCache = {};\n\t\t\tthis.pendingRequest = 0;\n\t\t\tthis.pending = {};\n\t\t\tthis.invalid = {};\n\t\t\tthis.reset();\n\n\t\t\tvar groups = ( this.groups = {} ),\n\t\t\t\trules;\n\t\t\t$.each( this.settings.groups, function( key, value ) {\n\t\t\t\tif ( typeof value === \"string\" ) {\n\t\t\t\t\tvalue = value.split( /\\s/ );\n\t\t\t\t}\n\t\t\t\t$.each( value, function( index, name ) {\n\t\t\t\t\tgroups[ name ] = key;\n\t\t\t\t} );\n\t\t\t} );\n\t\t\trules = this.settings.rules;\n\t\t\t$.each( rules, function( key, value ) {\n\t\t\t\trules[ key ] = $.validator.normalizeRule( value );\n\t\t\t} );\n\n\t\t\tfunction delegate( event ) {\n\n\t\t\t\t// Set form expando on contenteditable\n\t\t\t\tif ( !this.form && this.hasAttribute( \"contenteditable\" ) ) {\n\t\t\t\t\tthis.form = $( this ).closest( \"form\" )[ 0 ];\n\t\t\t\t\tthis.name = $( this ).attr( \"name\" );\n\t\t\t\t}\n\n\t\t\t\tvar validator = $.data( this.form, \"validator\" ),\n\t\t\t\t\teventType = \"on\" + event.type.replace( /^validate/, \"\" ),\n\t\t\t\t\tsettings = validator.settings;\n\t\t\t\tif ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {\n\t\t\t\t\tsettings[ eventType ].call( validator, this, event );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$( this.currentForm )\n\t\t\t\t.on( \"focusin.validate focusout.validate keyup.validate\",\n\t\t\t\t\t\":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], \" +\n\t\t\t\t\t\"[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], \" +\n\t\t\t\t\t\"[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], \" +\n\t\t\t\t\t\"[type='radio'], [type='checkbox'], [contenteditable], [type='button']\", delegate )\n\n\t\t\t\t// Support: Chrome, oldIE\n\t\t\t\t// \"select\" is provided as event.target when clicking a option\n\t\t\t\t.on( \"click.validate\", \"select, option, [type='radio'], [type='checkbox']\", delegate );\n\n\t\t\tif ( this.settings.invalidHandler ) {\n\t\t\t\t$( this.currentForm ).on( \"invalid-form.validate\", this.settings.invalidHandler );\n\t\t\t}\n\t\t},\n\n\t\t// https://jqueryvalidation.org/Validator.form/\n\t\tform: function() {\n\t\t\tthis.checkForm();\n\t\t\t$.extend( this.submitted, this.errorMap );\n\t\t\tthis.invalid = $.extend( {}, this.errorMap );\n\t\t\tif ( !this.valid() ) {\n\t\t\t\t$( this.currentForm ).triggerHandler( \"invalid-form\", [ this ] );\n\t\t\t}\n\t\t\tthis.showErrors();\n\t\t\treturn this.valid();\n\t\t},\n\n\t\tcheckForm: function() {\n\t\t\tthis.prepareForm();\n\t\t\tfor ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {\n\t\t\t\tthis.check( elements[ i ] );\n\t\t\t}\n\t\t\treturn this.valid();\n\t\t},\n\n\t\t// https://jqueryvalidation.org/Validator.element/\n\t\telement: function( element ) {\n\t\t\tvar cleanElement = this.clean( element ),\n\t\t\t\tcheckElement = this.validationTargetFor( cleanElement ),\n\t\t\t\tv = this,\n\t\t\t\tresult = true,\n\t\t\t\trs, group;\n\n\t\t\tif ( checkElement === undefined ) {\n\t\t\t\tdelete this.invalid[ cleanElement.name ];\n\t\t\t} else {\n\t\t\t\tthis.prepareElement( checkElement );\n\t\t\t\tthis.currentElements = $( checkElement );\n\n\t\t\t\t// If this element is grouped, then validate all group elements already\n\t\t\t\t// containing a value\n\t\t\t\tgroup = this.groups[ checkElement.name ];\n\t\t\t\tif ( group ) {\n\t\t\t\t\t$.each( this.groups, function( name, testgroup ) {\n\t\t\t\t\t\tif ( testgroup === group && name !== checkElement.name ) {\n\t\t\t\t\t\t\tcleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );\n\t\t\t\t\t\t\tif ( cleanElement && cleanElement.name in v.invalid ) {\n\t\t\t\t\t\t\t\tv.currentElements.push( cleanElement );\n\t\t\t\t\t\t\t\tresult = v.check( cleanElement ) && result;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\trs = this.check( checkElement ) !== false;\n\t\t\t\tresult = result && rs;\n\t\t\t\tif ( rs ) {\n\t\t\t\t\tthis.invalid[ checkElement.name ] = false;\n\t\t\t\t} else {\n\t\t\t\t\tthis.invalid[ checkElement.name ] = true;\n\t\t\t\t}\n\n\t\t\t\tif ( !this.numberOfInvalids() ) {\n\n\t\t\t\t\t// Hide error containers on last error\n\t\t\t\t\tthis.toHide = this.toHide.add( this.containers );\n\t\t\t\t}\n\t\t\t\tthis.showErrors();\n\n\t\t\t\t// Add aria-invalid status for screen readers\n\t\t\t\t$( element ).attr( \"aria-invalid\", !rs );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/Validator.showErrors/\n\t\tshowErrors: function( errors ) {\n\t\t\tif ( errors ) {\n\t\t\t\tvar validator = this;\n\n\t\t\t\t// Add items to error list and map\n\t\t\t\t$.extend( this.errorMap, errors );\n\t\t\t\tthis.errorList = $.map( this.errorMap, function( message, name ) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessage: message,\n\t\t\t\t\t\telement: validator.findByName( name )[ 0 ]\n\t\t\t\t\t};\n\t\t\t\t} );\n\n\t\t\t\t// Remove items from success list\n\t\t\t\tthis.successList = $.grep( this.successList, function( element ) {\n\t\t\t\t\treturn !( element.name in errors );\n\t\t\t\t} );\n\t\t\t}\n\t\t\tif ( this.settings.showErrors ) {\n\t\t\t\tthis.settings.showErrors.call( this, this.errorMap, this.errorList );\n\t\t\t} else {\n\t\t\t\tthis.defaultShowErrors();\n\t\t\t}\n\t\t},\n\n\t\t// https://jqueryvalidation.org/Validator.resetForm/\n\t\tresetForm: function() {\n\t\t\tif ( $.fn.resetForm ) {\n\t\t\t\t$( this.currentForm ).resetForm();\n\t\t\t}\n\t\t\tthis.invalid = {};\n\t\t\tthis.submitted = {};\n\t\t\tthis.prepareForm();\n\t\t\tthis.hideErrors();\n\t\t\tvar elements = this.elements()\n\t\t\t\t.removeData( \"previousValue\" )\n\t\t\t\t.removeAttr( \"aria-invalid\" );\n\n\t\t\tthis.resetElements( elements );\n\t\t},\n\n\t\tresetElements: function( elements ) {\n\t\t\tvar i;\n\n\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\tfor ( i = 0; elements[ i ]; i++ ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, elements[ i ],\n\t\t\t\t\t\tthis.settings.errorClass, \"\" );\n\t\t\t\t\tthis.findByName( elements[ i ].name ).removeClass( this.settings.validClass );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\telements\n\t\t\t\t\t.removeClass( this.settings.errorClass )\n\t\t\t\t\t.removeClass( this.settings.validClass );\n\t\t\t}\n\t\t},\n\n\t\tnumberOfInvalids: function() {\n\t\t\treturn this.objectLength( this.invalid );\n\t\t},\n\n\t\tobjectLength: function( obj ) {\n\t\t\t/* jshint unused: false */\n\t\t\tvar count = 0,\n\t\t\t\ti;\n\t\t\tfor ( i in obj ) {\n\n\t\t\t\t// This check allows counting elements with empty error\n\t\t\t\t// message as invalid elements\n\t\t\t\tif ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn count;\n\t\t},\n\n\t\thideErrors: function() {\n\t\t\tthis.hideThese( this.toHide );\n\t\t},\n\n\t\thideThese: function( errors ) {\n\t\t\terrors.not( this.containers ).text( \"\" );\n\t\t\tthis.addWrapper( errors ).hide();\n\t\t},\n\n\t\tvalid: function() {\n\t\t\treturn this.size() === 0;\n\t\t},\n\n\t\tsize: function() {\n\t\t\treturn this.errorList.length;\n\t\t},\n\n\t\tfocusInvalid: function() {\n\t\t\tif ( this.settings.focusInvalid ) {\n\t\t\t\ttry {\n\t\t\t\t\t$( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )\n\t\t\t\t\t.filter( \":visible\" )\n\t\t\t\t\t.focus()\n\n\t\t\t\t\t// Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find\n\t\t\t\t\t.trigger( \"focusin\" );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// Ignore IE throwing errors when focusing hidden elements\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tfindLastActive: function() {\n\t\t\tvar lastActive = this.lastActive;\n\t\t\treturn lastActive && $.grep( this.errorList, function( n ) {\n\t\t\t\treturn n.element.name === lastActive.name;\n\t\t\t} ).length === 1 && lastActive;\n\t\t},\n\n\t\telements: function() {\n\t\t\tvar validator = this,\n\t\t\t\trulesCache = {};\n\n\t\t\t// Select all valid inputs inside the form (no submit or reset buttons)\n\t\t\treturn $( this.currentForm )\n\t\t\t.find( \"input, select, textarea, [contenteditable]\" )\n\t\t\t.not( \":submit, :reset, :image, :disabled\" )\n\t\t\t.not( this.settings.ignore )\n\t\t\t.filter( function() {\n\t\t\t\tvar name = this.name || $( this ).attr( \"name\" ); // For contenteditable\n\t\t\t\tif ( !name && validator.settings.debug && window.console ) {\n\t\t\t\t\tconsole.error( \"%o has no name assigned\", this );\n\t\t\t\t}\n\n\t\t\t\t// Set form expando on contenteditable\n\t\t\t\tif ( this.hasAttribute( \"contenteditable\" ) ) {\n\t\t\t\t\tthis.form = $( this ).closest( \"form\" )[ 0 ];\n\t\t\t\t\tthis.name = name;\n\t\t\t\t}\n\n\t\t\t\t// Select only the first element for each name, and only those with rules specified\n\t\t\t\tif ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\trulesCache[ name ] = true;\n\t\t\t\treturn true;\n\t\t\t} );\n\t\t},\n\n\t\tclean: function( selector ) {\n\t\t\treturn $( selector )[ 0 ];\n\t\t},\n\n\t\terrors: function() {\n\t\t\tvar errorClass = this.settings.errorClass.split( \" \" ).join( \".\" );\n\t\t\treturn $( this.settings.errorElement + \".\" + errorClass, this.errorContext );\n\t\t},\n\n\t\tresetInternals: function() {\n\t\t\tthis.successList = [];\n\t\t\tthis.errorList = [];\n\t\t\tthis.errorMap = {};\n\t\t\tthis.toShow = $( [] );\n\t\t\tthis.toHide = $( [] );\n\t\t},\n\n\t\treset: function() {\n\t\t\tthis.resetInternals();\n\t\t\tthis.currentElements = $( [] );\n\t\t},\n\n\t\tprepareForm: function() {\n\t\t\tthis.reset();\n\t\t\tthis.toHide = this.errors().add( this.containers );\n\t\t},\n\n\t\tprepareElement: function( element ) {\n\t\t\tthis.reset();\n\t\t\tthis.toHide = this.errorsFor( element );\n\t\t},\n\n\t\telementValue: function( element ) {\n\t\t\tvar $element = $( element ),\n\t\t\t\ttype = element.type,\n\t\t\t\tval, idx;\n\n\t\t\tif ( type === \"radio\" || type === \"checkbox\" ) {\n\t\t\t\treturn this.findByName( element.name ).filter( \":checked\" ).val();\n\t\t\t} else if ( type === \"number\" && typeof element.validity !== \"undefined\" ) {\n\t\t\t\treturn element.validity.badInput ? \"NaN\" : $element.val();\n\t\t\t}\n\n\t\t\tif ( element.hasAttribute( \"contenteditable\" ) ) {\n\t\t\t\tval = $element.text();\n\t\t\t} else {\n\t\t\t\tval = $element.val();\n\t\t\t}\n\n\t\t\tif ( type === \"file\" ) {\n\n\t\t\t\t// Modern browser (chrome & safari)\n\t\t\t\tif ( val.substr( 0, 12 ) === \"C:\\\\fakepath\\\\\" ) {\n\t\t\t\t\treturn val.substr( 12 );\n\t\t\t\t}\n\n\t\t\t\t// Legacy browsers\n\t\t\t\t// Unix-based path\n\t\t\t\tidx = val.lastIndexOf( \"/\" );\n\t\t\t\tif ( idx >= 0 ) {\n\t\t\t\t\treturn val.substr( idx + 1 );\n\t\t\t\t}\n\n\t\t\t\t// Windows-based path\n\t\t\t\tidx = val.lastIndexOf( \"\\\\\" );\n\t\t\t\tif ( idx >= 0 ) {\n\t\t\t\t\treturn val.substr( idx + 1 );\n\t\t\t\t}\n\n\t\t\t\t// Just the file name\n\t\t\t\treturn val;\n\t\t\t}\n\n\t\t\tif ( typeof val === \"string\" ) {\n\t\t\t\treturn val.replace( /\\r/g, \"\" );\n\t\t\t}\n\t\t\treturn val;\n\t\t},\n\n\t\tcheck: function( element ) {\n\t\t\telement = this.validationTargetFor( this.clean( element ) );\n\n\t\t\tvar rules = $( element ).rules(),\n\t\t\t\trulesCount = $.map( rules, function( n, i ) {\n\t\t\t\t\treturn i;\n\t\t\t\t} ).length,\n\t\t\t\tdependencyMismatch = false,\n\t\t\t\tval = this.elementValue( element ),\n\t\t\t\tresult, method, rule, normalizer;\n\n\t\t\t// Prioritize the local normalizer defined for this element over the global one\n\t\t\t// if the former exists, otherwise user the global one in case it exists.\n\t\t\tif ( typeof rules.normalizer === \"function\" ) {\n\t\t\t\tnormalizer = rules.normalizer;\n\t\t\t} else if (\ttypeof this.settings.normalizer === \"function\" ) {\n\t\t\t\tnormalizer = this.settings.normalizer;\n\t\t\t}\n\n\t\t\t// If normalizer is defined, then call it to retreive the changed value instead\n\t\t\t// of using the real one.\n\t\t\t// Note that `this` in the normalizer is `element`.\n\t\t\tif ( normalizer ) {\n\t\t\t\tval = normalizer.call( element, val );\n\n\t\t\t\tif ( typeof val !== \"string\" ) {\n\t\t\t\t\tthrow new TypeError( \"The normalizer should return a string value.\" );\n\t\t\t\t}\n\n\t\t\t\t// Delete the normalizer from rules to avoid treating it as a pre-defined method.\n\t\t\t\tdelete rules.normalizer;\n\t\t\t}\n\n\t\t\tfor ( method in rules ) {\n\t\t\t\trule = { method: method, parameters: rules[ method ] };\n\t\t\t\ttry {\n\t\t\t\t\tresult = $.validator.methods[ method ].call( this, val, element, rule.parameters );\n\n\t\t\t\t\t// If a method indicates that the field is optional and therefore valid,\n\t\t\t\t\t// don't mark it as valid when there are no other rules\n\t\t\t\t\tif ( result === \"dependency-mismatch\" && rulesCount === 1 ) {\n\t\t\t\t\t\tdependencyMismatch = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tdependencyMismatch = false;\n\n\t\t\t\t\tif ( result === \"pending\" ) {\n\t\t\t\t\t\tthis.toHide = this.toHide.not( this.errorsFor( element ) );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( !result ) {\n\t\t\t\t\t\tthis.formatAndAdd( element, rule );\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t} catch ( e ) {\n\t\t\t\t\tif ( this.settings.debug && window.console ) {\n\t\t\t\t\t\tconsole.log( \"Exception occurred when checking element \" + element.id + \", check the '\" + rule.method + \"' method.\", e );\n\t\t\t\t\t}\n\t\t\t\t\tif ( e instanceof TypeError ) {\n\t\t\t\t\t\te.message += \".  Exception occurred when checking element \" + element.id + \", check the '\" + rule.method + \"' method.\";\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( dependencyMismatch ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( this.objectLength( rules ) ) {\n\t\t\t\tthis.successList.push( element );\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t// Return the custom message for the given element and validation method\n\t\t// specified in the element's HTML5 data attribute\n\t\t// return the generic message if present and no method specific message is present\n\t\tcustomDataMessage: function( element, method ) {\n\t\t\treturn $( element ).data( \"msg\" + method.charAt( 0 ).toUpperCase() +\n\t\t\t\tmethod.substring( 1 ).toLowerCase() ) || $( element ).data( \"msg\" );\n\t\t},\n\n\t\t// Return the custom message for the given element name and validation method\n\t\tcustomMessage: function( name, method ) {\n\t\t\tvar m = this.settings.messages[ name ];\n\t\t\treturn m && ( m.constructor === String ? m : m[ method ] );\n\t\t},\n\n\t\t// Return the first defined argument, allowing empty strings\n\t\tfindDefined: function() {\n\t\t\tfor ( var i = 0; i < arguments.length; i++ ) {\n\t\t\t\tif ( arguments[ i ] !== undefined ) {\n\t\t\t\t\treturn arguments[ i ];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\n\t\t// The second parameter 'rule' used to be a string, and extended to an object literal\n\t\t// of the following form:\n\t\t// rule = {\n\t\t//     method: \"method name\",\n\t\t//     parameters: \"the given method parameters\"\n\t\t// }\n\t\t//\n\t\t// The old behavior still supported, kept to maintain backward compatibility with\n\t\t// old code, and will be removed in the next major release.\n\t\tdefaultMessage: function( element, rule ) {\n\t\t\tif ( typeof rule === \"string\" ) {\n\t\t\t\trule = { method: rule };\n\t\t\t}\n\n\t\t\tvar message = this.findDefined(\n\t\t\t\t\tthis.customMessage( element.name, rule.method ),\n\t\t\t\t\tthis.customDataMessage( element, rule.method ),\n\n\t\t\t\t\t// 'title' is never undefined, so handle empty string as undefined\n\t\t\t\t\t!this.settings.ignoreTitle && element.title || undefined,\n\t\t\t\t\t$.validator.messages[ rule.method ],\n\t\t\t\t\t\"<strong>Warning: No message defined for \" + element.name + \"</strong>\"\n\t\t\t\t),\n\t\t\t\ttheregex = /\\$?\\{(\\d+)\\}/g;\n\t\t\tif ( typeof message === \"function\" ) {\n\t\t\t\tmessage = message.call( this, rule.parameters, element );\n\t\t\t} else if ( theregex.test( message ) ) {\n\t\t\t\tmessage = $.validator.format( message.replace( theregex, \"{$1}\" ), rule.parameters );\n\t\t\t}\n\n\t\t\treturn message;\n\t\t},\n\n\t\tformatAndAdd: function( element, rule ) {\n\t\t\tvar message = this.defaultMessage( element, rule );\n\n\t\t\tthis.errorList.push( {\n\t\t\t\tmessage: message,\n\t\t\t\telement: element,\n\t\t\t\tmethod: rule.method\n\t\t\t} );\n\n\t\t\tthis.errorMap[ element.name ] = message;\n\t\t\tthis.submitted[ element.name ] = message;\n\t\t},\n\n\t\taddWrapper: function( toToggle ) {\n\t\t\tif ( this.settings.wrapper ) {\n\t\t\t\ttoToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );\n\t\t\t}\n\t\t\treturn toToggle;\n\t\t},\n\n\t\tdefaultShowErrors: function() {\n\t\t\tvar i, elements, error;\n\t\t\tfor ( i = 0; this.errorList[ i ]; i++ ) {\n\t\t\t\terror = this.errorList[ i ];\n\t\t\t\tif ( this.settings.highlight ) {\n\t\t\t\t\tthis.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t\tthis.showLabel( error.element, error.message );\n\t\t\t}\n\t\t\tif ( this.errorList.length ) {\n\t\t\t\tthis.toShow = this.toShow.add( this.containers );\n\t\t\t}\n\t\t\tif ( this.settings.success ) {\n\t\t\t\tfor ( i = 0; this.successList[ i ]; i++ ) {\n\t\t\t\t\tthis.showLabel( this.successList[ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\tfor ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.toHide = this.toHide.not( this.toShow );\n\t\t\tthis.hideErrors();\n\t\t\tthis.addWrapper( this.toShow ).show();\n\t\t},\n\n\t\tvalidElements: function() {\n\t\t\treturn this.currentElements.not( this.invalidElements() );\n\t\t},\n\n\t\tinvalidElements: function() {\n\t\t\treturn $( this.errorList ).map( function() {\n\t\t\t\treturn this.element;\n\t\t\t} );\n\t\t},\n\n\t\tshowLabel: function( element, message ) {\n\t\t\tvar place, group, errorID, v,\n\t\t\t\terror = this.errorsFor( element ),\n\t\t\t\telementID = this.idOrName( element ),\n\t\t\t\tdescribedBy = $( element ).attr( \"aria-describedby\" );\n\n\t\t\tif ( error.length ) {\n\n\t\t\t\t// Refresh error/success class\n\t\t\t\terror.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );\n\n\t\t\t\t// Replace message on existing label\n\t\t\t\terror.html( message );\n\t\t\t} else {\n\n\t\t\t\t// Create error element\n\t\t\t\terror = $( \"<\" + this.settings.errorElement + \">\" )\n\t\t\t\t\t.attr( \"id\", elementID + \"-error\" )\n\t\t\t\t\t.addClass( this.settings.errorClass )\n\t\t\t\t\t.html( message || \"\" );\n\n\t\t\t\t// Maintain reference to the element to be placed into the DOM\n\t\t\t\tplace = error;\n\t\t\t\tif ( this.settings.wrapper ) {\n\n\t\t\t\t\t// Make sure the element is visible, even in IE\n\t\t\t\t\t// actually showing the wrapped element is handled elsewhere\n\t\t\t\t\tplace = error.hide().show().wrap( \"<\" + this.settings.wrapper + \"/>\" ).parent();\n\t\t\t\t}\n\t\t\t\tif ( this.labelContainer.length ) {\n\t\t\t\t\tthis.labelContainer.append( place );\n\t\t\t\t} else if ( this.settings.errorPlacement ) {\n\t\t\t\t\tthis.settings.errorPlacement.call( this, place, $( element ) );\n\t\t\t\t} else {\n\t\t\t\t\tplace.insertAfter( element );\n\t\t\t\t}\n\n\t\t\t\t// Link error back to the element\n\t\t\t\tif ( error.is( \"label\" ) ) {\n\n\t\t\t\t\t// If the error is a label, then associate using 'for'\n\t\t\t\t\terror.attr( \"for\", elementID );\n\n\t\t\t\t\t// If the element is not a child of an associated label, then it's necessary\n\t\t\t\t\t// to explicitly apply aria-describedby\n\t\t\t\t} else if ( error.parents( \"label[for='\" + this.escapeCssMeta( elementID ) + \"']\" ).length === 0 ) {\n\t\t\t\t\terrorID = error.attr( \"id\" );\n\n\t\t\t\t\t// Respect existing non-error aria-describedby\n\t\t\t\t\tif ( !describedBy ) {\n\t\t\t\t\t\tdescribedBy = errorID;\n\t\t\t\t\t} else if ( !describedBy.match( new RegExp( \"\\\\b\" + this.escapeCssMeta( errorID ) + \"\\\\b\" ) ) ) {\n\n\t\t\t\t\t\t// Add to end of list if not already present\n\t\t\t\t\t\tdescribedBy += \" \" + errorID;\n\t\t\t\t\t}\n\t\t\t\t\t$( element ).attr( \"aria-describedby\", describedBy );\n\n\t\t\t\t\t// If this element is grouped, then assign to all elements in the same group\n\t\t\t\t\tgroup = this.groups[ element.name ];\n\t\t\t\t\tif ( group ) {\n\t\t\t\t\t\tv = this;\n\t\t\t\t\t\t$.each( v.groups, function( name, testgroup ) {\n\t\t\t\t\t\t\tif ( testgroup === group ) {\n\t\t\t\t\t\t\t\t$( \"[name='\" + v.escapeCssMeta( name ) + \"']\", v.currentForm )\n\t\t\t\t\t\t\t\t\t.attr( \"aria-describedby\", error.attr( \"id\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( !message && this.settings.success ) {\n\t\t\t\terror.text( \"\" );\n\t\t\t\tif ( typeof this.settings.success === \"string\" ) {\n\t\t\t\t\terror.addClass( this.settings.success );\n\t\t\t\t} else {\n\t\t\t\t\tthis.settings.success( error, element );\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.toShow = this.toShow.add( error );\n\t\t},\n\n\t\terrorsFor: function( element ) {\n\t\t\tvar name = this.escapeCssMeta( this.idOrName( element ) ),\n\t\t\t\tdescriber = $( element ).attr( \"aria-describedby\" ),\n\t\t\t\tselector = \"label[for='\" + name + \"'], label[for='\" + name + \"'] *\";\n\n\t\t\t// 'aria-describedby' should directly reference the error element\n\t\t\tif ( describer ) {\n\t\t\t\tselector = selector + \", #\" + this.escapeCssMeta( describer )\n\t\t\t\t\t.replace( /\\s+/g, \", #\" );\n\t\t\t}\n\n\t\t\treturn this\n\t\t\t\t.errors()\n\t\t\t\t.filter( selector );\n\t\t},\n\n\t\t// See https://api.jquery.com/category/selectors/, for CSS\n\t\t// meta-characters that should be escaped in order to be used with JQuery\n\t\t// as a literal part of a name/id or any selector.\n\t\tescapeCssMeta: function( string ) {\n\t\t\treturn string.replace( /([\\\\!\"#$%&'()*+,./:;<=>?@\\[\\]^`{|}~])/g, \"\\\\$1\" );\n\t\t},\n\n\t\tidOrName: function( element ) {\n\t\t\treturn this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );\n\t\t},\n\n\t\tvalidationTargetFor: function( element ) {\n\n\t\t\t// If radio/checkbox, validate first element in group instead\n\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\telement = this.findByName( element.name );\n\t\t\t}\n\n\t\t\t// Always apply ignore filter\n\t\t\treturn $( element ).not( this.settings.ignore )[ 0 ];\n\t\t},\n\n\t\tcheckable: function( element ) {\n\t\t\treturn ( /radio|checkbox/i ).test( element.type );\n\t\t},\n\n\t\tfindByName: function( name ) {\n\t\t\treturn $( this.currentForm ).find( \"[name='\" + this.escapeCssMeta( name ) + \"']\" );\n\t\t},\n\n\t\tgetLength: function( value, element ) {\n\t\t\tswitch ( element.nodeName.toLowerCase() ) {\n\t\t\tcase \"select\":\n\t\t\t\treturn $( \"option:selected\", element ).length;\n\t\t\tcase \"input\":\n\t\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\t\treturn this.findByName( element.name ).filter( \":checked\" ).length;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn value.length;\n\t\t},\n\n\t\tdepend: function( param, element ) {\n\t\t\treturn this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;\n\t\t},\n\n\t\tdependTypes: {\n\t\t\t\"boolean\": function( param ) {\n\t\t\t\treturn param;\n\t\t\t},\n\t\t\t\"string\": function( param, element ) {\n\t\t\t\treturn !!$( param, element.form ).length;\n\t\t\t},\n\t\t\t\"function\": function( param, element ) {\n\t\t\t\treturn param( element );\n\t\t\t}\n\t\t},\n\n\t\toptional: function( element ) {\n\t\t\tvar val = this.elementValue( element );\n\t\t\treturn !$.validator.methods.required.call( this, val, element ) && \"dependency-mismatch\";\n\t\t},\n\n\t\tstartRequest: function( element ) {\n\t\t\tif ( !this.pending[ element.name ] ) {\n\t\t\t\tthis.pendingRequest++;\n\t\t\t\t$( element ).addClass( this.settings.pendingClass );\n\t\t\t\tthis.pending[ element.name ] = true;\n\t\t\t}\n\t\t},\n\n\t\tstopRequest: function( element, valid ) {\n\t\t\tthis.pendingRequest--;\n\n\t\t\t// Sometimes synchronization fails, make sure pendingRequest is never < 0\n\t\t\tif ( this.pendingRequest < 0 ) {\n\t\t\t\tthis.pendingRequest = 0;\n\t\t\t}\n\t\t\tdelete this.pending[ element.name ];\n\t\t\t$( element ).removeClass( this.settings.pendingClass );\n\t\t\tif ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {\n\t\t\t\t$( this.currentForm ).submit();\n\n\t\t\t\t// Remove the hidden input that was used as a replacement for the\n\t\t\t\t// missing submit button. The hidden input is added by `handle()`\n\t\t\t\t// to ensure that the value of the used submit button is passed on\n\t\t\t\t// for scripted submits triggered by this method\n\t\t\t\tif ( this.submitButton ) {\n\t\t\t\t\t$( \"input:hidden[name='\" + this.submitButton.name + \"']\", this.currentForm ).remove();\n\t\t\t\t}\n\n\t\t\t\tthis.formSubmitted = false;\n\t\t\t} else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {\n\t\t\t\t$( this.currentForm ).triggerHandler( \"invalid-form\", [ this ] );\n\t\t\t\tthis.formSubmitted = false;\n\t\t\t}\n\t\t},\n\n\t\tpreviousValue: function( element, method ) {\n\t\t\tmethod = typeof method === \"string\" && method || \"remote\";\n\n\t\t\treturn $.data( element, \"previousValue\" ) || $.data( element, \"previousValue\", {\n\t\t\t\told: null,\n\t\t\t\tvalid: true,\n\t\t\t\tmessage: this.defaultMessage( element, { method: method } )\n\t\t\t} );\n\t\t},\n\n\t\t// Cleans up all forms and elements, removes validator-specific events\n\t\tdestroy: function() {\n\t\t\tthis.resetForm();\n\n\t\t\t$( this.currentForm )\n\t\t\t\t.off( \".validate\" )\n\t\t\t\t.removeData( \"validator\" )\n\t\t\t\t.find( \".validate-equalTo-blur\" )\n\t\t\t\t\t.off( \".validate-equalTo\" )\n\t\t\t\t\t.removeClass( \"validate-equalTo-blur\" );\n\t\t}\n\n\t},\n\n\tclassRuleSettings: {\n\t\trequired: { required: true },\n\t\temail: { email: true },\n\t\turl: { url: true },\n\t\tdate: { date: true },\n\t\tdateISO: { dateISO: true },\n\t\tnumber: { number: true },\n\t\tdigits: { digits: true },\n\t\tcreditcard: { creditcard: true }\n\t},\n\n\taddClassRules: function( className, rules ) {\n\t\tif ( className.constructor === String ) {\n\t\t\tthis.classRuleSettings[ className ] = rules;\n\t\t} else {\n\t\t\t$.extend( this.classRuleSettings, className );\n\t\t}\n\t},\n\n\tclassRules: function( element ) {\n\t\tvar rules = {},\n\t\t\tclasses = $( element ).attr( \"class\" );\n\n\t\tif ( classes ) {\n\t\t\t$.each( classes.split( \" \" ), function() {\n\t\t\t\tif ( this in $.validator.classRuleSettings ) {\n\t\t\t\t\t$.extend( rules, $.validator.classRuleSettings[ this ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\treturn rules;\n\t},\n\n\tnormalizeAttributeRule: function( rules, type, method, value ) {\n\n\t\t// Convert the value to a number for number inputs, and for text for backwards compability\n\t\t// allows type=\"date\" and others to be compared as strings\n\t\tif ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {\n\t\t\tvalue = Number( value );\n\n\t\t\t// Support Opera Mini, which returns NaN for undefined minlength\n\t\t\tif ( isNaN( value ) ) {\n\t\t\t\tvalue = undefined;\n\t\t\t}\n\t\t}\n\n\t\tif ( value || value === 0 ) {\n\t\t\trules[ method ] = value;\n\t\t} else if ( type === method && type !== \"range\" ) {\n\n\t\t\t// Exception: the jquery validate 'range' method\n\t\t\t// does not test for the html5 'range' type\n\t\t\trules[ method ] = true;\n\t\t}\n\t},\n\n\tattributeRules: function( element ) {\n\t\tvar rules = {},\n\t\t\t$element = $( element ),\n\t\t\ttype = element.getAttribute( \"type\" ),\n\t\t\tmethod, value;\n\n\t\tfor ( method in $.validator.methods ) {\n\n\t\t\t// Support for <input required> in both html5 and older browsers\n\t\t\tif ( method === \"required\" ) {\n\t\t\t\tvalue = element.getAttribute( method );\n\n\t\t\t\t// Some browsers return an empty string for the required attribute\n\t\t\t\t// and non-HTML5 browsers might have required=\"\" markup\n\t\t\t\tif ( value === \"\" ) {\n\t\t\t\t\tvalue = true;\n\t\t\t\t}\n\n\t\t\t\t// Force non-HTML5 browsers to return bool\n\t\t\t\tvalue = !!value;\n\t\t\t} else {\n\t\t\t\tvalue = $element.attr( method );\n\t\t\t}\n\n\t\t\tthis.normalizeAttributeRule( rules, type, method, value );\n\t\t}\n\n\t\t// 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs\n\t\tif ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {\n\t\t\tdelete rules.maxlength;\n\t\t}\n\n\t\treturn rules;\n\t},\n\n\tdataRules: function( element ) {\n\t\tvar rules = {},\n\t\t\t$element = $( element ),\n\t\t\ttype = element.getAttribute( \"type\" ),\n\t\t\tmethod, value;\n\n\t\tfor ( method in $.validator.methods ) {\n\t\t\tvalue = $element.data( \"rule\" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );\n\t\t\tthis.normalizeAttributeRule( rules, type, method, value );\n\t\t}\n\t\treturn rules;\n\t},\n\n\tstaticRules: function( element ) {\n\t\tvar rules = {},\n\t\t\tvalidator = $.data( element.form, \"validator\" );\n\n\t\tif ( validator.settings.rules ) {\n\t\t\trules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};\n\t\t}\n\t\treturn rules;\n\t},\n\n\tnormalizeRules: function( rules, element ) {\n\n\t\t// Handle dependency check\n\t\t$.each( rules, function( prop, val ) {\n\n\t\t\t// Ignore rule when param is explicitly false, eg. required:false\n\t\t\tif ( val === false ) {\n\t\t\t\tdelete rules[ prop ];\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( val.param || val.depends ) {\n\t\t\t\tvar keepRule = true;\n\t\t\t\tswitch ( typeof val.depends ) {\n\t\t\t\tcase \"string\":\n\t\t\t\t\tkeepRule = !!$( val.depends, element.form ).length;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"function\":\n\t\t\t\t\tkeepRule = val.depends.call( element, element );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ( keepRule ) {\n\t\t\t\t\trules[ prop ] = val.param !== undefined ? val.param : true;\n\t\t\t\t} else {\n\t\t\t\t\t$.data( element.form, \"validator\" ).resetElements( $( element ) );\n\t\t\t\t\tdelete rules[ prop ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Evaluate parameters\n\t\t$.each( rules, function( rule, parameter ) {\n\t\t\trules[ rule ] = $.isFunction( parameter ) && rule !== \"normalizer\" ? parameter( element ) : parameter;\n\t\t} );\n\n\t\t// Clean number parameters\n\t\t$.each( [ \"minlength\", \"maxlength\" ], function() {\n\t\t\tif ( rules[ this ] ) {\n\t\t\t\trules[ this ] = Number( rules[ this ] );\n\t\t\t}\n\t\t} );\n\t\t$.each( [ \"rangelength\", \"range\" ], function() {\n\t\t\tvar parts;\n\t\t\tif ( rules[ this ] ) {\n\t\t\t\tif ( $.isArray( rules[ this ] ) ) {\n\t\t\t\t\trules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];\n\t\t\t\t} else if ( typeof rules[ this ] === \"string\" ) {\n\t\t\t\t\tparts = rules[ this ].replace( /[\\[\\]]/g, \"\" ).split( /[\\s,]+/ );\n\t\t\t\t\trules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tif ( $.validator.autoCreateRanges ) {\n\n\t\t\t// Auto-create ranges\n\t\t\tif ( rules.min != null && rules.max != null ) {\n\t\t\t\trules.range = [ rules.min, rules.max ];\n\t\t\t\tdelete rules.min;\n\t\t\t\tdelete rules.max;\n\t\t\t}\n\t\t\tif ( rules.minlength != null && rules.maxlength != null ) {\n\t\t\t\trules.rangelength = [ rules.minlength, rules.maxlength ];\n\t\t\t\tdelete rules.minlength;\n\t\t\t\tdelete rules.maxlength;\n\t\t\t}\n\t\t}\n\n\t\treturn rules;\n\t},\n\n\t// Converts a simple string to a {string: true} rule, e.g., \"required\" to {required:true}\n\tnormalizeRule: function( data ) {\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tvar transformed = {};\n\t\t\t$.each( data.split( /\\s/ ), function() {\n\t\t\t\ttransformed[ this ] = true;\n\t\t\t} );\n\t\t\tdata = transformed;\n\t\t}\n\t\treturn data;\n\t},\n\n\t// https://jqueryvalidation.org/jQuery.validator.addMethod/\n\taddMethod: function( name, method, message ) {\n\t\t$.validator.methods[ name ] = method;\n\t\t$.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];\n\t\tif ( method.length < 3 ) {\n\t\t\t$.validator.addClassRules( name, $.validator.normalizeRule( name ) );\n\t\t}\n\t},\n\n\t// https://jqueryvalidation.org/jQuery.validator.methods/\n\tmethods: {\n\n\t\t// https://jqueryvalidation.org/required-method/\n\t\trequired: function( value, element, param ) {\n\n\t\t\t// Check if dependency is met\n\t\t\tif ( !this.depend( param, element ) ) {\n\t\t\t\treturn \"dependency-mismatch\";\n\t\t\t}\n\t\t\tif ( element.nodeName.toLowerCase() === \"select\" ) {\n\n\t\t\t\t// Could be an array for select-multiple or a string, both are fine this way\n\t\t\t\tvar val = $( element ).val();\n\t\t\t\treturn val && val.length > 0;\n\t\t\t}\n\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\treturn this.getLength( value, element ) > 0;\n\t\t\t}\n\t\t\treturn value.length > 0;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/email-method/\n\t\temail: function( value, element ) {\n\n\t\t\t// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address\n\t\t\t// Retrieved 2014-01-14\n\t\t\t// If you have a problem with this implementation, report a bug against the above spec\n\t\t\t// Or use custom methods to implement your own email validation\n\t\t\treturn this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/url-method/\n\t\turl: function( value, element ) {\n\n\t\t\t// Copyright (c) 2010-2013 Diego Perini, MIT licensed\n\t\t\t// https://gist.github.com/dperini/729294\n\t\t\t// see also https://mathiasbynens.be/demo/url-regex\n\t\t\t// modified to allow protocol-relative URLs\n\t\t\treturn this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})).?)(?::\\d{2,5})?(?:[/?#]\\S*)?$/i.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/date-method/\n\t\tdate: function( value, element ) {\n\t\t\treturn this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/dateISO-method/\n\t\tdateISO: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^\\d{4}[\\/\\-](0?[1-9]|1[012])[\\/\\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/number-method/\n\t\tnumber: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^(?:-?\\d+|-?\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/digits-method/\n\t\tdigits: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^\\d+$/.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/minlength-method/\n\t\tminlength: function( value, element, param ) {\n\t\t\tvar length = $.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || length >= param;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/maxlength-method/\n\t\tmaxlength: function( value, element, param ) {\n\t\t\tvar length = $.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || length <= param;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/rangelength-method/\n\t\trangelength: function( value, element, param ) {\n\t\t\tvar length = $.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/min-method/\n\t\tmin: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || value >= param;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/max-method/\n\t\tmax: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || value <= param;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/range-method/\n\t\trange: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/step-method/\n\t\tstep: function( value, element, param ) {\n\t\t\tvar type = $( element ).attr( \"type\" ),\n\t\t\t\terrorMessage = \"Step attribute on input type \" + type + \" is not supported.\",\n\t\t\t\tsupportedTypes = [ \"text\", \"number\", \"range\" ],\n\t\t\t\tre = new RegExp( \"\\\\b\" + type + \"\\\\b\" ),\n\t\t\t\tnotSupported = type && !re.test( supportedTypes.join() ),\n\t\t\t\tdecimalPlaces = function( num ) {\n\t\t\t\t\tvar match = ( \"\" + num ).match( /(?:\\.(\\d+))?$/ );\n\t\t\t\t\tif ( !match ) {\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Number of digits right of decimal point.\n\t\t\t\t\treturn match[ 1 ] ? match[ 1 ].length : 0;\n\t\t\t\t},\n\t\t\t\ttoInt = function( num ) {\n\t\t\t\t\treturn Math.round( num * Math.pow( 10, decimals ) );\n\t\t\t\t},\n\t\t\t\tvalid = true,\n\t\t\t\tdecimals;\n\n\t\t\t// Works only for text, number and range input types\n\t\t\t// TODO find a way to support input types date, datetime, datetime-local, month, time and week\n\t\t\tif ( notSupported ) {\n\t\t\t\tthrow new Error( errorMessage );\n\t\t\t}\n\n\t\t\tdecimals = decimalPlaces( param );\n\n\t\t\t// Value can't have too many decimals\n\t\t\tif ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {\n\t\t\t\tvalid = false;\n\t\t\t}\n\n\t\t\treturn this.optional( element ) || valid;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/equalTo-method/\n\t\tequalTo: function( value, element, param ) {\n\n\t\t\t// Bind to the blur event of the target in order to revalidate whenever the target field is updated\n\t\t\tvar target = $( param );\n\t\t\tif ( this.settings.onfocusout && target.not( \".validate-equalTo-blur\" ).length ) {\n\t\t\t\ttarget.addClass( \"validate-equalTo-blur\" ).on( \"blur.validate-equalTo\", function() {\n\t\t\t\t\t$( element ).valid();\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn value === target.val();\n\t\t},\n\n\t\t// https://jqueryvalidation.org/remote-method/\n\t\tremote: function( value, element, param, method ) {\n\t\t\tif ( this.optional( element ) ) {\n\t\t\t\treturn \"dependency-mismatch\";\n\t\t\t}\n\n\t\t\tmethod = typeof method === \"string\" && method || \"remote\";\n\n\t\t\tvar previous = this.previousValue( element, method ),\n\t\t\t\tvalidator, data, optionDataString;\n\n\t\t\tif ( !this.settings.messages[ element.name ] ) {\n\t\t\t\tthis.settings.messages[ element.name ] = {};\n\t\t\t}\n\t\t\tprevious.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];\n\t\t\tthis.settings.messages[ element.name ][ method ] = previous.message;\n\n\t\t\tparam = typeof param === \"string\" && { url: param } || param;\n\t\t\toptionDataString = $.param( $.extend( { data: value }, param.data ) );\n\t\t\tif ( previous.old === optionDataString ) {\n\t\t\t\treturn previous.valid;\n\t\t\t}\n\n\t\t\tprevious.old = optionDataString;\n\t\t\tvalidator = this;\n\t\t\tthis.startRequest( element );\n\t\t\tdata = {};\n\t\t\tdata[ element.name ] = value;\n\t\t\t$.ajax( $.extend( true, {\n\t\t\t\tmode: \"abort\",\n\t\t\t\tport: \"validate\" + element.name,\n\t\t\t\tdataType: \"json\",\n\t\t\t\tdata: data,\n\t\t\t\tcontext: validator.currentForm,\n\t\t\t\tsuccess: function( response ) {\n\t\t\t\t\tvar valid = response === true || response === \"true\",\n\t\t\t\t\t\terrors, message, submitted;\n\n\t\t\t\t\tvalidator.settings.messages[ element.name ][ method ] = previous.originalMessage;\n\t\t\t\t\tif ( valid ) {\n\t\t\t\t\t\tsubmitted = validator.formSubmitted;\n\t\t\t\t\t\tvalidator.resetInternals();\n\t\t\t\t\t\tvalidator.toHide = validator.errorsFor( element );\n\t\t\t\t\t\tvalidator.formSubmitted = submitted;\n\t\t\t\t\t\tvalidator.successList.push( element );\n\t\t\t\t\t\tvalidator.invalid[ element.name ] = false;\n\t\t\t\t\t\tvalidator.showErrors();\n\t\t\t\t\t} else {\n\t\t\t\t\t\terrors = {};\n\t\t\t\t\t\tmessage = response || validator.defaultMessage( element, { method: method, parameters: value } );\n\t\t\t\t\t\terrors[ element.name ] = previous.message = message;\n\t\t\t\t\t\tvalidator.invalid[ element.name ] = true;\n\t\t\t\t\t\tvalidator.showErrors( errors );\n\t\t\t\t\t}\n\t\t\t\t\tprevious.valid = valid;\n\t\t\t\t\tvalidator.stopRequest( element, valid );\n\t\t\t\t}\n\t\t\t}, param ) );\n\t\t\treturn \"pending\";\n\t\t}\n\t}\n\n} );\n\n// Ajax mode: abort\n// usage: $.ajax({ mode: \"abort\"[, port: \"uniqueport\"]});\n// if mode:\"abort\" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()\n\nvar pendingRequests = {},\n\tajax;\n\n// Use a prefilter if available (1.5+)\nif ( $.ajaxPrefilter ) {\n\t$.ajaxPrefilter( function( settings, _, xhr ) {\n\t\tvar port = settings.port;\n\t\tif ( settings.mode === \"abort\" ) {\n\t\t\tif ( pendingRequests[ port ] ) {\n\t\t\t\tpendingRequests[ port ].abort();\n\t\t\t}\n\t\t\tpendingRequests[ port ] = xhr;\n\t\t}\n\t} );\n} else {\n\n\t// Proxy ajax\n\tajax = $.ajax;\n\t$.ajax = function( settings ) {\n\t\tvar mode = ( \"mode\" in settings ? settings : $.ajaxSettings ).mode,\n\t\t\tport = ( \"port\" in settings ? settings : $.ajaxSettings ).port;\n\t\tif ( mode === \"abort\" ) {\n\t\t\tif ( pendingRequests[ port ] ) {\n\t\t\t\tpendingRequests[ port ].abort();\n\t\t\t}\n\t\t\tpendingRequests[ port ] = ajax.apply( this, arguments );\n\t\t\treturn pendingRequests[ port ];\n\t\t}\n\t\treturn ajax.apply( this, arguments );\n\t};\n}\nreturn $;\n}));"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt",
    "content": "Copyright (c) .NET Foundation. All rights reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nthese files except in compliance with the License. You may obtain a copy of the\nLicense at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.\n"
  },
  {
    "path": "Src/Mvc/Website/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js",
    "content": "// Unobtrusive validation support library for jQuery and jQuery Validate\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n// @version v3.2.11\n\n/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */\n/*global document: false, jQuery: false */\n\n(function (factory) {\n    if (typeof define === 'function' && define.amd) {\n        // AMD. Register as an anonymous module.\n        define(\"jquery.validate.unobtrusive\", ['jquery-validation'], factory);\n    } else if (typeof module === 'object' && module.exports) {\n        // CommonJS-like environments that support module.exports     \n        module.exports = factory(require('jquery-validation'));\n    } else {\n        // Browser global\n        jQuery.validator.unobtrusive = factory(jQuery);\n    }\n}(function ($) {\n    var $jQval = $.validator,\n        adapters,\n        data_validation = \"unobtrusiveValidation\";\n\n    function setValidationValues(options, ruleName, value) {\n        options.rules[ruleName] = value;\n        if (options.message) {\n            options.messages[ruleName] = options.message;\n        }\n    }\n\n    function splitAndTrim(value) {\n        return value.replace(/^\\s+|\\s+$/g, \"\").split(/\\s*,\\s*/g);\n    }\n\n    function escapeAttributeValue(value) {\n        // As mentioned on http://api.jquery.com/category/selectors/\n        return value.replace(/([!\"#$%&'()*+,./:;<=>?@\\[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n    }\n\n    function getModelPrefix(fieldName) {\n        return fieldName.substr(0, fieldName.lastIndexOf(\".\") + 1);\n    }\n\n    function appendModelPrefix(value, prefix) {\n        if (value.indexOf(\"*.\") === 0) {\n            value = value.replace(\"*.\", prefix);\n        }\n        return value;\n    }\n\n    function onError(error, inputElement) {  // 'this' is the form element\n        var container = $(this).find(\"[data-valmsg-for='\" + escapeAttributeValue(inputElement[0].name) + \"']\"),\n            replaceAttrValue = container.attr(\"data-valmsg-replace\"),\n            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;\n\n        container.removeClass(\"field-validation-valid\").addClass(\"field-validation-error\");\n        error.data(\"unobtrusiveContainer\", container);\n\n        if (replace) {\n            container.empty();\n            error.removeClass(\"input-validation-error\").appendTo(container);\n        }\n        else {\n            error.hide();\n        }\n    }\n\n    function onErrors(event, validator) {  // 'this' is the form element\n        var container = $(this).find(\"[data-valmsg-summary=true]\"),\n            list = container.find(\"ul\");\n\n        if (list && list.length && validator.errorList.length) {\n            list.empty();\n            container.addClass(\"validation-summary-errors\").removeClass(\"validation-summary-valid\");\n\n            $.each(validator.errorList, function () {\n                $(\"<li />\").html(this.message).appendTo(list);\n            });\n        }\n    }\n\n    function onSuccess(error) {  // 'this' is the form element\n        var container = error.data(\"unobtrusiveContainer\");\n\n        if (container) {\n            var replaceAttrValue = container.attr(\"data-valmsg-replace\"),\n                replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;\n\n            container.addClass(\"field-validation-valid\").removeClass(\"field-validation-error\");\n            error.removeData(\"unobtrusiveContainer\");\n\n            if (replace) {\n                container.empty();\n            }\n        }\n    }\n\n    function onReset(event) {  // 'this' is the form element\n        var $form = $(this),\n            key = '__jquery_unobtrusive_validation_form_reset';\n        if ($form.data(key)) {\n            return;\n        }\n        // Set a flag that indicates we're currently resetting the form.\n        $form.data(key, true);\n        try {\n            $form.data(\"validator\").resetForm();\n        } finally {\n            $form.removeData(key);\n        }\n\n        $form.find(\".validation-summary-errors\")\n            .addClass(\"validation-summary-valid\")\n            .removeClass(\"validation-summary-errors\");\n        $form.find(\".field-validation-error\")\n            .addClass(\"field-validation-valid\")\n            .removeClass(\"field-validation-error\")\n            .removeData(\"unobtrusiveContainer\")\n            .find(\">*\")  // If we were using valmsg-replace, get the underlying error\n            .removeData(\"unobtrusiveContainer\");\n    }\n\n    function validationInfo(form) {\n        var $form = $(form),\n            result = $form.data(data_validation),\n            onResetProxy = $.proxy(onReset, form),\n            defaultOptions = $jQval.unobtrusive.options || {},\n            execInContext = function (name, args) {\n                var func = defaultOptions[name];\n                func && $.isFunction(func) && func.apply(form, args);\n            };\n\n        if (!result) {\n            result = {\n                options: {  // options structure passed to jQuery Validate's validate() method\n                    errorClass: defaultOptions.errorClass || \"input-validation-error\",\n                    errorElement: defaultOptions.errorElement || \"span\",\n                    errorPlacement: function () {\n                        onError.apply(form, arguments);\n                        execInContext(\"errorPlacement\", arguments);\n                    },\n                    invalidHandler: function () {\n                        onErrors.apply(form, arguments);\n                        execInContext(\"invalidHandler\", arguments);\n                    },\n                    messages: {},\n                    rules: {},\n                    success: function () {\n                        onSuccess.apply(form, arguments);\n                        execInContext(\"success\", arguments);\n                    }\n                },\n                attachValidation: function () {\n                    $form\n                        .off(\"reset.\" + data_validation, onResetProxy)\n                        .on(\"reset.\" + data_validation, onResetProxy)\n                        .validate(this.options);\n                },\n                validate: function () {  // a validation function that is called by unobtrusive Ajax\n                    $form.validate();\n                    return $form.valid();\n                }\n            };\n            $form.data(data_validation, result);\n        }\n\n        return result;\n    }\n\n    $jQval.unobtrusive = {\n        adapters: [],\n\n        parseElement: function (element, skipAttach) {\n            /// <summary>\n            /// Parses a single HTML element for unobtrusive validation attributes.\n            /// </summary>\n            /// <param name=\"element\" domElement=\"true\">The HTML element to be parsed.</param>\n            /// <param name=\"skipAttach\" type=\"Boolean\">[Optional] true to skip attaching the\n            /// validation to the form. If parsing just this single element, you should specify true.\n            /// If parsing several elements, you should specify false, and manually attach the validation\n            /// to the form when you are finished. The default is false.</param>\n            var $element = $(element),\n                form = $element.parents(\"form\")[0],\n                valInfo, rules, messages;\n\n            if (!form) {  // Cannot do client-side validation without a form\n                return;\n            }\n\n            valInfo = validationInfo(form);\n            valInfo.options.rules[element.name] = rules = {};\n            valInfo.options.messages[element.name] = messages = {};\n\n            $.each(this.adapters, function () {\n                var prefix = \"data-val-\" + this.name,\n                    message = $element.attr(prefix),\n                    paramValues = {};\n\n                if (message !== undefined) {  // Compare against undefined, because an empty message is legal (and falsy)\n                    prefix += \"-\";\n\n                    $.each(this.params, function () {\n                        paramValues[this] = $element.attr(prefix + this);\n                    });\n\n                    this.adapt({\n                        element: element,\n                        form: form,\n                        message: message,\n                        params: paramValues,\n                        rules: rules,\n                        messages: messages\n                    });\n                }\n            });\n\n            $.extend(rules, { \"__dummy__\": true });\n\n            if (!skipAttach) {\n                valInfo.attachValidation();\n            }\n        },\n\n        parse: function (selector) {\n            /// <summary>\n            /// Parses all the HTML elements in the specified selector. It looks for input elements decorated\n            /// with the [data-val=true] attribute value and enables validation according to the data-val-*\n            /// attribute values.\n            /// </summary>\n            /// <param name=\"selector\" type=\"String\">Any valid jQuery selector.</param>\n\n            // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one\n            // element with data-val=true\n            var $selector = $(selector),\n                $forms = $selector.parents()\n                    .addBack()\n                    .filter(\"form\")\n                    .add($selector.find(\"form\"))\n                    .has(\"[data-val=true]\");\n\n            $selector.find(\"[data-val=true]\").each(function () {\n                $jQval.unobtrusive.parseElement(this, true);\n            });\n\n            $forms.each(function () {\n                var info = validationInfo(this);\n                if (info) {\n                    info.attachValidation();\n                }\n            });\n        }\n    };\n\n    adapters = $jQval.unobtrusive.adapters;\n\n    adapters.add = function (adapterName, params, fn) {\n        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>\n        /// <param name=\"adapterName\" type=\"String\">The name of the adapter to be added. This matches the name used\n        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>\n        /// <param name=\"params\" type=\"Array\" optional=\"true\">[Optional] An array of parameter names (strings) that will\n        /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and\n        /// mmmm is the parameter name).</param>\n        /// <param name=\"fn\" type=\"Function\">The function to call, which adapts the values from the HTML\n        /// attributes into jQuery Validate rules and/or messages.</param>\n        /// <returns type=\"jQuery.validator.unobtrusive.adapters\" />\n        if (!fn) {  // Called with no params, just a function\n            fn = params;\n            params = [];\n        }\n        this.push({ name: adapterName, params: params, adapt: fn });\n        return this;\n    };\n\n    adapters.addBool = function (adapterName, ruleName) {\n        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where\n        /// the jQuery Validate validation rule has no parameter values.</summary>\n        /// <param name=\"adapterName\" type=\"String\">The name of the adapter to be added. This matches the name used\n        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>\n        /// <param name=\"ruleName\" type=\"String\" optional=\"true\">[Optional] The name of the jQuery Validate rule. If not provided, the value\n        /// of adapterName will be used instead.</param>\n        /// <returns type=\"jQuery.validator.unobtrusive.adapters\" />\n        return this.add(adapterName, function (options) {\n            setValidationValues(options, ruleName || adapterName, true);\n        });\n    };\n\n    adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {\n        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where\n        /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and\n        /// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>\n        /// <param name=\"adapterName\" type=\"String\">The name of the adapter to be added. This matches the name used\n        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>\n        /// <param name=\"minRuleName\" type=\"String\">The name of the jQuery Validate rule to be used when you only\n        /// have a minimum value.</param>\n        /// <param name=\"maxRuleName\" type=\"String\">The name of the jQuery Validate rule to be used when you only\n        /// have a maximum value.</param>\n        /// <param name=\"minMaxRuleName\" type=\"String\">The name of the jQuery Validate rule to be used when you\n        /// have both a minimum and maximum value.</param>\n        /// <param name=\"minAttribute\" type=\"String\" optional=\"true\">[Optional] The name of the HTML attribute that\n        /// contains the minimum value. The default is \"min\".</param>\n        /// <param name=\"maxAttribute\" type=\"String\" optional=\"true\">[Optional] The name of the HTML attribute that\n        /// contains the maximum value. The default is \"max\".</param>\n        /// <returns type=\"jQuery.validator.unobtrusive.adapters\" />\n        return this.add(adapterName, [minAttribute || \"min\", maxAttribute || \"max\"], function (options) {\n            var min = options.params.min,\n                max = options.params.max;\n\n            if (min && max) {\n                setValidationValues(options, minMaxRuleName, [min, max]);\n            }\n            else if (min) {\n                setValidationValues(options, minRuleName, min);\n            }\n            else if (max) {\n                setValidationValues(options, maxRuleName, max);\n            }\n        });\n    };\n\n    adapters.addSingleVal = function (adapterName, attribute, ruleName) {\n        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where\n        /// the jQuery Validate validation rule has a single value.</summary>\n        /// <param name=\"adapterName\" type=\"String\">The name of the adapter to be added. This matches the name used\n        /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>\n        /// <param name=\"attribute\" type=\"String\">[Optional] The name of the HTML attribute that contains the value.\n        /// The default is \"val\".</param>\n        /// <param name=\"ruleName\" type=\"String\" optional=\"true\">[Optional] The name of the jQuery Validate rule. If not provided, the value\n        /// of adapterName will be used instead.</param>\n        /// <returns type=\"jQuery.validator.unobtrusive.adapters\" />\n        return this.add(adapterName, [attribute || \"val\"], function (options) {\n            setValidationValues(options, ruleName || adapterName, options.params[attribute]);\n        });\n    };\n\n    $jQval.addMethod(\"__dummy__\", function (value, element, params) {\n        return true;\n    });\n\n    $jQval.addMethod(\"regex\", function (value, element, params) {\n        var match;\n        if (this.optional(element)) {\n            return true;\n        }\n\n        match = new RegExp(params).exec(value);\n        return (match && (match.index === 0) && (match[0].length === value.length));\n    });\n\n    $jQval.addMethod(\"nonalphamin\", function (value, element, nonalphamin) {\n        var match;\n        if (nonalphamin) {\n            match = value.match(/\\W/g);\n            match = match && match.length >= nonalphamin;\n        }\n        return match;\n    });\n\n    if ($jQval.methods.extension) {\n        adapters.addSingleVal(\"accept\", \"mimtype\");\n        adapters.addSingleVal(\"extension\", \"extension\");\n    } else {\n        // for backward compatibility, when the 'extension' validation method does not exist, such as with versions\n        // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for\n        // validating the extension, and ignore mime-type validations as they are not supported.\n        adapters.addSingleVal(\"extension\", \"extension\", \"accept\");\n    }\n\n    adapters.addSingleVal(\"regex\", \"pattern\");\n    adapters.addBool(\"creditcard\").addBool(\"date\").addBool(\"digits\").addBool(\"email\").addBool(\"number\").addBool(\"url\");\n    adapters.addMinMax(\"length\", \"minlength\", \"maxlength\", \"rangelength\").addMinMax(\"range\", \"min\", \"max\", \"range\");\n    adapters.addMinMax(\"minlength\", \"minlength\").addMinMax(\"maxlength\", \"minlength\", \"maxlength\");\n    adapters.add(\"equalto\", [\"other\"], function (options) {\n        var prefix = getModelPrefix(options.element.name),\n            other = options.params.other,\n            fullOtherName = appendModelPrefix(other, prefix),\n            element = $(options.form).find(\":input\").filter(\"[name='\" + escapeAttributeValue(fullOtherName) + \"']\")[0];\n\n        setValidationValues(options, \"equalTo\", element);\n    });\n    adapters.add(\"required\", function (options) {\n        // jQuery Validate equates \"required\" with \"mandatory\" for checkbox elements\n        if (options.element.tagName.toUpperCase() !== \"INPUT\" || options.element.type.toUpperCase() !== \"CHECKBOX\") {\n            setValidationValues(options, \"required\", true);\n        }\n    });\n    adapters.add(\"remote\", [\"url\", \"type\", \"additionalfields\"], function (options) {\n        var value = {\n            url: options.params.url,\n            type: options.params.type || \"GET\",\n            data: {}\n        },\n            prefix = getModelPrefix(options.element.name);\n\n        $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {\n            var paramName = appendModelPrefix(fieldName, prefix);\n            value.data[paramName] = function () {\n                var field = $(options.form).find(\":input\").filter(\"[name='\" + escapeAttributeValue(paramName) + \"']\");\n                // For checkboxes and radio buttons, only pick up values from checked fields.\n                if (field.is(\":checkbox\")) {\n                    return field.filter(\":checked\").val() || field.filter(\":hidden\").val() || '';\n                }\n                else if (field.is(\":radio\")) {\n                    return field.filter(\":checked\").val() || '';\n                }\n                return field.val();\n            };\n        });\n\n        setValidationValues(options, \"remote\", value);\n    });\n    adapters.add(\"password\", [\"min\", \"nonalphamin\", \"regex\"], function (options) {\n        if (options.params.min) {\n            setValidationValues(options, \"minlength\", options.params.min);\n        }\n        if (options.params.nonalphamin) {\n            setValidationValues(options, \"nonalphamin\", options.params.nonalphamin);\n        }\n        if (options.params.regex) {\n            setValidationValues(options, \"regex\", options.params.regex);\n        }\n    });\n    adapters.add(\"fileextensions\", [\"extensions\"], function (options) {\n        setValidationValues(options, \"extension\", options.params.extensions);\n    });\n\n    $(function () {\n        $jQval.unobtrusive.parse(document);\n    });\n\n    return $jQval.unobtrusive;\n}));\n"
  },
  {
    "path": "Src/Oqtane/.gitignore",
    "content": ".vs/\nbin/\nobj/\n*.user\nartifacts/\nmsbuild.binlog\n.vscode/\n*.binlog\n*.nupkg\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/App/Index.razor",
    "content": "@* ReSharper disable once CheckNamespace *@\n@namespace ToSic.Sxc.Oqt.App\n@inherits ModuleProBase\n@((MarkupString)Content)\n\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/App/Index.razor.cs",
    "content": "﻿using Microsoft.AspNetCore.Components;\nusing Microsoft.JSInterop;\nusing Oqtane.Models;\nusing Oqtane.Shared;\nusing System.Globalization;\nusing ToSic.Sxc.Oqt.Client.Services;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Oqt.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class Index : ModuleProBase\n{\n    #region Injected Services\n\n    [Inject] public IOqtSxcRenderService OqtSxcRenderService { get; set; } = null!;\n    [Inject] public OqtPageChangeService OqtPageChangeService { get; set; } = null!;\n    [Inject] public IJSRuntime JsRuntime { get; set; } = null!;\n    [Inject] public IOqtPageChangesOnServerService OqtPageChangesOnServerService { get; set; } = null!;\n    [Inject] public IOqtPrerenderService OqtPrerenderService { get; set; } = null!;\n    [Inject] public RenderSpecificLockManager RenderSpecificLockManager { get; set; } = null!;\n    [Inject] public IRenderInfoService RenderInfoService { get; set; } = null!;\n    #endregion\n\n    #region Oqtane Properties\n\n    public override string RenderMode => RenderModes.Static;\n\n    public override List<Resource> Resources =>\n    [\n        // Reload = true for Oqtane 6.0.0 or older (remove when dependency is updated to Oqtane 6.0.1)\n        new Script($\"Modules/{OqtConstants.PackageName}/Module.js\"),\n        new Script($\"Modules/{OqtConstants.PackageName}/dist/turnOn/turn-on.js\"),\n    ];\n\n    #endregion\n\n    #region Shared Variables\n\n    protected string Content { get; private set; } = \"\";\n\n    private OqtViewResultsDto? _viewResults;\n    private RenderParameters? _renderedParameters;\n    private bool _newDataArrived;\n\n    #endregion\n\n    protected override void OnInitialized()\n    {\n        Log($\"2sxc Blazor Logging Enabled on {OqtDebugStateService.Platform}\");  // will only show if it's enabled\n        Log($\"- ModuleState.RenderMode: {RenderMode}\");\n        Log($\"- PageState.RenderMode: {PageState?.RenderMode}\");\n        Log($\"- PageState.Runtime: {PageState?.Runtime}\");\n        Log($\"- Static SSR: {RenderInfoService.IsStaticSsr(RenderMode)}\");\n        Log($\"- Blazor Enhanced Nav: {RenderInfoService.IsBlazorEnhancedNav(RenderMode)}\");\n        Log($\"- SSR Framing: {RenderInfoService.IsSsrFraming(RenderMode)}\");\n        Log($\"- RendererInfo.IsInteractive: {RendererInfo.IsInteractive}\");\n        Log($\"- RendererInfo.Name: {RendererInfo.Name}\");\n    }\n\n    //protected override async Task OnInitializedAsync()\n    //{\n    //    await base.OnInitializedAsync();\n    //    Log($\"2sxc Blazor Logging Enabled on {OqtDebugStateService.Platform}\");  // will only show if it's enabled\n    //}\n\n    /// <summary>\n    /// Lifecycle method is executed for every component parameters change\n    /// </summary>\n    /// <remarks>\n    /// This method is called before the first render of the component and whenever the component's parameters are updated: PageState, ModuleState, ModuleInstance.\n    /// Route change will create new PageState in Oqtane Router, etc...\n    /// </remarks>\n    /// <returns></returns>\n    protected override async Task OnParametersSetAsync()\n    {\n        await base.OnParametersSetAsync();\n\n        var @params = new RenderParameters\n        {\n            AliasId = PageState.Alias.AliasId,\n            PageId = PageState.Page.PageId,\n            ModuleId = ModuleState.ModuleId,\n            Culture = CultureInfo.CurrentUICulture.Name,\n            PreRender = IsPrerendering(),\n            OriginalParameters = NavigationManager.ToAbsoluteUri(NavigationManager.Uri).Query\n        };\n\n        try\n        {\n            Log($\"OnParametersSetAsync(NewDataArrived:{_newDataArrived})\");\n\n            // Call 2sxc engine only when is necessary to render control, because it is heavy operation and\n            // OnParametersSetAsync is executed more than ounce for single page navigation change.\n            // 2sxc module render state depends on AliasId, PageId, ModuleId, Culture, Query...\n            // Optimally it should be executed ounce for single page navigation change, but with correct PageId and ModuleId.\n            // Still during change of PageState and ModuleState sometimes we get old ModuleId from older page, before we get correct ModuleId from new page.\n            if (ShouldRenderSxcView(@params))\n            {\n                Log(\"Need to render\");\n\n                // Ensure that only one thread is rendering the module at a time.\n                // This prevents exception \"Some Stream-Wirings were not created\" #3291\n                using (await RenderSpecificLockManager.LockAsync(ModuleState.RenderId))\n                {\n                    _viewResults = await RenderSxcView(@params);\n                    if (_viewResults != null)\n                    {\n                        _newDataArrived = true;\n                        Log($\"NewDataArrived:{_newDataArrived}\");\n\n                        var newContent = OqtPageChangeService.ProcessPageChanges(_viewResults, SiteState, this);\n\n                        #region Static SSR\n                        if (PageState.RenderMode == RenderModes.Static)\n                            if (!RenderInfoService.IsSsrFraming(PageState.RenderMode)) // SSR First load on 2sxc page\n                            {\n                                Log($\"SSR First load on 2sxc page - {nameof(OqtPageChangeService.AttachScriptsAndStylesStaticallyInHtml)}\");\n                                newContent = OqtPageChangeService.AttachScriptsAndStylesStaticallyInHtml(_viewResults, SiteState, newContent, Theme?.Name ?? \"error\");\n                            }\n                            else // SSR Partial load after starting on 2sxc page\n                            {\n                                Log($\"SSR Partial load after starting on 2sxc page - {nameof(OqtPageChangeService.AttachScriptsAndStylesDynamicallyWithTurnOn)}\");\n                                newContent = OqtPageChangeService.AttachScriptsAndStylesDynamicallyWithTurnOn(_viewResults, SiteState, newContent, Theme?.Name ?? \"error\", ModuleState.RenderId);\n                            }\n                        #endregion\n\n                        if (Content != newContent)\n                        {\n                            Log($\"Set Content (old:{Content.Length}; new:{newContent.Length})\");\n                            Content = newContent;\n                        }\n\n                        // convenient place to apply Csp HttpHeaders to response\n                        var count = OqtPageChangesOnServerService.ApplyHttpHeaders(_viewResults, this);\n                        Log($\"Csp:{count}\");\n                    }\n                }\n            }\n        }\n        catch (Exception ex)\n        {\n            LogError(ex);\n        }\n    }\n\n    /// <inheritdoc/>\n    protected override async Task OnAfterRenderAsync(bool firstRender)\n    {\n        // INTERACTIVE mode only\n        await base.OnAfterRenderAsync(firstRender);\n\n        try\n        {\n            Log($\"OnAfterRenderAsync(firstRender:{firstRender},NewDataArrived:{_newDataArrived},ViewResults:{_viewResults != null})\");\n\n            // 2sxc part should be executed only if new 2sxc data arrived from server (ounce per view)\n            if (IsSafeToRunJs && _newDataArrived && _viewResults != null)\n            {\n                _newDataArrived = false;\n\n                #region HTML response, part 2 (Interactive)\n                Log(\"2.1: NewDataArrived\");\n                await OqtPageChangeService.AttachScriptsAndStylesForInteractiveRendering(_viewResults, SxcInterop, this);\n                #endregion\n\n                StateHasChanged();\n\n                _dotNetObjectReference = DotNetObjectReference.Create(this);\n                // Register ReloadModule\n                //if (PageState.Runtime is Runtime.WebAssembly /*or Runtime.Auto*/) \n                await JSRuntime.InvokeVoidAsync($\"{OqtConstants.PackageName}.registerReloadModule\", _dotNetObjectReference, ModuleState.ModuleId);\n            }\n\n            Log($\"2 end: OnAfterRenderAsync(firstRender:{firstRender},NewDataArrived:{_newDataArrived},ViewResults:{_viewResults != null})\");\n        }\n        catch (Exception ex)\n        {\n            LogError(ex);\n        }\n    }\n    private DotNetObjectReference<Index>? _dotNetObjectReference;\n\n    // This is called from JS to reload module content from blazor (instead of ajax that breaks blazor)\n    // 2024-07-04 stv, looks that is not necessary anymore, we can probably remove it\n    // we had different strategy for Interactive and SSR to refresh module content on page after edit using 2sxc Edit UI\n    // Interactive use this 'ReloadModule' method to update DOM, but this breaks from Oqtane 5.1.2 because of blazor.web.js\n    // so initial fix was just to reload page with window.location.reload()\n    // but after more testing it looks that strategy we use for Static SSR is good enough for all cases\n    // if this is true we can remove this code in total\n    [JSInvokable(\"ReloadModule\")]\n    public async Task ReloadModule()\n    {\n        var @params = new RenderParameters\n        {\n            AliasId = PageState.Alias.AliasId,\n            PageId = PageState.Page.PageId,\n            ModuleId = ModuleState.ModuleId,\n            Culture = CultureInfo.CurrentUICulture.Name,\n            PreRender = IsPrerendering(),\n            OriginalParameters = NavigationManager.ToAbsoluteUri(NavigationManager.Uri).Query\n        };\n\n        try\n        {\n            Log(\"3: ReloadModule\");\n            _viewResults = await RenderSxcView(@params);\n\n            if (_viewResults != null)\n            {\n                var newContent = _viewResults.FinalHtml;\n\n                OqtPageChangeService.ProcessPageChanges(_viewResults, SiteState, this);\n\n                if (PageState.RenderMode == RenderModes.Static) // Static SSR\n                    newContent = OqtPageChangeService.AttachScriptsAndStylesStaticallyInHtml(_viewResults, SiteState, newContent, Theme?.Name ?? \"error\");\n                else // Interactive\n                    await OqtPageChangeService.AttachScriptsAndStylesForInteractiveRendering(_viewResults, SxcInterop, this);\n\n                if (Content != newContent) Content = newContent;\n\n                StateHasChanged();\n            }\n        }\n        catch (Exception ex)\n        {\n            LogError(ex);\n        }\n    }\n\n    public void Dispose()\n    {\n        _dotNetObjectReference?.Dispose();\n    }\n\n    /// <summary>\n    /// Filter to render the control only when is necessary.\n    /// </summary>\n    /// <remarks>\n    /// Call 2sxc engine only when is necessary to render control, because it is heavy operation and\n    /// OnParametersSetAsync is executed more than ounce for single page navigation change.\n    /// 2sxc module render state depends on AliasId, PageId, ModuleId, Culture, Query...\n    /// Optimally it should be executed ounce for single page navigation change, but with correct PageId and ModuleId.\n    /// Still during change of PageState and ModuleState sometimes we get old ModuleId from older page, before we get correct ModuleId from new page.\n    /// </remarks>\n    /// <returns></returns>\n    private bool ShouldRenderSxcView(RenderParameters @params)\n    {\n        // 1st criteria\n        if (!ShouldRender()) return false;\n\n        // first render of new instance of oqtane module\n        if (_renderedParameters == null)\n        {\n            _renderedParameters = @params;\n            return true;\n        }\n\n        // 2nd criteria - render parameters are not changed from the last render\n        if (_renderedParameters.Equals(@params)) return false;\n\n        // render parameters are changed, store them for the next render\n        _renderedParameters = @params;\n        return true;\n    }\n\n    /// <summary>\n    /// Prepare the html / headers for later rendering\n    /// </summary>\n    private async Task<OqtViewResultsDto?> RenderSxcView(RenderParameters @params)\n    {\n        Log(\"Get html and other view resources from server\");\n        var viewResults = await OqtSxcRenderService.RenderAsync(@params);\n\n        if (!string.IsNullOrEmpty(viewResults?.ErrorMessage))\n            LogError(viewResults.ErrorMessage);\n\n        Log($\"Html:{viewResults?.Html?.Length ?? -1}\");\n\n        // finalize with prerendered html\n        if (viewResults != null)\n            viewResults.PrerenderHtml = OqtPrerenderService.GetPrerenderHtml(@params.PreRender, viewResults, SiteState, ThemeType);\n\n        return viewResults;\n    }\n\n    #region Theme\n    private Theme? Theme => PageState.Site.Themes.FirstOrDefault(theme => theme.Themes.Any(themeControl => themeControl.TypeName == ThemeType));\n\n    private string ThemeType => PageState.Page.ThemeType ?? PageState.Site.DefaultThemeType;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/App/ModuleInfo.cs",
    "content": "using Oqtane.Models;\nusing Oqtane.Modules;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Oqt.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ModuleInfo : IModule\n{\n    public ModuleDefinition ModuleDefinition => Content.ModuleInfo.BuildModuleDefinition(\"App\", \"2sxc Apps are rich, self-contained extensions\");\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/App/ModuleProBase.razor.cs",
    "content": "﻿using Microsoft.AspNetCore.Components;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.JSInterop;\nusing Oqtane.Modules;\nusing Oqtane.Security;\nusing Oqtane.Shared;\nusing System.Collections.Concurrent;\nusing ToSic.Sxc.Oqt.Client;\nusing ToSic.Sxc.Oqt.Shared.Helpers;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Oqt.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class ModuleProBase: ModuleBase, IOqtHybridLog\n{\n    #region Injected Services\n\n    [Inject] public NavigationManager NavigationManager { get; set; } = null!;\n    [Inject] public IOqtDebugStateService OqtDebugStateService { get; set; } = null!;\n    [Inject] public IConfiguration Configuration { get; set; } = null!;\n\n    #endregion\n\n    #region Shared Variables\n    public bool IsSuperUser => _isSuperUser ??= UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);\n    private bool? _isSuperUser;\n\n    [InternalApi_DoNotUse_MayChangeWithoutNotice]\n    public bool IsAdmin => _isAdmin ??= UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);\n    private bool? _isAdmin;\n\n    public SxcInterop SxcInterop = null!;\n    public bool IsSafeToRunJs;\n    public readonly ConcurrentQueue<object[]> LogMessageQueue = new();\n\n    public bool FirstRender = true;\n\n    #endregion\n\n    protected override async Task OnParametersSetAsync()\n    {\n        await base.OnParametersSetAsync();\n\n        var debugEnabled = await OqtDebugStateService.GetDebugAsync();\n        if (!debugEnabled && NavigationManager.TryGetQueryString<bool>(\"debug\", out var debugInQueryString))\n            OqtDebugStateService.SetDebug(debugInQueryString);\n    }\n\n    protected override async Task OnAfterRenderAsync(bool firstRender)\n    {\n        await base.OnAfterRenderAsync(firstRender);\n        FirstRender = firstRender;\n\n        // Only enable JS after the page is interactive (not during prerender)\n        if (!IsSafeToRunJs && !IsPrerendering())\n        {\n            SxcInterop ??= new(JSRuntime);\n            IsSafeToRunJs = true;\n        }\n    }\n\n    /// <summary>\n    /// Determines if the current page is in the prerendering phase.\n    /// </summary>\n    /// <remarks>\n    /// This is a 2sxc implementation which provides an approximation suitable for PreRendering purposes. \n    /// However, it may not always return accurate results, especially with \"WebAssemblyPrerendered\" where it might return an incorrect true value.\n    /// This behavior is acceptable for our PreRendering support.\n    /// It's important to note that we cannot solely rely on Oqtane.Shared.SiteState.IsPrerendering property. \n    /// In Oqtane, this property indicates that a page isn't prerendering if the response has already started, which differs from our use-case.\n    /// </remarks>\n    /// <returns>True if the page is in the prerendering phase; otherwise, false.</returns>\n    public bool IsPrerendering() =>\n        (PageState.Site.Prerender) // Checks the site's render mode.\n        && FirstRender // Ensures this is the first render.\n        && SiteState.IsPrerendering; // Validates the prerendering state of the current page.\n\n    #region Log Helpers\n    /// <summary>\n    /// console.log\n    /// </summary>\n    /// <param name=\"message\"></param>\n    /// <returns></returns>\n    public void Log(params object[] message)\n    {\n        // If the url has a debug=true and we are the super-user\n        if (message == null! || !message.Any() || !OqtDebugStateService.IsDebugEnabled || !IsSuperUser) return;\n\n        _logPrefix ??= $\"2sxc:Page({PageState?.Page?.PageId}):Mod({ModuleState?.ModuleId}):Render({ModuleState?.RenderId}):\";\n        try\n        {\n            // log on web server / webassembly console\n            foreach (var item in message)\n                Console.WriteLine($\"{_logPrefix} {item}\");\n\n            if (OqtDebugStateService.Platform == \"Server\")\n            {\n                // log to browser console\n                if (IsSafeToRunJs)\n                {\n                    // first log messages from queue\n                    var timeOut = 0;\n                    while (!LogMessageQueue.IsEmpty && timeOut < 100)\n                    {\n                        if (LogMessageQueue.TryDequeue(out var messageToLog))\n                        {\n                            ConsoleLog(new List<object> { $\"dequeue({LogMessageQueue.Count}):\" }.Concat(messageToLog).ToArray());\n                            timeOut = 0;\n                        }\n                        else\n                            timeOut++;\n                    }\n\n                    // than log current message\n                    ConsoleLog(message);\n                }\n                else\n                {\n                    // browser is not ready, so store messages in queue\n                    LogMessageQueue.Enqueue(message.ToArray());\n                }\n            }\n\n            // log to oqtane log if possible\n            try\n            {\n                foreach (var item in message)\n                    logger.LogDebug($\"{_logPrefix} {item}\");\n            }\n            catch\n            {\n                // sink\n            }\n        }\n        catch (Exception ex)\n        {\n            LogError(ex);\n        }\n    }\n        \n    [InternalApi_DoNotUse_MayChangeWithoutNotice]\n    public void LogError(Exception ex) => LogError(ErrorHelper.ErrorMessage(ex, IsSuperUser || IsAdmin));\n        \n    [InternalApi_DoNotUse_MayChangeWithoutNotice]\n    public void LogError(string errorMessage)\n    {\n        try\n        {\n            // log to web server log\n            Console.WriteLine($\"Error:{_logPrefix}:{errorMessage}\");\n\n            // log to browser console\n            if (IsSafeToRunJs)\n                JSRuntime.InvokeVoidAsync(ConsoleLogJs, \"Error:\", _logPrefix, errorMessage);\n            else\n                LogMessageQueue.Enqueue(new List<object> { \"Error:\", _logPrefix ?? \"\", errorMessage }.ToArray());\n\n            // log error to oqtane log if possible\n            try\n            {\n                logger.LogError(errorMessage);\n            }\n            catch\n            {\n                // sink\n            }\n            AddModuleMessage(errorMessage, MessageType.Warning);\n        }\n        catch\n        {\n            // sink\n        }\n    }\n        \n    private void ConsoleLog(object[] message)\n    {\n        var data = new List<object?> { _logPrefix }.Concat(message);\n        JSRuntime.InvokeVoidAsync(ConsoleLogJs, data.ToArray());\n    } \n    private string? _logPrefix;\n    private const string ConsoleLogJs = \"console.log\";\n    #endregion\n\n    public bool IsDev => Configuration[\"Environment\"] == \"Development\";\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/App/Settings.razor",
    "content": "@* ReSharper disable once CheckNamespace *@\n@namespace ToSic.Sxc.Oqt.App\n@inherits ModuleBase\n@inject ISettingService SettingService\n\n<table class=\"table table-borderless\"></table>\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/App/Settings.razor.cs",
    "content": "﻿using Oqtane.Modules;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Oqt.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class Settings\n{\n    public override string Title => \"2sxc App Settings\";\n\n    protected override async Task OnInitializedAsync()\n    {\n        try\n        {\n\n        }\n        catch (Exception ex)\n        {\n            await Task.Run(() => ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error));\n        }\n    }\n\n    public async Task UpdateSettings()\n    {\n        try\n        {\n\n        }\n        catch (Exception ex)\n        {\n            await Task.Run(() => ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error));\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/ClientStartup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Oqtane.Services;\nusing ToSic.Sxc.Oqt.Client.Services;\nusing ToSic.Sxc.Oqt.Client.Services.NoOp;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\n\nnamespace ToSic.Sxc.Oqt.Client;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ClientStartup : IClientStartup\n{\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public void ConfigureServices(IServiceCollection services)\n    {\n        // Must register services here, because can not use IService for registration when service has DI interface in another assembly (like ToSic.Sxc.Oqtane.Shared.dll)\n        services.TryAddScoped<OqtPageChangeService>();\n        services.TryAddScoped<IOqtSxcRenderService, OqtSxcRenderService>();\n        services.TryAddScoped<IRenderInfoService, RenderInfoService>();\n        services.TryAddScoped<IOqtTurnOnService, OqtTurnOnService>();\n        services.TryAddScoped<IOqtDebugStateService, OqtDebugStateService>();\n        services.TryAddScoped<CacheBustingService>();\n\n        // No Operation Service\n        services.AddScoped<IOqtPageChangesOnServerService, OqtPageChangesOnServerNoOpService>();\n        services.TryAddScoped<IOqtPrerenderService, OqtPrerenderNoOpService>();\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Content/Index.razor",
    "content": "@* ReSharper disable once CheckNamespace *@\n@namespace ToSic.Sxc.Oqt.Content\n@inherits ToSic.Sxc.Oqt.App.Index\n@((MarkupString)Content)\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Content/ModuleInfo.cs",
    "content": "using Oqtane.Models;\nusing Oqtane.Modules;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Oqt.Content;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ModuleInfo : IModule\n{\n    private const string Content = \"Content\";\n    /*\n     * History\n     * These version numbers shouldn't be exactly like the normal ones, so we use a \"-\" instead of \".\" so it won't be replaced on search/replace\n     *\n     * List of 2sxc versions with special relevance to Oqtane\n     * 12-00-00 - SQL - 2sxc oqtane module first release.\n     * 12-05-00 - SQL - Oqtane db fix for folders\n     * 13-00-00 - SQL - update TargetTypes Metadata\n     * 13-01-00 - SQL - add SysSettings column to Apps table + add TargetTypes Metadata\n     * 15-00-00 - SQL - updates for DataTimeline table\n     * 16-07-01 - SQL - add Json for Attribute and ContentType configuration + Guid for Attribute\n     * 18-03-00 - SQL - remove AttributeGroups SQL table and related\n     * 19-00-00 - SQL - CASCADE DELETE on REFERENCE constraint FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes\n     * 20-00-00 - SQL - Drop table ToSIC_EAV_ContextInfo, ToSIC_EAV_AttributesInSets, etc\n     * 20-00-05 - SQL - Fixes and small updates, etc\n     * 21-00-00 - SQL - TsDynDataHistory: add ParentRef\n     */\n    \n    /// <summary>\n    /// The SQL versions must use a \"-\" to avoid being replaced on search/replace when releasing a new version.\n    /// When SQL script is added in new version, include new version explicitly in this array.\n    /// </summary>\n    internal static string[] SqlScriptVersions =\n    [\n        \"12-00-00\",\n        \"12-05-00\",\n        \"13-00-00\",\n        \"13-01-00\",\n        \"15-00-00\",\n        \"16-07-01\",\n        \"18-03-00\",\n        \"19-00-00\",\n        ModuleInfoConstants.V20_00_00,\n        \"20-00-05\",\n        ModuleInfoConstants.V21_00_00,\n    ];\n\n    /// <summary>\n    /// Merge versions for use in Oqtane version list\n    /// </summary>\n    /// <returns></returns>\n    internal static string GetSqlAndLatestVersions(string name)\n    {\n        if (name != Content) return \"\";\n        var versionsWithDot = SqlScriptVersions\n            .Select(v => v.Replace('-', '.'))\n            .Append(EavSystemInfo.VersionString)\n            .ToList();\n        // remove duplicates in case the current version also has SQL scripts\n        var versions = versionsWithDot.Distinct();\n        return string.Join(',', versions);\n    }\n\n    internal static ModuleDefinition BuildModuleDefinition(string name, string description) => new()\n    {\n        Name = name,\n        Description = description,\n        Categories = \"Common\",\n        Version = EavSystemInfo.VersionString, // Must be duplicated here, so Oqtane Client doesn't depend on server DLLs\n        Owner = \"2sic Internet Solutions\",\n        Url = \"https://2sxc.org\",\n        Contact = \"@iJungleboy\",\n        License = \"MIT\",\n        Dependencies = \"ToSic.Sxc.Oqtane.Shared,ToSic.Sys.Core\",\n        // PermissionNames = \"\",\n        ServerManagerType = \"ToSic.Sxc.Oqt.Server.Installation.SxcManager, ToSic.Sxc.Oqtane.Server\",\n        // ControlTypeRoutes = \"\",\n        // This must contain all versions with a SQL script and current/latest version\n        // list versions with sql scripts in \\ToSic.Sxc.Oqt.Server\\Scripts\\\n        ReleaseVersions = GetSqlAndLatestVersions(name),\n        // DefaultAction = \"\",\n        // SettingsType = \"\",\n        PackageName = OqtConstants.PackageName, // \"ToSic.Sxc.Oqtane\"\n        Runtimes = \"\", // string.Empty enables all runtimes\n        Template = \"\", // \"External\" (not \"internal\") \"Default Module Template\"\n\n    };\n\n    public ModuleDefinition ModuleDefinition => BuildModuleDefinition(Content, \"Text/Image layouts using structured content\");\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Content/Settings.razor",
    "content": "@* ReSharper disable once CheckNamespace *@\n@namespace ToSic.Sxc.Oqt.Content\n@inherits ModuleBase\n@inject ISettingService SettingService\n\n<table class=\"table table-borderless\"></table>\n\n@code {\n    public override string Title => \"2sxc Content Settings\";\n\n    protected override async Task OnInitializedAsync()\n    {\n        try\n        {\n\n        }\n        catch (Exception ex)\n        {\n          await Task.Run(() => ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error));\n        }\n    }\n\n    public async Task UpdateSettings()\n    {\n        try\n        {\n\n        }\n        catch (Exception ex)\n        {\n          await Task.Run(() => ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error));\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using Oqtane.Documentation;\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Helpers/NavigationManagerExtensions.cs",
    "content": "﻿using Microsoft.AspNetCore.Components;\nusing System.Collections.Specialized;\nusing UrlHelpers = ToSic.Sxc.Oqt.Shared.UrlHelpers;\n\nnamespace ToSic.Sxc.Oqt.Client;\n\n/// <summary>\n/// https://chrissainty.com/working-with-query-strings-in-blazor/\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class NavigationManagerExtensions\n{\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static bool TryGetQueryString<T>(this NavigationManager navManager, string key, out T? value)\n    {\n        var uri = navManager.ToAbsoluteUri(navManager.Uri);\n\n        if (TryGetValue(UrlHelpers.ParseQueryString(uri.Query), key, out var valueFromQueryString))\n        {\n            if (typeof(T) == typeof(bool) && bool.TryParse(valueFromQueryString, out var valueAsBool))\n            {\n                value = (T)(object)valueAsBool;\n                return true;\n            }\n\n            if (typeof(T) == typeof(int) && int.TryParse(valueFromQueryString, out var valueAsInt))\n            {\n                value = (T)(object)valueAsInt;\n                return true;\n            }\n\n            if (typeof(T) == typeof(string))\n            {\n                value = (T?)(object?)valueFromQueryString;\n                return true;\n            }\n\n            if (typeof(T) == typeof(decimal) && decimal.TryParse(valueFromQueryString, out var valueAsDecimal))\n            {\n                value = (T)(object)valueAsDecimal;\n                return true;\n            }\n        }\n\n        value = default;\n        return false;\n    }\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static bool TryGetValue(NameValueCollection collection, string key, out string? value)\n    {\n        value = collection[key];\n        return value != null;\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/CacheBustingService.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Client.Services;\n\npublic class CacheBustingService\n{\n    private readonly Dictionary<Guid, int> _cache = [];\n        \n    public int Get(Guid renderId)\n    {\n        if (_cache.TryGetValue(renderId, out var cache)) \n            return cache;\n            \n        var bytes = renderId.ToByteArray();\n        var sum = bytes.Aggregate(0, (current, b) => current + b);\n        // Ensure the result is within the 7-digit range\n        var sevenDigitInt = 1000000 + (sum % 9000000);\n\n        _cache[renderId] = sevenDigitInt;\n\n        return sevenDigitInt;\n    }\n\n    public string CacheBusting(string? url, Guid renderId)\n    {\n        if (string.IsNullOrEmpty(url))\n            return \"\";\n\n        if (!url.Contains('#'))\n            return UrlWithCacheBusting(url, renderId);\n\n        return UrlWithCacheBusting(url + \"!\", renderId);\n    }\n\n    private string UrlWithCacheBusting(string url, Guid renderId) => $\"{url}#{Get(renderId)}\";\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/NoOp/OqtPageChangesOnServerNoOpService.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Client.Services.NoOp;\n\n/// <summary>\n/// No Operation Service\n/// This is NoOp implementation, just to not break Sxc.Oqt.Client code, during service injection.\n/// This code is not doing real work, because it is done in Sxc.Oqt.Server\n/// </summary>\ninternal class OqtPageChangesOnServerNoOpService : IOqtPageChangesOnServerService\n{\n    public int ApplyHttpHeaders(OqtViewResultsDto result, IOqtHybridLog page) => 0;\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/NoOp/OqtPrerenderNoOpService.cs",
    "content": "﻿using Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Client.Services.NoOp;\n\n/// <summary>\n/// No Operation Service\n/// This is NoOp implementation, just to not break Sxc.Oqt.Client code, during service injection.\n/// This code is not doing real work, because prerendering is done in Sxc.Oqt.Server\n/// </summary>\ninternal class OqtPrerenderNoOpService : IOqtPrerenderService\n{\n    public string GetPrerenderHtml(bool isPrerendered, OqtViewResultsDto viewResults, SiteState siteState, string themeType) => string.Empty;\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/OqtDebugStateService.cs",
    "content": "﻿using Microsoft.JSInterop;\nusing System.Text.Json;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\n\nnamespace ToSic.Sxc.Oqt.Client.Services;\n\ninternal class OqtDebugStateService(IJSRuntime jsRuntime) : IOqtDebugStateService\n{\n    public const string DebugKey = \"2sxcDebug\";\n\n    public bool IsDebugEnabled => _debug ??= false; \n\n    public async Task<bool> GetDebugAsync() => await GetState<bool>(DebugKey);\n\n    public void SetDebug(bool value)\n    {\n        _debug = value;\n#pragma warning disable CS4014\n        SaveState(DebugKey, value);\n#pragma warning restore CS4014\n    }\n\n    private bool? _debug;\n\n    private async Task SaveState(string key, object value)\n    {\n        var json = JsonSerializer.Serialize(value);\n        await jsRuntime.InvokeVoidAsync(\"sessionStorage.setItem\", key, json);\n    }\n\n    private async ValueTask<T> GetState<T>(string? key)\n    {\n        var json = await jsRuntime.InvokeAsync<string?>(\"sessionStorage.getItem\", key);\n        if (json is null)\n            return default!;\n        return JsonSerializer.Deserialize<T>(json)!;\n    }\n\n    public string Platform => \"Client\";\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/OqtPageChangeService.cs",
    "content": "﻿using Oqtane.Shared;\nusing ToSic.Sxc.Oqt.App;\nusing ToSic.Sxc.Oqt.Shared.Helpers;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Client.Services;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtPageChangeService(IOqtTurnOnService turnOnService, CacheBustingService noCache)\n{\n    /// <summary>\n    /// Ensure standard assets like java-scripts and styles.\n    /// </summary>\n    /// <param name=\"viewResults\"></param>\n    /// <param name=\"siteState\"></param>\n    /// <param name=\"content\"></param>\n    /// <param name=\"themeName\"></param>\n    /// <returns></returns>\n    /// <remarks>SSR only</remarks>\n    public string AttachScriptsAndStylesStaticallyInHtml(OqtViewResultsDto viewResults, SiteState siteState, string content, string themeName)\n    {\n        siteState.Properties.HeadContent = HtmlHelper.ManageStyleSheets(siteState.Properties.HeadContent, viewResults, siteState.Alias, themeName);\n        //content = HtmlHelper.ManageStyleSheets(content, viewResults, siteState.Alias, themeName);\n        //siteState.Properties.HeadContent = HtmlHelper.ManageScripts(siteState.Properties.HeadContent, viewResults, siteState.Alias);\n        content = HtmlHelper.ManageScripts(content, viewResults, siteState.Alias);\n        return HtmlHelper.ManageInlineScripts(content, viewResults, siteState.Alias);\n    }\n\n    public string AttachScriptsAndStylesDynamicallyWithTurnOn(OqtViewResultsDto viewResults, SiteState siteState, string content, string themeName, Guid renderId)\n    {\n        var scripts = new List<object>();\n        var links = new List<object>();\n        var inlineScripts = new List<object>();\n\n        #region 2sxc Standard Assets and Header\n\n        // Load all 2sxc js dependencies (js / styles)\n        // Not done the official Oqtane way, because that asks for the scripts before\n        // the razor component reported what it needs\n        if (viewResults.SxcScripts != null)\n        {\n            scripts.AddRange(viewResults.SxcScripts\n                .DistinctBy(url => url)\n                .Select(url => new\n                {\n                    id = \"\",\n                    href = noCache.CacheBusting(url, renderId),\n                    bundle = \"\",\n                    location = \"body\",\n                    integrity = \"\",\n                    crossorigin = \"\",\n                    type=\"\",\n                    dataAttributes = new Dictionary<string, string>(),\n                }));\n        }\n\n        if (viewResults.SxcStyles != null)\n        {\n            links.AddRange(viewResults.SxcStyles\n                .DistinctBy(url => url)\n                .Select(url => new\n                {\n                    id = \"\",\n                    rel= \"stylesheet\",\n                    href = url,\n                    type = \"text/css\",\n                    integrity = \"\",\n                    crossorigin = \"\",\n                    insertbefore = \"app-stylesheet-module\"\n                }));\n        }\n\n        #endregion\n\n        #region External resources requested by the razor template\n\n        if (viewResults.TemplateResources != null)\n        {\n            // External resources = independent files (so not inline JS in the template)\n            var externalResources = viewResults.TemplateResources.Where(r => r.IsExternal).ToArray();\n\n            links.AddRange(externalResources.Where(r => r.ResourceType == ResourceType.Stylesheet)\n                .DistinctBy(r => r.Url)\n                .Select(link => new\n                {\n                    id = string.IsNullOrWhiteSpace(link.UniqueId) ? \"\" : link.UniqueId, // bug in Oqtane, needs to be an empty string instead of null or undefined\n                    rel = \"stylesheet\",\n                    href = link.Url,\n                    type = \"text/css\",\n                    integrity = \"\",\n                    crossorigin = \"\",\n                    insertbefore = \"app-stylesheet-module\" // bug in Oqtane, needs to be an empty string instead of null or undefined\n                }));\n\n            // 2. Scripts - usually libraries etc.\n            // Important: the IncludeClientScripts (IncludeScripts) works very different from LoadScript\n            // it uses LoadJS and bundles\n            scripts.AddRange(externalResources.Where(r => r.ResourceType == ResourceType.Script)\n                .DistinctBy(r => r.Url)\n                .Select(script => new\n                {\n                    id = string.IsNullOrWhiteSpace(script.UniqueId) ? \"\" : script.UniqueId, // bug in Oqtane, needs to be an empty string instead of null or undefined\n                    href = noCache.CacheBusting(script.Url, renderId),\n                    bundle = \"\", // not working when bundleId is provided\n                    location = \"body\", // script.Location,\n                    htmlAttributes = script.HtmlAttributes,\n                    integrity = script.Integrity ?? \"\", // bug in Oqtane, needs to be an empty string to not throw errors\n                    crossorigin = script.CrossOrigin ?? \"\",\n                    es6module = script.ES6Module, // remove when Oqtane dependency is updated to 6.0.1\n                    type = script.Type ?? \"\", // bug in Oqtane, needs to be an empty string to skip loading script\n                    //defer = script.HtmlAttributes.TryGetValue(\"defer\", out var deferValue) ? deferValue : \"\",\n                    //async = script.HtmlAttributes.TryGetValue(\"async\", out var asyncValue) ? asyncValue : \"\",\n                    dataAttributes = new Dictionary<string, string> { },\n                }));\n\n            // 3. Inline JS code which was extracted from the template\n            var inlineResources = viewResults.TemplateResources.Where(r => !r.IsExternal)\n                .DistinctBy(r => r.Content)\n                .ToArray();\n            inlineScripts.AddRange(inlineResources.Select(inline => new\n            {\n                id = string.IsNullOrWhiteSpace(inline.UniqueId) ? \"\" : inline.UniqueId, // bug in Oqtane, needs to be an empty string instead of null or undefined\n                src = \"\",\n                bundle = \"\",\n                integrity = \"\",\n                crossorigin = \"\",\n                type = \"text/javascript\",\n                content = inline.Content,\n                location = \"body\",\n                dataAttributes = new Dictionary<string, string>(),\n            }));\n        }\n        #endregion\n\n        //// ensure that tun-on is loaded\n        //var turnOnScript = $\"<page-script src='./Modules/ToSic.Sxc.Oqtane/dist/turnOn/turn-on.js'></page-script>\";\n\n        //content += turnOnScript + Environment.NewLine;\n\n        if (links.Any())\n            content += turnOnService.Run(\"window.Oqtane.Interop.includeLinks()\", data: links.ToArray()) + Environment.NewLine;\n\n        if (scripts.Any()) \n            content += turnOnService.Run(\"window.Oqtane.Interop.includeScripts()\", data: scripts.ToArray()) + Environment.NewLine;\n\n        if (inlineScripts.Any())\n            content += turnOnService.Run(\"window.ToSic.Sxc.Oqtane.includeInlineScripts()\", data: inlineScripts.ToArray()) + Environment.NewLine;\n\n        //content += turnOnService.Run(\"window.ToSic.Sxc.Oqtane.reExecuteScripts()\") + Environment.NewLine;\n\n        return content;\n    }\n\n    /// <summary>\n    /// Ensure standard assets like java-scripts and styles.\n    /// This is done with interop after the page is rendered.\n    /// </summary>\n    /// <returns></returns>\n    public async Task AttachScriptsAndStylesForInteractiveRendering(OqtViewResultsDto viewResults, SxcInterop sxcInterop, IOqtHybridLog page)\n    {\n        var logPrefix = $\"{nameof(AttachScriptsAndStylesForInteractiveRendering)}(...) - \";\n\n        // Add Context-Meta first, because it should be available when $2sxc loads\n        if (viewResults.SxcContextMetaName != null)\n        {\n            page.Log($\"2.2: Context-Meta\");\n            await sxcInterop.IncludeMeta(\"\", \"name\", viewResults.SxcContextMetaName, viewResults.SxcContextMetaContents);\n        }\n\n        #region 2sxc Standard Assets and Header\n\n        // Lets load all 2sxc js dependencies (js / styles)\n        // Not done the official Oqtane way, because that asks for the scripts before\n        // the razor component reported what it needs   \n        if (viewResults.SxcScripts != null)\n            foreach (var url in viewResults.SxcScripts.DistinctBy(url => url))\n            {\n                page.Log($\"2.3: IncludeScript:{url}\");\n                await sxcInterop.IncludeScript(\"\", url, \"\", \"\", \"\", \"head\");\n            }\n\n        if (viewResults.SxcStyles != null)\n            foreach (var url in viewResults.SxcStyles.DistinctBy(url => url))\n            {\n                page.Log($\"2.4: IncludeCss:{url}\");\n                await sxcInterop.IncludeLink(\"\", \"stylesheet\", url, \"text/css\", \"\", \"\", \"\");\n            }\n\n        #endregion\n\n        #region External resources requested by the razor template\n\n        if (viewResults.TemplateResources != null)\n        {\n            page.Log($\"2.5: AttachScriptsAndStylesForInteractiveRendering\");\n            // External resources = independent files (so not inline JS in the template)\n            var externalResources = viewResults.TemplateResources.Where(r => r.IsExternal).ToArray();\n\n            // 1. Style Sheets, ideally before JS\n            var css = externalResources\n                .Where(r => r.ResourceType == ResourceType.Stylesheet)\n                .DistinctBy(r => r.Url)\n                .Select(a => new\n                {\n                    id = string.IsNullOrWhiteSpace(a.UniqueId)\n                        ? \"\"\n                        : a.UniqueId, // bug in Oqtane, needs to be an empty string instead of null or undefined\n                    rel = \"stylesheet\",\n                    href = a.Url,\n                    type = \"text/css\",\n                    integrity = \"\",\n                    crossorigin = \"\",\n                    insertbefore = \"\" // bug in Oqtane, needs to be an empty string instead of null or undefined\n                })\n                .Cast<object>()\n                .ToArray();\n\n            // Log CSS and then add to page\n            page.Log($\"{logPrefix}CSS: {css.Length}\", css);\n            if (css.Any())\n                await sxcInterop.IncludeLinks(css);\n\n            // 2. Scripts - usually libraries etc.\n            // Important: the IncludeClientScripts (IncludeScripts) works very different from LoadScript\n            // it uses LoadJS and bundles\n            var scripts = externalResources\n                .Where(r => r.ResourceType == ResourceType.Script)\n                .DistinctBy(r => r.Url)\n                .Select(a => new\n                {\n                    href = a.Url,\n                    bundle = \"\", // not working when bundleId is provided\n                    id = string.IsNullOrWhiteSpace(a.UniqueId) ? \"\" : a.UniqueId, // bug in Oqtane, needs to be an empty string instead of null or undefined\n                    location = a.Location,\n                    htmlAttributes = a.HtmlAttributes,\n                    integrity = a.Integrity ?? \"\", // bug in Oqtane, needs to be an empty string to not throw errors\n                    crossorigin = a.CrossOrigin ?? \"\",\n                })\n                .Cast<object>()\n                .ToArray();\n\n            // Log scripts and then add to page\n            page.Log($\"{logPrefix}Scripts: {scripts.Length}\", scripts);\n            if (scripts.Any())\n                await sxcInterop.IncludeScriptsWithAttributes(scripts);\n\n            // 3. Inline JS code which was extracted from the template\n            var inlineResources = viewResults.TemplateResources.Where(r => !r.IsExternal)\n                .DistinctBy(r => r.Content)\n                .ToArray();\n            // Log inline\n            page.Log($\"{logPrefix}Inline: {inlineResources.Length}\", inlineResources);\n            foreach (var inline in inlineResources)\n                await sxcInterop.IncludeScript(string.IsNullOrWhiteSpace(inline.UniqueId) ? \"\" : inline.UniqueId, // bug in Oqtane, needs to be an empty string instead of null or undefined\n                    \"\",\n                    \"\",\n                    \"\",\n                    inline.Content,\n                    \"body\");\n        }\n\n        #endregion\n    }\n\n\n    /// <summary>\n    /// Process page changes in html for title, keywords, descriptions and other meta or html tags.\n    /// Oqtane decide to directly render this changes in page html as part of first request, or later with interop.\n    /// </summary>\n    /// <param name=\"viewResults\"></param>\n    /// <param name=\"siteState\"></param>\n    /// <param name=\"page\"></param>\n    public string ProcessPageChanges(OqtViewResultsDto viewResults, SiteState siteState, ModuleProBase page)\n    {\n        page.Log($\"1.3: ProcessPageChanges\");\n\n        if (viewResults.PageProperties?.Any() ?? false)\n        {\n            page.Log($\"1.3.2: UpdatePageProperties title, keywords, description\");\n            UpdatePageProperties(siteState, viewResults, page);\n        }\n\n        if (viewResults.HeadChanges?.Any() ?? false)\n        {\n            page?.Log($\"1.3.3: AddHeadChanges:{viewResults.HeadChanges.Count()}\");\n            siteState.Properties.HeadContent = HtmlHelper.AddHeadChanges(siteState.Properties.HeadContent, viewResults.HeadChanges);\n        }\n\n        // Add Context-Meta first, because it should be available when $2sxc loads\n        if (viewResults.SxcContextMetaName != null)\n        {\n            page?.Log($\"1.3.4: Context-Meta\");\n            siteState.Properties.HeadContent = HtmlHelper.AddOrUpdateMetaTagContent(siteState.Properties.HeadContent, viewResults.SxcContextMetaName, viewResults.SxcContextMetaContents, false);\n        }\n\n        //// Lets load all 2sxc js dependencies (js / styles)\n        //var index = 0;\n        //if (ViewResults?.SxcScripts != null)\n        //    foreach (var resource in ViewResults.SxcScripts)\n        //    {\n        //        Log($\"1.3.4.{++index}: IncludeScript:{resource}\");\n        //        SiteState.Properties.HeadContent = HtmlHelper.AddScript(SiteState.Properties.HeadContent, resource, SiteState.Alias);\n        //    }\n\n        page?.Log($\"1.3.1: module html content set on page\");\n        return viewResults.FinalHtml;\n    }\n\n    private void UpdatePageProperties(SiteState siteState, OqtViewResultsDto viewResults, ModuleProBase page)\n    {\n        var logPrefix = $\"{nameof(UpdatePageProperties)}(...) - \";\n\n        if (viewResults.PageProperties == null)\n            return;\n\n        // Go through Page Properties\n        foreach (var p in viewResults.PageProperties)\n        {\n            switch (p.Property)\n            {\n                case OqtPageProperties.Title:\n                    var currentTitle = siteState.Properties.PageTitle;\n                    var updatedTitle = UpdateProperty(currentTitle, p.InjectOriginalInValue(currentTitle), page);\n                    page?.Log($\"{logPrefix}UpdateTitle:\", updatedTitle);\n                    siteState.Properties.PageTitle = updatedTitle;\n                    break;\n                case OqtPageProperties.Keywords:\n                    var currentKeywords = HtmlHelper.GetMetaTagContent(siteState.Properties.HeadContent, \"KEYWORDS\");\n                    var updatedKeywords = UpdateProperty(currentKeywords, p.InjectOriginalInValue(currentKeywords), page);\n                    page?.Log($\"{logPrefix}Keywords:\", updatedKeywords);\n                    siteState.Properties.HeadContent = HtmlHelper.AddOrUpdateMetaTagContent(siteState.Properties.HeadContent, \"KEYWORDS\", updatedKeywords);\n                    break;\n                case OqtPageProperties.Description:\n                    var currentDescription = HtmlHelper.GetMetaTagContent(siteState.Properties.HeadContent, \"DESCRIPTION\");\n                    var updatedDescription = UpdateProperty(currentDescription, p.InjectOriginalInValue(currentDescription), page);\n                    page?.Log($\"{logPrefix}Description:\", updatedDescription);\n                    siteState.Properties.HeadContent = HtmlHelper.AddOrUpdateMetaTagContent(siteState.Properties.HeadContent, \"DESCRIPTION\", updatedDescription);\n                    break;\n                case OqtPageProperties.Base:\n                    // For base - ignore for now as we don't know what side-effects this could have\n                    page?.Log($\"{logPrefix}Base ignore for now\");\n                    break;\n                default:\n                    page?.Log($\"{logPrefix} ArgumentOutOfRangeException\");\n                    throw new ArgumentOutOfRangeException();\n            }\n        }\n    }\n\n    private string UpdateProperty(string original, OqtPagePropertyChanges change, IOqtHybridLog page)\n    {\n        var logPrefix = $\"{nameof(UpdateProperty)}(original:{original}) - \";\n\n        if (string.IsNullOrEmpty(original))\n        {\n            var result = change.Value ?? original;\n            page?.Log($\"{logPrefix}is empty, UpdateTitle:{result}\");\n            return result;\n        };\n\n        // 1. Check if we have a replacement token - if yes, try to replace it\n        if (!string.IsNullOrEmpty(change.Placeholder))\n        {\n            var pos = original.IndexOf(change.Placeholder, StringComparison.InvariantCultureIgnoreCase);\n            if (pos >= 0)\n            {\n                var suffixPos = pos + change.Placeholder.Length;\n                var suffix = suffixPos < original.Length ? original.Substring(suffixPos) : \"\";\n                var result2 = original.Substring(0, pos) + change.Value + suffix;\n                page?.Log($\"{logPrefix}token replaced, UpdateTitle:{result2}\");\n                return result2;\n            }\n\n            page?.Log($\"{logPrefix}replace token not found, UpdateTitle:{original}\");\n            if (change.Change == OqtPagePropertyOperation.ReplaceOrSkip) return original;\n        }\n\n        // 2. If not, try to prefix / suffix / replace depending on the property\n        var result3 = change.Change switch\n        {\n            OqtPagePropertyOperation.Replace => change.Value ?? original,\n            OqtPagePropertyOperation.Suffix => $\"{original}{change.Value}\",\n            OqtPagePropertyOperation.Prefix => $\"{change.Value}{original}\",\n            OqtPagePropertyOperation.ReplaceOrSkip => original,\n            _ => throw new ArgumentOutOfRangeException()\n        };\n        page?.Log($\"{logPrefix}{change.Change}, UpdateTitle:{result3}\");\n        return result3;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/OqtSxcRenderService.cs",
    "content": "using Oqtane.Modules;\nusing Oqtane.Services;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Client.Services;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtSxcRenderService(HttpClient http, SiteState siteState) : ServiceBase(http, siteState), IOqtSxcRenderService, IClientService\n{\n    private string ApiUrl => CreateApiUrl(\"OqtSxcRender\");\n\n    public async Task<OqtViewResultsDto> RenderAsync(RenderParameters @params)\n    {\n        var url = CreateAuthorizationPolicyUrl($\"{ApiUrl}/{@params.AliasId}/{@params.PageId}/{@params.ModuleId}/{@params.Culture}/{@params.PreRender}/Render{@params.OriginalParameters}\", EntityNames.Module, @params.ModuleId);\n        return await GetJsonAsync<OqtViewResultsDto>(url);\n    }\n\n    public OqtViewResultsDto Render(RenderParameters @params) => RenderAsync(@params).GetAwaiter().GetResult();\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/OqtTurnOnService.cs",
    "content": "﻿using ToSic.Oqt.Coding;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\n\nnamespace ToSic.Sxc.Oqt.Client.Services;\n\n/// <inheritdoc />\ninternal class OqtTurnOnService : IOqtTurnOnService\n{\n    public string Run(object runOrSpecs, NoParamOrderOqtane noParamOrder = default, object? require = null, object? data = null,\n        IEnumerable<object>? args = default, string? addContext = default)\n    {\n        throw new System.NotImplementedException();\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/RenderInfoService.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Shared.Interfaces;\n\nnamespace ToSic.Sxc.Oqt.Client.Services;\n\n/// <inheritdoc />\npublic class RenderInfoService : IRenderInfoService\n{\n    /// <inheritdoc />\n    public bool IsStaticSsr(string renderMode) => false;\n\n    /// <inheritdoc />\n    public bool IsBlazorEnhancedNav(string renderMode) => false;\n\n    /// <inheritdoc />\n    public bool IsSsrFraming(string renderMode) => false;\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/Services/RenderSpecificLockManager.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing Oqtane.Modules;\n\nnamespace ToSic.Sxc.Oqt.Client.Services;\n\npublic class RenderSpecificLockManager : IService\n{\n    private readonly ConcurrentDictionary<Guid, SemaphoreSlim> _locks = new();\n\n    public async Task<IDisposable> LockAsync(Guid renderId)\n    {\n        var semaphore = _locks.GetOrAdd(renderId, _ => new SemaphoreSlim(1, 1));\n        await semaphore.WaitAsync();\n        return new ReleaseHandle(() => Release(renderId));\n    }\n\n    private void Release(Guid requestId)\n    {\n        if (_locks.TryGetValue(requestId, out var semaphore))\n        {\n            semaphore.Release();\n\n            // Consider removing the semaphore from the dictionary if no longer needed,\n            // but be cautious of race conditions and ensure proper synchronization.\n        }\n    }\n\n    private class ReleaseHandle(Action releaseAction) : IDisposable\n    {\n        public void Dispose()\n        {\n            releaseAction();\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/SxcInterop.cs",
    "content": "﻿using Microsoft.JSInterop;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Client;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcInterop : Oqtane.UI.Interop\n{\n    private readonly IJSRuntime _jsRuntime;\n\n    public SxcInterop(IJSRuntime jsRuntime) : base(jsRuntime)\n    {\n        _jsRuntime = jsRuntime;\n\n    }\n    public ValueTask<string> GetTitleValue()\n    {\n        try\n        {\n            return _jsRuntime.InvokeAsync<string>($\"{OqtConstants.PackageName}.getTitleValue\");\n        }\n        catch\n        {\n            return new ValueTask<string>(Task.FromResult(string.Empty));\n        }\n    }\n\n    public ValueTask<string> GetMetaTagContentByName(string name)\n    {\n        try\n        {\n            return _jsRuntime.InvokeAsync<string>(\n                $\"{OqtConstants.PackageName}.getMetaTagContentByName\",\n                name);\n        }\n        catch\n        {\n            return new ValueTask<string>(Task.FromResult(string.Empty));\n        }\n    }\n\n    /// <summary>\n    /// IncludeScriptsWithAttributes is fork of\n    /// Oqtane.SxcInterop.IncludeScripts from Oqtane v3.1.0\n    /// with addition of httpAttributes support\n    /// </summary>\n    /// <param name=\"scripts\"> scripts (object[]),\n    /// script (object) is with optional property httpAttributes (object)\n    /// </param>\n    /// <returns></returns>\n    public async Task IncludeScriptsWithAttributes(object[] scripts)\n    {\n        // fix for https://github.com/2sic/2sxc/issues/2844\n        // we use solution with javascript native module import \"./Modules/ToSic.Sxc.Oqtane/NativeModule.js\"\n        // instead of default oqtane Module.js pattern (that is commented bellow)\n        // because our PageChangesHelper.AttachScriptsAndStylesForInteractiveRendering in OnAfterRenderAsync in index.razor.cs\n        // is sometimes executing interop call to 'ToSic.Sxc.Oqtane.includeScriptsWithAttributes'\n        // earlier than \"Modules/ToSic.Sxc.Oqtane/Module.js\" is loaded in browser by oqtane ModuleBase.cs\n        var module = await _jsRuntime.InvokeAsync<IJSObjectReference>(\"import\", $\"./Modules/{OqtConstants.PackageName}/NativeModule.js\");\n        await module.InvokeVoidAsync($\"includeScriptsWithAttributes\", (object)scripts);\n        //try\n        //{\n        //    await _jsRuntime.InvokeVoidAsync(\n        //        $\"{OqtConstants.PackageName}.includeScriptsWithAttributes\",\n        //        (object)scripts);\n        //}\n        //catch\n        //{\n        //    // ignore exception\n        //}\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/ToSic.Sxc.Oqt.Client.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Razor\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-NetCore.props\" />\n\n  \n  <PropertyGroup>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>ToSic.Sxc.Oqt.Client</RootNamespace>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RazorLangVersion>3.0</RazorLangVersion>\n    <AssemblyName>ToSic.Sxc.Oqtane.Client</AssemblyName>\n  </PropertyGroup>\n  \n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Components.WebAssembly\" Version=\"9.0.5\" /><!-- from Oqtane.Client.csproj -->\n    <PackageReference Include=\"Microsoft.AspNetCore.Components.WebAssembly.DevServer\" Version=\"9.0.5\" PrivateAssets=\"all\" /><!-- from Oqtane.Client.csproj -->\n    <PackageReference Include=\"Microsoft.AspNetCore.Components.WebAssembly.Authentication\" Version=\"9.0.5\" /><!-- from Oqtane.Client.csproj -->\n    <PackageReference Include=\"Microsoft.AspNetCore.Components.Authorization\" Version=\"9.0.5\" /><!-- from Oqtane.Maui.csproj -->\n    <PackageReference Include=\"Microsoft.Extensions.Localization\" Version=\"9.0.5\" /><!-- from Oqtane.Client.csproj -->\n    <PackageReference Include=\"Microsoft.Extensions.Http\" Version=\"9.0.5\" /><!-- from Oqtane.Client.csproj -->\n    <PackageReference Include=\"System.Net.Http.Json\" Version=\"9.0.5\" /><!-- from Oqtane.Client.csproj -->\n    <PackageReference Include=\"Oqtane.Client\" Version=\"6.1.3\" />\n    <PackageReference Include=\"Oqtane.Shared\" Version=\"6.1.3\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <!--<ProjectReference Include=\"..\\..\\..\\..\\oqtane\\oqtane.framework\\Oqtane.Client\\Oqtane.Client.csproj\" />-->\n    <ProjectReference Include=\"..\\ToSic.Sxc.Oqt.Shared\\ToSic.Sxc.Oqt.Shared.csproj\" />\n  </ItemGroup>\n\n  <PropertyGroup>\n    <!-- there may be other elements here -->\n    <BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>\n    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/ToSic.Sxc.Oqt.Client.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helpers/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Client/_Imports.razor",
    "content": "@using System\n@using System.Linq\n@using System.Collections.Generic\n@using System.Net.Http\n@using System.Net.Http.Json\n\n@using Microsoft.AspNetCore.Components.Authorization\n@using Microsoft.AspNetCore.Components.Routing\n@using Microsoft.AspNetCore.Components.Web\n@using Microsoft.Extensions.Localization\n@using Microsoft.JSInterop\n\n@using Oqtane.Models\n@using Oqtane.Modules\n@using Oqtane.Modules.Controls\n@using Oqtane.Providers\n@using Oqtane.Security\n@using Oqtane.Services\n@using Oqtane.Shared\n@using Oqtane.Themes\n@using Oqtane.Themes.Controls\n@using Oqtane.UI\n@using Oqtane.Enums\n@using Oqtane.Interfaces "
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Package/BuildScripts/LoadBuildConfig.Targets",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n\n  <Target Name=\"CheckBuildTool\" AfterTargets=\"Build\" BeforeTargets=\"PostBuild\">\n    <Message Text=\"Running CheckBuildTool\" Importance=\"high\"/>\n    <Message Text=\"MSBuildRuntimeType: $(MSBuildRuntimeType)\" Importance=\"high\"/>\n    <Message Text=\"MSBuildProjectDirectory: $(MSBuildProjectDirectory)\" Importance=\"high\"/>\n    <Message Text=\"Running on .NET Core MSBuild\" Condition=\"'$(MSBuildRuntimeType)' == 'Core'\" Importance=\"high\"/>\n    <Message Text=\"Running on Full MSBuild\" Condition=\"'$(MSBuildRuntimeType)' != 'Core'\" Importance=\"high\"/>\n  </Target>\n\n  <!-- Use different helper DLLs depending on run mode - in VS 2022 it's .net Framework, in the command line it's .net core -->\n  <UsingTask Condition=\"'$(MSBuildRuntimeType)' == 'Core'\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net9.0\\ToSic.Sxc.BuildTasks.dll\" TaskName=\"GetBuildConfig\"/>\n  <UsingTask Condition=\"'$(MSBuildRuntimeType)' != 'Core'\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net472\\ToSic.Sxc.BuildTasks.dll\" TaskName=\"GetBuildConfig\"/>\n  <UsingTask Condition=\"'$(MSBuildRuntimeType)' == 'Core'\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net9.0\\ToSic.Sxc.BuildTasks.dll\" TaskName=\"ColorMessage\"/>\n  <UsingTask Condition=\"'$(MSBuildRuntimeType)' != 'Core'\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net472\\ToSic.Sxc.BuildTasks.dll\" TaskName=\"ColorMessage\"/>\n  <UsingTask Condition=\"'$(MSBuildRuntimeType)' == 'Core'\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net9.0\\ToSic.Sxc.BuildTasks.dll\" TaskName=\"ModifyXmlDocumentation\"/>\n  <UsingTask Condition=\"'$(MSBuildRuntimeType)' != 'Core'\" AssemblyFile=\"$(MSBuildProjectDirectory)\\..\\..\\Build\\ToSic.Sxc.BuildTasks\\bin\\Debug\\net472\\ToSic.Sxc.BuildTasks.dll\" TaskName=\"ModifyXmlDocumentation\"/>\n\n  <Target Name=\"BuildConfigTarget\" AfterTargets=\"CheckBuildTool\">\n    <Message Text=\"Running BuildConfigTarget\" Importance=\"high\"/>\n\n    <!-- Get parameters from the JSON configuration file \"2sxc-build.config.json\" -->\n    <GetBuildConfig>\n      <Output TaskParameter=\"BuildConfigPath\" PropertyName=\"BuildConfigPath\" />\n      <Output TaskParameter=\"OqtaneTargets\" PropertyName=\"OqtaneTargets\" />\n      <Output TaskParameter=\"OqtaneTarget\" PropertyName=\"OqtaneTarget\" />\n      <Output TaskParameter=\"Sources\" PropertyName=\"Sources\" />\n      <Output TaskParameter=\"Source\" PropertyName=\"Source\" />\n      <Output TaskParameter=\"OqtaneInstallPackage\" PropertyName=\"OqtaneInstallPackage\" />\n    </GetBuildConfig>\n\n    <!-- Create a property to capture the result of the Exists function -->\n    <PropertyGroup>\n      <SourceExist Condition=\"Exists('$(Source)')\">true</SourceExist>\n      <SourceExist Condition=\"!Exists('$(Source)')\">false</SourceExist>\n      <OqtaneExist Condition=\"Exists('$(OqtaneTarget)')\">true</OqtaneExist>\n      <OqtaneExist Condition=\"!Exists('$(OqtaneTarget)')\">false</OqtaneExist>\n    </PropertyGroup>\n    <Message Text=\"SourceExist: $(SourceExist) - $(Source)\" Importance=\"high\"/>\n    <Message Text=\"OqtaneExist: $(OqtaneExist) - $(OqtaneTarget)\" Importance=\"high\"/>\n\n    <ColorMessage Text=\"------------------------------------------------------------------------------\" ForegroundColor=\"White\" BackgroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"$(BuildConfigPath)\" ForegroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"------------------------------------------------------------------------------\" ForegroundColor=\"White\" BackgroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"OqtaneTargets:\" ForegroundColor=\"White\"/>\n    <ColorMessage Text=\"$(OqtaneTargets)\" ForegroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"Source:\" ForegroundColor=\"White\"/>\n    <ColorMessage Text=\"$(Source)\" ForegroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"OqtaneInstallPackage:\" ForegroundColor=\"White\"/>\n    <ColorMessage Text=\"$(OqtaneInstallPackage)\" ForegroundColor=\"Magenta\"/>\n    <ColorMessage Text=\"------------------------------------------------------------------------------\" ForegroundColor=\"White\" BackgroundColor=\"Magenta\"/>\n\n  </Target>\n\n</Project>"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Package/Properties/PublishProfiles/FolderProfile.pubxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nhttps://go.microsoft.com/fwlink/?LinkID=208121. \n-->\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>bin\\Release\\net5.0\\publish\\</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Package/README.md",
    "content": "﻿# 2sxc - CMS & App-Engine for DNN and Oqtane\n\n> you can't use DNN or Oqtane without 2sxc 😉\n\n2sxc helps web designers and developers prepare great looking, animated and sexy content and applications in DNN (DotNetNuke) and Oqtane. \nIt works in .NET Framework and .NET.\n\nVisit [2sxc.org](https://2sxc.org/) for more information.\n\nVisit [docs.2sxc.org](https://docs.2sxc.org) for API docs.\n\nVisit [DNN & Razor Tutorials](https://2sxc.org/dnn-tutorials/) for tutorials.\n\nVisit [2sxc Blogs](https://2sxc.org/en/blog) for news, updates, articles.\n\nVisit https://github.com/2sic/2sxc/releases for the latest releases.\n\n![2sxc](https://raw.githubusercontent.com/2sic/2sxc-docs/master/docs/assets/logos/vcurrent/150.png)\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Package/ToSic.Sxc.Oqt.Package.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net9.0</TargetFramework>\n    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>\n    <AssemblyName>ToSic.Sxc.Oqtane.Package</AssemblyName>\n    <Configurations>Debug;Release;DebugOqtane;DebugDnn</Configurations>\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n    <RestoreSources>$(RestoreSources);../../packages/;../../../../oqtane/oqtane-imageflow/InstallPackages/</RestoreSources>\n    <!-- Don't generate assembly properties from this XML which should come from the core file, like version - these lines must be in sync in all ToSic.Eav.*.csproj files -->\n    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>\n    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>\n    <GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>\n    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>\n    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>\n    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>\n    <!-- end: Don't generate... -->\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Oqt.Client\\ToSic.Sxc.Oqt.Client.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Oqt.Server\\ToSic.Sxc.Oqt.Server.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Oqt.Shared\\ToSic.Sxc.Oqt.Shared.csproj\" />\n  </ItemGroup>\n\n  <Import Project=\"BuildScripts\\LoadBuildConfig.Targets\" />\n\n  <Target Name=\"PostBuild\" AfterTargets=\"Build\" DependsOnTargets=\"BuildConfigTarget\" Condition=\"'$(SourceExist)|$(OqtaneExist)' == 'true|true'\">\n    <Message Text=\"Running PostBuild\" Importance=\"high\"/>\n    <!-- XML documentation -->\n    <ItemGroup Condition=\"'$(Configuration)'=='Release'\">\n      <AssemblyDocumentation Include=\"$(OutDir)\\ToSic.*.xml\" Exclude=\"**\\ToSic.Sxc.Oqtane.Package.xml\" />\n    </ItemGroup>\n    <!-- Run the modification task for each documentation file -->\n    <ModifyXmlDocumentation XmlDocumentationPath=\"%(AssemblyDocumentation.Identity)\" Condition=\"'$(Configuration)'=='Release'\"/>\n    \n    <PropertyGroup>\n      <OqtaneInstallPackage Condition=\" '$(OqtaneInstallPackage)' == '' \">$(MSBuildProjectDirectory)\\..\\..\\..\\InstallPackages\\OqtaneModule\\</OqtaneInstallPackage>\n    </PropertyGroup>\n    <Exec Command=\"IF $(ConfigurationName) == Release (release.cmd $(Source) $(OqtaneInstallPackage) $(TargetFramework))\" />\n  </Target>\n\n  <Target Name=\"PostBuild2\" AfterTargets=\"Build\" DependsOnTargets=\"BuildConfigTarget\" Condition=\"'$(ConfigurationName)|$(OqtaneExist)' == 'Debug|true' OR '$(ConfigurationName)|$(OqtaneExist)' == 'DebugOqtane|true'\">\n    <Message Text=\"OqtaneTargets='$(OqtaneTargets)'\" Importance=\"High\"/>\n    <!--Split the paths in OqtaneTargets into individual items-->\n    <ItemGroup>\n      <OqtaneRoot Include=\"$(OqtaneTargets)\"/>\n    </ItemGroup>\n  </Target>\n\n  <Target Name=\"PostBuildForEachItem\" AfterTargets=\"PostBuild2\" DependsOnTargets=\"BuildConfigTarget;PostBuild2\" Condition=\"'$(ConfigurationName)|$(OqtaneExist)' == 'Debug|true' OR '$(ConfigurationName)|$(OqtaneExist)' == 'DebugOqtane|true'\" Outputs=\"%(OqtaneRoot.Identity)\">\n    <PropertyGroup>\n      <CurrentOqtaneRoot>%(OqtaneRoot.Identity)</CurrentOqtaneRoot>\n    </PropertyGroup>\n    <Message Text=\"CurrentOqtaneRoot='$(CurrentOqtaneRoot)'\" Importance=\"High\"/>\n    <Exec Command=\"debug.cmd $(ConfigurationName) $(CurrentOqtaneRoot) $(TargetFramework)\" />\n  </Target>\n\n  <Target Name=\"BuildConfigTarget2\" AfterTargets=\"Build\" DependsOnTargets=\"BuildConfigTarget\" Condition=\" '$(OqtaneExist)' == 'true'\">\n\n    <Message Text=\"------------------------------------------------------------------------------\" Importance=\"high\"/>\n    <Message Text=\"$(BuildConfigPath)\" Importance=\"high\"/>\n    <Message Text=\"------------------------------------------------------------------------------\" Importance=\"high\"/>\n    <Message Text=\"OqtaneTargets:\" Importance=\"high\"/>\n    <Message Text=\"$(OqtaneTargets)\" Importance=\"high\"/>\n    <Message Text=\"Source:\" Importance=\"high\"/>\n    <Message Text=\"$(Source)\" Importance=\"high\"/>\n    <Message Text=\"OqtaneInstallPackage:\" Importance=\"high\"/>\n    <Message Text=\"$(OqtaneInstallPackage)\" Importance=\"high\"/>\n    <Message Text=\"------------------------------------------------------------------------------\" Importance=\"high\"/>\n\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Package/ToSic.Sxc.Oqtane.Install.nuspec",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package>\n  <metadata>\n    <id>ToSic.Sxc.Oqtane.Install</id>\n    <version>21.07.00</version>\n    <authors>2sic internet solutions GmbH, Switzerland</authors>\n    <owners>2sic internet solutions GmbH, Switzerland</owners>\n    <title>2sxc CMS and Meta-Module for Oqtane</title>\n    <description>2sxc is an Oqtane module to create attractive and designed content. It solves the common problem, allowing the web designer to create designed templates for different content elements, so that the user must only fill in fields and receive a perfectly designed and animated output.</description>\n    <copyright>Copyright MIT © 2sic 2025</copyright>\n    <requireLicenseAcceptance>false</requireLicenseAcceptance>\n    <license type=\"expression\">MIT</license>\n    <projectUrl>https://github.com/2sic/2sxc</projectUrl>\n    <repository type=\"git\" url=\"https://github.com/2sic/2sxc.git\" branch=\"master\" />\n    <iconUrl>https://raw.githubusercontent.com/2sic/2sxc-docs/master/docs/assets/logos/v13/2sxc13-500.png</iconUrl>\n    <icon>images\\1000.png</icon>\n    <tags>oqtane module</tags>\n    <readme>docs\\README.md</readme>\n    <releaseNotes>https://github.com/2sic/2sxc/releases</releaseNotes>\n    <summary>2sxc - CMS &amp; App-Engine for Oqtane</summary>\n    <dependencies>\n      <dependency id=\"Oqtane.Framework\" version=\"6.1.3\" />\n      <dependency id=\"ToSic.Imageflow.Oqtane\" version=\"1.12.0\" />\n    </dependencies>\n  </metadata>\n  <files>\n    <file src=\"images\\1000.png\" target=\"images\\\" />\n    <file src=\"README.md\" target=\"docs\\\" />\n    <file src=\"..\\ToSic.Sxc.Oqt.Package\\bin\\Release\\$targetframework$\\ToSic.*.dll\" exclude=\"**\\ToSic.Sxc.Oqtane.Package.dll\" target=\"lib\\$targetframework$\" />\n    <file src=\"..\\ToSic.Sxc.Oqt.Package\\bin\\Release\\$targetframework$\\ToSic.*.pdb\" exclude=\"**\\ToSic.Sxc.Oqtane.Package.pdb\" target=\"lib\\$targetframework$\" />\n    <file src=\"..\\..\\Data\\App_Data\\new-app\\**\\*.*\" target=\"content\\2sxc\\system\\App_Data\\new-app\" />\n    <file src=\"..\\..\\Data\\App_Data\\system\\**\\*.*\" target=\"content\\2sxc\\system\\App_Data\\system\" />\n    <file src=\"..\\..\\Dnn\\ToSic.Sxc.Dnn\\ImportExport\\**\\*.*\" target=\"content\\2sxc\\system\\ImportExport\" />\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\wwwroot\\Modules\\ToSic.Sxc.Oqtane\\**\\*.*\" exclude=\"**\\*.map;\" target=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane\" />\n    <!-- XML documentation -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Package\\bin\\Release\\$targetframework$\\ToSic.*.xml\" exclude=\"**\\ToSic.Sxc.Oqtane.Package.xml\" target=\"lib\\$targetframework$\" />\n    <!-- 3rd party dependencies -->\n\n    <!-- ToSic.Sxc.Dnn.Main PackageReference -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\Connect.Koi.dll\" target=\"lib\\$targetframework$\" />\n    <!-- ToSic.Eav.DataSources PackageReference -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\CsvHelper.dll\" target=\"lib\\$targetframework$\" />\n    <!-- Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation v9.0.0 transitive dependency: Microsoft.AspNetCore.Mvc.Razor.Extensions (>= 6.0.0) -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\Microsoft.AspNetCore.Mvc.Razor.Extensions.dll\" target=\"lib\\$targetframework$\" />\n    <!-- ToSic.Sxc.Razor PackageReference -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.dll\" target=\"lib\\$targetframework$\" />\n    <!-- Microsoft.CodeAnalysis.Razor transitive dependency -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\Microsoft.AspNetCore.Razor.Language.dll\" target=\"lib\\$targetframework$\" />\n    <!-- Microsoft.CodeAnalysis.Razor transitive dependency:  -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\Microsoft.CodeAnalysis.CSharp.dll\" target=\"lib\\$targetframework$\" />\n    <!-- Microsoft.CodeAnalysis.Razor transitive dependency -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\Microsoft.CodeAnalysis.dll\" target=\"lib\\$targetframework$\" />\n    <!-- Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation transitive dependency: Microsoft.CodeAnalysis.Razor (>= 6.0.0) -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\Microsoft.CodeAnalysis.Razor.dll\" target=\"lib\\$targetframework$\" />\n    <!-- Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation transitive dependency: Microsoft.Extensions.DependencyModel (>= 9.0.0) -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\Microsoft.Extensions.DependencyModel.dll\" target=\"lib\\$targetframework$\" />\n    <!-- ToSic.Sxc dependency -->\n    <file src=\"..\\ToSic.Sxc.Oqt.Server\\bin\\Release\\$targetframework$\\System.Runtime.Caching.dll\" target=\"lib\\$targetframework$\" />\n \n    <!-- ToSic.Imageflow.Oqtane v1.12.0 -->\n    <file src=\"..\\..\\packages\\tosic.imageflow.oqtane\\1.12.0\\lib\\net9.0\\ToSic.Imageflow.Oqt.Server.Oqtane.dll\" target=\"lib\\$targetframework$\" />\n    <file src=\"..\\..\\packages\\tosic.imageflow.oqtane\\1.12.0\\lib\\net9.0\\ToSic.Imageflow.Oqt.Server.Oqtane.pdb\" target=\"lib\\$targetframework$\" />\n    <file src=\"..\\..\\packages\\tosic.imageflow.oqtane\\1.12.0\\lib\\net9.0\\Imageflow.*\" target=\"lib\\$targetframework$\" />\n    <file src=\"..\\..\\packages\\tosic.imageflow.oqtane\\1.12.0\\lib\\net9.0\\Imazen.*\" target=\"lib\\$targetframework$\" />\n    <file src=\"..\\..\\packages\\tosic.imageflow.oqtane\\1.12.0\\lib\\net9.0\\Microsoft.IO.*\" target=\"lib\\$targetframework$\" />\n    <file src=\"..\\..\\packages\\tosic.imageflow.oqtane\\1.12.0\\runtimes\\win-x64*\\**\\*imageflow.*\" target=\"runtimes\" />\n  </files>\n</package>\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Package/debug.cmd",
    "content": "@ECHO off\nECHO(\nECHO the build folder (Debug or DebugOqtane) must be passed in as a parameter\n\nSET BuildFolder=%1\nSET OqtaneTarget=%2\nSET ModuleTargetFramework=%3\nREM ModuleTargetFramework is sometimes older than OqtaneTargetFramework to preserve compatibility with older Oqtane versions.\nREM Change the OqtaneTargetFramework to TargetFramework from Oqtane.Server.csproj\nSET OqtaneTargetFramework=net10.0\n\nREM Displaying the parameters received\nECHO BuildFolder=%BuildFolder%\nECHO OqtaneTarget=%OqtaneTarget%\nECHO ModuleTargetFramework=%ModuleTargetFramework%\nECHO OqtaneTargetFramework=%OqtaneTargetFramework%\n\nSET OqtaneBin=%OqtaneTarget%bin\\%BuildFolder%\\%OqtaneTargetFramework%\nSET PackageName=ToSic.Sxc.Oqtane\nSET BuildTarget=%OqtaneTarget%wwwroot\\Modules\\%PackageName%\nECHO The target folder is: %OqtaneBin%\n\nECHO(\nECHO 2sxc Oqtane - Client\nXCOPY \"..\\ToSic.Sxc.Oqt.Client\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\ToSic.*.dll\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\ToSic.Sxc.Oqt.Client\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\ToSic.*.pdb\" \"%OqtaneBin%\\\" /Y\n\nECHO(\nECHO 2sxc Oqtane - Server\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\ToSic.*.dll\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\ToSic.*.pdb\" \"%OqtaneBin%\\\" /Y\n\nECHO(\nECHO 2sxc Oqtane - Server Framework DLLs\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\Microsoft.AspNetCore.Mvc.Razor.*.dll\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\Microsoft.AspNetCore.Razor.*\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\Microsoft.CodeAnalys*.*\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\Microsoft.Extensions.DependencyModel.dll\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\System.Runtime.Caching.dll\" \"%OqtaneBin%\\\" /Y\n\nECHO(\nECHO 2sxc Oqtane - 3rd party deps\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\CsvHelper.dll\" \"%OqtaneBin%\\\" /Y\n\nECHO(\nECHO 2sxc Oqtane - Shared\nXCOPY \"..\\ToSic.Sxc.Oqt.Shared\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\ToSic.*.dll\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\ToSic.Sxc.Oqt.Shared\\bin\\%BuildFolder%\\%ModuleTargetFramework%\\ToSic.*.pdb\" \"%OqtaneBin%\\\" /Y\n\nECHO(\nECHO 2sxc Oqtane - Client Assets\nXCOPY \"..\\ToSic.Sxc.Oqt.Server\\wwwroot\\Modules\\%PackageName%\\*\" \"%BuildTarget%\\\" /Y /S /I\n\nECHO(\nECHO nuget dependencies - oqt-imageflow\nXCOPY \"..\\..\\packages\\tosic.imageflow.oqtane\\1.12.0\\lib\\net9.0\\*\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\..\\packages\\tosic.imageflow.oqtane\\1.12.0\\runtimes\\*\" \"%OqtaneBin%\\runtimes\\\" /S /C /Y\n\nECHO(\nECHO Copy Koi DLLs\nXCOPY \"..\\..\\..\\Dependencies\\Koi\\net6.0\\Connect.Koi.dll\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\..\\..\\Dependencies\\Koi\\net6.0\\Connect.Koi.pdb\" \"%OqtaneBin%\\\" /Y\n\nECHO(\nECHO Copy RazorBlade DLLs from Debug\nXCOPY \"..\\..\\..\\Dependencies\\RazorBlade\\Release\\net6.0\\ToSic.Razor.dll\" \"%OqtaneBin%\\\" /Y\nXCOPY \"..\\..\\..\\Dependencies\\RazorBlade\\Release\\net6.0\\ToSic.Razor.pdb\" \"%OqtaneBin%\\\" /Y\n\nECHO(\nECHO the target for js, css, json etc is: %BuildTarget%\nREM robocopy /mir \"..\\ToSic.Sxc.Oqt.Server\\wwwroot\\Modules\\ToSic.Sxc.Oqtane\\js\\ \" \"%BuildTarget%\\js\\ \"\nREM robocopy /mir \"..\\ToSic.Sxc.Oqt.Server\\wwwroot\\Modules\\ToSic.Sxc.Oqtane\\dist\\ \" \"%BuildTarget%\\dist\\ \"\nREM robocopy /mir \"..\\ToSic.Sxc.Oqt.Server\\wwwroot\\Modules\\ToSic.Sxc.Oqtane\\extensions\\ \" \"%BuildTarget%\\extensions\\ \"\n\nECHO(\nECHO Copy ImportExport instructions\nrobocopy /mir \"..\\..\\Dnn\\ToSic.Sxc.Dnn\\ImportExport\\ \" \"%OqtaneTarget%\\Content\\2sxc\\system\\ImportExport\\ \"\n\nECHO(\nECHO Copy the data folders\nrobocopy /mir \"..\\..\\Data\\App_Data\\ \" \"%OqtaneTarget%\\Content\\2sxc\\system\\App_Data\\ \"\nrobocopy /s \"..\\..\\..\\..\\2sxc-dev-materials\\App_Data\\ \" \"%OqtaneTarget%\\Content\\2sxc\\system\\App_Data\\ \"\nrobocopy /mir \"..\\..\\Data\\assets\\ \" \"%BuildTarget%\\assets\\ \"\n\nECHO(\nECHO Copied all files to this Website target: '%BuildTarget%' in mode '%BuildFolder%'\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Package/package.cmd",
    "content": "del \"*.nupkg\"\ndel \"*.zip\"\ndotnet clean -c Release ..\\ToSic.Sxc.Oqt.Server\ndotnet clean -c Release ..\\ToSic.Sxc.Oqt.Package \n:: dotnet build -c Release ..\\ToSic.Sxc.Oqt.Server\ndotnet build -c Release ..\\ToSic.Sxc.Oqt.Package\nrelease.cmd\npause \n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Package/release.cmd",
    "content": "@ECHO off\nSET Source=%1\nSET OqtaneInstallPackage=%2\nSET TargetFramework=%3\nECHO Source=%Source%\nECHO OqtaneInstallPackage=%OqtaneInstallPackage%\nECHO TargetFramework=%TargetFramework%\n\nREM enables the use of the ! delimiter for delayed variable expansion.\nSETLOCAL enabledelayedexpansion \n\nSET OqtaneRoot=..\\ToSic.Sxc.Oqt.Server\nSET PackageName=ToSic.Sxc.Oqtane\nSET BuildTarget=%OqtaneRoot%\\wwwroot\\Modules\\%PackageName%\n\nREM Copy the data folders\nROBOCOPY /mir \"..\\..\\Data\\assets\\ \" \"%BuildTarget%\\assets\\ \"\n\nREM Copy 2sxc JS stuff\nROBOCOPY /mir \"%Source%\\js\\ \" \"%BuildTarget%\\js\\ \"\nROBOCOPY /mir \"%Source%\\extensions\\ \" \"%BuildTarget%\\extensions\\ \"\nROBOCOPY /mir \"%Source%\\dist\\ \" \"%BuildTarget%\\dist\\ \"\n\n.nuget\\nuget.exe pack %PackageName%.Install.nuspec -Properties targetframework=%TargetFramework%;projectname=%PackageName%\n\nREM performs the string substitution. Specifically, it replaces forward slashes (/) with backslashes (\\).\nSET \"NormalizedPath=!OqtaneInstallPackage:/=\\!\"\nMOVE \"*.nupkg\" \"%NormalizedPath%\"\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/AdamFolderHelper.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Server.Integration;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam;\n\ninternal static class AdamFolderHelper\n{\n    public static Folder NewVirtualFolder(int siteId, int? parentId, string path, string folder)\n    {\n        return new()\n        {\n            SiteId = siteId,\n            ParentId = parentId,\n            Name = folder,\n            Path = path.EnsureOqtaneFolderFormat(),\n            Order = 1,\n            IsSystem = false,\n            Type = FolderTypes.Private,\n            PermissionList = [\n                new(PermissionNames.Browse, RoleNames.Everyone, true),\n                new(PermissionNames.View, RoleNames.Everyone, true),\n                new(PermissionNames.Browse, RoleNames.Admin, true),\n                new(PermissionNames.View, RoleNames.Admin, true),\n                new(PermissionNames.Edit, RoleNames.Admin, true)\n            ]\n        };\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/Imageflow/BlobProviderFile.cs",
    "content": "﻿using Imazen.Common.Storage;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam.Imageflow;\n#pragma warning disable S3881 // \"IDisposable\" should be implemented correctly\ninternal class BlobProviderFile : IBlobData\n#pragma warning restore S3881 // \"IDisposable\" should be implemented correctly\n{\n    public string Path;\n    public bool? Exists { get; set; }\n    public DateTime? LastModifiedDateUtc { get; set; }\n    public Stream OpenRead()\n    {\n        return new FileStream(Path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan);\n    }\n\n    public void Dispose()\n    {\n        // Method intentionally left empty.\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/Imageflow/ImageflowRewriteMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam.Imageflow;\n\n// This middleware is dynamically registered in oqtane imageflow module\n// to be executed before main imageflow middleware because we need to\n// rewrite query string params for imageflow\ninternal class ImageflowRewriteMiddleware : IMiddleware\n{\n    public Task InvokeAsync(HttpContext context, RequestDelegate next)\n    {\n        if (!ShouldHandleRequest(context) || !context.Request.QueryString.HasValue)\n        {\n            return next.Invoke(context);\n        }\n\n        Console.WriteLine($\"ImageflowRewriteMiddleware.Before:{context.Request.QueryString.Value}\");\n\n        var qs = UrlHelpers.ParseQueryString(context.Request.QueryString.Value);\n        var queryString = \"?\" + ImageflowRewrite.QueryStringRewrite(qs).NvcToString();\n        context.Request.QueryString = new(queryString);\n\n        Console.WriteLine($\"ImageflowRewriteMiddleware.After:{context.Request.QueryString.Value}\");\n\n        // Call the next delegate/middleware in the pipeline.\n        return next(context);\n    }\n\n    private static bool ShouldHandleRequest(HttpContext context)\n    {\n        // If the path is empty or null we don't handle it\n        var pathValue = context.Request.Path;\n        if (pathValue == null || !pathValue.HasValue)\n            return false;\n\n        var path = pathValue.Value;\n        if (path == null)\n            return false;\n\n        // We handle image request extensions\n        return IsImagePath(path);\n    }\n\n    private static readonly string[] Suffixes =\n    [\n        \".png\",\n        \".jpg\",\n        \".jpeg\",\n        \".jfif\",\n        \".jif\",\n        \".jfi\",\n        \".jpe\",\n        \".gif\",\n        \".webp\"\n    ];\n\n    private static bool IsImagePath(string path)\n    {\n        return Suffixes.Any(suffix => path.EndsWith(suffix, StringComparison.OrdinalIgnoreCase));\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/Imageflow/OqtaneBlobService.cs",
    "content": "﻿using Imazen.Common.Storage;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Diagnostics;\nusing System.Text.RegularExpressions;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam.Imageflow;\n\ninternal class OqtaneBlobService(IServiceProvider serviceProvider) : IBlobProvider\n{\n    private const string Prefix = \"/\";\n    private const string AdamPath = \"/adam/\";\n    private const string SxcPath = \"/assets/\";\n    private const string SharedPath = \"/shared/\";\n\n    // TODO: Why do we need the IServiceProvider? this should probably get Generators or something\n    // service provider is need to create new scope on each image request\n\n    public IEnumerable<string> GetPrefixes() \n        => Enumerable.Repeat(Prefix, 1);\n\n    public bool SupportsPath(string virtualPath)\n        => ContainsSharedPath(virtualPath) || ContainsAdamPath(virtualPath) || ContainsSxcPath(virtualPath);\n\n    public async Task<IBlobData> Fetch(string virtualPath) \n        => await Task.Run(() =>\n        {\n            if (!SupportsPath(virtualPath)) return null;\n\n            // Get appName and filePath.\n            if (!GetAppNameAndFilePath(virtualPath, out var appName, out var filePath))\n                return null;\n\n            // Get route.\n            var route = GetRoute(virtualPath);\n\n            // We need new scope on each request to avoid sharing the same instance of services.\n            using var scope = serviceProvider.CreateScope();\n\n            var webHostEnvironment = scope.ServiceProvider.GetRequiredService<IWebHostEnvironment>();\n            if (ExistUnderWebRootPath(webHostEnvironment, virtualPath, out var webRootFilePath)) \n                return BlobData(webRootFilePath);\n\n            // Get alias.\n            var aliasResolver = scope.ServiceProvider.GetRequiredService<AliasResolver>();\n            var alias = aliasResolver.Alias;\n\n            // Build physicalPath.\n            var fileHelper = scope.ServiceProvider.GetService<OqtAssetsFileHelper>(); // this service sometimes was not working when was lazy and not scoped\n            var physicalPath = fileHelper.GetFilePath(webHostEnvironment.ContentRootPath, alias, route, appName, filePath);\n\n            try\n            {\n                if (string.IsNullOrEmpty(physicalPath)) throw new BlobMissingException($\"Oqtane blob \\\"{virtualPath}\\\" not found.\");\n            }\n            catch (BlobMissingException) when (Debugger.IsAttached)\n            {\n                // Ignore during interactive debugging – still logs for visibility\n                Debug.WriteLine(\"Blob was missing; ignored in debug session.\");\n                return null;\n            }\n\n            return BlobData(physicalPath);\n        });\n\n    private static IBlobData BlobData(string physicalPath) \n        => new BlobProviderFile\n        {\n            Path = physicalPath,\n            Exists = true,\n            LastModifiedDateUtc = File.GetLastWriteTimeUtc(physicalPath)\n        };\n\n    public static bool GetAppNameAndFilePath(string virtualPath, out string appName, out string filePath)\n    {\n        // setup\n        var temp = (ContainsSharedPath(virtualPath)) ? \"shared/\" : \"app/\";\n        appName = string.Empty;\n        filePath = string.Empty;\n        // get appName\n        var prefixStart = virtualPath.IndexOf(temp, StringComparison.OrdinalIgnoreCase);\n        appName = virtualPath.Substring(prefixStart + temp.Length).TrimStart('/');\n        var indexOfSlash = appName.IndexOf('/');\n        if (indexOfSlash < 1) return false;\n        appName = appName.Substring(0, indexOfSlash);\n\n        // get filePath\n        if (ContainsAdamPath(virtualPath)) temp = AdamPath;\n        if (ContainsSxcPath(virtualPath)) temp = SxcPath;\n        if (ContainsSharedPath(virtualPath)) temp = $\"{SharedPath}{appName}/\";\n\n        var find = virtualPath.IndexOf(temp, StringComparison.OrdinalIgnoreCase);\n        if (find < 1) return false;\n        filePath = virtualPath.Substring(find + temp.Length).TrimStart('/');\n\n        return true;\n    }\n\n    private static bool ContainsSharedPath(string virtualPath)\n        => virtualPath.Contains(SharedPath, StringComparison.OrdinalIgnoreCase);\n\n    private static bool ContainsAdamPath(string virtualPath)\n        => Regex.IsMatch(virtualPath, @\"^.*app/[a-zA-Z \\d-_]+/adam/.*$\");\n\n    public static bool ContainsSxcPath(string virtualPath)\n        => Regex.IsMatch(virtualPath, @\"^.*app/[a-zA-Z \\d-_]+/assets/.*$\");\n\n    private static string GetRoute(string virtualPath)\n        => ContainsSharedPath(virtualPath) ? OqtAssetsFileHelper.RouteShared :\n            ContainsAdamPath(virtualPath) ? OqtAssetsFileHelper.RouteAdam :\n            ContainsSxcPath(virtualPath) ? OqtAssetsFileHelper.RouteAssets : string.Empty;\n\n    private static bool ExistUnderWebRootPath(IWebHostEnvironment webHostEnvironment, string virtualPath, out string filePath)\n    {\n        var path = virtualPath.Backslash().TrimPrefixSlash();\n        filePath = Path.Combine(webHostEnvironment.WebRootPath, path);\n        return File.Exists(filePath);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/Imageflow/OqtaneBlobServiceExtension.cs",
    "content": "﻿using Imazen.Common.Storage;\nusing Microsoft.Extensions.DependencyInjection;\nusing ToSic.Imageflow.Oqt.Server;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam.Imageflow;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class ImageflowExtensions\n{\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static IServiceCollection AddImageflowExtensions(this IServiceCollection services)\n    {\n        services.AddSingleton<IBlobProvider>((container) => new OqtaneBlobService(container));\n        services.AddSingleton<ImageflowRewriteMiddleware>();\n        services.AddSingleton<IPreregisterImageFlowMiddleware, PreregisterImageFlowMiddleware>(); // query string rewriting middleware\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/Imageflow/PreregisterImageFlowMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing ToSic.Imageflow.Oqt.Server;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam.Imageflow;\n\n// IPreregisterImageFlowMiddleware interface belongs to oqtane imageflow module.\n// PreregisterImageFlowMiddleware implementation enables dynamic registration of\n// ImageflowRewriteMiddleware in oqtane imageflow module to be executed in\n// request pipeline exactly before main imageflow middleware because we need to\n// rewrite query string params before imageflow middleware take a care of them.\ninternal class PreregisterImageFlowMiddleware : IPreregisterImageFlowMiddleware\n{\n    public void Register(IApplicationBuilder app) => app.UseMiddleware<ImageflowRewriteMiddleware>();\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/OqtAdam.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam;\n\n/// <summary>\n/// Casting helpers so DNN code can work with the file / folder in the DNN signature\n/// </summary>\ninternal static class OqtAdam\n{\n    internal static File<int, int> AsOqt(this IFile file)\n    {\n        if (file == null) return null;\n        if (file is not File<int, int> recast) throw new(\"Tried to cast IFile to internal type, failed\");\n        return recast;\n    }\n\n    internal static Folder<int, int> AsOqt(this IFolder folder)\n    {\n        if (folder == null) return null;\n        if (folder is not Folder<int, int> recast) throw new(\"Tried to cast IFolder to internal type, failed\");\n        return recast;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/OqtAdamFileSystem.cs",
    "content": "﻿using Microsoft.Data.SqlClient;\nusing Microsoft.EntityFrameworkCore;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.FileSystem;\nusing ToSic.Sxc.Adam.Sys.Paths;\nusing ToSic.Sxc.Oqt.Server.Integration;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Oqt.Shared.Dev;\nusing ToSic.Sys.Utils;\nusing File = Oqtane.Models.File;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam;\n\ninternal class OqtAdamFileSystem(\n    IFileRepository oqtFileRepository,\n    IFolderRepository oqtFolderRepository,\n    IServerPaths serverPaths,\n    IAdamPaths adamPaths)\n    : AdamFileSystemBase(adamPaths, OqtConstants.OqtLogPrefix, [serverPaths, oqtFileRepository, oqtFolderRepository]),\n        IAdamFileSystem\n{\n    public IFileRepository OqtFileRepository { get; } = oqtFileRepository;\n    public IFolderRepository OqtFolderRepository { get; } = oqtFolderRepository;\n\n    #region Files\n\n    public override IFile GetFile(AdamAssetIdentifier fileId)\n    {\n        var id = ((AdamAssetId<int>)fileId).SysId;\n        var file = OqtFileRepository.GetFile(id);\n        return OqtToAdam(file);\n    }\n\n    public override void Rename(IFile file, string newName)\n    {\n        var l = Log.Fn();\n        try\n        {\n            var path = serverPaths.FullContentPath(file.Path);\n\n            var currentFilePath = Path.Combine(path, file.FullName);\n            if (!FsHelpers.TryToRenameFile(currentFilePath, newName))\n            {\n                l.Done(\"\");\n                return;\n            }\n\n            var oqtFile = OqtFileRepository.GetFile(file.AsOqt().SysId);\n            oqtFile.Name = newName;\n            OqtFileRepository.UpdateFile(oqtFile);\n            l.A($\"VirtualFile {oqtFile.FileId} renamed to {oqtFile.Name}\");\n\n            l.Done(\"ok\");\n        }\n        catch (Exception e)\n        {\n            l.Done($\"Error:{e.Message}; {e.InnerException}\");\n        }\n    }\n\n    public override void Delete(IFile file)\n    {\n        var l = Log.Fn();\n        var oqtFile = OqtFileRepository.GetFile(file.AsOqt().SysId);\n        OqtFileRepository.DeleteFile(oqtFile.FileId);\n        l.Done();\n    }\n\n    public override IFile Add(IFolder parent, Stream body, string fileName, bool ensureUniqueName)\n    {\n        var l = Log.Fn<IFile>($\"..., ..., {fileName}, {ensureUniqueName}\");\n        if (ensureUniqueName)\n            fileName = FindUniqueFileName(parent, fileName);\n        var fullContentPath = serverPaths.FullContentPath(parent.Path);\n        Directory.CreateDirectory(fullContentPath);\n        var filePath = Path.Combine(fullContentPath, fileName);\n        using (var stream = new FileStream(filePath, FileMode.Create))\n        {\n            body.CopyTo(stream);\n        }\n        var fileInfo = new FileInfo(filePath);\n\n        // register into oqtane\n        var oqtFileData = new File\n        {\n            Name = Path.GetFileName(fileName),\n            FolderId = parent.Id,\n            Extension = fileInfo.Extension.ToLowerInvariant().Replace(\".\", \"\"),\n            Size = (int)fileInfo.Length,\n            ImageHeight = 0,\n            ImageWidth = 0\n        };\n        var oqtFile = OqtFileRepository.AddFile(oqtFileData);\n        var file = GetFile(AdamAssetIdentifier.Create(oqtFile.FileId));\n        return l.ReturnAsOk(file);\n    }\n\n    /// <summary>\n    /// When uploading a new file, we must verify that the name isn't used.\n    /// If it is used, walk through numbers to make a new name which isn't used.\n    /// </summary>\n    /// <param name=\"parentFolder\"></param>\n    /// <param name=\"fileName\"></param>\n    /// <returns></returns>\n    private string FindUniqueFileName(IFolder parentFolder, string fileName)\n    {\n        var l = Log.Fn<string>($\"..., {fileName}\");\n\n        var oqtFolder = OqtFolderRepository.GetFolder(parentFolder.AsOqt().SysId);\n        var serverPath = Path.Combine(serverPaths.FullContentPath(AdamManager.Site.ContentPath), oqtFolder.Path);\n\n        return l.Return(FsHelpers.FindUniqueFileName(serverPath, fileName));\n    }\n\n    #endregion\n\n\n\n    #region Folders\n\n\n    public override bool FolderExists(string path) => GetOqtFolderByName(path) != null;\n\n    private Folder GetOqtFolderByName(string path) => OqtFolderRepository.GetFolder(AdamManager.Site.Id, path.EnsureOqtaneFolderFormat());\n\n    public override void AddFolder(string path) => Log.Do(() =>\n    {\n        path = path.Backslash();\n        if (FolderExists(path)) return \"\";\n\n        try\n        {\n            // find parent\n            var pathWithPretendFileName = path.TrimLastSlash();\n            var parent = Path.GetDirectoryName(pathWithPretendFileName) + \"/\";\n            var subfolder = Path.GetFileName(pathWithPretendFileName);\n            var parentFolder = GetOqtFolderByName(parent) ?? GetOqtFolderByName(\"\");\n\n            // Create the new virtual folder\n            CreateVirtualFolder(parentFolder, path, subfolder);\n            return \"ok\";\n        }\n        catch (SqlException)\n        {\n            // don't do anything - this happens when multiple processes try to add the folder at the same time\n            // like when two fields in a dialog cause the web-api to create the folders in parallel calls\n            // see also https://github.com/2sic/2sxc/issues/811\n            return \"error in SQL, probably folder already exists\";\n        }\n        catch (DbUpdateException)\n        {\n            return $\"error in EF, probably folder already exists\";\n        }\n        catch (NullReferenceException)\n        {\n            // also catch this, as it's an additional exception which also happens in the AddFolder when a folder already existed\n            return \"error, probably folder already exists\";\n        }\n    });\n\n    private Folder CreateVirtualFolder(Folder parentFolder, string path, string folder)\n    {\n        var newVirtualFolder = AdamFolderHelper.NewVirtualFolder(AdamManager.Site.Id, parentFolder.FolderId, path, folder);\n        OqtFolderRepository.AddFolder(newVirtualFolder);\n        return newVirtualFolder;\n    }\n\n    public override void Rename(IFolder folder, string newName) => Log.Do($\"..., {newName}\", () =>\n    {\n        var fld = OqtFolderRepository.GetFolder(folder.AsOqt().SysId);\n        WipConstants.AdamNotImplementedYet();\n        Log.A(\"Not implement yet in Oqtane\");\n    });\n\n    public override void Delete(IFolder folder) => Log.Do(() => OqtFolderRepository.DeleteFolder(folder.AsOqt().SysId));\n\n    public override IFolder Get(string path) => OqtToAdam(GetOqtFolderByName(path));\n\n\n    public override List<IFolder> GetFolders(IFolder folder)\n    {\n        var l = Log.Fn<List<IFolder>>();\n        var fldObj = GetOqtFolder(folder.AsOqt().SysId);\n        if (fldObj == null) return [];\n\n        var firstList = GetSubFoldersRecursive(fldObj);\n        var folders = firstList?.Select(OqtToAdam).ToList()\n                      ?? [];\n        return l.Return(folders, $\"{folders.Count}\");\n    }\n\n    private List<Folder> GetSubFoldersRecursive(Folder parentFolder, List<Folder> allFolders = null, List<Folder> subFolders = null)\n    {\n        allFolders ??= OqtFolderRepository.GetFolders(parentFolder.SiteId).ToList();\n        subFolders ??= [];\n        allFolders.Where(f => f.ParentId == parentFolder.FolderId).ToList().ForEach(f =>\n        {\n            subFolders.Add(f);\n            GetSubFoldersRecursive(f, allFolders, subFolders);\n        });\n        return subFolders;\n    }\n\n    //public override Folder<int, int> GetFolder(int folderId)\n    //    => OqtToAdam(GetOqtFolder(folderId));\n\n    public override IFolder GetFolder(AdamAssetIdentifier folderId)\n        => OqtToAdam(GetOqtFolder(((AdamAssetId<int>)folderId).SysId));\n\n    #endregion\n\n    #region Oqtane typed calls\n\n    private Folder GetOqtFolder(int folderId) => OqtFolderRepository.GetFolder(folderId);\n\n\n    public override List<IFile> GetFiles(IFolder folder)\n    {\n        var l = Log.Fn<List<IFile>>();\n        var fldObj = OqtFolderRepository.GetFolder(folder.AsOqt().SysId);\n        // sometimes the folder doesn't exist for whatever reason\n        if (fldObj == null)\n            return [];\n\n        // try to find the files\n        var firstList = OqtFileRepository.GetFiles(fldObj.FolderId);\n        var files = firstList?.Select(OqtToAdam).ToList()\n                    ?? [];\n        return l.Return(files, $\"{files.Count}\");\n    }\n\n    #endregion\n\n    #region OqtToAdam\n\n    //public string GetUrl(string folderPath) => _adamPaths.Url(folderPath.ForwardSlash());\n\n    private IFolder OqtToAdam(Folder f)\n    {\n        var l = Log.Fn<Folder<int, int>>($\"folderName: {f.Name}\");\n\n        var typed = new Folder<int, int>(AdamManager)\n        {\n            Path = ((OqtAdamPaths)AdamPaths).Path(f.Path),\n            SysId = f.FolderId,\n\n            ParentSysId = f.ParentId ?? WipConstants.ParentFolderNotFound,\n\n            Name = f.Name,\n            Created = f.CreatedOn,\n            Modified = f.ModifiedOn,\n            Url = GetUrl(f.Path),\n            PhysicalPath = AdamPaths.PhysicalPath(f.Path),\n        };\n        if (AdamManager.UseTypedAssets)\n            return l.Return(typed, \"typed\");\n\n        var dyn = FolderDynamic<int, int>.Create(AdamManager, typed);\n        return l.Return(dyn, \"dynamic\");\n    }\n\n\n    private IFile OqtToAdam(File f)\n    {\n        var l = Log.Fn<File<int, int>>($\"fileName: {f.Name}\");\n\n        var typed = new File<int, int>(AdamManager)\n        {\n            FullName = f.Name,\n            Extension = f.Extension,\n            Size = f.Size,\n            SysId = f.FileId,\n            Folder = f.Folder.Name,\n            ParentSysId = f.FolderId,\n\n            Path = ((OqtAdamPaths)AdamPaths).Path(f.Folder.Path),\n\n            Created = f.CreatedOn,\n            Modified = f.ModifiedOn,\n            Name = Path.GetFileNameWithoutExtension(f.Name)!,\n            Url = AdamPaths.Url(Path.Combine(f.Folder.Path, f.Name!).ForwardSlash()),\n            PhysicalPath = AdamPaths.PhysicalPath(Path.Combine(f.Folder.Path, f.Name)),\n        };\n        if (AdamManager.UseTypedAssets)\n            return l.Return(typed, \"typed\");\n\n        var dyn = FileDynamic<int, int>.Create(AdamManager, typed);\n        return l.Return(dyn, \"dynamic\");\n\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/OqtAdamItemDtoMaker.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Backend.Adam;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam;\n\n// TODO: @STV - this doesn't seem to be used, as it's not even registered in DI\n// Pls find out why, and if we don't need it, remove\ninternal class OqtAdamItemDtoMaker(AdamItemDtoMaker<int, int>.Dependencies services)\n    : AdamItemDtoMaker<int, int>(services)\n{\n    public override AdamItemDto Create(IFile original)\n    {\n        var item = base.Create(original);\n        if(item is AdamItemDto<int, int> typed)\n            item.Path = string.Format(OqtConstants.DownloadLinkTemplate, AdamContext.Context.Site.Id, typed.Id);\n\n        return item;\n    }\n\n\n    public override AdamItemDto Create(IFolder folder)\n    {\n        var item = base.Create(folder);\n        if (item is AdamItemDto<int, int> typed)\n            item.Path = \"/\" + AdamContext.Context.Site.Id + \"/api/file/download/\" + typed.Id;\n        return item;\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/OqtAdamPaths.cs",
    "content": "﻿using ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Adam.Sys.Paths;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam;\n\n/// <summary>\n/// Basic AdamPaths resolver, assumes that files are in Content/[tenant]/site/[site]/adam for now\n/// </summary>\ninternal class OqtAdamPaths(IServerPaths serverPaths, AliasResolver aliasResolver)\n    : AdamPathsBase(serverPaths, OqtConstants.OqtLogPrefix)\n{\n    public string Path(string path)\n    {\n        var original = base.Url(path);\n        return original.PrefixSlash();\n    }\n\n    public override string Url(string path)\n    {\n        // Convert path to url.\n        string url = path.ForwardSlash();\n        var parts = url.Split(\"/\").ToList();\n        if (parts[0] == \"adam\")\n        {\n            // Swap 'adam' and appName.\n            parts[0] = parts[1];\n            parts[1] = \"adam\";\n\n            // Insert alias path.\n            var alias = aliasResolver.Alias;\n            var aliasPath = alias.Path;\n            parts.Insert(0, $\"{aliasPath}/app\");\n\n            // Build url string.\n            url = string.Join('/', parts.ToArray());\n        }\n\n        return url.PrefixSlash();\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Adam/OqtAssetsFileHelper.cs",
    "content": "using System.Text.RegularExpressions;\nusing Microsoft.AspNetCore.StaticFiles;\nusing Oqtane.Models;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sys.Utils;\nusing File = System.IO.File;\n\nnamespace ToSic.Sxc.Oqt.Server.Adam;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtAssetsFileHelper() : ServiceBase(OqtConstants.OqtLogPrefix + \".FilHlp\")\n{\n    public const string RouteAdam = \"adam\";\n    public const string RouteAssets = \"assets\";\n    public const string RouteShared = \"shared\";\n\n    public static readonly Regex RiskyDetector = Eav.Security.Files.FileNames.RiskyDownloadDetector;\n\n    public const string FallbackMimeType = MimeTypeConstants.FallbackType;\n\n\n    public static string GetMimeType(string fileName)\n    {\n        if (string.IsNullOrWhiteSpace(fileName)) return FallbackMimeType;\n        var provider = new FileExtensionContentTypeProvider();\n        if (!provider.TryGetContentType(fileName, out var contentType)) \n            contentType = FallbackMimeType;\n        return contentType;\n    }\n\n    public string GetFilePath(string contentRootPath, Alias alias, string filePath) \n        => GetFilePath(contentRootPath, alias, string.Empty,  string.Empty, filePath);\n\n    public string GetFilePath(string contentRootPath, Alias alias, string route, string appName, string filePath)\n    {\n        var l = Log.Fn<string>(\n            $\"{nameof(contentRootPath)}: '{contentRootPath}'; {nameof(route)}: {route}; {nameof(appName)}: '{appName}'; {nameof(filePath)}: '{filePath}'\");\n            \n        // Validate for alias.\n        if (alias == null) \n            return l.Return(string.Empty, \"no site alias\");\n\n        // Oqtane path and file name validation.\n        // Partly commented because Path validation is not working as expected.\n        if (!appName.IsPathOrFileValid()) \n            return l.Return(string.Empty, \"not valid\");\n\n        // Blacklist extensions should be denied.\n        if (IsKnownRiskyExtension(filePath))\n            return l.Return(string.Empty, \"risky extension\");\n\n        if (Eav.Security.Files.FileNames.IsKnownCodeExtension(filePath))\n            return l.Return(string.Empty, \"code extension\");\n\n        // Nothing in a \".xyz\" folder or a subfolder of this should be allowed (like .data must be protected).\n        if (appName.StartsWith(\".\") || filePath.StartsWith(\".\") || Path.GetDirectoryName(filePath).Backslash().Contains(@\"\\.\")) \n            return l.Return(string.Empty, \"folders or subfolder that start with . are not allowed\");\n\n        string fullFilePath = route switch\n        {\n            \"\" => AdamPathWithoutAppName(contentRootPath, alias, filePath),\n            RouteAdam => AdamPath(contentRootPath, alias, appName, filePath),\n            RouteAssets => SxcPath(contentRootPath, alias, appName, filePath),\n            RouteShared => SharedPath(contentRootPath, alias, appName, filePath),\n\n            _ => SxcPath(contentRootPath, alias, appName, filePath),\n        };\n\n        // Check that file exists in file system.\n        return File.Exists(fullFilePath) \n            ? l.Return(fullFilePath, \"found\")\n            : l.Return(string.Empty, \"file not found\");\n    }\n\n    private static bool IsKnownRiskyExtension(string fileName)\n    {\n        var extension = Path.GetExtension(fileName);\n        return !string.IsNullOrEmpty(extension) && RiskyDetector.IsMatch(extension);\n    }\n\n    private static string AdamPathWithoutAppName(string contentRootPath, Alias alias, string filePath)\n        => Path.Combine(contentRootPath, string.Format(OqtConstants.ContentRootPublicBase, alias.TenantId, alias.SiteId), filePath).Backslash();\n\n    private static string AdamPath(string contentRootPath, Alias alias, string appName, string filePath)\n        => Path.Combine(contentRootPath, string.Format(OqtConstants.ContentRootPublicBase, alias.TenantId, alias.SiteId), \"adam\", appName, filePath).Backslash();\n\n    private static string SxcPath(string contentRootPath, Alias alias, string appName, string filePath)\n        => Path.Combine(contentRootPath, string.Format(OqtConstants.AppRootTenantSiteBase, alias.TenantId, alias.SiteId), appName, filePath).Backslash();\n\n    private static string SharedPath(string contentRootPath, Alias alias, string appName, string filePath)\n        => Path.Combine(contentRootPath, string.Format(OqtConstants.AppRootTenantSiteBase, alias.TenantId, OqtConstants.SharedAppFolder), appName, filePath).Backslash();\n\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/IOqtSxcViewBuilder.cs",
    "content": "﻿using Oqtane.Models;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks;\n\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOqtSxcViewBuilder\n{\n    /// <summary>\n    /// Render must always be the first thing to be called - to ensure that afterward both headers and html are known.\n    /// </summary>\n    OqtViewResultsDto Render(Alias alias, Site site, Page page, Module module, bool preRender);\n\n    Page Page { get; }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/OqtCodeApiService.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks;\n\n[PrivateApi]\ninternal class OqtExecutionContext(\n    ExecutionContext.Dependencies services,\n    LazySvc<AliasResolver> aliasResolverLazy)\n    : OqtExecutionContext<object, ServiceKit>(services, aliasResolverLazy);"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/OqtDynamicCodeRoot_TT.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks;\n\n[PrivateApi]\ninternal class OqtExecutionContext<TModel, TServiceKit> : ExecutionContext<TModel, TServiceKit> where TServiceKit : ServiceKit where TModel : class\n{\n    private readonly LazySvc<AliasResolver> _aliasResolverLazy;\n    public OqtExecutionContext(Dependencies services, LazySvc<AliasResolver> aliasResolverLazy) : base(services, OqtConstants.OqtLogPrefix)\n    {\n        ConnectLogs([\n            _aliasResolverLazy = aliasResolverLazy\n        ]);\n    }\n\n    public override IExecutionContext Setup(ExecutionContextOptions options)\n    {\n        _aliasResolverLazy.Value.InitIfEmpty(options.BlockOrNull?.Context?.Site?.Id);\n        return base.Setup(options);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/OqtGetBlock.cs",
    "content": "﻿using Oqtane.Repository;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Backend.Context;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing static ToSic.Sxc.Backend.SxcWebApiConstants;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks;\n\n/// <summary>\n/// WIP - separating concerns in OqtState to get the block and provide the state...\n/// </summary>\ninternal class OqtGetBlock(\n    LazySvc<IModuleRepository> modRepoLazy,\n    RequestHelper requestHelper,\n    ISxcCurrentContextService currentContextServiceToInit,\n    Generator<IContextOfBlock> cntOfBlkGen,\n    Generator<BlockOfModule> blkFromModGen,\n    Generator<BlockOfEntity> blkFromEntGen)\n    : ServiceBase(\"Sxc.GetBlk\",\n            connect: [modRepoLazy, requestHelper, currentContextServiceToInit, cntOfBlkGen, blkFromModGen, blkFromEntGen]),\n        IWebApiContextBuilder\n{\n    public ISxcCurrentContextService PrepareContextResolverForApiRequest()\n    {\n        if (_alreadyTriedToLoad) return currentContextServiceToInit;\n        _alreadyTriedToLoad = true;\n\n        var block = InitializeBlock();\n        currentContextServiceToInit.AttachBlock(block);\n        return currentContextServiceToInit;\n    }\n    private bool _alreadyTriedToLoad;\n\n\n    private IBlock InitializeBlock()\n    {\n        var l = Log.Fn<IBlock>();\n\n        // WebAPI calls can contain the original parameters that made the page, so that views can respect that\n        var moduleId = TryGetId(ContextConstants.ModuleIdKey);\n        if (moduleId == Eav.Sys.EavConstants.NullId)\n            return l.ReturnNull(\"missing block because ModuleId not found in request\");\n\n        var pageId = TryGetId(ContextConstants.PageIdKey);\n        if (pageId == Eav.Sys.EavConstants.NullId)\n            return l.ReturnNull(\"missing block because PageId not found in request\");\n\n        var module = modRepoLazy.Value.GetModule(moduleId);\n        var ctx = cntOfBlkGen.New().Init(pageId, module);\n        var block = blkFromModGen.New().GetBlockOfModule(ctx);\n\n        // only if it's negative, do we load the inner block\n        var contentBlockId = requestHelper.GetTypedHeader(HeaderContentBlockId, 0); // this can be negative, so use 0\n        if (contentBlockId >= 0)\n            return l.Return(block, \"found block\");\n\n        l.A($\"Inner Content: {contentBlockId}\");\n        var entityBlock = blkFromEntGen.New().GetBlockOfEntity(block, null, contentBlockId);\n        return l.Return(entityBlock, $\"inner block {contentBlockId}\");\n    }\n\n    private int TryGetId(string key)\n    {\n        var l = Log.Fn<int>(key);\n        var id = requestHelper.TryGetId(key);\n        return l.Return(id, id == Eav.Sys.EavConstants.NullId ? \"not found\" : $\"found {id}\");\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/OqtModuleAndBlockBuilder.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Repository;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks;\n\ninternal class OqtModuleAndBlockBuilder(\n    Generator<IModule> moduleGenerator,\n    Generator<IContextOfBlock> contextGenerator,\n    Generator<BlockOfModule> blockGenerator,\n    Generator<IModuleRepository> moduleRepositoryGenerator,\n    RequestHelper requestHelper)\n    : ModuleAndBlockBuilder(blockGenerator, OqtConstants.OqtLogPrefix,\n        connect: [moduleGenerator, contextGenerator, moduleRepositoryGenerator, requestHelper])\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"pageId\">not required in Oqtane</param>\n    /// <param name=\"moduleId\"></param>\n    /// <returns></returns>\n    public override IModule GetModule(int pageId, int moduleId)\n    {\n        var oqtModule = moduleRepositoryGenerator.New().GetModule(moduleId);\n        ThrowIfModuleIsNull(pageId, moduleId, oqtModule);\n        var module = ((OqtModule) moduleGenerator.New()).Init(oqtModule);\n        return module;\n    }\n\n    protected override IContextOfBlock GetContextOfBlock(IModule module, int? pageId)\n        => GetContextOfBlock((module as OqtModule)?.GetContents(), pageId);\n\n    protected override IContextOfBlock GetContextOfBlock<TPlatformModule>(TPlatformModule module, int? pageId)\n    {\n        var l = Log.Fn<IContextOfBlock>();\n        if (module == null) throw new ArgumentNullException(nameof(module));\n\n        var oqtModule = module switch\n        {\n            Module oModule => oModule,\n            PageModule oPageModule => oPageModule.Module,\n            _ => throw new ArgumentException(\"Given data is not a module\")\n        };\n\n        l.A($\"Module: {oqtModule.ModuleId}\");\n        var initializedCtx = InitOqtSiteModuleAndBlockContext(oqtModule, pageId);\n        return l.ReturnAsOk(initializedCtx);\n    }\n\n\n    private IContextOfBlock InitOqtSiteModuleAndBlockContext(Module oqtModule, int? pageId)\n    {\n        var l = Log.Fn<IContextOfBlock>();\n        var context = contextGenerator.New();\n        l.A(\"Will init module\");\n        ((OqtModule) context.Module).Init(oqtModule);\n        return l.Return(InitPageOnly(context, pageId));\n    }\n\n    private IContextOfBlock InitPageOnly(IContextOfBlock context, int? pageId)\n    {\n        // TODO: try to use the pageId if given, would usually only be used in inner-content / IRenderService scenarios\n        var l = Log.Fn<IContextOfBlock>();\n        // Collect / assemble page information\n        context.Page.Init(requestHelper.TryGetId(ContextConstants.PageIdKey));\n        var url = context.Page.Url;\n        return l.Return(context, url);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/OqtSxcViewBuilder.cs",
    "content": "﻿using Oqtane.Models;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sxc.Oqt.Server.Installation;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Oqt.Shared.Models;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.RenderBlock;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sxc.Web.Sys.Url;\nusing Page = Oqtane.Models.Page;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class OqtSxcViewBuilder : ServiceBase, IOqtSxcViewBuilder\n{\n    #region Constructor and DI\n\n    public OqtSxcViewBuilder(\n        Output.OqtPageOutput pageOutput,\n        IContextOfBlock contextOfBlockEmpty,\n        BlockOfModule blockModuleEmpty,\n        ISxcCurrentContextService currentContextServiceForLookUps,\n        ILogStore logStore,\n        GlobalTypesCheck globalTypesCheck,\n        IOutputCache outputCache,\n        Generator<IBlockBuilder> blockBuilderGenerator) : base($\"{OqtConstants.OqtLogPrefix}.Buildr\", connect: [pageOutput, contextOfBlockEmpty, blockModuleEmpty, currentContextServiceForLookUps, globalTypesCheck, outputCache, pageOutput, blockBuilderGenerator])\n    {\n        _contextOfBlockEmpty = contextOfBlockEmpty;\n        _blockModuleEmpty = blockModuleEmpty;\n        _currentContextServiceForLookUps = currentContextServiceForLookUps;\n        _globalTypesCheck = globalTypesCheck;\n        OutputCache = outputCache;\n        PageOutput = pageOutput;\n        _blockBuilderGenerator = blockBuilderGenerator;\n        logStore.Add(\"oqt-view\", Log);\n    }\n\n    public Output.OqtPageOutput PageOutput { get; }\n    private readonly IContextOfBlock _contextOfBlockEmpty;\n    private readonly BlockOfModule _blockModuleEmpty;\n    private readonly ISxcCurrentContextService _currentContextServiceForLookUps;\n    private readonly GlobalTypesCheck _globalTypesCheck;\n    private readonly Generator<IBlockBuilder> _blockBuilderGenerator;\n\n    #endregion\n\n    #region Prepare\n\n    /// <summary>\n    /// Render must always be the first thing to be called - to ensure that afterward both headers and html are known.\n    /// </summary>\n    public OqtViewResultsDto Render(Alias alias, Site site, Page page, Module module, bool preRender)\n    {\n        Alias = alias;\n        Site = site;\n        Page = page;\n        Module = module;\n        PreRender = preRender;\n\n        // Check for installation errors before even trying to build a view, and otherwise return this object if Refs are missing.\n        if (RefsInstalledCheck.WarnIfRefsAreNotInstalled(out var oqtViewResultsDtoWarning)) return oqtViewResultsDtoWarning;\n\n        OqtViewResultsDto ret = null;\n        IRenderResult renderResult = null;\n        var finalMessage = \"\";\n        LogTimer.DoInTimer(() => Log.Do(timer: true, action: () =>\n        {\n            #region Lightspeed output caching\n            var useLightspeed = OutputCache?.IsEnabled ?? false;\n            var cachedResult = OutputCache?.Existing?.Data;\n            var cacheHit = cachedResult != null;\n            if (cacheHit) Log.A(\"Lightspeed hit - will use cached\");\n            renderResult = cachedResult\n                           ?? _blockBuilderGenerator.New().Setup(Block).Run(true, specs: new()\n                           {\n                               UseLightspeed = useLightspeed,\n                               IncludeAllAssetsInOqtane = site.RenderMode == \"Interactive\",\n                           });\n            finalMessage = !useLightspeed ? \"\" :\n                cacheHit ? \"⚡⚡\" : \"⚡⏳\";\n\n            // Do not save cache hits again. Cached entries may already carry compressed HTML,\n            // so saving them again would just trigger another decompress/recompress cycle.\n            if (!cacheHit)\n                OutputCache?.Save(renderResult);\n\n            #endregion\n\n            PageOutput.Init(this, renderResult);\n\n            ret = new()\n            {\n                Html = renderResult.Html,\n                TemplateResources = PageOutput.GetSxcResources(),\n                SxcContextMetaName = PageOutput.AddContextMeta\n                    ? PageOutput.ContextMetaName\n                    : null,\n                SxcContextMetaContents = PageOutput.AddContextMeta\n                    ? PageOutput.ContextMetaContents()\n                    : null,\n                SxcScripts = PageOutput.Scripts().ToList(),\n                SxcStyles = PageOutput.Styles().ToList(),\n                PageProperties = PageOutput.GetOqtPagePropertyChangesList(renderResult.PageChanges),\n                HeadChanges = PageOutput.GetHeadChanges(),\n                HttpHeaders = ConvertHttpHeaders(renderResult.HttpHeaders),\n                // CSP settings\n                CspEnabled = renderResult.CspEnabled,\n                CspEnforced = renderResult.CspEnforced,\n                CspParameters = renderResult.CspParameters\n                    .Select(c => c.NvcToString())\n                    .ToList(), // convert NameValueCollection to (query) string because can't serialize NameValueCollection to json\n            };\n        }));\n        LogTimer.Done(renderResult?.IsError ?? false ? \"⚠️\" : finalMessage);\n\n        // Check if there is less than 50 global types and warn user to restart application\n        // HACK: in v14.03 this check was moved bellow LogTimer.DoInTimer because we got exception (probably timing issue)\n        // \"Object reference not set to an instance of an object. at ToSic.Eav.Apps.AppStates.Get(IAppIdentity app)\"\n        // TODO: STV find correct fix\n        if (_globalTypesCheck.WarnIfGlobalTypesAreNotLoaded(out var oqtViewResultsDtoWarning2))\n            return oqtViewResultsDtoWarning2;\n\n        return ret;\n    }\n\n    // convert System.Collections.Generic.IList<ToSic.Sxc.Web.PageService.HttpHeader> to System.Collections.Generic.IList<ToSic.Sxc.Oqt.Shared.HttpHeader>\n    private static IList<HttpHeader> ConvertHttpHeaders(IList<Sys.Render.PageContext.HttpHeader> httpHeaders) \n        => httpHeaders.Select(httpHeader => new HttpHeader(httpHeader.Name, httpHeader.Value)).ToList();\n\n    internal Alias Alias;\n    internal Site Site;\n    public Page Page { get; private set; }\n    internal Module Module;\n    internal bool PreRender;\n\n    private IBlock Block => _blockGetOnce.Get(() => LogTimer.DoInTimer(() =>\n    {\n        var ctx = _contextOfBlockEmpty.Init(Page.PageId, Module);\n        var block = _blockModuleEmpty.GetBlockOfModule(ctx);\n\n        // Special for Oqtane - normally the IContextResolver is only used in WebAPIs\n        // But the ModuleLookUp and PageLookUp also rely on this, so the IContextResolver must know about this for now\n        // In future, we should find a better way for this, so that IContextResolver is really only used on WebApis\n        _currentContextServiceForLookUps.AttachBlock(block);\n        return block;\n    }));\n    private readonly GetOnce<IBlock> _blockGetOnce = new();\n\n    private ILogCall LogTimer => _logTimer.Get(() => Log.Fn(message: $\"PreRender:{PreRender}, Page:{Page?.PageId} '{Page?.Name}', Module:{Module?.ModuleId} '{Module?.Title}'\"));\n    private readonly GetOnce<ILogCall> _logTimer = new();\n\n\n    private IOutputCache OutputCache => _oc.Get(() => field.Init(Module.ModuleId, Page?.PageId ?? 0, Block));\n    private readonly GetOnce<IOutputCache> _oc = new();\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/Output/OqtJsApiService.cs",
    "content": "﻿using Microsoft.AspNetCore.Antiforgery;\nusing Microsoft.AspNetCore.Http;\nusing System.Text.Json;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Server.WebApi;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sxc.Web.Sys.EditUi;\nusing ToSic.Sys.Security.Encryption;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks.Output;\n\ninternal class OqtJsApiService(\n    IAntiforgery antiForgery,\n    IHttpContextAccessor http,\n    JsApiCacheService jsApiCache,\n    AliasResolver aliasResolver,\n    RsaCryptographyService rsaCryptographyService)\n    : ServiceBase(\"OqtJsApi\", connect: [antiForgery, http, jsApiCache, aliasResolver, rsaCryptographyService]), IJsApiService\n{\n    public string GetJsApiJson(int? pageId = null, string siteRoot = null, string rvt = null, bool withPublicKey = false) \n        => JsonSerializer.Serialize(GetJsApi(pageId, siteRoot, rvt, withPublicKey));\n\n    public JsApi GetJsApi(int? pageId = null, string siteRoot = null, string rvt = null, bool withPublicKey = false)\n    {\n        return jsApiCache.JsApiJson(\n            platform: PlatformType.Oqtane.ToString(),\n            pageId: pageId ?? -1,\n            siteRoot: SiteRootFn,\n            apiRoot: ApiRootFn,\n            appApiRoot: SiteRootFn, // without \"app/\" because the UI will add that later on,\n            uiRoot: UiRootFn,\n            rvtHeader: Oqtane.Shared.Constants.AntiForgeryTokenHeaderName,\n            rvt: RvtFn,\n            withPublicKey: withPublicKey,\n            secureEndpointPublicKey: SecureEndpointPrimaryKeyFn,\n            dialogQuery: $\"{HtmlDialog.TenantIdInUrl}={aliasResolver.Alias.TenantId}&{HtmlDialog.AliasIdInUrl}={aliasResolver.Alias.AliasId}\");\n\n        string SiteRootFn() => siteRoot.IsEmpty() ? OqtPageOutput.GetSiteRoot(aliasResolver.Alias) : siteRoot;\n        string ApiRootFn() => SiteRootFn() + OqtWebApiConstants.ApiRootNoLanguage + \"/\";\n        string UiRootFn() => OqtConstants.UiRoot + \"/\";\n        string RvtFn() => rvt.IsEmpty() && http?.HttpContext != null ? antiForgery.GetAndStoreTokens(http.HttpContext).RequestToken : rvt;\n        string SecureEndpointPrimaryKeyFn() => rsaCryptographyService.PublicKey;\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/Output/OqtPageOutput.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks.Output;\n\n[PrivateApi]\ninternal partial class OqtPageOutput(\n    SiteState siteState,\n    IBlockResourceExtractor blockResourceExtractor,\n    IJsApiService jsApiService)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.AssHdr\", connect: [siteState, blockResourceExtractor, jsApiService])\n{\n    #region Constructor and DI\n\n    public void Init(IOqtSxcViewBuilder parent, IRenderResult renderResult)\n    {\n        Parent = parent;\n        RenderResult = renderResult;\n    }\n\n    protected IOqtSxcViewBuilder Parent;\n    protected IRenderResult RenderResult;\n\n    #endregion\n\n\n    private bool AddJsCore => Features.Contains(SxcPageFeatures.JsCore);\n    private bool AddJsEdit => Features.Contains(SxcPageFeatures.JsCmsInternal);\n\n\n    /// <summary>\n    /// The JavaScripts needed\n    /// </summary>\n    /// <returns></returns>\n    public IEnumerable<string> Scripts()\n    {\n        var list = new List<string>();\n\n        // v12.03, Oqtane 2.2 with Bootstrap 5 do not includes jQuery any more\n        // as Oqtane 2.1 with Bootstrap 4\n        if (Features.Contains(SxcPageFeatures.JQuery)) \n            list.Add(\"//code.jquery.com/jquery-3.5.1.min.js\");\n\n        if (AddJsCore)\n            list.Add($\"{OqtConstants.UiRoot}/{SxcPageFeatures.JsCore.UrlInDist}\");\n\n        if (AddJsEdit)\n            list.Add($\"{OqtConstants.UiRoot}/{SxcPageFeatures.JsCmsInternal.UrlInDist}\");\n\n        // New in 12.02\n        if (Features.Contains(SxcPageFeatures.TurnOn))\n            list.Add($\"{OqtConstants.UiRoot}/{SxcPageFeatures.TurnOn.UrlInDist}\");\n\n            \n        return list;\n    }\n\n    /// <summary>\n    /// The styles to add\n    /// </summary>\n    /// <returns></returns>\n    public IEnumerable<string> Styles()\n    {\n        var list = new List<string>();\n        if (Features.Contains(SxcPageFeatures.ToolbarsInternal))\n            list.Add($\"{OqtConstants.UiRoot}/{SxcPageFeatures.ToolbarsInternal.UrlInDist}\");\n\n        // New 15.01\n        if (Features.Contains(SxcPageFeatures.CmsWysiwyg))\n            list.Add($\"{OqtConstants.UiRoot}/{SxcPageFeatures.CmsWysiwyg.UrlInDist}\");\n        return list;\n    }\n\n    [PrivateApi]\n    public static string GetSiteRoot(Alias alias)\n        => alias?.Name == null ? OqtConstants.SiteRoot : new Uri($\"http://{alias.Name}/\").AbsolutePath.SuffixSlash();\n\n    internal IList<IPageFeature> Features => _features ??= RenderResult.Features ?? new List<IPageFeature>();\n    private IList<IPageFeature> _features;\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/Output/OqtPageOutput_HeadChanges.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks.Output;\n\npartial class OqtPageOutput\n{\n    public IEnumerable<OqtHeadChange> GetHeadChanges()\n    {\n        var l = Log.Fn<IEnumerable<OqtHeadChange>>();\n\n        var changes = RenderResult.HeadChanges ?? [];\n\n        var result = changes\n            .Select(p => new OqtHeadChange\n            {\n                PropertyOperation = GetOp(p.ChangeMode),\n                Tag = p.Tag.ToString(),\n                ReplacementIdentifier = p.ReplacementIdentifier,\n            });\n\n        var count = changes.Count;\n\n        return l.ReturnAndLog(result, $\"Changes: {count}\");\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/Output/OqtPageOutput_MetaContext.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys.JsContext;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks.Output;\n\n[PrivateApi]\npartial class OqtPageOutput\n{\n    /// <summary>\n    /// Determines if the context header is needed\n    /// </summary>\n    public bool AddContextMeta => AddJsCore || AddJsEdit;\n\n    /// <summary>\n    /// Will return the meta-header which the $2sxc client needs for context, page id, request verification token etc.\n    /// </summary>\n    /// <returns></returns>\n    public string ContextMetaContents()\n    {\n        var l = Log.Fn<string>();\n        var pageId = Parent?.Page.PageId ?? -1;\n        var siteRoot = GetSiteRoot(siteState.Alias);\n        var rvt = AntiForgeryToken();\n        var result = jsApiService.GetJsApiJson(pageId, siteRoot, rvt);\n        return l.ReturnAsOk(result);\n    }\n\n    /// <summary>\n    /// Empty / Fake Anti-Forgery Token \n    /// </summary>\n    /// <returns></returns>\n    /// <remarks>\n    /// 2021-05-11 the Token given by IAntiforgery is always wrong, so better keep it empty\n    /// Reason is probably that at this moment the render-request is running in another HttpContext\n    /// </remarks>\n    private string AntiForgeryToken() => \"\";\n\n    public string ContextMetaName => JsApi.MetaName;\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/Output/OqtPageOutput_PageProperties.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Shared.Models;\nusing ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks.Output;\n\npartial class OqtPageOutput\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <returns></returns>\n    /// <remarks>New in 12.02</remarks>\n    //public IEnumerable<OqtPagePropertyChanges> GetPagePropertyChanges()\n    //{\n    //    var wrapLog = Log.Call<IEnumerable<OqtPagePropertyChanges>>();\n    //    // If we get something invalid, return 0 (nothing changed)\n    //    if (!(PageServiceShared is IChangeQueue changes)) return wrapLog($\"not {nameof(IChangeQueue)}\", new OqtPagePropertyChanges[] { });\n\n    //    var props = changes.GetPropertyChangesAndFlush();\n    //    var result = GetOqtPagePropertyChangesList(props);\n\n    //    var count = props.Count;\n\n    //    return wrapLog($\"Changes: {count}\", result);\n    //}\n\n    public IEnumerable<OqtPagePropertyChanges> GetOqtPagePropertyChangesList(IList<PagePropertyChange> props)\n    {\n        var l = Log.Fn<IEnumerable<OqtPagePropertyChanges>>();\n\n        var result = new List<OqtPagePropertyChanges>();\n        foreach (var p in props)\n            switch (p.Property)\n            {\n                case PageProperties.Base:\n                    result.Add(new() { Property = OqtPageProperties.Base, Value = p.Value });\n                    break;\n                case PageProperties.Title:\n                    result.Add(new()\n                    {\n                        Property = OqtPageProperties.Title, Value = p.Value, Placeholder = p.ReplacementIdentifier,\n                        Change = GetOp(p.ChangeMode)\n                    });\n                    break;\n                case PageProperties.Description:\n                    result.Add(new()\n                    {\n                        Property = OqtPageProperties.Description, Value = p.Value, Placeholder = p.ReplacementIdentifier,\n                        Change = GetOp(p.ChangeMode)\n                    });\n                    break;\n                case PageProperties.Keywords:\n                    result.Add(new()\n                    {\n                        Property = OqtPageProperties.Keywords, Value = p.Value, Placeholder = p.ReplacementIdentifier,\n                        Change = GetOp(p.ChangeMode)\n                    });\n                    break;\n                default: // ignore\n                    break;\n            }\n\n        var count = props.Count;\n\n        return l.Return(result, $\"Changes: {count}\");\n    }\n\n    private static OqtPagePropertyOperation GetOp(PageChangeModes changeMode)\n    {\n\n        switch (changeMode)\n        {\n            // The core 3 properties default to prefix\n            case PageChangeModes.Default:\n            case PageChangeModes.Auto:\n                return OqtPagePropertyOperation.Prefix;\n            case PageChangeModes.Replace:\n                return OqtPagePropertyOperation.Replace;\n            case PageChangeModes.Append:\n                return OqtPagePropertyOperation.Suffix;\n            case PageChangeModes.Prepend:\n                return OqtPagePropertyOperation.Prefix;\n            case PageChangeModes.ReplaceOrSkip:\n                return OqtPagePropertyOperation.ReplaceOrSkip;\n            default:\n                throw new ArgumentOutOfRangeException();\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Blocks/Output/OqtPageOutput_TemplateResources.cs",
    "content": "﻿using Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared.Models;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.ClientAssets;\n\nnamespace ToSic.Sxc.Oqt.Server.Blocks.Output;\n\npartial class OqtPageOutput\n{\n    /// <summary>\n    /// The JavaScript and Style assets\n    /// from razor template and manual features\n    /// </summary>\n    /// <returns></returns>\n    public List<SxcResource> GetSxcResources()\n    {\n        // assets from razor template\n        var resources = SxcResourcesBuilder(RenderResult.Assets);\n        // assets from manual features\n        resources.AddRange(SxcResourcesBuilder(GetAssetsFromManualFeatures(RenderResult.FeaturesFromResources)));\n        return resources;\n    }\n\n    private static List<SxcResource> SxcResourcesBuilder(IList<ClientAsset> assets)\n    {\n        var resources = assets\n            .Select(a => new SxcResource\n            {\n                ResourceType = a.IsJs ? ResourceType.Script : ResourceType.Stylesheet,\n                Url = a.Url,\n                IsExternal = a.IsExternal,\n                Content = a.Content,\n                UniqueId = a.Id,\n                HtmlAttributes =\n                    a.HtmlAttributes // will copy HtmlAttributes and also try to set Integrity and CrossOrigin properties\n            })\n            .ToList();\n        return resources;\n    }\n\n    private List<ClientAsset> GetAssetsFromManualFeatures(IList<PageFeatureFromSettings> manualFeatures)\n    {\n        var assets = new List<ClientAsset>();\n        foreach (var manualFeature in manualFeatures)\n        {\n            // process manual features to get assets\n            if (manualFeature.Html == null)\n                continue; // skip if no HTML is defined\n            var result = blockResourceExtractor.Process(manualFeature.Html);\n            assets.AddRange(result.Assets);\n        }\n        return assets;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Cms/OqtPagePublishing.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Cms;\n\ninternal class OqtPagePublishing() : ServiceBase($\"{OqtConstants.OqtLogPrefix}.Publsh\"), IPagePublishing\n{\n    public void DoInsidePublishing(IContextOfSite context, Action<VersioningActionInfo> action)\n    {\n        var containerId = (context as IContextOfBlock)?.Module.Id ?? Eav.Sys.EavConstants.IdNotInitialized;\n        var userId = 0;\n        var enabled = false;\n        Log.A($\"DoInsidePublishing(module:{containerId}, user:{userId}, enabled:{enabled})\");\n        if (enabled)\n        {\n            /* ignore */\n        }\n\n        var versioningActionInfo = new VersioningActionInfo();\n        action.Invoke(versioningActionInfo);\n        Log.A(\"/DoInsidePublishing\");\n    }\n\n\n\n    public int GetLatestVersion(int instanceId) => 0;\n\n    public int GetPublishedVersion(int instanceId) => 0;\n\n\n    public void Publish(int instanceId, int version) \n        => Log.A($\"Publish(m:{instanceId}, v:{version}) - not supported in Oqtane, publish never happened \");\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Cms/OqtPagePublishingGetSettings.cs",
    "content": "﻿using ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Cms;\n\ninternal class OqtPagePublishingGetGetSettings() : PagePublishingGetSettingsBase(OqtConstants.OqtLogPrefix)\n{\n    #region Constructor / DI\n\n    #endregion\n\n\n    protected override PublishingMode LookupRequirements(int instanceId)\n        => PublishingMode.DraftOptional;\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Code/Sys/AppCodeCompilerNetCore.cs",
    "content": "﻿using ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sys.Configuration;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Code.Sys;\n\n[PrivateApi]\ninternal class AppCodeCompilerNetCore(\n    LazySvc<IServerPaths> serverPaths,\n    Generator<Compiler> compiler,\n    IGlobalConfiguration globalConfiguration,\n    SourceCodeHasher sourceCodeHasher)\n    : AppCodeCompiler(globalConfiguration, sourceCodeHasher, connect: [serverPaths, compiler, sourceCodeHasher])\n{\n\n    public override AssemblyResult GetAppCode(string virtualPath, HotBuildSpecWithSharedSuffix spec)\n    {\n        var l = Log.Fn<AssemblyResult>($\"{nameof(virtualPath)}: '{virtualPath}'; {spec}\", timer: true);\n\n        try\n        {\n            var sourceRootPath = NormalizeFullPath(serverPaths.Value.FullContentPath(virtualPath.Backslash()));\n            var sourceFiles = GetSourceFiles(sourceRootPath);\n            if (sourceFiles.Length == 0)\n                return l.ReturnAsOk(new());\n\n            var (symbolsPath, assemblyPath) = GetAssemblyLocations(spec, sourceRootPath);\n            var dllName = Path.GetFileName(assemblyPath);\n\n            var result = LockAppCodeAssemblyProvider.Call(\n                conditionToGenerate: () => ShouldGenerate(assemblyPath),\n                generator: () => compiler.New().GetCompiledAssemblyFromFolder(sourceFiles, assemblyPath, symbolsPath, dllName, spec, sourceRootPath),\n                cacheOrFallback: () => new AssemblyResult(assembly: new SimpleUnloadableAssemblyLoadContext().LoadFromAssemblyPath(assemblyPath))\n            );\n\n            var assemblyResult = result.Result;\n\n            var dicInfos = new Dictionary<string, string>\n            {\n                [\"DllName\"] = dllName,\n                [\"Files\"] = sourceFiles.Length.ToString(),\n                [\"Errors\"] = assemblyResult.ErrorMessages?.Length.ToString(),\n                [\"Assembly\"] = assemblyResult.Assembly?.FullName ?? \"null\",\n                [\"AssemblyPath\"] = assemblyPath,\n                [\"SymbolsPath\"] = symbolsPath,\n            };\n\n            // Success\n            if (assemblyResult.ErrorMessages.IsEmpty())\n            {\n                LogAllTypes(assemblyResult.Assembly);\n                return l.ReturnAsOk(new(assemblyResult.Assembly)\n                {\n                    AssemblyLocations = [symbolsPath, assemblyPath],\n                    Infos = dicInfos,\n                });\n            }\n\n            // Errors and warnings\n            return l.ReturnAsError(new()\n            {\n                ErrorMessages = assemblyResult.ErrorMessages,\n                Infos = dicInfos,\n            }, assemblyResult.ErrorMessages);\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            var errorMessage = $\"Error: Can't compile '{AppCodeDll}' in {Path.GetFileName(virtualPath)}. Details are logged into insights. {ex.Message}\";\n            return l.ReturnAsError(new() { ErrorMessages = errorMessage, });\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Code/Sys/CodeCompilerNetCore.cs",
    "content": "﻿using ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Code.Sys;\n\n[PrivateApi]\ninternal class CodeCompilerNetCore(\n    IServiceProvider serviceProvider,\n    LazySvc<IServerPaths> serverPaths,\n    Generator<Compiler> compiler)\n    : CodeCompiler(serviceProvider, connect: [serverPaths, compiler])\n{\n    protected override (Type Type, string ErrorMessage) GetCsHtmlType(string virtualPath)\n        => throw new(\"Runtime Compile of .cshtml is Not Implemented in .net standard / core\");\n\n    public override AssemblyResult GetAssembly(string virtualPath, string className, HotBuildSpec spec)\n    {\n        var l = Log.Fn<AssemblyResult>(\n            $\"{nameof(virtualPath)}: '{virtualPath}'; {nameof(className)}: '{className}'; {spec}\", timer: true);\n        var fullContentPath = serverPaths.Value.FullContentPath(virtualPath.Backslash());\n        var fullPath = NormalizeFullFilePath(fullContentPath);\n        l.A($\"New paths: '{fullContentPath}', '{fullPath}'\");\n        try\n        {\n            return l.ReturnAsOk(compiler.New().Compile(fullPath, className, spec));\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            var errorMessage =\n                $\"Error: Can't compile '{className}' in {Path.GetFileName(virtualPath)}. Details are logged into insights. \" +\n                ex.Message;\n            return l.ReturnAsError(new() { ErrorMessages = errorMessage, }, \"error\");\n        }\n    }\n\n    /// <summary>\n    /// Normalize full file path, so it is without redirections like \"../\" in \"dir1/dir2/../file.cs\"\n    /// </summary>\n    /// <param name=\"fullPath\"></param>\n    /// <returns></returns>\n    private static string NormalizeFullFilePath(string fullPath) => new FileInfo(fullPath).FullName;\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Code/Sys/Compiler.cs",
    "content": "using System.Runtime.CompilerServices;\nusing System.Text;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Emit;\nusing Microsoft.CodeAnalysis.Text;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Razor;\n\nnamespace ToSic.Sxc.Oqt.Server.Code.Sys\n{\n\n    // Code is based on DynamicRun by Laurent Kempé\n    // https://github.com/laurentkempe/DynamicRun\n    // https://laurentkempe.com/2019/02/18/dynamically-compile-and-run-code-using-dotNET-Core-3.0/\n    internal class Compiler(LazySvc<AppCodeLoader> appCodeLoader, HotBuildReferenceManager referenceManager)\n        : ServiceBase(\"Sys.CodCpl\", connect: [appCodeLoader, referenceManager])\n    {\n        // Ensure that can't be kept alive by stack slot references (real- or JIT-introduced locals).\n        // That could keep the SimpleUnloadableAssemblyLoadContext alive and prevent the unload.\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        internal AssemblyResult Compile(string sourceFile, string dllName, HotBuildSpec spec)\n        {\n            var l = Log.Fn<AssemblyResult>($\"Starting compilation of: '{sourceFile}'; {nameof(dllName)}: '{dllName}'; {spec}'.\");\n\n            var (assemblyResult, _) = appCodeLoader.Value.GetAppCode(spec);\n\n            var encoding = Encoding.UTF8;\n\n            var options = CSharpParseOptions.Default\n                .WithLanguageVersion(OqtRoslynConstants.LanguageVersion)\n                .WithPreprocessorSymbols(OqtRoslynConstants.PreprocessorSymbols);\n\n            var syntaxTrees = new List<SyntaxTree>();\n            var embeddedTexts = new List<EmbeddedText>();\n\n            var sourceCode = File.ReadAllText(sourceFile);\n            syntaxTrees.Add(SyntaxFactory.ParseSyntaxTree(sourceCode, options));\n            embeddedTexts.Add(EmbeddedText.FromSource(sourceFile, SourceText.From(sourceCode, encoding)));\n\n            var assemblyName = dllName.EndsWith(\".dll\", StringComparison.OrdinalIgnoreCase) ? dllName.Substring(0, dllName.Length - 4) : dllName;\n\n            var compilation = CSharpCompilation.Create(\n                $\"{assemblyName}.dll\",\n                syntaxTrees,\n                references: referenceManager.GetMetadataReferences(assemblyResult?.Assembly?.Location, spec, sourceFile),\n                options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,\n                    optimizationLevel: OptimizationLevel.Debug,\n                    assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default));\n\n            var assemblyLoadContext = new SimpleUnloadableAssemblyLoadContext();\n\n            // Compile to in-memory streams\n            using var peStream = new MemoryStream();\n            using var pdbStream = new MemoryStream();\n            var result = compilation.Emit(peStream, pdbStream, embeddedTexts: embeddedTexts,\n                options: new EmitOptions(\n                    debugInformationFormat: DebugInformationFormat.PortablePdb,\n                    pdbFilePath: $\"{assemblyName}.pdb\"));\n\n            if (!result.Success)\n            {\n                l.E(\"Compilation done with error.\");\n\n                var errors = new List<string>();\n\n                var failures = result.Diagnostics.Where(diagnostic =>\n                    diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error);\n\n                foreach (var diagnostic in failures)\n                {\n                    // ReSharper disable once ExplicitCallerInfoArgument\n                    l.A(\"{0}: {1}\", diagnostic.Id, diagnostic.GetMessage());\n                    errors.Add($\"{diagnostic.Id}: {diagnostic.GetMessage()}\");\n                }\n\n                //throw l.Done(new InvalidOperationException(string.Join(\"\\n\", errors)));\n                return l.ReturnAsError(new() { ErrorMessages = string.Join(\"\\n\", errors), });\n            }\n\n            peStream.Seek(0, SeekOrigin.Begin);\n            pdbStream.Seek(0, SeekOrigin.Begin);\n\n            var assembly = assemblyLoadContext.LoadFromStream(peStream, pdbStream);\n\n            return l.ReturnAsOk(new(assembly));\n        }\n\n        // Ensure that can't be kept alive by stack slot references (real- or JIT-introduced locals).\n        // That could keep the SimpleUnloadableAssemblyLoadContext alive and prevent an unload.\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        internal AssemblyResult GetCompiledAssemblyFromFolder(string[] sourceFiles, string assemblyFilePath, string pdbFilePath, string dllName, HotBuildSpec spec, string sourceRootPath)\n        {\n            var l = Log.Fn<AssemblyResult>($\"{nameof(sourceFiles)}: {sourceFiles.Length}; {nameof(assemblyFilePath)}: '{assemblyFilePath}'\", timer: true);\n\n            var encoding = Encoding.UTF8;\n\n            var options = CSharpParseOptions.Default\n                .WithLanguageVersion(OqtRoslynConstants.LanguageVersion)\n                .WithPreprocessorSymbols(OqtRoslynConstants.PreprocessorSymbols);\n\n            var syntaxTrees = new List<SyntaxTree>();\n            var embeddedTexts = new List<EmbeddedText>();\n\n            foreach (var sourceFile in sourceFiles)\n            {\n                var sourceCode = File.ReadAllText(sourceFile);\n                syntaxTrees.Add(SyntaxFactory.ParseSyntaxTree(sourceCode, options));\n                embeddedTexts.Add(EmbeddedText.FromSource(sourceFile, SourceText.From(sourceCode, encoding)));\n            }\n\n            var compilation = CSharpCompilation.Create(\n                dllName,\n                syntaxTrees,\n                references: referenceManager.GetMetadataReferences(assemblyFilePath, spec, sourceRootPath),\n                options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,\n                    optimizationLevel: OptimizationLevel.Debug,\n                    assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default));\n\n            var assemblyLoadContext = new SimpleUnloadableAssemblyLoadContext();\n\n            try\n            {\n                using var peStream = new MemoryStream();\n                using var pdbStream = new MemoryStream();\n                var result = compilation.Emit(peStream, pdbStream, embeddedTexts: embeddedTexts,\n                    options: new EmitOptions(\n                        debugInformationFormat: DebugInformationFormat.PortablePdb,\n                        pdbFilePath: pdbFilePath));\n\n                if (!result.Success)\n                {\n                    l.E(\"Compilation done with error.\");\n\n                    var errors = new List<string>();\n\n                    var failures = result.Diagnostics.Where(diagnostic =>\n                        diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error);\n\n                    foreach (var diagnostic in failures)\n                    {\n                        // ReSharper disable once ExplicitCallerInfoArgument\n                        l.A(\"{0}: {1}\", diagnostic.Id, diagnostic.GetMessage());\n                        errors.Add($\"{diagnostic.Id}: {diagnostic.GetMessage()}\");\n                    }\n\n                    //throw l.Done(new IOException(string.Join(\"\\n\", errors)));\n                    return l.ReturnAsError(new() { ErrorMessages = string.Join(\"\\n\", errors), });\n                }\n\n                // Create file streams to save the compiled assembly and PDB to disk\n                peStream.Seek(0, SeekOrigin.Begin);\n                pdbStream.Seek(0, SeekOrigin.Begin);\n\n                using (var peFileStream = new FileStream(assemblyFilePath, FileMode.Create, FileAccess.Write))\n                    peStream.CopyTo(peFileStream);\n\n                using (var pdbFileStream = new FileStream(pdbFilePath, FileMode.Create, FileAccess.Write)) \n                    pdbStream.CopyTo(pdbFileStream);\n\n                var assembly = assemblyLoadContext.LoadFromAssemblyPath(assemblyFilePath);\n\n\n                return l.ReturnAsOk(new(assembly));\n            }\n            catch (Exception ex)\n            {\n                l.E($\"Exception during compilation: {ex.Message}\");\n                return l.ReturnAsError(new() { ErrorMessages = ex.Message, });\n            }\n            finally\n            {\n                // Ensure that can't be kept alive.\n                if (assemblyLoadContext.IsCollectible)\n                    assemblyLoadContext.Unload();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Code/Sys/OqtRoslynConstants.cs",
    "content": "﻿using Microsoft.CodeAnalysis.CSharp;\nusing System.Collections.Immutable;\nusing ToSic.Sxc.Code.Sys.HotBuild;\n\nnamespace ToSic.Sxc.Oqt.Server.Code.Sys;\n\n/// <summary>\n/// Contains constants and settings for Roslyn compilation in the Oqtane context.\n/// These settings define the language version and preprocessor symbols used during compilation.\n/// </summary>\ninternal class OqtRoslynConstants\n{\n    /// <summary>\n    /// Specifies the C# language version to use during Roslyn compilation.\n    /// The \"Preview\" version allows the use of the latest language features.\n    /// </summary>\n    public static readonly LanguageVersion LanguageVersion = Enum.TryParse<LanguageVersion>(RoslynConstants.LanguageVersion, out var languageVersion) ? languageVersion : LanguageVersion.Preview;\n\n    /// <summary>\n    /// Defines the preprocessor symbols to be used during compilation.\n    /// These symbols allow conditional compilation for different build configurations and platforms.\n    /// Examples:\n    /// - NETCOREAPP: Indicates targeting .NET Core or .NET 5+, used for Oqtane.\n    /// </summary>\n    public static ImmutableArray<string> PreprocessorSymbols = [\"NETCOREAPP\"];\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Code/Sys/SimpleUnloadableAssemblyLoadContext.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.Loader;\n\nnamespace ToSic.Sxc.Oqt.Server.Code.Sys\n{\n\n    // Create a collectible AssemblyLoadContext\n    // https://docs.microsoft.com/en-us/dotnet/standard/assembly/unloadability#create-a-collectible-assemblyloadcontext\n    public class SimpleUnloadableAssemblyLoadContext : AssemblyLoadContext\n    {\n        public SimpleUnloadableAssemblyLoadContext() : base(/* true */)\n        {\n        }\n\n        protected override Assembly Load(AssemblyName assemblyName)\n        {\n            return null; // That means that all the dependency assemblies are loaded into the default context, and the new context contains only the assemblies explicitly loaded into it.\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Configuration/OqtGlobalConfiguration.cs",
    "content": "using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sys.Configuration;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Configuration;\n\n/// <summary>\n/// Oqtane-specific GlobalConfiguration which resolves ConnectionString dynamically per-request/tenant.\n/// For all other configuration values it falls back to the base GlobalConfiguration storage.\n/// </summary>\ninternal class OqtGlobalConfiguration(IHttpContextAccessor httpContextAccessor) : GlobalConfiguration, IGlobalConfiguration\n{\n    private const string KeyConnectionString = nameof(GlobalConfigDb.ConnectionString);\n\n    public new string GetThis(string key)\n    {\n        // Only special-case the ConnectionString; everything else defer to base implementation\n        if (key.HasValue() && key.EqualsInsensitive(KeyConnectionString))\n        {\n            // Only attempt tenant-based resolution when a request/tenant scope exists.\n            var cs = TryResolveTenantConnectionString();\n            if (cs.HasValue())\n                return cs;\n        }\n        return base.GetThis(key);\n    }\n\n    public new string GetThisOrSet(Func<string> generator, string key)\n    {\n        // Delegate to the interface GetThis which we override for ConnectionString\n        var current = GetThis(key);\n        if (current.HasValue())\n            return current!;\n\n        var value = generator();\n        SetThis(value, key);\n        return value;\n    }\n\n    public new string GetThisErrorOnNull(string key)\n    {\n        var value = GetThis(key);\n        return value ?? throw new ArgumentNullException(ErrorMessageNullNotAllowed(nameof(key)));\n    }\n\n    public new string SetThis(string value, string key)\n        // For ConnectionString we still allow setting a default/fallback value (eg. during boot),\n        // but per-request access will prefer the dynamic tenant value when available.\n        => base.SetThis(value, key);\n\n    private string TryResolveTenantConnectionString()\n    {\n        // Only resolve tenant when a request scope is present; otherwise use the base/fallback value.\n        var requestServices = httpContextAccessor?.HttpContext?.RequestServices;\n        if (requestServices == null)\n            return null;\n\n        var ctx = requestServices.GetService<IOqtTenantContext>()?.Get();\n        return ctx is { } info && info.ConnectionString.HasValue()\n            ? info.ConnectionString\n            : null;\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/IOqtTenantContext.cs",
    "content": "namespace ToSic.Sxc.Oqt.Server.Context;\n\ninternal interface IOqtTenantContext\n{\n    OqtTenantContextInfo? Get();\n\n    OqtTenantContextInfo GetRequired();\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtContextOfBlockExtensions.cs",
    "content": "﻿using Oqtane.Models;\nusing ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\ninternal static class OqtContextOfBlockExtensions\n{\n    public static IContextOfBlock Init(this IContextOfBlock context, int pageId, Module oqtModule)\n    {\n        ((OqtPage)context.Page).Init(pageId);\n        ((OqtModule)context.Module).Init(oqtModule);\n        return context;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtCulture.cs",
    "content": "﻿using System.Globalization;\nusing Oqtane.Infrastructure;\nusing Oqtane.Repository;\nusing ToSic.Eav.Context.Sys;\nusing ToSic.Eav.Data.Sys.Dimensions;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\n/// <summary>\n/// Manage oqtane site culture info\n/// </summary>\ninternal class OqtCulture(\n    LazySvc<ILocalizationManager> localizationManager,\n    LazySvc<ILanguageRepository> languageRepository)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.Cultur\", connect: [localizationManager, languageRepository])\n{\n    const string FallbackLanguageCode = \"en-us\";\n\n    /// <inheritdoc />\n    public string DefaultCultureCode => MapTwoLetterCulture(localizationManager.Value.GetDefaultCulture().ToLowerInvariant()) ?? FallbackLanguageCode;\n\n    // When culture code is not provided for selected default language, use defaultLanguageCode.\n    public string DefaultLanguageCode(int siteId)\n    {\n        return (languageRepository.Value.GetLanguages(siteId).FirstOrDefault(l => l.IsDefault)?.Code ?? FallbackLanguageCode).ToLowerInvariant();\n    }\n\n    public string CurrentCultureCode => MapTwoLetterCulture(CultureInfo.CurrentCulture.Name).ToLowerInvariant();\n\n    public List<ISiteLanguageState> GetSupportedCultures(int siteId, List<DimensionDefinition>  availableEavLanguages)\n    {\n        var cultures = new List<string>([DefaultCultureCode]);\n        cultures.AddRange(languageRepository.Value.GetLanguages(siteId).Select(language => MapTwoLetterCulture(language.Code)));\n\n        // List of localizations enabled in Oqtane site.\n        var siteCultures = cultures\n            .Select(CultureInfo.GetCultureInfo)\n            .Select(c => new SiteLanguageState(\n                c.Name.ToLowerInvariant(), \n                c.EnglishName, \n                availableEavLanguages.Any(a => a.Active && a.Matches(c.Name))\n            ))\n            .ToList();\n            \n        return siteCultures\n            .OrderByDescending(c => c.Code == DefaultLanguageCode(siteId))\n            .Cast<ISiteLanguageState>()\n            .ToList();\n    }\n\n    public static void SetCulture(string culture)\n    {\n        var cultureInfo = CultureInfo.GetCultureInfo(MapTwoLetterCulture(culture));\n        CultureInfo.DefaultThreadCurrentCulture = cultureInfo;\n        CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;\n    }\n\n    public static string MapTwoLetterCulture(string culture)\n    {\n        if (string.IsNullOrEmpty(culture)) return FallbackLanguageCode;\n\n        if (culture.Length > 3) return culture;\n\n        // 1. For \"en\" return \"en-us\".\n        if (culture.ToLowerInvariant() == \"en\") return FallbackLanguageCode;\n\n        // 2. For other cultures first find is there simple de-de culture\n        var simpleLanguageCode = CultureInfo.GetCultures(CultureTypes.AllCultures)\n            .FirstOrDefault(c => c.Name.ToLowerInvariant() == $\"{culture}-{culture}\");\n\n        if (simpleLanguageCode != null) return simpleLanguageCode.Name.ToLowerInvariant();\n\n        // 3. If not, find first in list and return\n        var firstLanguageCode = CultureInfo.GetCultures(CultureTypes.AllCultures)\n            .OrderBy(c => c.Name)\n            .FirstOrDefault(c => c.TwoLetterISOLanguageName.ToLowerInvariant() == culture \n                                 && c.IsNeutralCulture == false);\n\n        if (firstLanguageCode != null) return firstLanguageCode.Name.ToLowerInvariant();\n\n        // 4. Fallback\n        return FallbackLanguageCode;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtModule.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys.Module;\nusing ToSic.Sxc.Oqt.Server.Integration;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\ninternal class OqtModule(\n    SettingsHelper settingsHelper,\n    IModuleRepository moduleRepository,\n    IAppsCatalog appsCatalog,\n    LazySvc<AppFinder> appFinderLazy,\n    ISite site)\n    : Module<Module>($\"{OqtConstants.OqtLogPrefix}.Cont\",\n        connect: [settingsHelper, moduleRepository, appsCatalog, appFinderLazy, site])\n{\n    private Dictionary<string, string> _settings;\n\n    public new OqtModule Init(Module module)\n    {\n        base.Init(module);\n        var l = Log.Fn<OqtModule>($\"id:{module.ModuleId}\", timer: true);\n\n        InitializeIsPrimary(module);\n\n        _settings = settingsHelper.Init(EntityNames.Module, module.ModuleId).Settings;\n\n        _id = module.ModuleId;\n\n        return l.ReturnAsOk(this);\n    }\n\n    /// <summary>\n    /// Need module definition to get module name to check is PrimaryApp.\n    /// </summary>\n    /// <param name=\"module\"></param>\n    private void InitializeIsPrimary(Module module)\n    {\n        if (module == null) return;\n        // note that it's \"ToSic.Sxc.Oqt.App, ToSic.Sxc.Oqtane.Client\" or \"ToSic.Sxc.Oqt.Content, ToSic.Sxc.Oqtane.Client\"\n        _isContent = module.ModuleDefinitionName.Contains(\".Content\");\n    }\n\n    // Temp implementation, don't support im MVC\n    public override IModule Init(int id)\n    {\n        var module = moduleRepository.GetModule(id);\n        return Init(module);\n    }\n\n    /// <inheritdoc />\n    public override int Id => _id;\n    private int _id;\n\n    /// <inheritdoc />\n    public override bool IsContent => _isContent;\n    private bool _isContent = true;\n\n    public override IBlockIdentifier BlockIdentifier\n    {\n        get\n        {\n            if (_blockIdentifier != null)\n                return _blockIdentifier;\n\n            // find ZoneId, AppId and prepare settings for next values\n            var zoneId = site.ZoneId; // ZoneMapper.GetZoneId(UnwrappedContents.SiteId);\n            var (appId, appNameId) = GetInstanceAppId(zoneId); //appId ?? TestIds.Blog.App;\n            var block = Guid.Empty;\n            if (_settings.ContainsKey(ModuleSettingNames.ContentGroup))\n                Guid.TryParse(_settings[ModuleSettingNames.ContentGroup], out block);\n\n            // Check if we have preview-view identifier - for blocks which don't exist yet\n            var overrideView = new Guid();\n            if (_settings.TryGetValue(ModuleSettingNames.PreviewView, out var previewId) && !string.IsNullOrEmpty(previewId))\n                Guid.TryParse(previewId, out overrideView);\n\n            _blockIdentifier = new BlockIdentifier(zoneId, appId, appNameId, block, overrideView);\n\n            return _blockIdentifier;\n        }\n    }\n\n    private IBlockIdentifier _blockIdentifier;\n\n\n    private (int AppId, string AppNameId) GetInstanceAppId(int zoneId)\n    {\n        var l = Log.Fn<(int, string)>($\"{zoneId}\", timer: true);\n\n        if (IsContent) \n            return l.Return((appsCatalog.DefaultAppIdentity(zoneId).AppId, \"Content\"), \"Content\");\n\n        if (!_settings.TryGetValue(ModuleSettingNames.AppName, out var setting)) \n            return l.Return((KnownAppsConstants.AppIdEmpty, KnownAppsConstants.AppNameIdEmpty), KnownAppsConstants.AppNameIdEmpty);\n\n        var guid = setting ?? \"\";\n        var appId = appFinderLazy.Value.FindAppId(zoneId, guid);\n        return l.ReturnAsOk((appId, guid));\n\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtPage.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sxc.Web.Sys.Http;\nusing ToSic.Sxc.Web.Sys.Parameters;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\nusing Page_Page = ToSic.Sxc.Context.Sys.Page.Page;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\ninternal class OqtPage(\n    LazySvc<IHttp> httpBlazor,\n    SiteState siteState,\n    LazySvc<AliasResolver> aliasResolver,\n    LazySvc<IPageRepository> pages,\n    LazySvc<ILinkPaths> linkPathsLazy)\n    : Page_Page(httpBlazor), IWrapper<Oqtane.Models.Page>\n{\n    // ReSharper disable once InconsistentNaming\n    private readonly LazySvc<IHttp> httpBlazor = httpBlazor;\n\n    public Alias Alias { get; set; }\n\n    protected Oqtane.Models.Page UnwrappedPage;\n    public Oqtane.Models.Page GetContents() => UnwrappedPage;\n    public new OqtPage Init(int id)\n    {\n        base.Init(id);\n\n        UnwrappedPage = pages.Value.GetPage(id);\n\n        Url = GetUrl(GetAlias(UnwrappedPage.SiteId));\n        return this;\n    }\n\n    private ILinkPaths LinkPaths => linkPathsLazy.Value;\n\n    public string GetUrl(Alias alias)\n    {\n        // Page url in Oqtane is without protocol, so we need to add it from current request for consistency\n        // also without trailing slash\n        var parts = new UrlParts(LinkPaths.GetCurrentRequestUrl());\n        return $\"{parts.Protocol}{alias.Name}/{UnwrappedPage.Path}\".TrimLastSlash();\n    }\n\n    private Alias GetAlias(int siteId)\n    {\n        Alias ??= siteState.Alias;\n        if (Alias != null && Alias.SiteId == siteId) return Alias;\n        if (aliasResolver.Value.InitIfEmpty(siteId)) Alias = aliasResolver.Value.Alias;\n        return Alias;\n    }\n\n    // caching is disabled because in Blazor Interactive the query string parameters are changed after the page is created\n    public override IParameters Parameters => new Parameters\n    {\n        Nvc = OriginalParameters.GetOverrideParams(httpBlazor.Value?.QueryStringParams)\n    };\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtPlatformContext.cs",
    "content": "﻿using Oqtane.Infrastructure;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys.Platform;\nusing ToSic.Sys.Capabilities.Platform;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\ninternal class OqtPlatformContext(LazySvc<IConfigManager> configManager) : Platform, IPlatformInfo\n{\n    public override PlatformType Type => PlatformType.Oqtane;\n\n    public override Version Version => new(Oqtane.Shared.Constants.Version);\n\n    string IPlatformInfo.Identity => configManager.Value.GetInstallationId();\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtRuntimeKeyService.cs",
    "content": "using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\ninternal sealed class OqtRuntimeKeyService(IHttpContextAccessor httpContextAccessor) : IRuntimeKeyService\n{\n    public string AppRuntimeKey(IAppIdentity appIdentity)\n    {\n        if (appIdentity.AppId == KnownAppsConstants.PresetAppId\n            || appIdentity.AppId == KnownAppsConstants.GlobalPresetAppId)\n            return $\"t{KnownAppsConstants.PresetTenantId:D2}-z{KnownAppsConstants.PresetZoneId:D3}-a{appIdentity.AppId:D5}\";\n\n        var tenantId = GetTenantIdOrThrow();\n        return $\"t{tenantId:D2}-z{appIdentity.ZoneId:D3}-a{appIdentity.AppId:D5}\"; // app runtime identifier\n    }\n\n    private int GetTenantIdOrThrow()\n    {\n        var requestServices = httpContextAccessor?.HttpContext?.RequestServices;\n        var context = requestServices?.GetService<IOqtTenantContext>()?.Get();\n        return context?.TenantId\n               ?? throw new InvalidOperationException(\"Tenant not found\");\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtSite.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Services;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.Site;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Server.WebApi;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing OqtPageOutput = ToSic.Sxc.Oqt.Server.Blocks.Output.OqtPageOutput;\nusing UrlParts = ToSic.Sxc.Web.Sys.Url.UrlParts;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\n/// <summary>\n/// This is a Mvc implementation of a Tenant-object.\n/// </summary>\n[PrivateApi]\ninternal sealed class OqtSite(\n    AliasResolver aliasResolver,\n    LazySvc<ISiteService> siteService,\n    LazySvc<IServerPaths> serverPaths,\n    LazySvc<IZoneMapper> zoneMapper,\n    LazySvc<OqtCulture> oqtCulture,\n    LazySvc<ILinkPaths> linkPathsLazy)\n    : Site<Site>(OqtConstants.OqtLogPrefix,\n        connect: [aliasResolver, siteService, serverPaths, zoneMapper, oqtCulture, linkPathsLazy])\n{\n    private ILinkPaths LinkPaths => linkPathsLazy.Value;\n\n\n    public OqtSite Init(Site site)\n    {\n        UnwrappedSite = site;\n        return this;\n    }\n\n    public override ISite Init(int siteId, ILog? parentLogOrNull)\n    {\n        UnwrappedSite = siteService.Value.GetSiteAsync(siteId).GetAwaiter().GetResult();\n        return this;\n    }\n\n    protected override Site UnwrappedSite => base.UnwrappedSite ??= siteService.Value.GetSiteAsync(Alias.SiteId).GetAwaiter().GetResult();\n    private Alias Alias => aliasResolver.Alias;\n    public override Site GetContents() => UnwrappedSite;\n\n    /// <inheritdoc />\n    public override string DefaultCultureCode => field ??= oqtCulture.Value.DefaultCultureCode;\n\n    public string DefaultLanguageCode => field ??= oqtCulture.Value.DefaultLanguageCode(Alias.SiteId).ToLowerInvariant();\n\n    /// <inheritdoc />\n    public override string CurrentCultureCode => field ??= oqtCulture.Value.CurrentCultureCode.ToLowerInvariant();\n\n    /// <inheritdoc />\n    public override int Id => UnwrappedSite.SiteId;\n\n    public override string Url\n    {\n        get\n        {\n            if (field != null) return field;\n            // Site Alias in Oqtane is without protocol, so we need to add it from current request for consistency\n            // also without trailing slash\n            var parts = new UrlParts(LinkPaths.GetCurrentRequestUrl());\n            field = $\"{parts.Protocol}{Alias.Name}\";\n            return field;\n        }\n    }\n\n    public override string UrlRoot => Alias.Name;\n\n    /// <inheritdoc />\n    public override string Name => UnwrappedSite.Name;\n\n    [PrivateApi]\n    public override string AppsRootPhysical\n        => string.Format(OqtConstants.AppRootTenantSiteBase, Alias.TenantId, Id);\n\n    [PrivateApi]\n    public override string AppAssetsLinkTemplate => OqtPageOutput.GetSiteRoot(aliasResolver.Alias)\n                                                    + OqtWebApiConstants.AppRootNoLanguage + \"/\" + AppConstants.AppFolderPlaceholder + \"/assets\";\n\n    [PrivateApi] public override string AppsRootPhysicalFull => serverPaths.Value.FullAppPath(AppsRootPhysical);\n\n\n    /// <inheritdoc />\n    public override string ContentPath => string.Format(OqtConstants.ContentRootPublicBase, Alias.TenantId, Id);\n\n    public override int ZoneId\n    {\n        get\n        {\n            if (_zoneId != null) return _zoneId.Value;\n            // check if id is negative; 0 is a valid tenant id\n            if (Id < 0) return (_zoneId = Eav.Sys.EavConstants.NullId).Value;\n            _zoneId = zoneMapper.Value.GetZoneId(Id);\n            return _zoneId.Value;\n        }\n    }\n    private int? _zoneId;\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtTenantContext.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Oqtane.Infrastructure;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\n\ninternal class OqtTenantContext(\n    ITenantManager tenantManager,\n    IConfiguration configuration)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.TenCtx\", connect: [tenantManager]), IOqtTenantContext\n{\n    public OqtTenantContextInfo? Get()\n    {\n        var l = Log.Fn<OqtTenantContextInfo?>();\n\n        var alias = tenantManager.GetAlias();\n        if (alias == null)\n            return l.ReturnNull(\"alias not resolved\");\n\n        var tenant = tenantManager.GetTenant();\n        if (tenant == null)\n            return l.ReturnNull(\"tenant not resolved\");\n\n        var tenantConnection = tenant.DBConnectionString;\n        var connectionString = ResolveConnectionString(tenantConnection);\n        if (!connectionString.HasValue())\n            return l.ReturnNull(\"connection string missing\");\n\n        var context = new OqtTenantContextInfo(\n            TenantId: tenant.TenantId,\n            SiteId: alias.SiteId,\n            ConnectionStringName: tenantConnection.HasValue() && !tenantConnection.Contains('=')\n                ? tenantConnection\n                : \"\",\n            ConnectionString: connectionString\n        );\n\n        return l.Return(context, $\"tenant:{tenant.TenantId}, site:{alias.SiteId}\");\n    }\n\n    public OqtTenantContextInfo GetRequired()\n        => Get() ?? throw new InvalidOperationException(\"Unable to resolve Oqtane tenant context for the current execution scope.\");\n\n    private string ResolveConnectionString(string keyOrValue)\n    {\n        if (keyOrValue.IsEmpty())\n            return null;\n\n        if (keyOrValue.Contains('='))\n            return keyOrValue;\n\n        var connection = configuration.GetConnectionString(keyOrValue);\n        return connection.HasValue()\n            ? connection\n            : null;\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtTenantContextInfo.cs",
    "content": "namespace ToSic.Sxc.Oqt.Server.Context;\n\ninternal readonly record struct OqtTenantContextInfo(\n    int TenantId,\n    int SiteId,\n    string ConnectionStringName,\n    string ConnectionString\n    );\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Context/OqtUser.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing System.Security.Claims;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Oqt.Server.Context;\n\ninternal class OqtUser(\n    LazySvc<IUserRepository> userRepository,\n    LazySvc<OqtSecurity> oqtSecurity,\n    IHttpContextAccessor httpContextAccessor,\n    SiteState siteState)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.User\",\n        connect: [userRepository, oqtSecurity, httpContextAccessor, siteState]), IUser<User>\n{\n    protected User UnwrappedUser => _unwrappedUser.Get(GetUser);\n    private readonly GetOnce<User> _unwrappedUser = new();\n    public User GetContents() => UnwrappedUser;\n\n    private User GetUser()\n    {\n        var identity = GetUserFromIdentity();\n        if (identity.UserId == -1) return identity;\n        var user = userRepository.Value.GetUser(identity.UserId);\n        user.Roles = identity.Roles;\n        // siteId is not user info, but comes from env\n        user.SiteId = siteState?.Alias?.SiteId ?? identity.SiteId;\n        return user;\n    }\n\n    public int Id => oqtSecurity.Value.Id(UnwrappedUser);\n\n    public string Username => oqtSecurity.Value.Username(UnwrappedUser);\n\n    public string Name => oqtSecurity.Value.Name(UnwrappedUser);\n\n    public string Email => oqtSecurity.Value.Email(UnwrappedUser);\n\n    public string IdentityToken => oqtSecurity.Value.UserIdentityToken(UnwrappedUser);\n\n    public Guid Guid { get; private set; }\n\n    public List<int> Roles => _roles.Get(() => oqtSecurity.Value.Roles(UnwrappedUser));\n    private readonly GetOnce<List<int>> _roles = new();\n\n    public bool IsSystemAdmin => _isSystemAdmin.Get(() => oqtSecurity.Value.IsSystemAdmin(UnwrappedUser));\n    private readonly GetOnce<bool> _isSystemAdmin = new();\n\n    public bool IsSiteAdmin => _isSiteAdmin.Get(() => oqtSecurity.Value.IsSiteAdmin(UnwrappedUser));\n    private readonly GetOnce<bool> _isSiteAdmin = new();\n\n    public bool IsContentAdmin => IsSiteAdmin;\n\n    public bool IsContentEditor => IsSiteAdmin;\n\n    public bool IsSiteDeveloper => IsSystemAdmin;\n\n    #region New Permission properties for v12\n\n    ///// <inheritdoc />\n    //// This is a hopefully clearer implementation of what the user can do\n    //public bool IsSiteAdmin => IsAdmin;\n\n    ///// <inheritdoc />\n    //// This is a hopefully clearer implementation of what the user can do\n    //public bool IsSiteDeveloper => IsDesigner;\n\n    ///// <inheritdoc />\n    //// This is a hopefully clearer implementation of what the user can do\n    //public bool IsSystemAdmin => IsSuperUser;\n\n    #endregion\n\n    public bool IsAnonymous => oqtSecurity.Value.IsAnonymous(UnwrappedUser);\n\n\n    #region Private methods\n\n    public User GetUserFromIdentity()\n    {\n        var user = new User\n        {\n            IsAuthenticated = false, \n            Username = string.Empty, \n            UserId = -1, \n            Roles = string.Empty\n        };\n\n        // missing identity from http context\n        if (httpContextAccessor?.HttpContext?.User?.Identity == null) return user;\n\n        // user not auth\n        user.IsAuthenticated = httpContextAccessor.HttpContext.User.Identity.IsAuthenticated;\n        if (user.IsAuthenticated == false) return user;\n\n        user.Username = httpContextAccessor.HttpContext.User.Identity.Name;\n        user.UserId = UserIdFromClaims();\n        user.Roles = UserRolesFromClaims();\n\n        Guid = UserGuidFromIdentity();\n        return user;\n    }\n\n    private int UserIdFromClaims() \n        => int.Parse(httpContextAccessor.HttpContext!.User.Claims.First(item => item.Type is ClaimTypes.NameIdentifier or ClaimTypes.PrimarySid).Value);\n\n    private string UserRolesFromClaims()\n    {\n        var roles = httpContextAccessor.HttpContext!.User.Claims.Where(item => item.Type == ClaimTypes.Role)\n            .Aggregate(\"\", (current, claim) => current + (claim.Value + \";\"));\n        if (roles != \"\") roles = \";\" + roles;\n        return roles;\n    }\n\n    public Guid UserGuidFromIdentity()\n    {\n        var username = httpContextAccessor.HttpContext!.User.Identity!.Name;\n        return string.IsNullOrEmpty(username)\n            ? default\n            : oqtSecurity.Value.UserGuid(username);\n    }\n\n    #endregion\n\n    #region Deprecated in v15\n\n    //[Obsolete(\"deprecated in v14.09 2022-10, will be removed ca. v16 #remove16\")]\n    //public bool IsSuperUser => IsSystemAdmin;\n\n    //[Obsolete(\"deprecated in v14.09 2022-10, will be removed ca. v16 #remove16\")]\n    //public bool IsAdmin => IsSiteAdmin;\n\n\n    #endregion\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiActionContext.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Abstractions;\nusing Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.AspNetCore.Routing;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Net;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n// TODO: @STV - PLS EXPLAIN what this does / what it's for\ninternal class AppApiActionContext : IHasLog\n{\n    public AppApiActionContext(ILogStore logStore)\n    {\n        Log = new Log(HistoryLogName, null, \"AppApiActionContext\");\n        logStore.Add(HistoryLogGroup, Log);\n    }\n\n    public ILog Log { get; }\n    protected string HistoryLogGroup { get; } = \"app-api\";\n    protected static string HistoryLogName => \"ActionContext\";\n\n    public ActionContext Provide(HttpContext context, RouteValueDictionary values)\n    {\n        Log.A($\"get values: {values.Count}\");\n\n        var routeData = new RouteData(values);\n\n        var actionDescriptorCollectionProvider = context.RequestServices.GetRequiredService<IActionDescriptorCollectionProvider>();\n\n        var actionSelector = context.RequestServices.GetRequiredService<IActionSelector>();\n\n        var routeContext = new RouteContext(context)\n        {\n            RouteData = routeData\n        };\n\n        // default selector can not select correct candidates from dyncode app api\n        //var candidates = actionSelector.SelectCandidates(routeContext);\n\n        var displayName = GetDisplayName(values);\n        Log.A($\"app-api: {displayName}\");\n\n        List<ActionDescriptor> candidates;\n        // our custom selector for app api methods\n\n        candidates = actionDescriptorCollectionProvider.ActionDescriptors.Items.Where(\n            i => i.DisplayName != null\n                 && (string.Equals(i.DisplayName, displayName, StringComparison.OrdinalIgnoreCase)\n                     || i.DisplayName.EndsWith($\".{displayName}\", StringComparison.OrdinalIgnoreCase)) // try to find match in case we have unknown namespaces on controller name for WepApi method \n                                                                                                       // Ensure to have at least one HttpMethods attribute on the app api endpoint.\n                 && i.ActionConstraints != null\n                 && i.ActionConstraints.Any(c => (c.ToString() ?? \"\").Contains(\"HttpMethodActionConstraint\"))\n        ).ToList();\n\n        Log.A(candidates.Count > 0\n            ? $\"ok, have candidates: {candidates.Count}\"\n            : $\"error, missing candidates: {candidates.Count}, can't find right method for action: {values[\"action\"]} on controller: {values[\"controller\"]}.\");\n\n        if (candidates.Count == 0) throw new HttpExceptionAbstraction(HttpStatusCode.NotFound, $\"Can't find right method for action: {values[\"action\"]} on controller: {values[\"controllerTypeName\"]}.\", \"Not Found\");\n\n        Log.A($\"actionDescriptor SelectBestCandidate\");\n        var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);\n\n        var actionContext = new ActionContext(context, routeData, actionDescriptor);\n\n        // Map query string values as endpoint parameters.\n        MapQueryStringValuesAsEndpointParameters(actionContext, actionDescriptor, routeData);\n\n        return actionContext;\n    }\n\n    private static void MapQueryStringValuesAsEndpointParameters(ActionContext actionContext, ActionDescriptor actionDescriptor, RouteData routeData)\n    {\n        foreach (var t in actionDescriptor.Parameters)\n        {\n            var key = t.Name;\n            var value = actionContext.HttpContext.Request.Query[key];\n            if (!string.IsNullOrEmpty(value)) routeData.Values.TryAdd(key, value);\n        }\n    }\n\n    private static string GetDisplayName(RouteValueDictionary values)\n        => $\"{values[\"controllerTypeName\"]}.{values[\"action\"]} ({GetDllName(values)})\";\n\n    private static string GetDllName(RouteValueDictionary values)\n    {\n        if (AppApiFileSystemWatcher.CompiledAppApiControllers.TryGetValue((string)values[\"apiFile\"], out var appApiCacheItem))\n            if (appApiCacheItem.IsAppCode)\n                return appApiCacheItem.DllName;\n        return $\"{values[\"dllName\"]}.dll\";\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiActionDescriptorChangeProvider.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.Extensions.Primitives;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n\n/// <summary>\n/// Provides change notifications for action descriptors in the AppApi.\n/// 2sxc supports adding, modifying, or removing endpoints at runtime, and this is essential that \n/// the rest of the asp.net core is aware of these changes to adjust its behavior accordingly.\n/// This could include updating routing tables, clearing caches, or other refreshing to match the new set of available actions.\n/// </summary>\n/// <remarks>\n/// IActionDescriptorChangeProvider interface is part of the ASP.NET Core MVC framework, \n/// specifically designed for providing mechanisms to notify about changes in action descriptors.\n/// Action descriptors represent actions in MVC controllers that can be executed as a result of incoming HTTP requests.\n/// Knowing when these descriptors change is crucial for dynamic applications that may modify their available actions at runtime.\n/// </remarks>\ninternal class AppApiActionDescriptorChangeProvider : IActionDescriptorChangeProvider\n{\n    /// <summary>\n    /// Gets the singleton instance of the AppApiActionDescriptorChangeProvider class.\n    /// </summary>\n    public static AppApiActionDescriptorChangeProvider Instance { get; } = new();\n\n    /// <summary>\n    /// Gets or sets the cancellation token source.\n    /// </summary>\n    public CancellationTokenSource TokenSource { get; private set; }\n\n    /// <summary>\n    /// Gets a change token for monitoring changes in the action descriptors.\n    /// </summary>\n    /// <returns>The change token.</returns>\n    public IChangeToken GetChangeToken()\n    {\n        TokenSource = new();\n        return new CancellationChangeToken(TokenSource.Token);\n    }\n\n    /// <summary>\n    /// Gets or sets a value indicating whether the action descriptors have changed.\n    /// </summary>\n    public bool HasChanged { get; set; }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiActionInvoker.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n\n/// <summary>\n/// The AppApiActionInvoker class is a custom action invoker for an ASP.NET Core application, for use within \"AppApi\". \n/// An action invoker in ASP.NET Core is responsible for executing action methods within controllers based on incoming HTTP requests.\n/// </summary>\ninternal class AppApiActionInvoker : IHasLog\n{\n    public AppApiActionInvoker(ILogStore logStore)\n    {\n        Log = new Log(HistoryLogName, null, \"AppApiActionInvoker\");\n        logStore.Add(HistoryLogGroup, Log);\n    }\n\n    public ILog Log { get; }\n    protected string HistoryLogGroup => \"app-api\";\n    protected static string HistoryLogName => \"Invoker\";\n\n    public async Task Invoke(ActionContext actionContext)\n    {\n        var actionInvokerFactory = actionContext.HttpContext.RequestServices.GetRequiredService<IActionInvokerFactory>();\n\n        var actionInvoker = actionInvokerFactory.CreateInvoker(actionContext);\n\n        Log.A($\"invoke app api action\");\n        await actionInvoker.InvokeAsync();\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiAuthorization.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Authorization.Policy;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n// TODO: @STV - PLS EXPLAIN what this does / what it's for\n/**\n     * This is adjusted version of Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.\n     * For reference, original AuthorizationMiddleware class is commented on the bottom of this file.\n     * Our version is made because endpoint metadata is provided from our custom ActionContext.\n     */\ninternal class AppApiAuthorization: IHasLog\n{\n    public AppApiAuthorization(ILogStore logStore)\n    {\n        Log = new Log(HistoryLogName, null, \"AppApiAuthorization\");\n        logStore.Add(HistoryLogGroup, Log);\n    }\n\n    public AppApiAuthorization Init(RequestDelegate next)\n    {\n        _next = next;\n        return this;\n    }\n\n    public ILog Log { get; }\n    protected string HistoryLogGroup { get; } = \"app-api\";\n    protected static string HistoryLogName => \"Authorization\";\n\n    private const string SuppressUseHttpContextAsAuthorizationResource = \"Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource\";\n\n    // Property key is used by Endpoint routing to determine if Authorization has run\n    private const string AuthorizationMiddlewareInvokedWithEndpointKey = \"__AuthorizationMiddlewareWithEndpointInvoked\";\n\n    private static readonly object AuthorizationMiddlewareWithEndpointInvokedValue = new();\n\n    private RequestDelegate _next = (HttpContext _) => Task.CompletedTask;\n\n    /**\n         * Invoke is adjusted to work with ActionContext instead of HttpContext in AuthorizationMiddleware.\n         */\n    public async Task Invoke(ActionContext actionContext)\n    {\n        if (actionContext == null)\n        {\n            throw new ArgumentNullException(nameof(actionContext));\n        }\n\n        var context = actionContext.HttpContext;\n\n        var policyProvider = context.RequestServices.GetRequiredService<IAuthorizationPolicyProvider>();\n\n        // Code bellow is copy from Invoke in AuthorizationMiddleware.\n\n        var endpoint = context.GetEndpoint();\n\n        if (endpoint != null)\n        {\n            // EndpointRoutingMiddleware uses this flag to check if the Authorization middleware processed auth metadata on the endpoint.\n            // The Authorization middleware can only make this claim if it observes an actual endpoint.\n            context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = AuthorizationMiddlewareWithEndpointInvokedValue;\n        }\n\n        // IMPORTANT: Changes to authorization logic should be mirrored in MVC's AuthorizeFilter\n        //var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();\n        // Original code is commented because endpoint.Metadata is from middleware.\n        // In our version endpoint metadata should come from custom web api,\n        // so it is provided from ActionContext.ActionDescriptor.EndpointMetadata.\n        var authorizeData = actionContext.ActionDescriptor.EndpointMetadata.OfType<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();\n        var policy = await AuthorizationPolicy.CombineAsync(policyProvider, authorizeData);\n        if (policy == null)\n        {\n            await _next(context);\n            return;\n        }\n\n        // Policy evaluator has transient lifetime so it fetched from request services instead of injecting in constructor\n        var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();\n\n        var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context);\n\n        // Allow Anonymous skips all authorization\n        //if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)\n        // Original code is commented because endpoint.Metadata is from middleware.\n        // In our version endpoint metadata should come from custom web api,\n        // so it is provided from ActionContext.ActionDescriptor.EndpointMetadata.\n        if (actionContext.ActionDescriptor.EndpointMetadata.OfType<IAllowAnonymous>().Any())\n        {\n            await _next(context);\n            return;\n        }\n\n        object resource;\n        if (AppContext.TryGetSwitch(SuppressUseHttpContextAsAuthorizationResource, out var useEndpointAsResource) &&\n            useEndpointAsResource)\n        {\n            resource = endpoint;\n        }\n        else\n        {\n            resource = context;\n        }\n\n        var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource);\n        var authorizationMiddlewareResultHandler =\n            context.RequestServices.GetRequiredService<IAuthorizationMiddlewareResultHandler>();\n\n        await authorizationMiddlewareResultHandler.HandleAsync(_next, context, policy, authorizeResult);\n    }\n}\n\n\n//using System;\n//using System.Threading.Tasks;\n//using Microsoft.AspNetCore.Authorization.Policy;\n//using Microsoft.AspNetCore.Http;\n//using Microsoft.Extensions.DependencyInjection;\n\n//namespace Microsoft.AspNetCore.Authorization\n//{\n//    /// <summary>\n//    /// A middleware that enables authorization capabilities.\n//    /// </summary>\n//    public class AuthorizationMiddleware\n//    {\n//        // AppContext switch used to control whether HttpContext or endpoint is passed as a resource to AuthZ\n//        private const string SuppressUseHttpContextAsAuthorizationResource = \"Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource\";\n\n//        // Property key is used by Endpoint routing to determine if Authorization has run\n//        private const string AuthorizationMiddlewareInvokedWithEndpointKey = \"__AuthorizationMiddlewareWithEndpointInvoked\";\n//        private static readonly object AuthorizationMiddlewareWithEndpointInvokedValue = new object();\n\n//        private readonly RequestDelegate _next;\n//        private readonly IAuthorizationPolicyProvider _policyProvider;\n\n//        /// <summary>\n//        /// Initializes a new instance of <see cref=\"AuthorizationMiddleware\"/>.\n//        /// </summary>\n//        /// <param name=\"next\">The next middleware in the application middleware pipeline.</param>\n//        /// <param name=\"policyProvider\">The <see cref=\"IAuthorizationPolicyProvider\"/>.</param>\n//        public AuthorizationMiddleware(RequestDelegate next, IAuthorizationPolicyProvider policyProvider) \n//        {\n//            _next = next ?? throw new ArgumentNullException(nameof(next));\n//            _policyProvider = policyProvider ?? throw new ArgumentNullException(nameof(policyProvider));\n//        }\n\n//        /// <summary>\n//        /// Invokes the middleware performing authorization.\n//        /// </summary>\n//        /// <param name=\"context\">The <see cref=\"HttpContext\"/>.</param>\n//        public async Task Invoke(HttpContext context)\n//        {\n//            if (context == null)\n//            {\n//                throw new ArgumentNullException(nameof(context));\n//            }\n\n//            var endpoint = context.GetEndpoint();\n\n//            if (endpoint != null)\n//            {\n//                // EndpointRoutingMiddleware uses this flag to check if the Authorization middleware processed auth metadata on the endpoint.\n//                // The Authorization middleware can only make this claim if it observes an actual endpoint.\n//                context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = AuthorizationMiddlewareWithEndpointInvokedValue;\n//            }\n\n//            // IMPORTANT: Changes to authorization logic should be mirrored in MVC's AuthorizeFilter\n//            var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();\n//            var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData);\n//            if (policy == null)\n//            {\n//                await _next(context);\n//                return;\n//            }\n\n//            // Policy evaluator has transient lifetime so it fetched from request services instead of injecting in constructor\n//            var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();\n\n//            var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context);\n\n//            // Allow Anonymous skips all authorization\n//            if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)\n//            {\n//                await _next(context);\n//                return;\n//            }\n\n//            object? resource;\n//            if (AppContext.TryGetSwitch(SuppressUseHttpContextAsAuthorizationResource, out var useEndpointAsResource) && useEndpointAsResource)\n//            {\n//                resource = endpoint;\n//            }\n//            else\n//            {\n//                resource = context;\n//            }\n            \n//            var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource);\n//            var authorizationMiddlewareResultHandler = context.RequestServices.GetRequiredService<IAuthorizationMiddlewareResultHandler>();\n//            await authorizationMiddlewareResultHandler.HandleAsync(_next, context, policy, authorizeResult);\n//        }\n//    }\n//}\n\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiCacheItem.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Server.Controllers.AppApi\n{\n    internal class AppApiCacheItem\n    {\n        public bool FlagForRemove { get; set; } = default;\n        public bool IsAppCode { get; set; } = default;\n        public string AppCodePath { get; set; } = default;\n        public string DllName { get; set; } = default;\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiControllerManager.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc.ApplicationParts;\nusing Microsoft.AspNetCore.Routing;\nusing System.Reflection;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Backend.Context;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Server.Code.Sys;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Sys.Utils;\nusing Log = ToSic.Sys.Logging.Log;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n/// <summary>\n/// Manage app api controller compilation and registration so we can invoke action latter.\n/// </summary>\ninternal class AppApiControllerManager : IHasLog\n{\n    public AppApiControllerManager(ApplicationPartManager partManager, ILogStore logStore, Generator<Compiler> compiler, IWebApiContextBuilder webApiContextBuilder, PolymorphConfigReader polymorphism,\n        AppCodeLoader appCodeLoader)\n    {\n        _partManager = partManager;\n        _compiler = compiler;\n        _webApiContextBuilder = webApiContextBuilder;\n        _polymorphism = polymorphism;\n        _appCodeLoader = appCodeLoader;\n        Log = new Log(HistoryLogName, null, \"AppApiControllerManager\");\n        logStore.Add(HistoryLogGroup, Log);\n    }\n    private readonly ApplicationPartManager _partManager;\n    private readonly Generator<Compiler> _compiler;\n    private readonly IWebApiContextBuilder _webApiContextBuilder;\n    private readonly PolymorphConfigReader _polymorphism;\n    private readonly AppCodeLoader _appCodeLoader;\n\n    public ILog Log { get; }\n\n    protected string HistoryLogGroup { get; } = \"app-api\";\n\n    protected string HistoryLogName => \"Controller.Manager\";\n\n    private static readonly object LockObject = new();\n\n    /// <summary>\n    /// Compile and register dyncode app api controller (for new or updated app api).\n    /// </summary>\n    /// <param name=\"values\"></param>\n    /// <returns></returns>\n    public async ValueTask<bool> PrepareController(RouteValueDictionary values)\n    {\n        var l = Log.Fn<bool>();\n\n        var apiFile = (string)values[\"apiFile\"];\n        var dllName = (string)values[\"dllName\"];\n        var appFolder = (string)values[\"appFolder\"];\n        var controllerTypeName = (string)values[\"controllerTypeName\"];\n        l.A($\"{nameof(apiFile)}:'{apiFile}'; {nameof(dllName)}:'{dllName}'; {nameof(appFolder)}:'{appFolder}'; {nameof(controllerTypeName)}:'{controllerTypeName}'\");\n\n        // If we have a key (that controller is compiled and registered, but not updated) controller was prepared before, so just return values.\n        // Alternatively remove older version of AppApi controller (if we got updated flag from file system watcher).\n        if (AppApiFileSystemWatcher.CompiledAppApiControllers.TryGetValue(apiFile, out var appApiCacheItem))\n        {\n            if (!appApiCacheItem.FlagForRemove)\n                return l.ReturnTrue($\"ok, nothing to do, AppApi Controller is already compiled and added to ApplicationPart: {apiFile}.\");\n\n            lock (LockObject) // Only one thread can enter this block at a time\n            {\n                // Remove older version of AppApi controller\n                l.A($\"remove old version of controller for: {apiFile}.\");\n\n                l.A(AppApiFileSystemWatcher.CompiledAppApiControllers.TryRemove(apiFile, out _)\n                    ? $\"AppApi controller cache item removed for {apiFile}.\"\n                    : $\"Error, can't remove AppApi controller cache item for {apiFile}.\");\n\n                var dllNameToRemove = (appApiCacheItem.IsAppCode ? appApiCacheItem.DllName : dllName);\n                l.A($\"RemoveController: {dllNameToRemove} (ApplicationParts removed: {RemoveController(apiFile, dllNameToRemove)})\");\n            }\n        }\n\n        l.A($\"We need to prepare controller for: {apiFile}.\");\n\n        lock (LockObject) // Only one thread can enter this block at a time\n        {\n            // 1. check AppCode\n            l.A(\"Search for AppApi controller in AppCode\");\n            var spec = BuildHotBuildSpec(appFolder);\n            var (result, _) = _appCodeLoader.GetAppCode(spec);\n            if (result?.Assembly != null)\n            {\n                l.A($\"search in AppCode:{spec} for controller Type by its name {nameof(controllerTypeName)}:'{controllerTypeName}'\");\n                var type = result.Assembly.FindControllerTypeByName(controllerTypeName);\n                if (type != null)\n                {\n                    l.A($\"Controller Type found: {type.Name} in AppCode: {result.Assembly.GetName().Name}\");\n\n\n                    if (AppApiFileSystemWatcher.CompiledAppApiControllers.TryAdd(apiFile, new()\n                    {\n                        FlagForRemove = false,\n                        IsAppCode = true,\n                        AppCodePath = GetAppCodePathFromWatcherFolders(result.WatcherFolders),\n                        DllName = result.Assembly.GetName().Name\n                    }))\n                    {\n                        l.A($\"{nameof(AppApiFileSystemWatcher.CompiledAppApiControllers)} AppApi controller cache item added for '{apiFile}'.\"); // Add new key to concurrent dictionary, before registering new AppAPi controller.\n                                                                                                                                                 // Register new AppApi Controller.\n                        l.A($\"ApplicationPart from AppCode added: {AddController(result.Assembly)}\");\n                    }\n                    return l.ReturnTrue(\"Api controller from AppCode\");\n                }\n            }\n\n            // 2. Check for AppApi file\n            l.A($\"Search for AppApi controller file:{apiFile}.\");\n            if (!File.Exists(apiFile))\n                throw new IOException($\"Error, missing AppApi file {Path.GetFileName(apiFile)}.\");\n\n            // note: this may look like something you could optimize/cache the result, but that's a bad idea\n            // because when the file changes, the type-object will be different, so please don't optimize :)\n\n            // Check for AppApi source code\n            var apiCode = File.ReadAllText(apiFile);\n            if (string.IsNullOrWhiteSpace(apiCode))\n                throw new IOException($\"Error, missing AppApi code in file '{apiFile}'.\");\n\n            // Build new AppApi Controller\n            l.A($\"Compile assembly: {apiFile}; {nameof(dllName)}: '{dllName}'; {spec}\");\n            var assemblyResult = _compiler.New().Compile(apiFile, dllName, spec);\n\n            // Add new key to concurrent dictionary, before registering new AppAPi controller.\n            if (!AppApiFileSystemWatcher.CompiledAppApiControllers.TryAdd(apiFile, new()))\n                throw new IOException($\"Error, can't register updated controller '{controllerTypeName}' because older controller is already registered. Please try again in few moments.\");\n\n            // Register new AppApi Controller.\n            l.A($\"ApplicationPart from file added: {AddController(assemblyResult.Assembly, dllName)}\");\n        }\n\n        return l.ReturnTrue($\"ok, Controller is compiled and added to ApplicationParts: {apiFile}.\");\n    }\n\n\n    /// <summary>\n    /// Build HotBuildSpec for AppApi controller compilation.\n    /// </summary>\n    /// <param name=\"appFolder\"></param>\n    /// <returns></returns>\n    private HotBuildSpec BuildHotBuildSpec(string appFolder)\n    {\n        var l = Log.Fn<HotBuildSpec>($\"{appFolder}:'{appFolder}'\", timer: true);\n\n        // Prepare / Get App State, while possibly also initializing the App...\n        var ctxResolver = _webApiContextBuilder.PrepareContextResolverForApiRequest();\n        var appReader = ctxResolver.SetAppOrGetBlock(appFolder)?.AppReaderRequired;\n\n        // Figure out the current edition\n        var edition = FigureEdition(ctxResolver).TrimLastSlash();\n\n        var spec = new HotBuildSpec(appReader?.AppId ?? KnownAppsConstants.AppIdEmpty, edition: edition, appReader?.Specs.Name, appReader?.Specs.RuntimeKey);\n\n        return l.ReturnAsOk(spec);\n    }\n\n    /// <summary>\n    /// Figure out the current edition for HotBuildSpec.\n    /// </summary>\n    /// <returns></returns>\n    private string FigureEdition(ISxcCurrentContextService ctxService)\n    {\n        var l = Log.Fn<string>(timer: true);\n\n        var block = ctxService.BlockOrNull();\n        var edition = block.NullOrGetWith(_polymorphism.UseViewEditionOrGet);\n\n        return l.Return(edition);\n    }\n\n    private string GetAppCodePathFromWatcherFolders(IDictionary<string, bool> watcherFolders)\n        => watcherFolders.FirstOrDefault(x => x.Key.EndsWith(FolderConstants.AppCodeFolder)).Key;\n\n    private bool AddController(Assembly assembly, string dllName = null)\n    {\n        var l = Log.Fn<bool>($\"{nameof(dllName)}: '{dllName}'\", timer: true);\n\n        dllName ??= assembly.GetName().Name;\n        l.A($\"TryAdd ApplicationPart:'{dllName}'.\");\n\n        if (_partManager.ApplicationParts\n            .ToList() // ToList() prevents exception 'Collection was modified; enumeration operation may not execute'\n            .Any(a => a.Name.Equals($\"{Path.GetFileNameWithoutExtension(dllName)}.dll\")))\n            return l.ReturnFalse($\"OK, can't add ApplicationPart:'{dllName}' because it was already added before.\");\n\n        // Add ApplicationPart\n        _partManager.ApplicationParts.Add(new CompilationReferencesProvider(assembly));\n\n        // Notify change\n        NotifyChange();\n\n        return l.ReturnTrue($\"OK, applicationPart:'{dllName}' added.\");\n    }\n\n    private bool RemoveController(string apiFile, string dllName)\n    {\n        var l = Log.Fn<bool>($\"{nameof(apiFile)}: '{apiFile}'; {nameof(dllName)}: '{dllName}'\", timer: true);\n\n        l.A($\"In ApplicationParts, find AppApi controller: '{dllName}'.\");\n        // In edge cases the part may be already registered more than once, so we want to clean all\n        var applicationParts = _partManager.ApplicationParts\n            .Where(a => a.Name.Equals($\"{Path.GetFileNameWithoutExtension(dllName)}.dll\"))\n            .ToList();\n\n        if (!applicationParts.Any())\n            return l.ReturnFalse($\"In ApplicationParts, can't find AppApi controller to remove: {dllName}\");\n\n        var countRemoved = 0;\n        foreach (var applicationPart in applicationParts)\n        {\n            if (!_partManager.ApplicationParts.Remove(applicationPart)) continue;\n\n            l.A($\"From ApplicationParts, remove AppApi controller: {dllName}.\");\n            countRemoved++;\n        }\n        if (countRemoved > 0) NotifyChange();\n\n        return l.Return(countRemoved > 0, $\"ApplicationParts removed: {countRemoved}\");\n    }\n\n    private void NotifyChange()\n    {\n        // Notify change\n        Log.A(\"Notify change\");\n        AppApiActionDescriptorChangeProvider.Instance.HasChanged = true;\n        AppApiActionDescriptorChangeProvider.Instance.TokenSource.Cancel();\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiDynamicRouteValueTransformer.cs",
    "content": "﻿using Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc.Routing;\nusing Microsoft.AspNetCore.Routing;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing System.Net;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Backend;\nusing ToSic.Sxc.Backend.Context;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sxc.Oqt.Server.WebApi;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.WebApi.Sys;\nusing Log = ToSic.Sys.Logging.Log;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n/// <summary>\n/// Enable dynamically manipulating of route value to select a 2sxc app api dynamic code controller action.\n/// </summary>\ninternal class AppApiDynamicRouteValueTransformer : DynamicRouteValueTransformer, IHasLog\n{\n    private readonly ITenantResolver _tenantResolver;\n    private readonly IWebHostEnvironment _hostingEnvironment;\n\n\n    public AppApiDynamicRouteValueTransformer(\n        ITenantResolver tenantResolver,\n        IWebHostEnvironment hostingEnvironment,\n        ILogStore logStore)\n    {\n        Log = new Log(HistoryLogName, null, nameof(AppApiDynamicRouteValueTransformer));\n        logStore.Add(HistoryLogGroup, Log);\n        this.ConnectLogs([\n            _tenantResolver = tenantResolver,\n            _hostingEnvironment = hostingEnvironment\n        ]);\n    }\n\n    public ILog Log { get; }\n\n    protected string HistoryLogGroup { get; } = \"app-api\";\n\n    protected string HistoryLogName => \"Route.Values\";\n\n    public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)\n    {\n        return await Task.Run(() =>\n        {\n            var l = Log.Fn<RouteValueDictionary>();\n\n            #region Ensure required alias\n\n            Alias alias;\n            if (values.ContainsKey(\"alias\"))\n            {\n                alias = _tenantResolver.GetAlias();\n            }\n            else\n            {\n                var serviceProvider = httpContext.RequestServices;\n                // this transient dependency is not provided as usual constructor provided lazy/generator dependency (from root service provider)\n                // but as a transient dependency from the request service provider\n                var aliasResolver = serviceProvider.Build<AliasResolver>();\n                alias = aliasResolver.Alias\n                        ?? throw new HttpExceptionAbstraction(HttpStatusCode.NotFound,\n                            $\"Error: missing required 'alias' route value.\", \"Not Found\");\n            }\n\n            var aliasPart = OqtServerPaths.GetAppRootWithTenantAndSiteId(alias.TenantId, alias.SiteId);\n\n            #endregion\n\n            // Ensure required route values: alias, appFolder, controller, action.\n            if (!values.ContainsKey(\"appFolder\"))\n                throw new HttpExceptionAbstraction(HttpStatusCode.NotFound,\n                    $\"Error: missing required 'appFolder' route value.\", \"Not Found\");\n            var appFolder = (string) values[\"appFolder\"];\n            if (appFolder == OqtWebApiConstants.Auto)\n            {\n                // before trying to get the AppFolder, we must init the ICmsContext as this will\n                // this transient dependencies are not provided as usual constructor provided lazy/generator dependencies (from root service provider)\n                // but as a transient dependencies from the request service provider\n                var blockInitializer = httpContext.RequestServices.Build<IWebApiContextBuilder>();\n                blockInitializer.PrepareContextResolverForApiRequest();\n                appFolder = httpContext.RequestServices.Build<AppFolderLookupForWebApi>().GetAppFolder();\n            }\n\n            if (!values.ContainsKey(\"controller\"))\n                throw new HttpExceptionAbstraction(HttpStatusCode.NotFound,\n                    $\"Error: missing required 'controller' route value.\", \"Not Found\");\n            var controller = (string) values[\"controller\"];\n\n            if (!values.ContainsKey(\"action\"))\n                throw new HttpExceptionAbstraction(HttpStatusCode.NotFound,\n                    $\"Error: missing required 'action' route value.\", \"Not Found\");\n            var action = (string) values[\"action\"];\n\n            l.A(\n                $\"TransformAsync route required values are present, alias:{alias.AliasId}, app:{appFolder}, ctrl:{controller}, act:{action}.\");\n\n            var controllerTypeName = $\"{controller}Controller\";\n            l.A($\"Controller TypeName: {controllerTypeName}\");\n            values.Add(\"controllerTypeName\", controllerTypeName);\n\n            var edition = GetEdition(values);\n            l.A($\"Edition: {edition}\");\n\n\n            var controllerFolder = Path.Combine(aliasPart, appFolder, edition.Backslash(), \"api\");\n            l.A($\"Controller Folder: {controllerFolder}\");\n\n            var area = $\"{alias.SiteId}/{OqtConstants.ApiAppLinkPart}/{appFolder}/{edition}api\";\n            l.A($\"Area: {area}\");\n            values.Add(\"area\", area);\n\n            var controllerPath = Path.Combine(controllerFolder, controllerTypeName + \".cs\");\n            l.A($\"Controller Path: {controllerPath}\");\n\n            var apiFile = Path.Combine(_hostingEnvironment.ContentRootPath, controllerPath);\n            l.A($\"Absolute Path: {apiFile}\");\n            values.Add(\"apiFile\", apiFile);\n\n            var dllName = GetDllName(controllerFolder, apiFile);\n            l.A($\"Dll Name: {dllName}\");\n            values.Add(\"dllName\", dllName);\n\n            // help with path resolution for compilers running inside the created controller\n            httpContext./*Request?.HttpContext.*/Items.Add(SourceCodeConstants.SharedCodeRootPathKeyInCache, controllerFolder);\n\n            httpContext./*Request?.HttpContext.*/Items.Add(SxcWebApiConstants.HttpContextKeyForAppFolder, appFolder);\n\n            return l.Return(values, $\"ok, TransformAsync route required values are prepared\");\n        });\n    }\n\n    public static string GetDllName(string controllerFolder, string apiFile)\n    {\n        return\n            $\"DynCode_{controllerFolder.Replace(@\"\\\", \"_\")}_{Path.GetFileNameWithoutExtension(apiFile)}\";\n    }\n\n    private static string GetEdition(RouteValueDictionary values)\n    {\n        return VarNames.GetEdition(values);\n        //// new for 2sxc 9.34 #1651\n        //var edition = \"\";\n        //if (values.TryGetValue(VarNames.Edition, out var value)) edition = value?.ToString();\n        //return edition + (string.IsNullOrEmpty(edition) ? \"\" : \"/\");\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiFileSystemWatcher.cs",
    "content": "﻿using Microsoft.Extensions.Hosting;\nusing System.Collections.Concurrent;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n\n/// <summary>\n/// The AppApiFileSystemWatcher class is ensuring that the 2sxc app's in runtime remains up-to-date with the latest changes to its web APIs by tracking updates in .cs files.\n/// FileSystemWatcher monitor changes within the 2sxc application's source files. This detection is crucial for the application's runtime to know when web APIs implementation has changed, \n/// necessitating the removal of the outdated API components from the application's runtime.\n/// </summary>\ninternal class AppApiFileSystemWatcher : IDisposable, IHasLog\n{\n    private readonly FileSystemWatcher _watcher;\n\n    public static readonly ConcurrentDictionary<string, AppApiCacheItem> CompiledAppApiControllers = new(StringComparer.InvariantCultureIgnoreCase);\n\n    public AppApiFileSystemWatcher(IHostEnvironment hostingEnvironment, ILogStore logStore)\n    {\n        Log = new Log(HistoryLogName, null, \"new AppApiFileSystemWatcher()\");\n        logStore.Add(HistoryLogGroup, Log);\n\n        var appApiSource = Path.Combine(hostingEnvironment.ContentRootPath, OqtConstants.AppRoot, OqtConstants.TenantsFolderName);\n\n        _watcher = new()\n        {\n            Path = appApiSource,\n            NotifyFilter = NotifyFilters.LastWrite\n                           | NotifyFilters.FileName\n                           | NotifyFilters.DirectoryName,\n            Filter = \"*.cs\",\n            IncludeSubdirectories = true\n        };\n\n        // Add event handlers.\n        _watcher.Changed += OnChanged;\n        _watcher.Created += OnChanged;\n        _watcher.Deleted += OnChanged;\n        _watcher.Renamed += OnRenamed;\n\n        // Begin watching.\n        Log.A($\"Begin watching: {appApiSource}.\");\n        _watcher.EnableRaisingEvents = true;\n    }\n\n    public ILog Log { get; }\n\n    /// <summary>\n    /// The group name for log entries in insights.\n    /// Helps group various calls by use case.\n    /// </summary>\n    protected string HistoryLogGroup { get; } = \"app-api\";\n\n    /// <summary>\n    /// The name of the logger in insights.\n    /// /// </summary>\n    protected string HistoryLogName => \"FileSystemWatcher\";\n\n    public void Dispose()\n    {\n        Log.A(\"Stop watching.\");\n        _watcher.EnableRaisingEvents = false;\n        _watcher?.Dispose();\n    }\n\n    private void OnChanged(object source, FileSystemEventArgs e)\n    {\n        var appApiCacheItem = FlagForRemove(e.FullPath) ?? CheckAppCode(e.FullPath);\n        Log.A($\"Change type: {e.ChangeType}, file: {e.FullPath}, flag for remove: {appApiCacheItem?.FlagForRemove}.\");\n    }\n\n    private void OnRenamed(object source, RenamedEventArgs e)\n    {\n        var appApiCacheItem = FlagForRemove(e.OldFullPath) ?? CheckAppCode(e.OldFullPath);\n        Log.A($\"Renamed: {e.OldFullPath} to {e.FullPath}, flag for remove: {appApiCacheItem?.FlagForRemove}.\");\n    }\n\n    private AppApiCacheItem FlagForRemove(string path)\n    {\n        if (!CompiledAppApiControllers.TryGetValue(path, out var appApiCacheItem))\n            return null;\n        if (!appApiCacheItem.FlagForRemove)\n            appApiCacheItem.FlagForRemove = true;\n        return appApiCacheItem;\n    }\n\n    private AppApiCacheItem CheckAppCode(string path)\n    {\n        if (!path.Contains(FolderConstants.AppCodeFolder, StringComparison.InvariantCultureIgnoreCase))\n            return null;\n        AppApiCacheItem appApiCacheItem = null;\n        foreach (var controller in CompiledAppApiControllers)\n        {\n            if (!controller.Value.IsAppCode || !path.StartsWith(controller.Value.AppCodePath, StringComparison.InvariantCultureIgnoreCase))\n                continue;\n            appApiCacheItem = FlagForRemove(controller.Key);\n        }\n        return appApiCacheItem;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Net;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n\n/// <summary>\n/// Middleware for handling requests to the custom App API.\n/// - extract route values like appFolder, controller, action, apiFile, dllName, etc.\n/// - compile controller if not already compiled\n/// - ensure security, \n/// - provide action context and invoke controller action\n/// </summary>\ninternal static class AppApiMiddleware\n{\n  /// <summary>\n  /// Invokes the middleware asynchronously.\n  /// </summary>\n  /// <param name=\"context\">The HTTP context.</param>\n  [SuppressMessage(\"ReSharper\", \"PossibleNullReferenceException\")]\n  internal static async Task InvokeAsync(HttpContext context)\n  {\n    // Transform route values.\n    var appApiDynamicRouteValueTransformer = context.RequestServices.GetService<AppApiDynamicRouteValueTransformer>();\n    var values = await appApiDynamicRouteValueTransformer.TransformAsync(context, context.Request.RouteValues);\n\n    // Compile and register dyncode app api controller.\n    var appApiControllerManager = context.RequestServices.GetService<AppApiControllerManager>();\n    if (!await appApiControllerManager.PrepareController(values))\n      throw new HttpExceptionAbstraction(HttpStatusCode.NotFound, \"Error, can't compile controller.\", \"Not Found\");\n\n    // Provide ActionContext.\n    var appApiActionContext = context.RequestServices.GetService<AppApiActionContext>();\n    var actionContext = appApiActionContext.Provide(context, values);\n\n    async Task InvokeActionAfterAuthorization(HttpContext context)\n    {\n      // Invoke controller action.\n      var appApiActionInvoker = context.RequestServices.GetService<AppApiActionInvoker>();\n      await appApiActionInvoker.Invoke(actionContext);\n    }\n\n    // Check security.\n    var appApiAuthorization = context.RequestServices.GetService<AppApiAuthorization>().Init(InvokeActionAfterAuthorization);\n    await appApiAuthorization.Invoke(actionContext);\n  }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/AppApi/AppApiPermissionHandler.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Http;\nusing Oqtane.Infrastructure;\nusing Oqtane.Security;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\n/// <summary>\n/// Extend Oqtane default PermissionHandler to provide Oqt required \"entityId\"\n/// if missing from header \"moduleId\", or query string, or route value.\n/// </summary>\n[PrivateApi]\ninternal class AppApiPermissionHandler(\n    IHttpContextAccessor httpContextAccessor,\n    IUserPermissions userPermissions,\n    ILogManager logger,\n    RequestHelper requestHelper)\n    : PermissionHandler(httpContextAccessor, userPermissions, logger)\n{\n    private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor;\n\n    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)\n    {\n        var httpContext = _httpContextAccessor.HttpContext;\n        if (!httpContext.Request.Query.ContainsKey(\"entityid\"))\n        {\n            var moduleId = requestHelper.GetTypedHeader(ContextConstants.ModuleIdKey,\n                requestHelper.GetQueryString(ContextConstants.ModuleIdKey,\n                    requestHelper.GetRouteValuesString(ContextConstants.ModuleIdKey,\n                        -1)));\n            var queryString = httpContext.Request.QueryString.Add(new($\"?entityid={moduleId}\"));\n            httpContext.Request.QueryString = queryString;\n        }\n\n        base.HandleRequirementAsync(context, requirement);\n\n        return Task.CompletedTask;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/EditUiMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Antiforgery;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing Oqtane.Repository;\nusing System.Text;\nusing ToSic.Sxc.Oqt.Server.Blocks.Output;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sxc.Web.Sys.EditUi;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers;\n\ninternal class EditUiMiddleware\n{\n    private const int UnknownId = -1;\n\n    public static Task PageOutputCached(HttpContext context, IWebHostEnvironment env, string virtualPath, EditUiResourceSettings settings)\n    {\n        context.Response.Headers.TryAdd(\"test-dev\", \"2sxc\");\n\n        var sp = context.RequestServices;\n\n        var key = CacheKey(virtualPath);\n        var memoryCacheService = sp.GetService<MemoryCacheService>();\n        if (!memoryCacheService.TryGet<string>(key, out var html))\n        {\n            var path = Path.Combine(env.WebRootPath, virtualPath);\n            if (!File.Exists(path)) throw new FileNotFoundException(\"File not found: \" + path);\n\n            var bytesInFile = File.ReadAllBytes(path);\n            html = Encoding.Default.GetString(bytesInFile);\n            html = HtmlDialog.CleanImport(html);\n            memoryCacheService.Set(key, html, p => p.WatchFiles([path]));\n        }\n\n        var pageId = GetPageId(context);\n        var tenantId = GetTenantId(context);\n        var aliasId = GetAliasId(context);\n        var addOn = $\"{HtmlDialog.TenantIdInUrl}={tenantId}&{HtmlDialog.AliasIdInUrl}={aliasId}\";\n\n        // find siteId from pageId (if provided)\n        var aliasResolver = sp.GetService<AliasResolver>();\n\n        // 1. (keep order of lines)\n        var siteId = EnsureCorrectAliasAndGetSiteIdFromPageId(tenantId, aliasId, pageId, aliasResolver, sp);\n\n        // New feature to get resources\n        var htmlHead = \"\";\n        try\n        {\n            htmlHead = sp.GetRequiredService<EditUiResources>().GetResources(true, siteId, settings).HtmlHead;\n        }\n        catch { /* ignore */ }\n\n        // 2. (keep order of lines)\n        var siteRoot = OqtPageOutput.GetSiteRoot(aliasResolver.Alias);\n\n        var rvt = sp.GetRequiredService<IAntiforgery>().GetAndStoreTokens(context).RequestToken;\n\n        var withPublicKey = WithPublicKey(context);\n\n        // inject JsApi to html content\n        var content = sp.GetRequiredService<IJsApiService>().GetJsApiJson(pageId, siteRoot, rvt, withPublicKey);\n\n        html = HtmlDialog.UpdatePlaceholders(html, content, pageId, addOn, htmlHead, $\"<input name=\\\"__RequestVerificationToken\\\" type=\\\"hidden\\\" value=\\\"{rvt}\\\" >\");\n\n        var bytes = Encoding.Default.GetBytes(html);\n\n        // html response\n        context.Response.ContentType = \"text/html\";\n        //context.Response.Body.Write(Encoding.Unicode.GetBytes(html));\n        context.Response.Body.WriteAsync(bytes);\n\n        return Task.CompletedTask;\n    }\n\n    private static string CacheKey(string virtualPath) => $\"ToSic.Sxc.Oqt.Server.Controllers.{nameof(EditUiMiddleware)}:{virtualPath}\";\n    \n    private static bool WithPublicKey(HttpContext context)\n    {\n        // 'wpk' should be provided in query string\n        var withPublicKeyString = context.Request.Query[HtmlDialog.WithPublicKey];\n        return !string.IsNullOrEmpty(withPublicKeyString) && Convert.ToBoolean(withPublicKeyString);\n    }\n\n    /// <summary>\n    /// find siteId from pageId (if provided)\n    /// initialize SiteState for DB connection\n    /// </summary>\n    /// <param name=\"tenantId\"></param>\n    /// <param name=\"aliasId\"></param>\n    /// <param name=\"pageId\"></param>\n    /// <param name=\"aliasResolver\"></param>\n    /// <param name=\"sp\"></param>\n    /// <returns>siteId or NULL</returns>\n    /// <remarks>internally find correct alias and store it in SiteState.Alias for reuse</remarks>\n    private static int? EnsureCorrectAliasAndGetSiteIdFromPageId(int tenantId, int aliasId, int pageId, AliasResolver aliasResolver, IServiceProvider sp)\n    {\n        if (tenantId == UnknownId) return null;\n        if (aliasId == UnknownId) return null;\n        if (pageId == UnknownId) return null;\n\n        // FIX: No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider.\n        var _ = aliasResolver?.GetAndStoreAlias(aliasId);// do not remove or reorder this line (it will initialize SiteState for DB connection)\n\n        if (aliasResolver?.Alias.TenantId != tenantId) return null;\n\n        var pages = sp.GetRequiredService<IPageRepository>();\n        var page = pages.GetPage(pageId, false); // SiteState need to be initialized for DB connection\n\n        aliasResolver?.InitIfEmpty(page?.SiteId); // store correct alias in SiteState.Alias\n\n        return page?.SiteId;\n    }\n\n    private static int GetQueryParameterAsInt(HttpContext context, string parameterName)\n    {\n        var parameterValue = context.Request.Query[parameterName];\n        return !string.IsNullOrEmpty(parameterValue)\n            ? Convert.ToInt32(parameterValue)\n            : UnknownId;\n    }\n\n    private static int GetTenantId(HttpContext context) => GetQueryParameterAsInt(context, HtmlDialog.TenantIdInUrl);\n\n    private static int GetAliasId(HttpContext context) => GetQueryParameterAsInt(context, HtmlDialog.AliasIdInUrl);\n\n    private static int GetPageId(HttpContext context) => GetQueryParameterAsInt(context, HtmlDialog.PageIdInUrl);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/OqtControllerBase.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing ToSic.Sxc.Backend.Context;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.WebApi.Sys;\nusing ToSic.Sxc.WebApi.Sys.ActionFilters;\nusing Log = ToSic.Sys.Logging.Log;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers;\n\n/// <summary>\n/// Api controllers normally should inherit ControllerBase but we have a special case of inhering from Controller.\n/// It is because our custom dynamic 2sxc app api controllers (without constructor), depends on event OnActionExecuting\n/// to provide dependencies (without DI in constructor).\n/// </summary>\n[SystemTextJsonFormatter] // This is needed to preserve compatibility with previous api usage\n[ServiceFilter(typeof(OptionalBodyFilter))] // Instead of global options.AllowEmptyInputInBodyModelBinding = true;\n[ServiceFilter(typeof(HttpResponseExceptionFilter))]\npublic abstract class OqtControllerBase : ControllerBase, IHasLog, IActionFilter\n{\n    #region Setup\n\n    private readonly bool _withBlockContext;\n\n    protected OqtControllerBase(bool withBlockContext, string logSuffix)\n    {\n        _withBlockContext = withBlockContext;\n        Log = new Log($\"Api.{logSuffix}\", null, GetType().Name);\n        _helper = new(this);\n\n        if (withBlockContext)\n            CtxHlp = new(this, _helper);\n    }\n\n    #endregion\n\n\n    /// <summary>\n    /// The group name for log entries in insights.\n    /// Helps group various calls by use case.\n    /// </summary>\n    protected virtual string HistoryLogGroup => EavWebApiConstants.HistoryNameWebApi;\n\n    /// <inheritdoc />\n    public ILog Log { get; }\n        \n    /// <summary>\n    /// The helper to assist in timing and common operations of WebApi Controllers\n    /// </summary>\n    private readonly NetCoreControllersHelper _helper;\n\n    /// <summary>\n    /// Special helper to move all Razor logic into a separate class.\n    /// For architecture of Composition over Inheritance.\n    /// </summary>\n    [PrivateApi]\n    internal NetCoreWebApiContextHelper CtxHlp \n        => field ?? throw new($\"This controller doesn't have a {nameof(CtxHlp)}. Check your constructor.\");\n\n    /// <summary>\n    /// Initializer - just ensure SiteState is initialized thanks to our paths\n    /// </summary>\n    /// <param name=\"context\"></param>\n    [NonAction]\n    public virtual void OnActionExecuting(ActionExecutingContext context)\n    {\n        var l = Log.Fn();\n        _helper.OnActionExecuting(context, HistoryLogGroup);\n\n        // background processes can pass in an alias using the SiteState service\n        GetService<AliasResolver>().InitIfEmpty();\n            \n        if (_withBlockContext)\n            CtxHlp.InitializeBlockContext(context);\n        l.Done();\n    }\n\n    /// <inheritdoc/>\n    [NonAction]\n    public virtual void OnActionExecuted(ActionExecutedContext context)\n    {\n        var l = Log.Fn();\n        _helper.OnActionExecuted(context);\n        l.Done();\n    }\n\n    protected TService GetService<TService>() where TService : class\n        => _helper.GetService<TService>();\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/OqtStatefulControllerBase.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Server.Controllers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class OqtStatefulControllerBase(string logSuffix) : OqtControllerBase(true, logSuffix);"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/OqtSxcRenderController.cs",
    "content": "using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Controllers;\nusing Oqtane.Enums;\nusing Oqtane.Infrastructure;\nusing Oqtane.Shared;\nusing System.Net;\nusing ToSic.Sxc.Oqt.Shared.Helpers;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers;\n\n//[Route(\"{alias:int}/api/[controller]\")]\n[Route(ControllerRoutes.ApiRoute)]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtSxcRenderController(\n    IHttpContextAccessor accessor,\n    ILogManager logger,\n    IOqtSxcRenderService oqtSxcRenderService)\n    : ModuleControllerBase(logger, accessor)\n{\n    // ReSharper disable once InconsistentNaming\n    private readonly ILogManager logger = logger;\n\n    private bool IsSuperUser => User.IsInRole(RoleNames.Host) || User.IsInRole(RoleNames.Admin);\n\n\n    [HttpGet(\"{aliasId:int}/{pageId:int}/{moduleId:int}/{culture}/{preRender:bool}/Render\")]\n    //[Authorize(Policy = PolicyNames.ViewModule)]\n    public OqtViewResultsDto Render([FromRoute] int aliasId, [FromRoute] int pageId, [FromRoute] int moduleId, [FromRoute] string culture, [FromRoute] bool preRender, [FromQuery] string originalParameters)\n    {\n        var @params = new RenderParameters()\n        {\n            AliasId = aliasId,\n            PageId = pageId,\n            ModuleId = moduleId,\n            Culture = culture,\n            PreRender = preRender,\n            OriginalParameters = originalParameters\n        };\n\n        try\n        {\n            if (moduleId != AuthEntityId(EntityNames.Module))\n                return Forbidden(\"Unauthorized OqtSxcRenderController Get Attempt {ModuleId}\", moduleId);\n\n            return oqtSxcRenderService.Render(@params);\n        }\n        catch (Exception ex)\n        {\n            return Error(ex);\n        }\n    }\n\n    private OqtViewResultsDto Forbidden(string message, params object[] args)\n    {\n        logger.Log(LogLevel.Error, this, LogFunction.Security, message, args);\n        HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;\n        return null;\n    }\n\n    private OqtViewResultsDto Error(Exception ex)\n    {\n        logger.Log(LogLevel.Error, this, LogFunction.Read, ex, $\"exception in {nameof(Render)}\");\n        return new() { ErrorMessage = ErrorHelper.ErrorMessage(ex, IsSuperUser) };\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/OqtUiContextBuilder.cs",
    "content": "﻿using Oqtane.Shared;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Backend.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sxc.WebApi.Sys.ExternalLinks;\nusing OqtPageOutput = ToSic.Sxc.Oqt.Server.Blocks.Output.OqtPageOutput;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers;\n\ninternal class OqtUiContextBuilder(\n    ILinkPaths linkPaths,\n    IContextOfSite ctx,\n    SiteState siteState,\n    ExternalLinksService externalLinksService,\n    UiContextBuilderBase.Dependencies deps)\n    : UiContextBuilderBase(deps)\n{\n    protected override ContextResourceWithApp GetSystem(Ctx flags)\n    {\n        var result = base.GetSystem(flags);\n\n        result.Url = linkPaths.AsSeenFromTheDomainRoot(\"~/\");\n        return result;\n    }\n\n    protected override ContextResourceWithApp GetSite(Ctx flags)\n    {\n        var result = base.GetSite(flags);\n\n        result.Id = ctx.Site.Id;\n        result.Url = \"//\" + ctx.Site.UrlRoot;\n        return result;\n    }\n\n    protected override WebResourceDto GetPage() =>\n        new()\n        {\n            Id = (ctx as IContextOfBlock)?.Page.Id ?? Eav.Sys.EavConstants.NullId,\n        };\n\n    protected override ContextAppDto GetApp(Ctx flags)\n    {\n        var appDto = base.GetApp(flags);\n        if (appDto != null) appDto.Api = OqtPageOutput.GetSiteRoot(siteState.Alias);\n        return appDto;\n    }\n\n    protected override string GetGettingStartedUrl()\n    {\n        var blockCtx = ctx as IContextOfBlock; // may be null!\n\n        var gsUrl = externalLinksService.LinkToDestination(\n            ExternalSxcDestinations.GettingStarted,\n            Services.SiteCtx.Site,\n            blockCtx?.Module.Id ?? 0,\n            AppSpecsOrNull,\n            true\n        );\n        return gsUrl;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Controllers/PageResponseRewriteMiddleware.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Http;\n\nnamespace ToSic.Sxc.Oqt.Server.Controllers;\n\n// TODO: @STV WHAT IS THIS FOR? IT LOOKS LIKE IT WAS JUST A TEST?\n// Or will we need this for CSP headers etc.?\n/// <summary>\n/// WIP: response rewrite for razor pages (CSP, meta, etc...)\n/// </summary>\ninternal class PageResponseRewriteMiddleware(RequestDelegate next)\n{\n    public async Task InvokeAsync(HttpContext context)\n    {\n        context.Response.Headers.Add(\"test-dev-page-middleware\", \"2sxc\");\n\n        // Call the next delegate/middleware in the pipeline.\n        await next(context);\n    }\n}\n\npublic static class PageMiddlewareMiddlewareExtensions\n{\n    public static IApplicationBuilder UsePageResponseRewriteMiddleware(this IApplicationBuilder builder)\n    {\n        return builder.UseMiddleware<PageResponseRewriteMiddleware>();\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Custom/Hybrid/Api12.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.Oqt.Server.Custom;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.WebApi;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Custom base controller class for custom dynamic 2sxc app api controllers.\n/// It is without dependencies in class constructor, commonly provided with DI.\n/// </summary>\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\npublic abstract class Api12(string logSuffix) : OqtStatefulControllerBase(logSuffix), IDynamicWebApi, IDynamicCode12, IHasCodeLog\n{\n    #region Setup\n\n    protected Api12() : this(EavWebApiConstants.HistoryNameWebApi) { }\n\n    [PrivateApi] public int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtxOrNull.GetDynamicApi();\n\n    /// <summary>\n    /// Our custom dynamic 2sxc app api controllers, depends on event OnActionExecuting to provide dependencies (without DI in constructor).\n    /// </summary>\n    /// <param name=\"context\"></param>\n    [NonAction]\n    public override void OnActionExecuting(ActionExecutingContext context)\n    {\n        base.OnActionExecuting(context);\n        CtxHlp.OnActionExecutingEnd(context);\n    }\n\n    #endregion\n\n    #region Infrastructure\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => CtxHlp.CodeLog;\n\n    // ReSharper disable once InconsistentNaming\n    [PrivateApi]\n    public IExecutionContext ExCtxOrNull => CtxHlp.ExCtxOrNull;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public new TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    [PrivateApi(\"Not yet ready\")]\n    public IDevTools DevTools => CodeApi.DevTools;\n\n    #endregion\n\n    #region App, Data, Settings, Resources, CmsContext\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi?.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi?.Data;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    public dynamic Settings => CodeApi.Settings;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi?.CmsContext;\n\n\n    #endregion\n\n\n    #region AsDynamic / AsList implementations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    [NonAction]\n    public dynamic AsDynamic(string json, string fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    [NonAction]\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    [NonAction]\n    public dynamic AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    [NonAction]\n    public dynamic AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    [NonAction]\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi?.Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n    #region Convert-Service\n    [PrivateApi] public IConvertService Convert => field ??= CodeApi.Convert;\n\n    #endregion\n\n\n    #region CreateSource implementations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    [NonAction]\n    public T CreateSource<T>(IDataSource inSource = null, ILookUpEngine configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    [NonAction]\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    #endregion\n\n    #region Content, Presentation & List\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public new dynamic Content => CodeApi?.Content;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic Header => CodeApi?.Header;\n\n\n    #endregion\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    [NonAction]\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi?.AsAdam(item, fieldName);\n\n    /// <inheritdoc cref=\"IDynamicWebApi.SaveInAdam\"/>\n    [NonAction]\n    public IFile SaveInAdam(NoParamOrder npo = default,\n        Stream stream = null,\n        string fileName = null,\n        string contentType = null,\n        Guid? guid = null,\n        string field = null,\n        string subFolder = \"\")\n        => CtxHlp.SaveInAdam(stream: stream, fileName: fileName, contentType: contentType, guid: guid, field: field, subFolder: subFolder);\n\n    #endregion\n\n    #region Link & Edit - added to API in 2sxc 10.01\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi?.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi?.Edit;\n\n    #endregion\n\n    #region  CreateInstance implementation\n\n    string IGetCodePath.CreateInstancePath { get; set; }\n\n    protected CompileCodeHelper CompileCodeHlp => _compileCodeHlp ??= GetService<CompileCodeHelper>().Init(this);\n    private CompileCodeHelper _compileCodeHlp;\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\"/>\n    [NonAction]\n    public dynamic CreateInstance(string virtualPath, NoParamOrder npo = default, string name = null, string relativePath = null, bool throwOnError = true)\n        => CompileCodeHlp.CreateInstance(virtualPath: virtualPath, name: name, throwOnError: throwOnError);\n\n    #endregion\n\n    #region File Response / Download\n\n    /// <inheritdoc cref=\"IDynamicWebApi.File\"/>\n    public dynamic File(NoParamOrder npo = default,\n        bool? download = null,\n        string virtualPath = null,\n        string contentType = null,\n        string fileDownloadName = null,\n        object contents = null\n    ) =>\n        new OqtWebApiShim(response: Response, owner: this).File(download: download, virtualPath: virtualPath, contentType: contentType, fileDownloadName: fileDownloadName, contents: contents);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Custom/Hybrid/Api14.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Services;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Oqtane specific Api base class.\n///\n/// It's identical to [](xref:Custom.Hybrid.Api14) but this may be enhanced in future. \n/// </summary>\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\npublic abstract class Api14 : Api12, IDynamicCode14<object, ServiceKit14>\n{\n    public ServiceKit14 Kit => field ??= CodeApi.ServiceKit14;\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    [PrivateApi(\"added in 16.05, but not sure if it should be public\")]\n    public dynamic GetCode(string path, NoParamOrder npo = default, string className = default)\n        => CompileCodeHlp.GetCode(path: path, className: className);\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Custom/Hybrid/ApiTyped.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.WebApi;\nusing ToSic.Sxc.Oqt.Server.Custom;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Sxc.Adam;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Oqtane specific Api base class.\n///\n/// It's identical to [](xref:Custom.Hybrid.Api14) but this may be enhanced in future. \n/// </summary>\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\n[JsonFormatter]\npublic abstract class ApiTyped(string logSuffix) : OqtStatefulControllerBase(logSuffix), IDynamicWebApi, IHasCodeLog, ITypedCode16\n{\n    #region setup\n\n    protected ApiTyped() : this(EavWebApiConstants.HistoryNameWebApi) { }\n\n    internal ICodeTypedApiHelper CodeApi => field\n        ??= ExCtxOrNull.GetTypedApi();\n\n\n    /// <summary>\n    /// Our custom dynamic 2sxc app api controllers, depends on event OnActionExecuting to provide dependencies (without DI in constructor).\n    /// </summary>\n    /// <param name=\"context\"></param>\n    [NonAction]\n    public override void OnActionExecuting(ActionExecutingContext context)\n    {\n        base.OnActionExecuting(context);\n        CtxHlp.OnActionExecutingEnd(context);\n    }\n\n    [PrivateApi] public int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel16;\n\n    #endregion\n\n    #region Infrastructure\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => CtxHlp.CodeLog;\n\n    // ReSharper disable once InconsistentNaming\n    [PrivateApi] internal IExecutionContext ExCtxOrNull => CtxHlp.ExCtxOrNull;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public new TService GetService<TService>() where TService : class\n        => CodeApi.GetService<TService>();\n\n    /// <inheritdoc cref=\"ITypedCode16.GetService{TService}(NoParamOrder, string?)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TService GetService<TService>(NoParamOrder npo = default, string typeName = default) where TService : class\n        => AppCodeGetNamedServiceHelper.GetService<TService>(owner: this, CodeHelper.Specs, typeName);\n\n    /// <inheritdoc cref=\"IHasKit{TServiceKit}.Kit\"/>\n    public ServiceKit16 Kit => field ??= CodeApi.ServiceKit16;\n\n    [PrivateApi(\"Not yet ready\")]\n    public IDevTools DevTools => CodeHelper.DevTools;\n\n    #endregion\n\n    #region Link & Edit - added to API in 2sxc 10.01\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi?.Link;\n\n    #endregion\n\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicWebApi.SaveInAdam\"/>\n    [NonAction]\n    public IFile SaveInAdam(NoParamOrder npo = default,\n        Stream stream = null,\n        string fileName = null,\n        string contentType = null,\n        Guid? guid = null,\n        string field = null,\n        string subFolder = \"\")\n        => CtxHlp.SaveInAdam(stream: stream, fileName: fileName, contentType: contentType, guid: guid, field: field, subFolder: subFolder);\n\n    #endregion\n\n\n    #region New App, Settings, Resources\n\n    /// <inheritdoc />\n    public IAppTyped App => CodeApi?.AppTyped;\n\n    /// <inheritdoc cref=\"ITypedApi.AllResources\" />\n    public ITypedStack AllResources => CodeHelper.AllResources;\n\n    /// <inheritdoc cref=\"ITypedApi.AllSettings\" />\n    public ITypedStack AllSettings => CodeHelper.AllSettings;\n\n    #endregion\n\n    #region My... Stuff\n\n    private CodeHelperTypedData CodeHelper => field\n        ??= new(helperSpecs: new(ExCtxOrNull, false, ((IGetCodePath)this).CreateInstancePath));\n\n    public ITypedItem MyItem => CodeHelper.MyItem;\n\n    public IEnumerable<ITypedItem> MyItems => CodeHelper.MyItems;\n\n    public ITypedItem MyHeader => CodeHelper.MyHeader;\n\n    public IDataSource MyData => CodeApi.Data;\n\n    #endregion\n\n\n    #region As Conversions\n\n    /// <inheritdoc cref=\"ITypedApi.AsItem\" />\n    public ITypedItem AsItem(object data, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsItem(data, new() { ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsItems\" />\n    public IEnumerable<ITypedItem> AsItems(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsItems(list, new() { ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsEntity\" />\n    public IEntity AsEntity(ICanBeEntity thing)\n        => CodeApi.Cdf.AsEntity(thing);\n\n    /// <inheritdoc cref=\"ITypedApi.AsTyped\" />\n    public ITyped AsTyped(object original, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsTyped(original, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsTypedList\" />\n    public IEnumerable<ITyped> AsTypedList(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsTypedList(list, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack\" />\n    public ITypedStack AsStack(params object[] items)\n        => CodeApi.Cdf.AsStack(items);\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack{T}\" />\n    public T AsStack<T>(params object[] items)\n        where T : class, IModelFromData, new()\n        => CodeApi.Cdf.AsStack<T>(items);\n\n    #endregion\n\n    public ITypedRazorModel MyModel => throw new(\"MyModel isn't meant to work in WebApi\"); // v20 CodeHelper.MyModel;\n\n    private CompileCodeHelper CompileCodeHlp => field ??= GetService<CompileCodeHelper>().Init(this);\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    public dynamic GetCode(string path, NoParamOrder npo = default, string className = default)\n        => CompileCodeHlp.CreateInstance(path /*relativePath: (this as IGetCodePath).CreateInstancePath*/, name: className);\n\n    #region MyContext & UniqueKey\n\n    /// <inheritdoc cref=\"ITypedApi.MyContext\" />\n    public ICmsContext MyContext => CodeApi.CmsContext;\n\n    /// <inheritdoc cref=\"ITypedApi.MyPage\" />\n    public ICmsPage MyPage => CodeApi.CmsContext.Page;\n\n    /// <inheritdoc cref=\"ITypedApi.MyUser\" />\n    public ICmsUser MyUser => CodeApi.CmsContext.User;\n\n    /// <inheritdoc cref=\"ITypedApi.MyView\" />\n    public ICmsView MyView => CodeApi.CmsContext.View;\n\n    /// <inheritdoc cref=\"ITypedApi.UniqueKey\" />\n    public string UniqueKey => Kit.Key.UniqueKey;\n\n    #endregion\n\n    #region  CreateInstance implementation\n\n    string IGetCodePath.CreateInstancePath { get; set; }\n\n    #endregion\n\n\n    #region File Response / Download\n\n    /// <inheritdoc cref=\"IDynamicWebApi.File\"/>\n    public dynamic File(NoParamOrder npo = default,\n        bool? download = null,\n        string virtualPath = null,\n        string contentType = null,\n        string fileDownloadName = null,\n        object contents = null\n    ) => new OqtWebApiShim(response: Response, owner: this)\n        .File(download: download, virtualPath: virtualPath, contentType: contentType, fileDownloadName: fileDownloadName, contents: contents);\n\n    #endregion\n\n    #region As / AsList WIP v17\n\n    /// <inheritdoc />\n    public T As<T>(object source, NoParamOrder npo = default)\n        where T : class, IModelFromData\n        => CodeApi.Cdf.AsCustom<T>(source: source);\n\n    /// <inheritdoc />\n    public IEnumerable<T> AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData\n        => CodeApi.Cdf.AsCustomList<T>(source: source, npo: npo, nullIfNull: nullIfNull);\n\n    #endregion\n\n    #region Customize\n\n    /// <inheritdoc cref=\"CodeTyped.Customize\"/>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    protected ICodeCustomizer Customize => field ??= CodeApi.GetService<ICodeCustomizer>(reuse: true);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Custom/OqtWebApiShim.cs",
    "content": "﻿using System.Text;\nusing System.Xml;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Sxc.Backend;\nusing ToSic.Sxc.Oqt.Server.Adam;\n\nnamespace ToSic.Sxc.Oqt.Server.Custom;\n\ninternal class OqtWebApiShim(HttpResponse response, ControllerBase owner)\n{\n    public HttpResponse Response { get; } = response;\n\n    public dynamic File(NoParamOrder npo = default,\n        // Important: the second parameter should _not_ be a string, otherwise the signature looks the same as the built-in File(...) method\n        bool? download = null,\n        string virtualPath = null, // important: this is the virtualPath, but it should not have the same name, to not confuse the compiler with same sounding param names\n        string contentType = null,\n        string fileDownloadName = null,\n        object contents = null // can be stream, string or byte[]\n    )\n    {\n        fileDownloadName = CustomApiHelpers.FileParamsInitialCheck(npo: npo, download: download, virtualPath: virtualPath, fileDownloadName: fileDownloadName, contents: contents);\n\n        // Try to figure out file mime type as needed\n        if (string.IsNullOrWhiteSpace(contentType))\n            contentType = OqtAssetsFileHelper.GetMimeType(fileDownloadName ?? virtualPath);\n\n        // check if this may just be a call to the built in file, which has two strings\n        // this can only be possible if only the virtualPath and contentType were set\n        if (!string.IsNullOrWhiteSpace(virtualPath))\n            return owner.File(virtualPath, contentType, fileDownloadName);\n\n        // add only header \"Content-Disposition: inline, file...\"\n        if (download != true)\n            Response.Headers.Add(\"Content-Disposition\", CustomApiHelpers.PrepareContentDispositionHeaderValue(download, fileDownloadName).ToString());\n\n        // in aspNetCore for File stream/content result in response\n        // fileDownloadName should be null to get header \"Content-Disposition: inline\"\n        // that will directly show content response in browser\n        // opposed to \"Content-Disposition: attachment; filename=...\" that file start file download\n        fileDownloadName = CustomApiHelpers.EnsureFileDownloadNameIsNullForInline(download, fileDownloadName);\n        Encoding encoding;\n        string mediaTypeHeaderValue;\n\n        switch (contents)\n        {\n            case XmlDocument xmlDoc:\n                var xmlStream = new MemoryStream();\n                xmlDoc.Save(xmlStream);\n                xmlStream.Position = 0;\n                contentType = CustomApiHelpers.XmlContentTypeFromContent(true, contentType);\n                encoding = CustomApiHelpers.GetEncoding(xmlDoc);\n                mediaTypeHeaderValue = CustomApiHelpers.PrepareMediaTypeHeaderValue(contentType, encoding).ToString();\n                return owner.File(xmlStream, mediaTypeHeaderValue, fileDownloadName);\n            case string stringBody:\n                contentType = CustomApiHelpers.XmlContentTypeFromContent(CustomApiHelpers.IsValidXml(stringBody), contentType);\n                encoding = CustomApiHelpers.GetEncoding(stringBody);\n                mediaTypeHeaderValue = CustomApiHelpers.PrepareMediaTypeHeaderValue(contentType, encoding).ToString();\n                return owner.File(System.Text.Encoding.UTF8.GetBytes(stringBody), mediaTypeHeaderValue, fileDownloadName);\n            case Stream streamBody:\n                contentType = CustomApiHelpers.XmlContentTypeFromContent(CustomApiHelpers.IsValidXml(streamBody), contentType);\n                encoding = CustomApiHelpers.GetEncoding(streamBody);\n                mediaTypeHeaderValue = CustomApiHelpers.PrepareMediaTypeHeaderValue(contentType, encoding).ToString();\n                return owner.File(streamBody, mediaTypeHeaderValue, fileDownloadName);\n            case byte[] charBody:\n                contentType = CustomApiHelpers.XmlContentTypeFromContent(CustomApiHelpers.IsValidXml(charBody), contentType);\n                encoding = CustomApiHelpers.GetEncoding(charBody);\n                mediaTypeHeaderValue = CustomApiHelpers.PrepareMediaTypeHeaderValue(contentType, encoding).ToString();\n                return owner.File(charBody, mediaTypeHeaderValue, fileDownloadName);\n            default:\n                throw new ArgumentException(\"Tried to provide file download but couldn't find content\");\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Custom/Oqtane.Api12.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Oqtane;\n\n/// <summary>\n/// Oqtane specific Api base class.\n///\n/// As of 2sxc v12 it's identical to [](xref:Custom.Hybrid.Api12) but this may be enhanced in future. \n/// </summary>\n[PublicApi]\npublic abstract class Api12 : Hybrid.Api12;"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Custom/Oqtane.Code12.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Oqtane;\n\n[PublicApi]\npublic abstract class Code12: ToSic.Sxc.Code.DynamicCode12;"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Data/OqtValueConverter.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Repository;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Adam.Sys.Security;\nusing ToSic.Sxc.Oqt.Server.Integration;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sys.Capabilities.Features.BuiltInFeatures;\n\nnamespace ToSic.Sxc.Oqt.Server.Data;\n\n/// <summary>\n/// The Oqtane implementation of the <see cref=\"IValueConverter\"/> which converts \"file:22\" or \"page:5\" to the url,\n/// </summary>\n[PrivateApi]\ninternal class OqtValueConverter(\n    LazySvc<IFileRepository> fileRepository,\n    LazySvc<IFolderRepository> folderRepository,\n    LazySvc<ITenantResolver> tenantResolver,\n    LazySvc<IPageRepository> pageRepository,\n    LazySvc<IServerPaths> serverPaths,\n    LazySvc<AliasResolver> aliasResolverLazy,\n    LazySvc<ISysFeaturesService> featuresLazy)\n    : ValueConverterBase(\"Oqt.ValCn\",\n        connect: [featuresLazy, fileRepository, folderRepository, tenantResolver, pageRepository, serverPaths, aliasResolverLazy])\n{\n    public LazySvc<IFileRepository> FileRepository { get; } = fileRepository;\n    public LazySvc<IFolderRepository> FolderRepository { get; } = folderRepository;\n    public LazySvc<ITenantResolver> TenantResolver { get; } = tenantResolver;\n    public LazySvc<IPageRepository> PageRepository { get; } = pageRepository;\n    public LazySvc<IServerPaths> ServerPaths { get; } = serverPaths;\n    public LazySvc<AliasResolver> AliasResolverLazy { get; } = aliasResolverLazy;\n\n    #region DI Constructor\n\n    protected Alias Alias\n    {\n        get\n        {\n            if (_alias != null) return _alias;\n            _alias = AliasResolverLazy.Value.Alias;\n            return _alias;\n        }\n    }\n\n    private Alias _alias;\n\n    #endregion\n\n    /// <inheritdoc />\n    public override string ToReference(string value)\n        => TryToResolveOneLinkToInternalOqtCode(value);\n\n    /// <inheritdoc />\n    public override string? ToValue(string? reference, Guid itemGuid = default)\n        => TryToResolveCodeToLink(itemGuid, reference);\n\n    /// <summary>\n    /// Will take a link like http://... to a file or page and try to return a DNN-style info like\n    /// Page:35 or File:43003\n    /// </summary>\n    /// <param name=\"potentialFilePath\"></param>\n    /// <remarks>\n    /// note: this can always use the current context, because this should happen\n    /// when saving etc. - which is always expected to happen in the owning portal\n    /// </remarks>\n    /// <returns></returns>\n    private string TryToResolveOneLinkToInternalOqtCode(string potentialFilePath)\n    {\n        // Try to find the Folder\n        var pathAsFolder = potentialFilePath.Backslash();\n        var folderPath = Path.GetDirectoryName(pathAsFolder);\n        var folder = FolderRepository.Value.GetFolder(Alias.SiteId, folderPath.EnsureOqtaneFolderFormat());\n        if (folder != null)\n        {\n            // Try file reference\n            var fileName = Path.GetFileNameWithoutExtension(pathAsFolder);\n            var files = FileRepository.Value.GetFiles(folder.FolderId);\n            var fileInfo = files.FirstOrDefault(f => f.Name == fileName);\n            if (fileInfo != null) return \"file:\" + fileInfo.FileId;\n        }\n\n        var pathAsPageLink = potentialFilePath.TrimLastSlash(); // no trailing slashes\n        // Try page / tab ID\n        var page = PageRepository.Value.GetPage(pathAsPageLink, Alias.SiteId);\n        return page != null\n            ? \"page:\" + page.PageId\n            : potentialFilePath;\n    }\n\n    ///// <summary>\n    ///// Will take a link like \"File:17\" and convert to \"Faq/screenshot1.jpg\"\n    ///// It will always deliver a relative path to the portal root\n    ///// </summary>\n    ///// <param name=\"itemGuid\">the item we're in - important for the feature which checks if the file is in this items ADAM</param>\n    ///// <param name=\"originalValue\"></param>\n    ///// <returns></returns>\n    //private string TryToResolveOqtCodeToLink(Guid itemGuid, string originalValue)\n    //{\n    //    try\n    //    {\n    //        return TryToResolveCodeToLink(itemGuid, originalValue);\n    //    }\n    //    catch /*(Exception e)*/\n    //    {\n    //        return originalValue;\n    //    }\n    //}\n\n    /// <summary>\n    /// Don't do anything here\n    /// </summary>\n    protected override void LogConversionExceptions(string originalValue, Exception e)\n    {\n        // 2021-04-26 2dm: We can't log errors here\n        // - on one hand we would flood the logs\n        // - on the other hand we have issues that if this happens during json-creation of a web-api, the Logger often can't find the DB/SiteState\n        //var wrappedEx = new Exception(\"Error when trying to lookup a friendly url of \\\"\" + originalValue + \"\\\"\", e);\n        //Logger.Value.Log(LogLevel.Error, this, LogFunction.Other, wrappedEx.Message);\n    }\n\n\n    protected override string ResolveFileLink(int linkId, Guid itemGuid)\n    {\n        var fileInfo = FileRepository.Value.GetFile(linkId);\n        if (fileInfo == null)\n            return null;\n\n        // find out if the user is allowed to resolve this link\n        #region special handling of issues in case something in the background is broken\n        try\n        {\n            var pathInAdam = Path.Combine(fileInfo.Folder.Path, fileInfo.Name).ForwardSlash();\n\n            // get appName and filePath\n            var adamFolder = \"adam/\";\n            var prefixStart = pathInAdam.IndexOf(adamFolder, StringComparison.OrdinalIgnoreCase);\n            pathInAdam = pathInAdam[(prefixStart + adamFolder.Length)..].TrimStart('/');\n            var indexOfSlash = pathInAdam.IndexOf('/');\n            var appName = pathInAdam[..indexOfSlash];\n            var filePath = pathInAdam[indexOfSlash..].TrimStart('/');\n\n            var result = $\"{Alias.Path}/app/{appName}/adam/{filePath}\".PrefixSlash();\n\n            // optionally do extra security checks (new in 10.02)\n            if (!featuresLazy.Value.IsEnabled(AdamRestrictLookupToEntity.Guid)) return result;\n\n            // check if it's in this item. We won't check the field, just the item, so the field is \"\"\n            return !AdamSecurity.PathIsInItemAdam(itemGuid, \"\", pathInAdam)\n                ? null\n                : result;\n        }\n        catch\n        {\n            return null;\n        }\n        #endregion\n    }\n\n    protected override string ResolvePageLink(int id)\n    {\n        var pageResolver = PageRepository.Value;\n\n        var page = pageResolver.GetPage(id);\n        if (page == null) return null;\n\n        return string.IsNullOrEmpty(Alias.Path) ? $\"/{page.Path}\" : $\"/{Alias.Path}/{page.Path}\";\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System.Collections.Generic;\nglobal using System.Linq;\nglobal using ToSic.Eav.WebApi.Sys;\nglobal using ToSic.Eav.WebApi.Sys.Admin;\nglobal using ToSic.Eav.WebApi.Sys.Context;\nglobal using ToSic.Eav.WebApi.Sys.Dto;\nglobal using ToSic.Eav.WebApi.Sys.Routing;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Wrappers;\nglobal using ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Installation/GlobalTypesCheck.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Server.Installation;\n\n// On first installation of 2sxc module in oqtane, SystemLoader can not load all 2sxc global types\n// because it has dependency on ToSic_Eav_* sql tables, before this tables are actually created by oqtane 2.3.x,\n// but after next restart of oqtane application all is ok, and all 2sxc global types are loaded as expected\n// this code will check if there is less than 50 global types and warn user to restart application to fix that\ninternal class GlobalTypesCheck(LazySvc<IAppReaderFactory> appReaders)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.GlbTCh\", connect: [appReaders])\n{\n    private static bool? _globalTypesCheckedAndError;\n\n    internal static OqtViewResultsDto InstallationErrorResult;\n\n    public bool WarnIfGlobalTypesAreNotLoaded(out OqtViewResultsDto oqtViewResultsDto)\n    {\n        // Don't repeat if already checked\n        if(_globalTypesCheckedAndError.HasValue)\n        {\n            oqtViewResultsDto = InstallationErrorResult;\n            return _globalTypesCheckedAndError.Value;\n        }\n            \n        // First time, run all checks\n        var errorMessage = string.Empty;\n\n        // Check if there is less than 50 global types and warn user to restart application.\n        _globalTypesCheckedAndError = appReaders.Value.GetSystemPreset().ContentTypes.Count() < 50;\n        if (_globalTypesCheckedAndError.Value)\n        {\n            errorMessage = \"<strong>Warning:</strong> The \\\"global types\\\" are not loaded. Please <a href=\\\"/admin/system\\\">Restart Application</a>.\";\n            InstallationErrorResult = new()\n            {\n                ErrorMessage = errorMessage,\n            };\n        }\n\n        oqtViewResultsDto = InstallationErrorResult;\n            \n        return !string.IsNullOrEmpty(errorMessage);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Installation/HotReloadEnabledCheck.cs",
    "content": "﻿using System.Diagnostics;\nusing System.Text.Json.Nodes;\nusing ToSic.Eav.Serialization.Sys.Json;\n\nnamespace ToSic.Sxc.Oqt.Server.Installation;\n\ninternal static class HotReloadEnabledCheck\n{\n    private static bool? _hotReloadEnabledCheckedAndError;\n\n    private static string errorMessage = \"Warning: You must run Oqtane without Hot-Reload to install Apps. See https://go.2sxc.org/oqt-hr\";\n\n    internal static void Check()\n    {\n        // Don't repeat if already checked\n        if (!_hotReloadEnabledCheckedAndError.HasValue)\n        {\n            // Check if Hot Reload is Enabled.\n            // When HotReloadEnabled is not false, special modules are loaded, so we try to find them.\n            _hotReloadEnabledCheckedAndError = IsModuleLoaded(\"Microsoft.AspNetCore.Watch.BrowserRefresh.dll\");\n            if (_hotReloadEnabledCheckedAndError.Value) \n                AddHotReloadProperty();\n        }\n\n        if (_hotReloadEnabledCheckedAndError.Value)\n            throw new(errorMessage);\n         \n    }\n\n    private static bool IsModuleLoaded(string moduleName)\n    {\n        return Process.GetCurrentProcess().Modules.OfType<ProcessModule>().Any(m => m.ModuleName.Contains(moduleName));\n    }\n\n    private static bool AddHotReloadProperty()\n    {\n        var launchSettingsFile = Path.Combine(Directory.GetCurrentDirectory(), $\"Properties\\\\launchSettings.json\");\n        if (!File.Exists(launchSettingsFile)) return false;\n        try\n        {\n            var launchSettingsJson = File.ReadAllText(launchSettingsFile);\n\n            var launchSettings = JsonNode.Parse(launchSettingsJson, JsonOptions.JsonNodeDefaultOptions, JsonOptions.JsonDocumentDefaultOptions);\n            var profiles = launchSettings?[\"profiles\"]?.AsObject();\n            var iisExpress = profiles?[\"IIS Express\"]?.AsObject();\n\n            // json configuration is wrong\n            if (iisExpress is null) return false;\n\n            // if hotReloadEnabled property exists do nothing\n            if (iisExpress?[\"hotReloadEnabled\"]?.AsValue() is not null) return false;\n\n            // add hotReloadEnabled: true\n            iisExpress?.Add(\"hotReloadEnabled\", true);\n\n            File.WriteAllText(launchSettingsFile, launchSettings?.ToJsonString(JsonOptions.UnsafeJsonWithoutEncodingHtml));\n\n            return true;\n        }\n        catch\n        {\n            return false;\n        }           \n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Installation/RefsInstalledCheck.cs",
    "content": "﻿using System.Reflection;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Server.Installation;\n\ninternal static class RefsInstalledCheck\n{\n    private static bool? _refsCheckedAndError;\n\n    internal static OqtViewResultsDto InstallationErrorResult;\n\n    const string MicrosoftAspNetCoreDll = \"Microsoft.AspNetCore.dll\";\n\n    internal static bool WarnIfRefsAreNotInstalled(out OqtViewResultsDto oqtViewResultsDto)\n    {\n        // Don't repeat if already checked\n        if(_refsCheckedAndError.HasValue)\n        {\n            oqtViewResultsDto = InstallationErrorResult;\n            return _refsCheckedAndError.Value;\n        }\n            \n        // First time, run all checks\n        var errorMessage = string.Empty;\n\n        // Check for \"refs\" folder.\n        // https://github.com/oqtane/oqtane.framework/issues/1272\n        var dllLocation = AppContext.BaseDirectory;\n        var refsPath = Path.Combine(dllLocation, \"refs\");\n        _refsCheckedAndError = !Directory.Exists(refsPath);\n        if (_refsCheckedAndError.Value)\n        {\n            if (Environment.Version.Major >= 5 & Environment.Version.Major < 6) // missing refs for Oqtane 2.0.0 on .NET5.0\n                errorMessage = \"<strong>Warning:</strong> The \\\"refs\\\" folder is missing. Please ensure that <strong><a href=\\\"https://github.com/2sic/oqtane-razor-refs/releases/download/1.0.0/net5.0-refs.zip\\\">net5.0-refs.zip</a></strong> is unzipped as explained in the recipe <a href=\\\"https://azing.org/2sxc/r/P0_y3L4a\\\" target=\\\"new\\\">Install refs for Oqtane 2.0.0 on .NET5.0</a>.\";\n            else if (Environment.Version.Major >= 6) // missing refs for Oqtane 3.0.0 on .NET6.0\n                errorMessage = \"<strong>Warning:</strong> The \\\"refs\\\" folder is missing. Please ensure that <strong><a href=\\\"https://github.com/2sic/oqtane-razor-refs/releases/download/1.0.0/net6.0-refs.zip\\\">net6.0-refs.zip</a></strong> is unzipped as explained in the recipe <a href=\\\"https://azing.org/2sxc/r/nQjqJ_Wr\\\" target=\\\"new\\\">Install refs for Oqtane 3.0.0 on .NET6.0</a>.\";\n            else\n                errorMessage = \"<strong>Warning:</strong> The \\\"refs\\\" folder is missing. Please ensure that <strong>Razor.Compiler.Dependencies.zip</strong> is unzipped as explained in the installation recipe <a href=\\\"https://azing.org/2sxc/r/fOG3aByY\\\" target=\\\"new\\\">https://azing.org/2sxc/r/fOG3aByY</a>.\";\n        }\n        else\n        {\n            // When we have refs, we still need to check is it right version. It is possible that Oqtane was upgraded to newer version of run-time and that current refs are outdated.\n\n            // Microsoft.AspNetCore.dll will be used as significant reference assembly to check 'refs' version.\n            var referenceAssemblyPath = Path.Combine(refsPath, MicrosoftAspNetCoreDll);\n\n            _refsCheckedAndError = !File.Exists(referenceAssemblyPath);\n            if (_refsCheckedAndError.Value) // Microsoft.AspNetCore.dll is missing from 'refs' folder\n                errorMessage = \"<strong>Warning:</strong> The \\\"refs\\\" have missing Reference assemblies. Please ensure that all dlls from <strong>refs.zip</a></strong> are unzipped directly in 'refs' folder. You can get refs.zip from <a href=\\\"https://github.com/2sic/oqtane-razor-refs/releases\\\" target =\\\"new\\\">oqtane-razor-refs</a>.\";\n            else\n            {\n                // Is the 'refs' version older than current .NET run-time version?\n                var referenceAssemblyName = AssemblyName.GetAssemblyName(referenceAssemblyPath);\n                _refsCheckedAndError = referenceAssemblyName.Version?.Major < Environment.Version.Major;\n                if (_refsCheckedAndError.Value)\n                    errorMessage = $\"<strong>Warning:</strong> The Reference assemblies version {referenceAssemblyName.Version} in \\\"refs\\\" folder is older than current .NET run-time version {Environment.Version}. Please delete local \\\"refs\\\" folder and ensure that right <strong><a href=\\\"https://github.com/2sic/oqtane-razor-refs/releases/download/1.0.0/net6.0-refs.zip\\\">net6.0-refs.zip</a></strong> is unzipped as explained in the recipe <a href=\\\"https://azing.org/2sxc/r/nQjqJ_Wr\\\" target=\\\"new\\\">Install refs for Oqtane 3.0.0 on .NET6.0</a>.\";\n            }\n        }\n\n        // if we have any error, set InstallationErrorResult\n        if (_refsCheckedAndError.Value)\n        {\n            InstallationErrorResult = new()\n            {\n                ErrorMessage = errorMessage,\n            };\n        }\n\n        oqtViewResultsDto = InstallationErrorResult;\n\n        return _refsCheckedAndError.Value;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Installation/SxcManager.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Oqtane.Infrastructure;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing System.Reflection;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Oqt.Shared.Models;\nusing File = System.IO.File;\nusing LogLevel = Microsoft.Extensions.Logging.LogLevel;\n\nnamespace ToSic.Sxc.Oqt.Server.Installation;\n\n/// <summary>\n/// Handles install/upgrade steps for 2sxc on Oqtane.\n/// </summary>\n/// <remarks>\n/// WARNING: Careful when renaming / moving, the name is listed in the ModuleInfo.cs in the Client.\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcManager(\n    ISqlRepository sql,\n    IServiceScopeFactory serviceScopeFactory,\n    IWebHostEnvironment environment,\n    //IConfigManager configManager,\n    ILogger<SxcManager> logger) : IInstallable\n{\n    private const string CleanInstallMigrationId = \"ToSic.Sxc.Install\";\n    private const string MigrationPrefix = \"ToSic.Sxc.\";\n    private const string MigrationTable = \"__EFMigrationsHistory\";\n    private sealed record AssemblyCleanupRule(string AssemblyName, int? MinRuntimeMajor = null, int? MaxRuntimeMajor = null);\n\n    /// <summary>\n    /// Installs or upgrades 2sxc for the specified tenant and version.\n    /// </summary>\n    /// <param name=\"tenant\">The tenant being installed or upgraded.</param>\n    /// <param name=\"version\">The target module version.</param>\n    /// <returns>\n    /// <c>true</c> if installation/upgrade completed successfully; otherwise <c>false</c>.\n    /// </returns>\n    public bool Install(Tenant tenant, string version)\n    {\n        LogInfo($\"2sxc {EavSystemInfo.VersionString} install: Starting installation for version {version} on tenant '{tenant.Name}'\");\n\n        // 1) Clean install\n        if (IsCleanInstall(tenant))\n        {\n            LogInfo($\"2sxc {EavSystemInfo.VersionString} install: Clean install detected for tenant '{tenant.Name}'. Running '{CleanInstallMigrationId}.sql'.\");\n            if (!RunCleanInstall(tenant))\n            {\n                LogError($\"2sxc {EavSystemInfo.VersionString} install ERROR: Clean install script '{CleanInstallMigrationId}.sql' failed for tenant '{tenant.Name}'.\");\n                return false;\n            }\n\n            LogInfo($\"2sxc {EavSystemInfo.VersionString} install: Clean install completed successfully for tenant '{tenant.Name}'.\");\n            return true;\n        }\n\n        // 2) Version-specific upgrade hooks (non-SQL changes)\n        ApplyVersionUpgrade(tenant, version);\n\n        // 3) SQL migration per version (.sql embedded resource)\n        var migrationId = BuildMigrationId(version);\n        return ApplyMigrationIfNeeded(tenant, migrationId);\n    }\n\n    /// <summary>\n    /// Executes the uninstall SQL script for the specified tenant.\n    /// </summary>\n    /// <param name=\"tenant\">The tenant to uninstall 2sxc from.</param>\n    /// <returns><c>true</c> when the uninstall script succeeds; otherwise <c>false</c>.</returns>\n    public bool Uninstall(Tenant tenant)\n        => sql.ExecuteScript(tenant, GetType().Assembly, \"ToSic.Sxc.Uninstall.sql\");\n\n    /// <summary>\n    /// Applies non-SQL upgrade logic for known versions.\n    /// Runs on every install or upgrade for every explicitly defined version in ToSic.Sxc.Oqt.Client/Content/ModuleInfo.cs?plain=1#L35.\n    /// plus latest version, for all tenants, so it can be used for general cleanup tasks on every install/upgrade.\n    /// </summary>\n    /// <param name=\"tenant\">The current tenant context.</param>\n    /// <param name=\"version\">The version identifier from Oqtane.</param>\n    private void ApplyVersionUpgrade(Tenant tenant, string version)\n    {\n        using var scope = serviceScopeFactory.CreateScope();\n\n        // Set the current tenant context for the upgrade\n        scope.ServiceProvider.GetRequiredService<ITenantManager>()\n            .SetTenant(tenant.TenantId);\n\n        switch (version.Replace(\".\", \"-\"))\n        {\n            case ModuleInfoConstants.V20_00_00: // Runs on every install or upgrade since the version is hard-coded in ToSic.Sxc.Oqt.Client/Content/ModuleInfo.cs?plain=1#L35.\n                Upgrade_20_00_00(tenant, version);\n                break;\n            case ModuleInfoConstants.V21_00_00: // Runs on every install or upgrade since the version is hard-coded in ToSic.Sxc.Oqt.Client/Content/ModuleInfo.cs?plain=1#L35.\n                Upgrade_21_00_00(tenant, version);\n                break;\n        }\n    }\n\n    /// <summary>\n    /// Cleans up specific 2sxc/eav old assemblies in v20.00.00,\n    /// which are no longer needed and may cause conflicts.\n    /// </summary>\n    /// <param name=\"tenant\">The tenant being upgraded.</param>\n    /// <param name=\"version\">The version identifier being processed.</param>\n    private void Upgrade_20_00_00(Tenant tenant, string version)\n    {\n        LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {nameof(Upgrade_20_00_00)} {version}\");\n\n        AssemblyCleanupRule[] assemblyCleanupRules =\n        [\n            new(\"ToSic.Sxc.dll\"),\n            new(\"ToSic.Eav.dll\"),\n            new(\"ToSic.Eav.Core.dll\"),\n            new(\"ToSic.Lib.Core.dll\")\n        ];\n\n        RemoveAssemblies(tenant, assemblyCleanupRules, version);\n    }\n\n\n    /// <summary>\n    /// Performs 2sxc folder reorganization for multi tenants support in v21.00.00\n    /// and cleans up 1 net9 assembly in net10 runtime, which is no longer needed and may cause conflicts.\n    /// </summary>\n    /// <param name=\"tenant\">The tenant being upgraded.</param>\n    /// <param name=\"version\">The version identifier being processed.</param>\n    private void Upgrade_21_00_00(Tenant tenant, string version)\n    {\n        LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {nameof(Upgrade_21_00_00)} {version}\");\n\n        if (tenant.Name != TenantNames.Master)\n        {\n            LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {nameof(Upgrade_21_00_00)} skipped because tenant '{tenant.Name}' is not '{TenantNames.Master}'.\");\n            return;\n        }\n\n        try\n        {\n            var appRoot = Path.Combine(environment.ContentRootPath, OqtConstants.AppRoot);\n            var destinationBase = Path.Combine(appRoot, OqtConstants.TenantsFolderName, tenant.TenantId.ToString(), OqtConstants.SitesFolderName);\n\n            MoveSubfoldersToDestinationBase(appRoot, destinationBase, version);\n        }\n        catch (Exception ex)\n        {\n            LogError($\"2sxc {EavSystemInfo.VersionString} install error: {version} Upgrade Error moving 2sxc folders - {ex}\");\n        }\n\n        AssemblyCleanupRule[] assemblyCleanupRules =\n        [\n            new(\"Microsoft.AspNetCore.Authorization.dll\", MinRuntimeMajor: 10)\n        ];\n\n        RemoveAssemblies(tenant, assemblyCleanupRules, version);\n    }\n\n    /// <summary>\n    /// Removes outdated assemblies according to runtime-specific cleanup rules.\n    /// </summary>\n    /// <param name=\"tenant\">The tenant being upgraded.</param>\n    /// <param name=\"assemblyCleanupRules\">Assembly deletion rules with runtime constraints.</param>\n    /// <param name=\"version\">The version identifier for logging.</param>\n    private void RemoveAssemblies(Tenant tenant, AssemblyCleanupRule[] assemblyCleanupRules, string version)\n    {\n        var runtimeMajor = Environment.Version.Major;\n        LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {nameof(RemoveAssemblies)} rules:{assemblyCleanupRules.Length}, runtimeMajor:{runtimeMajor}, version:{version}\");\n\n        // In a development environment assemblies cannot be removed as the debugger runs from /bin and locks the files\n        if (tenant.Name == TenantNames.Master && !environment.IsDevelopment())\n        {\n            var matchingRules = assemblyCleanupRules\n                .Where(rule => IsRuntimeMatch(rule, runtimeMajor))\n                .ToArray();\n            var skippedRules = assemblyCleanupRules\n                .Where(rule => !IsRuntimeMatch(rule, runtimeMajor))\n                .ToArray();\n\n            LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {version} Assembly cleanup rule matches {matchingRules.Length}/{assemblyCleanupRules.Length} for runtime major {runtimeMajor}.\");\n            if (skippedRules.Length > 0)\n            {\n                LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {version} Skipping assembly cleanup due to runtime criteria: {string.Join(\", \", skippedRules.Select(DescribeRule))}\");\n            }\n\n            foreach (var rule in matchingRules)\n            {\n                try\n                {\n                    var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);\n                    var filepath = Path.Combine(binFolder!, rule.AssemblyName);\n                    LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {version} Removing {rule.AssemblyName} - '{filepath}'\");\n                    if (File.Exists(filepath))\n                        File.Delete(filepath);\n                }\n                catch (Exception ex)\n                {\n                    LogError($\"2sxc {EavSystemInfo.VersionString} install error: {version} Upgrade Error Removing {rule.AssemblyName} - {ex}\");\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Determines whether a cleanup rule applies to the current runtime major version.\n    /// </summary>\n    /// <param name=\"rule\">The cleanup rule to evaluate.</param>\n    /// <param name=\"runtimeMajor\">The runtime major version.</param>\n    /// <returns><c>true</c> if the runtime is within the rule bounds; otherwise <c>false</c>.</returns>\n    private static bool IsRuntimeMatch(AssemblyCleanupRule rule, int runtimeMajor)\n        => (!rule.MinRuntimeMajor.HasValue || runtimeMajor >= rule.MinRuntimeMajor.Value)\n           && (!rule.MaxRuntimeMajor.HasValue || runtimeMajor <= rule.MaxRuntimeMajor.Value);\n\n    /// <summary>\n    /// Creates a readable representation of an assembly cleanup rule.\n    /// </summary>\n    /// <param name=\"rule\">The rule to describe.</param>\n    /// <returns>A formatted string with assembly name and runtime bounds.</returns>\n    private static string DescribeRule(AssemblyCleanupRule rule)\n    {\n        var min = rule.MinRuntimeMajor?.ToString() ?? \"-inf\";\n        var max = rule.MaxRuntimeMajor?.ToString() ?? \"+inf\";\n        return $\"{rule.AssemblyName} [runtime {min}..{max}]\";\n    }\n\n    /// <summary>\n    /// Moves all first-level folders from the source root into the destination base.\n    /// </summary>\n    /// <param name=\"sourceRoot\">The root folder containing source subfolders.</param>\n    /// <param name=\"destinationBase\">The destination base folder.</param>\n    /// <param name=\"version\">The version identifier for logging.</param>\n    private void MoveSubfoldersToDestinationBase(string sourceRoot, string destinationBase, string version)\n    {\n        LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {nameof(MoveSubfoldersToDestinationBase)} source:'{sourceRoot}', dest:'{destinationBase}', version:{version}\");\n\n        if (!Directory.Exists(sourceRoot))\n        {\n            LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} Source folder not found, skipping: '{sourceRoot}'\");\n            return;\n        }\n\n        Directory.CreateDirectory(destinationBase);\n\n        foreach (var directory in Directory.GetDirectories(sourceRoot))\n        {\n            var folderName = Path.GetFileName(directory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));\n\n            if (string.IsNullOrWhiteSpace(folderName))\n                continue;\n\n            // Don't try to move the new structure folder back into itself.\n            if (folderName.Equals(OqtConstants.TenantsFolderName, StringComparison.OrdinalIgnoreCase))\n                continue;\n\n            var target = Path.Combine(destinationBase, folderName);\n            try\n            {\n                var success = MoveDirectoryWithRetry(source: directory, target: target, version: version);\n                if (!success)\n                    LogError($\"2sxc {EavSystemInfo.VersionString} install error: {version} Could not move folder '{directory}' -> '{target}'. Manual intervention may be required.\");\n            }\n            catch (Exception ex)\n            {\n                LogError($\"2sxc {EavSystemInfo.VersionString} install error: {version} Unexpected error moving folder '{directory}' -> '{target}' - {ex}\");\n            }\n        }\n    }\n\n    /// <summary>\n    /// Retries a folder move/merge operation multiple times before failing.\n    /// </summary>\n    /// <param name=\"source\">The source directory path.</param>\n    /// <param name=\"target\">The target directory path.</param>\n    /// <param name=\"version\">The version identifier for logging.</param>\n    /// <returns><c>true</c> if the directory was moved or merged; otherwise <c>false</c>.</returns>\n    private bool MoveDirectoryWithRetry(string source, string target, string version)\n    {\n        const int maxAttempts = 10;\n        for (var attempt = 1; attempt <= maxAttempts; attempt++)\n        {\n            try\n            {\n                MoveDirectoryMerged(source, target, version);\n                return true;\n            }\n            catch (IOException ex) when (attempt < maxAttempts)\n            {\n                LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} Move attempt {attempt}/{maxAttempts} IO error, retrying '{source}' -> '{target}': {ex.Message}\");\n                Thread.Sleep(150 * attempt);\n            }\n            catch (UnauthorizedAccessException ex) when (attempt < maxAttempts)\n            {\n                LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} Move attempt {attempt}/{maxAttempts} access error, retrying '{source}' -> '{target}': {ex.Message}\");\n                Thread.Sleep(150 * attempt);\n            }\n            catch (Exception ex) when (attempt < maxAttempts)\n            {\n                LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} Move attempt {attempt}/{maxAttempts} error, retrying '{source}' -> '{target}': {ex.Message}\");\n                Thread.Sleep(150 * attempt);\n            }\n        }\n\n        // Final attempt failed - don't throw, so we can continue with other folders.\n        try\n        {\n            MoveDirectoryMerged(source, target, version);\n            return true;\n        }\n        catch (Exception ex)\n        {\n            LogError($\"2sxc {EavSystemInfo.VersionString} install error: {version} Failed moving folder '{source}' -> '{target}' after {maxAttempts} attempts - {ex.Message}\");\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// Moves a directory if possible; otherwise merges content into an existing target.\n    /// </summary>\n    /// <param name=\"source\">The source directory path.</param>\n    /// <param name=\"target\">The target directory path.</param>\n    /// <param name=\"version\">The version identifier for logging.</param>\n    private void MoveDirectoryMerged(string source, string target, string version)\n    {\n        if (!Directory.Exists(source))\n            return;\n\n        if (!Directory.Exists(target))\n        {\n            try\n            {\n                LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {version} Moving folder '{source}' -> '{target}'\");\n                Directory.Move(source, target);\n                return;\n            }\n            catch (IOException ex)\n            {\n                LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} Could not move folder directly, will merge instead '{source}' -> '{target}': {ex.Message}\");\n            }\n            catch (UnauthorizedAccessException ex)\n            {\n                LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} Could not move folder directly due to access, will merge instead '{source}' -> '{target}': {ex.Message}\");\n            }\n\n            Directory.CreateDirectory(target);\n        }\n\n        LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {version} Merging folder '{source}' -> '{target}'\");\n\n        foreach (var subDir in Directory.GetDirectories(source))\n        {\n            var name = Path.GetFileName(subDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));\n            if (string.IsNullOrWhiteSpace(name)) continue;\n\n            var success = MoveDirectoryWithRetry(subDir, Path.Combine(target, name), version);\n            if (!success)\n                LogError($\"2sxc {EavSystemInfo.VersionString} install error: {version} Could not move subfolder '{subDir}' into '{target}'.\");\n        }\n\n        foreach (var file in Directory.GetFiles(source))\n        {\n            var name = Path.GetFileName(file);\n            if (string.IsNullOrWhiteSpace(name)) continue;\n\n            var destinationFile = Path.Combine(target, name);\n            if (File.Exists(destinationFile))\n            {\n                LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} Skipping file because destination already exists: '{destinationFile}'\");\n                continue;\n            }\n\n            MoveFileWithRetry(file, destinationFile, version);\n        }\n\n        // Try clean up the now-empty folder. Ignore errors in case something is still locked.\n        try\n        {\n            if (Directory.GetFileSystemEntries(source).Length == 0)\n            {\n                Directory.Delete(source, recursive: false);\n                LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {version} Removed empty folder '{source}'\");\n            }\n        }\n        catch (Exception ex)\n        {\n            LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} Could not delete folder '{source}': {ex.Message}\");\n        }\n    }\n\n    /// <summary>\n    /// Moves a file with retries to tolerate transient IO and access errors.\n    /// </summary>\n    /// <param name=\"sourceFile\">The source file path.</param>\n    /// <param name=\"targetFile\">The target file path.</param>\n    /// <param name=\"version\">The version identifier for logging.</param>\n    private void MoveFileWithRetry(string sourceFile, string targetFile, string version)\n    {\n        const int maxAttempts = 10;\n        for (var attempt = 1; attempt <= maxAttempts; attempt++)\n        {\n            try\n            {\n                LogInfo($\"2sxc {EavSystemInfo.VersionString} install: {version} Moving file '{sourceFile}' -> '{targetFile}'\");\n                File.Move(sourceFile, targetFile);\n                return;\n            }\n            catch (IOException ex) when (attempt < maxAttempts)\n            {\n                LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} File move attempt {attempt}/{maxAttempts} IO error, retrying '{sourceFile}' -> '{targetFile}': {ex.Message}\");\n                Thread.Sleep(150 * attempt);\n            }\n            catch (UnauthorizedAccessException ex) when (attempt < maxAttempts)\n            {\n                LogWarn($\"2sxc {EavSystemInfo.VersionString} install: {version} File move attempt {attempt}/{maxAttempts} access error, retrying '{sourceFile}' -> '{targetFile}': {ex.Message}\");\n                Thread.Sleep(150 * attempt);\n            }\n        }\n\n        LogError($\"2sxc {EavSystemInfo.VersionString} install error: {version} Failed moving file '{sourceFile}' -> '{targetFile}' after {maxAttempts} attempts.\");\n    }\n\n\n    #region Migration helpers\n    /// <summary>\n    /// Builds the migration identifier used for SQL scripts and history records.\n    /// </summary>\n    /// <param name=\"version\">The version string.</param>\n    /// <returns>The migration identifier.</returns>\n    private static string BuildMigrationId(string version) => $\"{MigrationPrefix}{version}\";\n\n    /// <summary>\n    /// Creates a SQL query that checks whether a migration is already registered.\n    /// </summary>\n    /// <param name=\"migrationId\">The migration identifier.</param>\n    /// <returns>A SQL select statement for existence checks.</returns>\n    private static string CheckMigrationHistory(string migrationId)\n        => $\"SELECT 1 FROM {MigrationTable} WHERE MigrationId = '{migrationId}'\";\n\n    // We are using SQL scripts rather than EF migrations, so we seed the migration history table\n    /// <summary>\n    /// Creates a SQL statement that records a migration in EF migration history if missing.\n    /// </summary>\n    /// <param name=\"migrationId\">The migration identifier.</param>\n    /// <returns>A SQL command that conditionally inserts a history record.</returns>\n    private static string RegisterInMigrationHistory(string migrationId)\n        => $\"\"\"\n            IF NOT EXISTS({CheckMigrationHistory(migrationId)})\n            INSERT INTO __EFMigrationsHistory(MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n            VALUES('{migrationId}', '{EavSystemInfo.VersionString}', SYSDATETIME(), '{Constants.Version}')\n            \"\"\";\n\n    /// <summary>\n    /// Executes a version migration script when needed and records it in migration history.\n    /// </summary>\n    /// <param name=\"tenant\">The tenant being upgraded.</param>\n    /// <param name=\"migrationId\">The migration identifier.</param>\n    /// <returns><c>true</c> if migration is applied or already present; otherwise <c>false</c>.</returns>\n    private bool ApplyMigrationIfNeeded(Tenant tenant, string migrationId)\n    {\n        var fileName = $\"{migrationId}.sql\";\n        var script = sql.GetScriptFromAssembly(GetType().Assembly, fileName);\n\n        if (string.IsNullOrEmpty(script))\n        {\n            LogWarn($\"2sxc {EavSystemInfo.VersionString} install: SQL script '{migrationId}.sql' do not exists as embedded resource in assembly. Skipping.\");\n            return true;\n        }\n\n        if (Exists(sql, tenant, CheckMigrationHistory(migrationId)))\n        {\n            LogWarn($\"2sxc {EavSystemInfo.VersionString} install: Migration for version '{migrationId}' already present in history. Skipping SQL script '{migrationId}.sql'.\");\n            return true;\n        }\n\n        try\n        {\n            sql.ExecuteScript(tenant, script);\n            LogInfo($\"2sxc {EavSystemInfo.VersionString} install: SQL script '{migrationId}.sql' executed successfully.\");\n        }\n        catch\n        {\n            LogError($\"2sxc {EavSystemInfo.VersionString} install ERROR: SQL script '{migrationId}.sql' failed.\");\n            return false;\n        }\n\n        var affected = sql.ExecuteNonQuery(tenant, RegisterInMigrationHistory(migrationId));\n        if (affected <= 0)\n        {\n            LogWarn($\"2sxc {EavSystemInfo.VersionString} install WARNING: Migration '{migrationId}' was already recorded in migration history.\");\n            return true;\n        }\n\n        LogInfo($\"2sxc {EavSystemInfo.VersionString} install: Migration history updated for '{migrationId}'.\");\n        return true;\n    }\n    #endregion\n\n\n    #region Existence checks\n    // DB-agnostic existence check using a SELECT (never use ExecuteNonQuery for SELECTs - it returns -1)\n    private static string HasSxcDb\n        => \"\"\"\n            SELECT 1\n            WHERE\n                (\n                    EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'TsDynData%' OR TABLE_NAME LIKE 'ToSIC_EAV_%')\n                )\n                OR\n                (\n                    EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '__EFMigrationsHistory')\n                    AND EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId LIKE 'ToSic.Sxc.%')\n                )\n            \"\"\";\n\n    /// <summary>\n    /// Determines whether the tenant already contains a 2sxc database footprint.\n    /// </summary>\n    /// <param name=\"tenant\">The tenant to inspect.</param>\n    /// <returns><c>true</c> if 2sxc data exists; otherwise <c>false</c>.</returns>\n    private bool IsCleanInstall(Tenant tenant)\n    {\n        var exists = Exists(sql, tenant, HasSxcDb);\n        LogInfo($\"2sxc {EavSystemInfo.VersionString} install: Clean install status: {!exists}\");\n        return !exists;\n    }\n\n    /// <summary>\n    /// Runs the clean-install SQL script for the tenant.\n    /// </summary>\n    /// <param name=\"tenant\">The tenant to initialize.</param>\n    /// <returns><c>true</c> when the clean install script succeeds; otherwise <c>false</c>.</returns>\n    private bool RunCleanInstall(Tenant tenant)\n        => sql.ExecuteScript(tenant, GetType().Assembly, $\"{CleanInstallMigrationId}.sql\");\n\n    /// <summary>\n    /// Executes a select query and returns whether at least one row exists.\n    /// </summary>\n    /// <param name=\"sql\">The SQL repository.</param>\n    /// <param name=\"tenant\">The tenant context for query execution.</param>\n    /// <param name=\"select\">The SQL select statement.</param>\n    /// <returns><c>true</c> if the query returns a row; otherwise <c>false</c>.</returns>\n    private static bool Exists(ISqlRepository sql, Tenant tenant, string select)\n    {\n        using var reader = sql.ExecuteReader(tenant, select);\n        return reader.Read();\n    }\n    #endregion\n\n\n    #region Logging helpers\n    /// <summary>\n    /// Writes an informational installation log entry.\n    /// </summary>\n    /// <param name=\"message\">The log message.</param>\n    private void LogInfo(string message) => logger.Log(LogLevel.Information, Utilities.LogMessage(this, message));\n    /// <summary>\n    /// Writes a warning installation log entry.\n    /// </summary>\n    /// <param name=\"message\">The log message.</param>\n    private void LogWarn(string message) => logger.Log(LogLevel.Warning, Utilities.LogMessage(this, message));\n    /// <summary>\n    /// Writes an error installation log entry.\n    /// </summary>\n    /// <param name=\"message\">The log message.</param>\n    private void LogError(string message) => logger.LogError(Utilities.LogMessage(this, message));\n    #endregion\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Integration/OqtFolderHelper.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Integration;\n\ninternal static class OqtFolderHelper\n{\n    // ensure backslash on the end of path, but not on the start\n    // except for edge case path = string.Empty\n    public static string EnsureOqtaneFolderFormat(this string path) => string.IsNullOrEmpty(path) ? path : path.Trim().ForwardSlash().TrimPrefixSlash().TrimLastSlash() + '/';\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Integration/OqtLogging.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Shared.Dev;\n\nnamespace ToSic.Sxc.Oqt.Server.Integration;\n\ninternal static class OqtLogging\n{\n    /// <summary>\n    /// Activate extended logging for a specific duration\n    /// </summary>\n    /// <param name=\"duration\"></param>\n    /// <returns></returns>\n    public static string ActivateForDuration(int duration)\n    {\n        WipConstants.DontDoAnythingImplementLater();\n\n        //var prop = GlobalConfiguration.Configuration.Properties;\n        //prop.GetOrAdd(Constants.AdvancedLoggingEnabledKey, duration > 0);\n        var timeout = DateTime.Now.AddMinutes(duration);\n        //prop.AddOrUpdate(Constants.AdvancedLoggingTillKey, timeout, (a, b) => timeout);\n        return $\"test-test Extended logging activated for {duration} minutes to {timeout}\";\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Integration/OqtModuleHelper.cs",
    "content": "﻿using Oqtane.Repository;\n\nnamespace ToSic.Sxc.Oqt.Server.Integration;\n\n// TODO: @STV I have a feeling this isn't used any where?\ninternal class OqtModuleHelper(\n    IModuleRepository moduleRepository,\n    IModuleDefinitionRepository moduleDefinitionRepository)\n{\n    /// <summary>\n    /// Detect is 2sxc Content app\n    /// </summary>\n    /// <param name=\"moduleId\">module id</param>\n    /// <returns>bool</returns>\n\n    public bool IsContentApp(int moduleId)\n    {\n        var module = moduleRepository.GetModule(moduleId);\n        var moduleDefinition = moduleDefinitionRepository.GetModuleDefinitions(module.SiteId).ToList().Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);\n        return moduleDefinition?.Name == \"Content\";\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Integration/Polymorphism/OqtKoiCssFrameworkDetector.cs",
    "content": "﻿using Connect.Koi.Detectors;\n\nnamespace ToSic.Sxc.Oqt.Server.Polymorphism;\n\ninternal class OqtKoiCssFrameworkDetector : ICssFrameworkDetector\n{\n    private string _bootstrapVersion;\n\n    public string AutoDetect()\n    {\n        return _bootstrapVersion ??= GetBootstrapVersion();\n    }\n\n    private static string GetBootstrapVersion()\n    {\n        var oqtaneVersion = GetOqtaneVersion();\n\n        // bs5 for 2.2\n        if (oqtaneVersion >= new Version(2, 2))\n            return Connect.Koi.CssFrameworks.Bootstrap5;\n\n        // bs4 for < 2.2\n        return Connect.Koi.CssFrameworks.Bootstrap4;\n    }\n\n    private static Version GetOqtaneVersion()\n    {\n        return Version.TryParse(Oqtane.Shared.Constants.Version, out var ver) ? ver : new(1, 0);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Integration/SettingsHelper.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared.Dev;\n\nnamespace ToSic.Sxc.Oqt.Server.Integration;\n\ninternal class SettingsHelper(ISettingRepository settingRepository)\n{\n    public Dictionary<string, string> Settings;\n\n    public SettingsHelper Init(string entityName, int? id)\n    {\n        Settings = GetSettings(settingRepository.GetSettings(entityName, id ?? -1).ToList());\n        return this;\n    }\n\n    // Convert settings collection to Dictionary.\n    private Dictionary<string, string> GetSettings(List<Setting> settings)\n    {\n        return settings.OrderBy(item => item.SettingName)\n            .ToList()\n            .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);\n    }\n\n    public Setting GetSetting(string entityName, int entityId, string settingName)\n    {\n        return settingRepository\n            .GetSettings(entityName, entityId)\n            .FirstOrDefault(item => item.SettingName == settingName);\n    }\n\n    public void DeleteSetting(string entityName, int entityId, string settingName)\n    {\n        var delete = settingRepository\n            .GetSettings(entityName, entityId)\n            .FirstOrDefault(item => item.SettingName == settingName);\n\n        if (delete != null)\n        {\n            //_settingRepository.DeleteSetting(settingId: delete.SettingId); // can't use in Oqt 3.0.1+ because of change in signature\n            // workaround code that works in Oqt 2.3.1+\n            delete.SettingValue = string.Empty;\n            delete.ModifiedOn = DateTime.UtcNow;\n            delete.ModifiedBy = WipConstants.SettingsChangeUserId;\n            settingRepository.UpdateSetting(delete);\n        }\n    }\n\n    public void UpdateSetting(string entityName, int entityId, string settingName, string settingValue)\n    {\n        var update = settingRepository\n            .GetSettings(entityName, entityId)\n            .FirstOrDefault(item => item.SettingName == settingName);\n\n        if (update != null)\n        {\n            update.SettingValue = settingValue;\n            update.ModifiedOn = DateTime.UtcNow;\n            update.ModifiedBy = WipConstants.SettingsChangeUserId;\n            settingRepository.UpdateSetting(update);\n        }\n        else\n            settingRepository.AddSetting(new()\n            {\n                CreatedBy = WipConstants.SettingsChangeUserId,\n                CreatedOn = DateTime.UtcNow,\n                EntityName = EntityNames.Module,\n                EntityId = entityId, \n                ModifiedOn = DateTime.UtcNow, \n                ModifiedBy = WipConstants.SettingsChangeUserId,\n                SettingName = settingName, \n                SettingValue = settingValue\n            });\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Integration/readme.md",
    "content": "﻿# Integration\n\nThis contains code/classes which are Oqtane only, so nothing that inherits from 2sxc or something."
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/LookUps/OqtModuleLookUp.cs",
    "content": "﻿using Oqtane.Models;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing static ToSic.Sxc.LookUp.Sys.LookUpConstants;\n\nnamespace ToSic.Sxc.Oqt.Server.LookUps;\n\ninternal class OqtModuleLookUp(ISxcCurrentContextService ctxService) : LookUpBase(SourceModule, \"LookUp in Oqtane Module\")\n{\n    private Module Module { get; set; }\n\n    public Module GetSource()\n    {\n        if (_alreadyTried) return null;\n        _alreadyTried = true;\n        var ctx = ctxService.BlockContextOrNull();\n        var module = (OqtModule)ctx?.Module;\n        return module?.GetContents();\n    }\n\n    private bool _alreadyTried;\n\n    public override string Get(string key, string format)\n    {\n        try\n        {\n            Module ??= GetSource();\n\n            if (Module == null) return null;\n\n            return key.ToLowerInvariant() switch\n            {\n                KeyId => $\"{Module.ModuleId}\",\n                OldDnnModuleId => $\"Warning: '{OldDnnModuleId}' was requested, but the {nameof(OqtModuleLookUp)} source can only answer to '{KeyId}'\",\n                _ => string.Empty\n            };\n        }\n        catch\n        {\n            return string.Empty;\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/LookUps/OqtPageLookUp.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sources;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing static ToSic.Sxc.LookUp.Sys.LookUpConstants;\n\nnamespace ToSic.Sxc.Oqt.Server.LookUps;\n\ninternal class OqtPageLookUp(ISxcCurrentContextService ctxService) : LookUpBase(SourcePage, \"LookUp in Oqtane Page\")\n{\n    protected Oqtane.Models.Page Page { get; set; }\n\n    public Oqtane.Models.Page GetSource()\n    {\n        if (_alreadyTried) return null;\n        _alreadyTried = true;\n        var ctx = ctxService.BlockContextOrNull();\n        return ((OqtPage)ctx?.Page)?.GetContents();\n    }\n    private bool _alreadyTried;\n\n    public override string Get(string key, string format)\n    {\n        try\n        {\n            Page ??= GetSource();\n\n            return key.ToLowerInvariant() switch\n            {\n                KeyId => $\"{Page.PageId}\",\n                OldDnnPageId => $\"Warning: '{OldDnnPageId}' was requested, but the {nameof(OqtPageLookUp)} source can only answer to '{KeyId}'\",\n                \"url\" => $\"{Page.Url}\",\n                _ => string.Empty\n            };\n        }\n        catch\n        {\n            return string.Empty;\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/LookUps/OqtSiteLookUp.cs",
    "content": "﻿using Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing static ToSic.Sxc.LookUp.Sys.LookUpConstants;\n\nnamespace ToSic.Sxc.Oqt.Server.LookUps;\n\ninternal class OqtSiteLookUp(LazySvc<AliasResolver> siteStateInitializer, SiteState siteState, LazySvc<SiteRepository> siteRepository)\n    : LookUpBase(SourceSite, \"LookUp in Oqtane Site\")\n{\n    public SiteState SiteState { get; } = siteState;\n    protected Oqtane.Models.Site Site { get; set; }\n\n    public Oqtane.Models.Site GetSource()\n    {\n        if (!siteStateInitializer.Value.InitIfEmpty()) return null;\n        var site = siteRepository.Value.GetSite(SiteState.Alias.SiteId);\n        return site;\n    }\n\n    public override string Get(string key, string format)\n    {\n        try\n        {\n            Site ??= GetSource();\n\n            return key.ToLowerInvariant() switch\n            {\n                KeyId => $\"{Site.SiteId}\",\n                KeyGuid => $\"{Site.SiteGuid}\",\n                OldDnnSiteId => $\"warning: you have requested '{OldDnnSiteId}' which doesn't work in hybrid/oqtane. Use {KeyId}\",\n                _ => string.Empty\n            };\n        }\n        catch\n        {\n            return string.Empty;\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/LookUps/OqtUserLookUp.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sources;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sys.Users;\nusing LookUpConstants = ToSic.Sxc.LookUp.Sys.LookUpConstants;\n\nnamespace ToSic.Sxc.Oqt.Server.LookUps;\n\ninternal class OqtUserLookUp(IUser oqtUser) : LookUpBase(LookUpConstants.SourceUser, \"LookUp in Oqtane User\")\n{\n    private readonly OqtUser _oqtUser = oqtUser as OqtUser;\n\n    public override string Get(string key, string format)\n    {\n        try\n        {\n            return key.ToLowerInvariant() switch\n            {\n                \"id\" => $\"{_oqtUser.Id}\",\n                \"username\" => $\"{_oqtUser.GetContents().Username}\",\n                \"displayname\" => $\"{_oqtUser.GetContents().DisplayName}\",\n                \"email\" => $\"{_oqtUser.GetContents().Email}\",\n                \"guid\" => $\"{_oqtUser.Guid}\",\n\n                //\"issuperuser\" => $\"{_oqtUser.IsSuperUser}\",\n                //\"isadmin\" => $\"{_oqtUser.IsAdmin}\",\n                //\"isanonymous\" => $\"{_oqtUser.IsAnonymous}\",\n\n                _ => string.Empty\n            };\n        }\n        catch\n        {\n            return string.Empty;\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Pages/Pages.cs",
    "content": "﻿using Oqtane.Repository;\nusing Oqtane.Models;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\nnamespace ToSic.Sxc.Oqt.Server.Pages;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class Pages(\n    IPageModuleRepository pageModuleRepository,\n    IPageRepository pageRepository,\n    ISettingRepository settingRepository)\n    : ServiceBase(\"Oqt.Pages\")\n{\n    public List<PageModule> AllModulesWithContent(int siteId)\n    {\n        var l = Log.Fn<List<PageModule>>($\"{siteId}\");\n\n        // create an array with all modules\n        var sxcContents = pageModuleRepository.GetPageModules(siteId)\n            .Where(pm => pm.Module.ModuleDefinitionName.Contains(\"ToSic.Sxc.Oqt.Content, ToSic.Sxc.Oqtane.Client\")).ToList();\n\n        var sxcApps = pageModuleRepository.GetPageModules(siteId)\n            .Where(pm => pm.Module.ModuleDefinitionName.Contains(\"ToSic.Sxc.Oqt.App, ToSic.Sxc.Oqtane.Client\")).ToList();\n\n        var sxcAll = sxcContents.Union(sxcApps).ToList();\n\n        Log.A($\"Mods for Content: {sxcContents.Count}, App: {sxcApps.Count}, Total: {sxcAll.Count}\");\n\n        var settings = settingRepository.GetSettings(EntityNames.Module).ToList();\n        foreach (var pageModule in sxcAll)\n        {\n            pageModule.Module.Settings = settings.Where(item => item.EntityId == pageModule.ModuleId)                   \n                .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);\n        }\n\n        // filter the results\n        var allMods = sxcAll\n            .Where(m => m.Module.Settings.ContainsKey(ModuleSettingNames.ContentGroup) && m.Module.Settings[ModuleSettingNames.ContentGroup] != Guid.Empty.ToString())\n            .ToList();\n\n        return l.Return(allMods, $\"{allMods.Count}\");\n    }\n\n\n    public ViewDto ViewDtoBuilder(IView view, ICollection<BlockConfiguration> blocks, List<PageModule> pageModules)\n    {\n        var dto = new ViewDto\n        {\n            Id = view.Entity.EntityId,\n            Guid = view.Entity.EntityGuid,\n            Name = view.Name,\n            Path = view.Path,\n            Blocks = blocks\n                .Where(b => b.View.Guid == view.Guid)\n                .Select(blWMod => ContentBlockDtoBuilder(blWMod,\n                    pageModules.Where(m => m.Module.Settings[ModuleSettingNames.ContentGroup] == blWMod.Guid.ToString())\n                        .ToList()))\n        };\n        return dto;\n    }\n\n    private ContentBlockDto ContentBlockDtoBuilder(BlockConfiguration block, List<PageModule> blockModules)\n        => new()\n        {\n            Id = block.Id,\n            Guid = block.Guid,\n            Modules = blockModules.Select(m => InstanceDtoBuilder(m, pageRepository.GetPage(m.PageId))),\n        };\n\n    private static InstanceDto InstanceDtoBuilder(PageModule pageModule, Page page)\n        => new()\n        {\n            Id = pageModule.ModuleId,\n            ShowOnAllPages = pageModule.Module.AllPages,\n            Title = pageModule.Title,\n            UsageId = pageModule.PageModuleId,\n            IsDeleted = pageModule.IsDeleted || page.IsDeleted,\n            Page = PageDtoBuilder(page),\n        };\n\n    private static PageDto PageDtoBuilder(Page page)\n        => new()\n        {\n            Id = page.PageId,\n            Url = page.Url,\n            Name = page.Name,\n            CultureCode = Eav.Sys.EavConstants.NullNameId,\n            Visible = !page.IsDeleted,\n            Title = page.Title,\n            Portal = new(page.SiteId),\n        };\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Plumbing/AliasResolver.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Oqtane.Infrastructure;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Plumbing;\n\n/// <summary>\n/// AliasResolver will provide correct Alias\n/// in addition of taking a care to set not mapped properties like BaseUrl, Protocol, etc.\n/// It will use HttpContext to cache correct Alias for the request.\n/// </summary>\n/// <param name=\"siteState\"></param>\n/// <param name=\"httpContextAccessor\"></param>\n/// <param name=\"aliasAccessor\"></param>\n/// <param name=\"aliasRepository\"></param>\n/// <param name=\"tenantManager\"></param>\n/// <remarks>\n/// in general to get Alias use AliasResolver, instead of working directly with IAliasRepository, \n/// to ensure that not mapped properties are also set\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AliasResolver(\n    SiteState siteState,\n    IHttpContextAccessor httpContextAccessor,\n    IAliasAccessor aliasAccessor,\n    LazySvc<IAliasRepository> aliasRepository,\n    LazySvc<ITenantManager> tenantManager)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.SSInit\",\n        connect: [])\n{\n    /// <summary>\n    /// Use this from inner code, which must always have an initialized state.\n    /// Usually this has been ensured at the very top - when razor starts or when WebApi start\n    /// </summary>\n    public Alias Alias\n    {\n        get\n        {\n            if (siteState.Alias != null && siteState.Alias.AliasId != -1) return siteState.Alias;\n            InitIfEmpty();\n            return siteState.Alias;\n        }\n    }\n\n    /// <summary>\n    /// Alias has not mapped properties like BaseUrl, Protocol, etc. so we need to do that here\n    /// </summary>\n    /// <param name=\"aliasId\"></param>\n    /// <returns></returns>\n    internal Alias GetAndStoreAlias(int aliasId)\n    {\n        var alias = aliasRepository.Value.GetAlias(aliasId);\n        AddMissingProperties(alias, httpContextAccessor?.HttpContext?.Request);\n        \n        // Store Alias in SiteState for background processing.\n        siteState.Alias = alias;\n        UpdateHttpContextItem(Constants.HttpContextAliasKey, siteState.Alias);\n\n        return siteState.Alias;\n    }\n\n    /// <summary>\n    /// Will initialize the SiteState if it has not been initialized yet\n    /// </summary>\n    /// <returns></returns>\n    internal bool InitIfEmpty(int? siteId = null)\n    {\n        var l = Log.Fn<bool>($\"{nameof(siteId)}:{siteId}\");\n\n        // This would indicate it was called improperly, because we need the shared SiteState variable to work properly\n        if (siteState == null) throw l.Ex(new ArgumentNullException(nameof(siteState)));\n\n        // Check if alias already set and if is for provided siteId (if provided), in which case we skip this\n        if (siteState.Alias != null && (!siteId.HasValue || siteId.Value == siteState.Alias.SiteId))\n            return l.ReturnTrue($\"siteState.Alias:'{siteState.Alias?.Name}'\");\n\n        // Check if alias already set and stored in HttpContext and if is for provided siteId (if provided), in which case we skip this\n        if (aliasAccessor.Alias != null && (!siteId.HasValue || siteId.Value == aliasAccessor.Alias.SiteId))\n        {\n            siteState.Alias = aliasAccessor.Alias;\n            return l.ReturnTrue($\"Alias from IAliasAccessor:'{siteState.Alias?.Name}'\");\n        }\n\n        // For anything else we need the HttpContext, otherwise skip\n        var request = httpContextAccessor?.HttpContext?.Request;\n        if (request == null) return l.ReturnFalse(\"request is NULL\");\n\n        // Find and build Alias\n        siteState.Alias = FindAlias();\n\n        // Store it\n        UpdateHttpContextItem(Constants.HttpContextAliasKey, siteState.Alias);\n\n        return l.Return(siteState.Alias != null, $\"resolved to siteState.Alias:'{siteState.Alias?.Name}'\");\n    }\n\n    private Alias FindAlias()\n    {\n        var l = Log.Fn<Alias>();\n\n        var alias= tenantManager.Value.GetAlias(); // get alias (note that this also sets SiteState.Alias)\n        l.A($\"siteState.Alias:'{siteState.Alias?.Name}'\");\n\n        return l.ReturnAsOk(alias);\n    }\n\n    /// <summary>\n    /// Oqtane v5.1+ builds BaseUrl for Alias, in \"Oqtane.Server\\Infrastructure\\TenantManager.cs\", line 52,\n    /// we need to repeat that functionality here\n    /// </summary>\n    /// <param name=\"alias\"></param>\n    /// <param name=\"request\"></param>\n    private void AddMissingProperties(Alias alias, HttpRequest request)\n    {\n        if (alias is not { BaseUrl: null }) return;\n        alias.BaseUrl = \"\";\n        alias.Protocol = (request?.IsHttps == true) ? \"https://\" : \"http://\";\n        if (request?.Headers.ContainsKey(\"User-Agent\") == true && request.Headers[\"User-Agent\"] == Constants.MauiUserAgent)\n            alias.BaseUrl = siteState.Alias.Protocol + siteState.Alias.Name.Replace(\"/\" + siteState.Alias.Path, \"\");\n    }\n\n    private void UpdateHttpContextItem(string key, Alias alias)\n    {\n        if (httpContextAccessor?.HttpContext != null && alias != null)\n            httpContextAccessor.HttpContext.Items[key] ??= alias;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Plumbing/CompilationReferencesProvider.cs",
    "content": "﻿using System.Collections;\nusing System.Reflection;\nusing System.Runtime.Loader;\nusing Microsoft.AspNetCore.Mvc.ApplicationParts;\n\n// Used by RazorView compilation.\n// Based on https://stackoverflow.com/questions/58685966/adding-assemblies-types-to-be-made-available-to-razor-page-at-runtime to work\nnamespace ToSic.Sxc.Oqt.Server.Plumbing;\n\ninternal class CompilationReferencesProvider(Assembly assembly) : AssemblyPart(assembly), ICompilationReferencesProvider\n{\n    private readonly Assembly _assembly = assembly;\n\n    public IEnumerable<string> GetReferencePaths()\n    {\n        // your `LoadPrivateBinAssemblies()` method needs to be called before the next line executes!\n        // So you should load all private bin's before the first RazorPage gets requested....\n\n        // 2022-11-09 2dm new code\n        // 1. Ensure we don't run into null problems\n        var loadContext = AssemblyLoadContext.GetLoadContext(_assembly);\n        if (loadContext == null) return Enumerable.Empty<string>();\n\n        var nonDynamicAssemblies = loadContext.Assemblies\n            .Where(_ => !_.IsDynamic)\n            .ToList();\n\n        // 2. use new code with location. has some duplicates and many \"\" empty strings\n        // which seem to be merged dynamic libraries - usually the CodeBase called them \"System.Private.CoreLib.dll\"\n        // But that one is already included\n        var newer = nonDynamicAssemblies.Select(_ => _.Location).ToList();\n        var newerDistinct = newer.Distinct().Where(path => !path.IsNullOrEmpty()).ToList();\n\n        // Temporary tests to figure out why we had missmatches\n        // Leave the code in for now, in case we need to debug\n\n        //var codeBase = nonDynamicAssemblies.Select(_ => new Uri(_.CodeBase).LocalPath).ToList();\n        //var codeBaseDistinct = codeBase.Distinct().ToList();\n\n        // if all is ok, remove 2023 #removeV15\n        //var notInNewer = newerDistinct.Where(n => !codeBaseDistinct.Contains(n)).ToList();\n        //var notInCodebase = codeBaseDistinct.Where(n => !newerDistinct.Contains(n)).ToList();\n\n        //if (codeBaseDistinct.Count != newerDistinct.Count)\n        //    throw new(\"count missmatch\");\n\n        //if (notInNewer.Count > 0)\n        //    throw new(\"not-in-newer has entries\");\n\n        //if (!codeBase.All(newer.Contains))\n        //    throw new(\"test 2\");\n\n        //foreach (var cbEntry in codeBase)\n        //    if (!newer.Contains(cbEntry))\n        //        throw new Exception(\"can't find \" + cbEntry);\n\n        return newerDistinct;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Plumbing/HttpBlazor.cs",
    "content": "﻿using System.Collections.Specialized;\nusing Microsoft.AspNetCore.Components;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.WebUtilities;\nusing ToSic.Sxc.Web.Sys.Http;\n\nnamespace ToSic.Sxc.Oqt.Server.Plumbing;\n\n/// <summary>\n/// This is responsible for providing the current HTTP context to the application.\n/// In addition, it also provides the Query-String params (which are hidden in the normal request)\n/// </summary>\n/// <remarks>\n/// Note that it's probably not yet complete. As of now, it only provides ?x=y&a=b stuff,\n/// but if Blazor has any cute-url system like x/y/a/b this would probably not work yet\n/// </remarks>\ninternal class HttpBlazor(IHttpContextAccessor contextAccessor, NavigationManager navigationManager) : HttpAbstractionBase, IHttp\n{\n    public override HttpContext Current => contextAccessor?.HttpContext!;\n\n    public override NameValueCollection QueryStringParams\n    {\n        get\n        {\n            // caching is disabled because in Blazor Interactive the query string parameters are changed after the page is created\n            //if (_queryStringValues != null) return _queryStringValues;\n\n            // this must behave differently in an API call, as the navigation manager will not be initialized\n            // but all the params will really be in the query\n            if (Current?.Request?.Path.Value?.Contains(\"_blazor\") == false)\n            {\n                var paramList = new NameValueCollection();\n                Current.Request.Query.ToList().ForEach(i => paramList.Add(i.Key, i.Value));\n                return /*_queryStringValues = */FilterOutOqtaneParams(paramList);\n            }\n            else\n            {\n\n                // Sample taken from https://chrissainty.com/working-with-query-strings-in-blazor/\n                var uri = navigationManager.ToAbsoluteUri(navigationManager.Uri);\n                var queryBits = QueryHelpers.ParseQuery(uri.Query);\n                    \n                if (!queryBits.Any()) \n                    return /*_queryStringValues = */[];\n\n                var paramList = new NameValueCollection();\n                queryBits.ToList().ForEach(i => paramList.Add(i.Key, i.Value));\n                return /*_queryStringValues = */FilterOutOqtaneParams(paramList);\n            }\n        }\n    }\n\n    //private NameValueCollection _queryStringValues;\n\n    private NameValueCollection FilterOutOqtaneParams(NameValueCollection original)\n    {\n        // Oqtane seems to add this automatically, at least in v2.2\n        original.Remove(\"authmoduleid\");\n        return original;\n    }\n\n    //public override IDictionary<object, object> Items => Current.Items;\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Plumbing/MyApplicationPartFactory.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc.ApplicationParts;\nusing System.Reflection;\n\n// Code is required to razor runtime compilation.\n// Required for functioning of ToSic.Sxc.Razor.RazorEngine.RenderTemplate() \n[assembly: ProvideApplicationPartFactory(typeof(ToSic.Sxc.Oqt.Server.Plumbing.MyApplicationPartFactory))]\nnamespace ToSic.Sxc.Oqt.Server.Plumbing;\n\n/// <summary>\n/// We're not 100% sure of this purpose again, but we believe the Razor compiler tries to go through application\n/// parts and fails if this isn't included\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class MyApplicationPartFactory : ApplicationPartFactory\n{\n    public override IEnumerable<ApplicationPart> GetApplicationParts(Assembly assembly)\n    {\n        yield return new CompilationReferencesProvider(assembly);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Oqt.Server.Tests\")]"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Properties/PublishProfiles/FolderProfile.pubxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nhttps://go.microsoft.com/fwlink/?LinkID=208121. \n-->\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>bin\\Release\\net5.0\\publish\\</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/Features/SysFeatureDetectorBlazor.cs",
    "content": "﻿using ToSic.Sys.Capabilities.SysFeatures;\nusing static ToSic.Sys.Capabilities.SysFeatures.SysFeatureSuggestions;\n// ReSharper disable UnusedMember.Global\n\nnamespace ToSic.Sxc.Oqt.Server.Run.Features;\n\ninternal class SysFeatureDetectorBlazor() : SysFeatureDetector(Blazor, true);"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/Features/SysFeatureDetectorCSharpInOqt.cs",
    "content": "﻿using ToSic.Sys.Capabilities.SysFeatures;\nusing static ToSic.Sys.Capabilities.SysFeatures.SysFeatureSuggestions;\n// ReSharper disable UnusedMember.Global\n\nnamespace ToSic.Sxc.Oqt.Server.Run.Features;\n\npublic class SysFeatureDetectorCSharp6() : SysFeatureDetector(CSharp06, true);\npublic class SysFeatureDetectorCSharp7() : SysFeatureDetector(CSharp07, true);\npublic class SysFeatureDetectorCSharp8() : SysFeatureDetector(CSharp08, true);\npublic class SysFeatureDetectorCSharp9() : SysFeatureDetector(CSharp09, true);\npublic class SysFeatureDetectorCSharp10() : SysFeatureDetector(CSharp10, true);\npublic class SysFeatureDetectorCSharp11() : SysFeatureDetector(CSharp11, true);\npublic class SysFeatureDetectorCSharp12() : SysFeatureDetector(CSharp12, false);"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtEnvironmentInstaller.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Apps.Sys.Installation;\nusing ToSic.Sxc.Apps.Sys.Work;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Sys.Integration.Installation;\nusing ToSic.Sxc.WebApi.Sys.ExternalLinks;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\ninternal class OqtEnvironmentInstaller(\n    GenWorkPlus<WorkViews> workViews,\n    ExternalLinksService externalLinksService,\n    IAppsCatalog appsCatalog)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.Instll\", connect: [externalLinksService, workViews, appsCatalog]),\n        IEnvironmentInstaller, IPlatformAppInstaller\n{\n    public string UpgradeMessages()\n    {\n        // for now, always assume installation worked\n        return null;\n    }\n\n    private bool IsUpgradeRunning => false;\n\n    public bool ResumeAbortedUpgrade()\n    {\n        // don't do anything for now\n        return true;\n    }\n\n    public string GetAutoInstallPackagesUiUrl(ISite site, IModule module, bool forContentApp)\n    {\n\n        // new: check if it should allow this\n        // it should only be allowed, if the current situation is either\n        // Content - and no views exist (even invisible ones)\n        // App - and no apps exist - this is already checked on client side, so I won't include a check here\n        if (forContentApp)\n            try\n            {\n                var contentAppId = appsCatalog.DefaultAppIdentity(site.ZoneId);\n                // we'll usually run into errors if nothing is installed yet, so on errors, we'll continue\n                var contentViews = workViews.New(contentAppId).GetAll();\n                if (contentViews.Any()) return null;\n            }\n            catch { /* ignore */ }\n\n        var link = externalLinksService.LinkToDestination(\n            ExternalSxcDestinations.AutoConfigure,\n            site,\n            module.Id,\n            appSpecsOrNull: null,\n            forContentApp);\n\n        return link;\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtEnvironmentPermission.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Oqtane.Security;\nusing Oqtane.Shared;\nusing System.Security.Claims;\nusing ToSic.Eav.Environment.Sys.Permissions;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sys.Users;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\ninternal class OqtEnvironmentPermission(\n    IHttpContextAccessor httpContextAccessor,\n    LazySvc<IUserPermissions> userPermissions,\n    LazySvc<IUser> oqtUser)\n    : EnvironmentPermission(OqtConstants.OqtLogPrefix, connect: [httpContextAccessor, userPermissions, oqtUser])\n{\n    /// <summary>\n    /// Gets the <see cref=\"ClaimsPrincipal\"/> for user associated with the executing action.\n    /// </summary>\n    private ClaimsPrincipal ClaimsPrincipal => httpContextAccessor.HttpContext?.User;\n\n    private IModule Module => _module ??= (Context as IContextOfBlock)?.Module;\n    private IModule _module;\n\n    public override bool VerifyConditionOfEnvironment(string condition)\n    {\n        // This terms are historic from DNN\n        if (condition.Equals(SalAnonymous, InvariantCultureIgnoreCase))\n            return true;\n\n        var m = Module;\n\n        if (condition.Equals(SalView, InvariantCultureIgnoreCase))\n            return m != null && userPermissions.Value.IsAuthorized(ClaimsPrincipal, EntityNames.Module, m.Id, PermissionNames.View);\n\n        if (condition.Equals(SalEdit, InvariantCultureIgnoreCase))\n            return m != null && userPermissions.Value.IsAuthorized(ClaimsPrincipal, EntityNames.Module, m.Id, PermissionNames.Edit);\n\n        if (condition.Equals(SalSiteAdmin, InvariantCultureIgnoreCase))\n            return oqtUser.Value.IsSiteAdmin;\n\n        if (condition.Equals(SalSystemUser, InvariantCultureIgnoreCase))\n            return oqtUser.Value.IsSystemAdmin;\n\n        return false;\n    }\n\n    protected override bool UserIsModuleAdmin()\n    {\n        var l = Log.Fn<bool>($\"{nameof(Module)}: {Module?.Id}.\");\n        return l.ReturnAsOk(UserIsModuleEditor());\n    }\n\n    protected override bool UserIsModuleEditor()\n    {\n        return _userIsModuleEditor ??= IsModuleEditor();\n        bool IsModuleEditor()\n        {\n            var l = Log.Fn<bool>();\n            if (Module == null)\n                return l.ReturnFalse();\n            try\n            {\n                return l.Return(userPermissions.Value.IsAuthorized(ClaimsPrincipal, EntityNames.Module, Module.Id, PermissionNames.Edit));\n            }\n            catch\n            {\n                return l.ReturnFalse();\n            }\n        }\n    }\n    private bool? _userIsModuleEditor;\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtImportExportEnvironment.cs",
    "content": "﻿using Microsoft.Data.SqlClient;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Sxc.Oqt.Server.Adam;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sxc.Oqt.Server.Integration;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Sys.Integration;\nusing ToSic.Sys.Utils;\nusing File = Oqtane.Models.File;\nusing IO = System.IO;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\ninternal class OqtImportExportEnvironment(\n    SxcImportExportEnvironmentBase.Dependencies services,\n    IServerPaths oqtServerPaths,\n    IFileRepository oqtFileRepository,\n    IFolderRepository oqtFolderRepository)\n    : SxcImportExportEnvironmentBase(services, $\"{OqtConstants.OqtLogPrefix}.IExEnv\")\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// Copy all files from SourceFolder to DestinationFolder\n    /// </summary>\n    /// <param name=\"sourceFolder\"></param>\n    /// <param name=\"destinationFolder\">The portal-relative path where the files should be copied to</param>\n    public override List<Message> TransferFilesToSite(string sourceFolder, string destinationFolder)\n    {\n        var l = Log.Fn<List<Message>>($\"{sourceFolder}, {destinationFolder}\");\n        var messages = new List<Message>();\n        var files = IO.Directory.GetFiles(sourceFolder, \"*.*\");\n        var siteId = Site.Id;\n        var oqtSite = (OqtSite)Site;\n\n        // Ensure trim prefixSlash and backslash at the end of folder path, because Oqtane require path like that.\n        destinationFolder = destinationFolder.EnsureOqtaneFolderFormat();\n\n        var destinationVirtualPath = IO.Path.Combine(oqtSite.ContentPath, destinationFolder);\n        var destinationFolderFullPath = oqtServerPaths.FullContentPath(destinationVirtualPath);\n\n        if (!IO.Directory.Exists(destinationFolderFullPath))\n        {\n            Log.A($\"Must create {destinationFolder} in site {siteId}\");\n            IO.Directory.CreateDirectory(destinationFolderFullPath);\n            AddFolder(destinationFolder);\n        }\n\n        var folderInfo = oqtFolderRepository.GetFolder(siteId, destinationFolder.EnsureOqtaneFolderFormat());\n\n        void MassLog(string msg, Exception exception)\n        {\n            Log.A(msg);\n            if (exception == null) return;\n            messages.Add(new(msg, Message.MessageTypes.Warning));\n            //Exceptions.LogException(exception);\n        }\n\n        foreach (var sourceFilePath in files)\n        {\n            var destinationFileName = IO.Path.GetFileName(sourceFilePath);\n            Log.A($\"Try to copy '{sourceFilePath}' to '{destinationFileName}'\");\n\n            if (!FileExists(folderInfo, destinationFileName))\n            {\n                try\n                {\n                    using var stream = IO.File.OpenRead(sourceFilePath);\n                    var fileInfo = Add(folderInfo, stream, destinationFileName, oqtSite);\n                    MassLog($\"Transferred '{destinationFileName}', file id is now {fileInfo?.FileId}\", null);\n                }\n                catch (Exception e)\n                {\n                    MassLog($\"Error: Can't copy '{destinationFileName}' because of an unknown error. \" +\n                            \"It's likely that your files and folders are not in sync with Oqtane.\", e);\n                }\n            }\n            else\n                messages.Add(new(\"File '\" + destinationFileName + \"' not copied because it already exists\", Message.MessageTypes.Warning));\n        }\n\n        // Call the method recursively to handle subdirectories\n        foreach (var sourceFolderPath in IO.Directory.GetDirectories(sourceFolder))\n        {\n            Log.A($\"subfolder:{sourceFolderPath}\");\n            var newDestinationFolder = IO.Path.Combine(destinationFolder, sourceFolderPath.Replace(sourceFolder, \"\").EnsureOqtaneFolderFormat());\n\n            TransferFilesToSite(sourceFolderPath, newDestinationFolder);\n        }\n\n        return l.Return(messages);\n    }\n\n    public override Version TenantVersion => typeof(OqtImportExportEnvironment).Assembly.GetName().Version!;\n\n    public override void MapExistingFilesToImportSet(Dictionary<int, string> filesAndPaths, Dictionary<int, int> fileIdMap\n    ) => Log.Do($\"files: {filesAndPaths.Count}, map size: {fileIdMap.Count}\", l =>\n    {\n        foreach (var file in filesAndPaths)\n        {\n            var fileId = file.Key;\n            var relativePath = file.Value;\n\n            var fileName = IO.Path.GetFileName(relativePath);\n            var directory = IO.Path.GetDirectoryName(relativePath).EnsureOqtaneFolderFormat();\n            if (directory == null)\n            {\n                l.A($\"Warning: File '{relativePath}', folder is 'null' doesn't exist on drive\");\n                continue;\n            }\n\n            if (!FolderExists(directory))\n            {\n                l.A($\"Warning: File '{relativePath}', folder '{directory}' doesn't exist in file system\");\n                continue;\n            }\n\n            var folderInfo = GetOqtFolderByPath(directory);\n            if (folderInfo == null)\n            {\n                l.A($\"Warning: File '{relativePath}', folder doesn't exist in Oqtane DB\");\n                continue;\n            }\n\n            if (!FileExists(folderInfo, fileName))\n            {\n                l.A(\n                    $\"Warning: File '{relativePath}', file '{fileName}' doesn't exist in folder #{folderInfo.FolderId} '{folderInfo.Name}' Oqtane DB\");\n                continue;\n            }\n\n            var fileInfo = GetFile(folderInfo, fileName);\n            if (fileInfo == null)\n            {\n                l.A($\"Warning: File '{relativePath}', file doesn't exist in Oqtane DB (2nd check)\");\n                continue;\n            }\n\n            fileIdMap.Add(fileId, fileInfo.FileId);\n            l.A($\"Map: {fileId} will be {fileInfo.FileId} ({relativePath})\");\n        }\n\n    });\n\n    public override void CreateFoldersAndMapToImportIds(Dictionary<int, string> foldersAndPath, Dictionary<int, int> folderIdCorrectionList, List<Message> importLog) \n    {\n        var l = Log.Fn($\"folders and paths: {foldersAndPath.Count}\");\n        foreach (var folder in foldersAndPath)\n            try\n            {\n                if (string.IsNullOrEmpty(folder.Value))\n                {\n                    l.A($\"{folder.Key} / {folder.Value} is empty\");\n                    continue;\n                }\n\n                var directory = IO.Path.GetDirectoryName(folder.Value);\n                if (directory == null)\n                {\n                    l.A($\"Parent folder of folder {folder.Value} doesn't exist\");\n                    continue;\n                }\n\n                // if not exist, create - important because we need for metadata assignment\n                var exists = FolderExists(directory);\n                var folderInfo = !exists\n                    ? AddFolder(directory)\n                    : GetOqtFolderByPath(directory);\n\n                folderIdCorrectionList.Add(folder.Key, folderInfo.FolderId);\n                l.A($\"Folder original #{folder.Key}/{folder.Value} - exists:{exists} in folder #{folderInfo.FolderId}\");\n            }\n            catch (Exception)\n            {\n                var msg = $\"Had a problem with folder of '{folder.Key}' path '{folder.Value}' - you'll have to figure out yourself if this is a problem\";\n                l.A(msg);\n                importLog.Add(new(msg, Message.MessageTypes.Warning));\n            }\n\n        l.Done($\"done - final count {folderIdCorrectionList.Count}\");\n    }\n\n    private File Add(Folder parent, IO.Stream body, string fileName, OqtSite oqtSite)\n    {\n        var l = Log.Fn<File>($\"Add {fileName}, folderId:{parent.FolderId}, siteId {oqtSite.Id}\");\n\n        var fullContentPath = IO.Path.Combine(oqtServerPaths.FullContentPath(oqtSite.ContentPath), parent.Path);\n        IO.Directory.CreateDirectory(fullContentPath);\n        var filePath = IO.Path.Combine(fullContentPath, fileName);\n        using (var stream = new IO.FileStream(filePath, IO.FileMode.Create))\n        {\n            body.CopyTo(stream);\n        }\n        var fileInfo = new IO.FileInfo(filePath);\n\n        // register into oqtane\n        var oqtFileData = new File\n        {\n            Name = IO.Path.GetFileName(fileName),\n            FolderId = parent.FolderId,\n            Extension = fileInfo.Extension.ToLowerInvariant().Replace(\".\", \"\"),\n            Size = (int)fileInfo.Length,\n            ImageHeight = 0,\n            ImageWidth = 0\n        };\n        var oqtFile = oqtFileRepository.AddFile(oqtFileData);\n        return l.ReturnAsOk(oqtFile);\n    }\n\n    private bool FolderExists(string path) => GetOqtFolderByPath(path) != null;\n\n    private bool FileExists(Folder folderInfo, string fileName) => GetFile(folderInfo, fileName) != null;\n\n    private File GetFile(Folder folderInfo, string fileName)\n        => oqtFileRepository.GetFiles(folderInfo.FolderId, false)\n            .FirstOrDefault(f => f.Name.Equals(fileName, StringComparison.OrdinalIgnoreCase));\n\n    private Folder GetOqtFolderByPath(string path) => oqtFolderRepository.GetFolder(Site.Id, path.EnsureOqtaneFolderFormat());\n\n    private Folder AddFolder(string path)\n    {\n        path = path.EnsureOqtaneFolderFormat();\n        var l = Log.Fn<Folder>(path);\n\n        if (FolderExists(path)) return l.ReturnNull(\"error, missing folder\");\n\n        try\n        {\n            // find parent\n            var pathWithPretendFileName = path.TrimLastSlash();\n            var parent = IO.Path.GetDirectoryName(pathWithPretendFileName) + \"/\";\n            var subfolder = IO.Path.GetFileName(pathWithPretendFileName);\n            var parentFolder = GetOqtFolderByPath(parent) ?? GetOqtFolderByPath(\"\");\n\n            // Create the new virtual folder\n            var newFolder = CreateVirtualFolder(parentFolder, path, subfolder);\n            return l.ReturnAsOk(newFolder);\n        }\n        catch (SqlException)\n        {\n            // don't do anything - this happens when multiple processes try to add the folder at the same time\n            // like when two fields in a dialog cause the web-api to create the folders in parallel calls\n            // see also https://github.com/2sic/2sxc/issues/811\n            Log.A(\"error in SQL, probably folder already exists\");\n        }\n        catch (NullReferenceException)\n        {\n            // also catch this, as it's an additional exception which also happens in the AddFolder when a folder already existed\n            Log.A(\"error, probably folder already exists\");\n        }\n\n        return l.ReturnNull(\"?\");\n    }\n\n    private Folder CreateVirtualFolder(Folder parentFolder, string path, string folder)\n    {\n        var newVirtualFolder = AdamFolderHelper.NewVirtualFolder(Site.Id, parentFolder.FolderId, path, folder);\n        oqtFolderRepository.AddFolder(newVirtualFolder);\n        return newVirtualFolder;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtLinkPaths.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Http.Extensions;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sys.Utils;\nusing OqtPageOutput = ToSic.Sxc.Oqt.Server.Blocks.Output.OqtPageOutput;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\ninternal class OqtLinkPaths(IHttpContextAccessor contextAccessor, AliasResolver aliasResolver)\n    : ILinkPaths\n{\n    #region Paths\n\n    private string ToWebAbsolute(string virtualPath)\n    {\n        virtualPath = virtualPath.TrimStart('~');\n        return virtualPath.PrefixSlash().ForwardSlash();\n    }\n\n    public string AsSeenFromTheDomainRoot(string virtualPath) => ToWebAbsolute(virtualPath);\n\n    public string ApiFromSiteRoot(string appFolder, string apiPath) => $\"/app/{appFolder}/{apiPath}\";\n\n    public string AppFromTheDomainRoot(string appFolder, string pagePath)\n    {\n        var siteRoot = OqtPageOutput.GetSiteRoot(aliasResolver.Alias).TrimLastSlash();\n        return AppFromTheDomainRoot(siteRoot, appFolder, pagePath);\n    }\n\n    public string AppFromTheDomainRoot(string siteRoot, string appFolder, string pagePath) => $\"{siteRoot}/app/{appFolder}/{pagePath}\";\n\n    #endregion\n\n    public string GetCurrentRequestUrl() => contextAccessor.HttpContext?.Request?.GetEncodedUrl() ?? string.Empty;\n\n    public string GetCurrentLinkRoot()\n    {\n        var scheme = contextAccessor?.HttpContext?.Request?.Scheme ?? \"http\";\n        var alias = aliasResolver.Alias;\n        var domainName = string.IsNullOrEmpty(alias.Path)\n            ? alias.Name\n            : alias.Name.Substring(0, alias.Name.Length - alias.Path.Length - 1);\n        return $\"{scheme}://{domainName}\";\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtModuleUpdater.cs",
    "content": "﻿using Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Data;\nusing ToSic.Sxc.Apps.Sys.Work;\nusing ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Integration.Modules;\nusing ToSic.Sxc.Oqt.Server.Integration;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\n// TODO: @STV - this looks very similar to the Dnn implementation\n// Probably best to make a base class and de-duplicate.\ninternal class OqtModuleUpdater(\n    SettingsHelper settingsHelper,\n    IPageModuleRepository pageModuleRepository,\n    GenWorkPlus<WorkViews> workViews,\n    LazySvc<IAppsCatalog> appsCatalog,\n    ISite site)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.MapA2I\",\n        connect: [settingsHelper, pageModuleRepository, appsCatalog, workViews, site]), IPlatformModuleUpdater\n{\n    public void SetAppId(IModule instance, int? appId)\n    {\n        var l = Log.Fn($\"SetAppIdForInstance({instance.Id}, -, appid: {appId})\");\n        // Reset temporary template\n        ClearPreview(instance.Id);\n\n        // ToDo: Should throw exception if a real BlockConfiguration exists\n\n        if (appId is KnownAppsConstants.AppIdEmpty or null)\n            UpdateInstanceSetting(instance.Id, ModuleSettingNames.AppName, null, Log);\n        else\n        {\n            var appName = appsCatalog.Value.AppNameId(new AppIdentity(site.ZoneId, appId.Value));\n            UpdateInstanceSetting(instance.Id, ModuleSettingNames.AppName, appName, Log);\n        }\n\n        // Change to 1. available template if app has been set\n        if (appId.HasValue)\n        {\n            var appIdentity = new AppIdentity(site.ZoneId, appId.Value);\n            var templateGuid = workViews.New(appIdentity).GetAll()\n                .FirstOrDefault(t => !t.IsHidden)?.Guid;\n            if (templateGuid.HasValue) SetPreview(instance.Id, templateGuid.Value);\n        }\n\n        l.Done();\n    }\n\n    protected void ClearPreview(int instanceId)\n    {\n        Log.A($\"ClearPreviewTemplate(iid: {instanceId})\");\n        UpdateInstanceSetting(instanceId, ModuleSettingNames.PreviewView, null, Log);\n    }\n\n    /// <summary>\n    /// Update a setting for all language-versions of a module\n    /// </summary>\n    public void UpdateInstanceSetting(int instanceId, string key, string value, ILog log)\n    {\n        log.A($\"UpdateInstanceSetting(iid: {instanceId}, key: {key}, val: {value})\");\n\n        if (value == null)\n            settingsHelper.DeleteSetting(EntityNames.Module, instanceId, key);\n        else\n            settingsHelper.UpdateSetting(EntityNames.Module, instanceId, key, value);\n    }\n\n    /// <summary>\n    /// Saves a temporary templateId to the module's settings\n    /// This templateId will be used until a ContentGroup exists\n    /// </summary>\n    public void SetPreview(int instanceId, Guid previewTemplateGuid)\n    {\n        var settings = settingsHelper.Init(EntityNames.Module, instanceId).Settings;\n\n        // Do not allow saving the temporary template id if a ContentGroup exists for this module\n        if (settings.TryGetValue(ModuleSettingNames.ContentGroup, out var value) && !string.IsNullOrEmpty(value))\n            throw new(\"Preview template id cannot be set for a module that already has content.\");\n\n        UpdateInstanceSetting(instanceId, ModuleSettingNames.PreviewView, previewTemplateGuid.ToString(), Log);\n    }\n    public void SetContentGroup(int instanceId, bool wasCreated, Guid guid)\n    {\n        Log.A($\"SetContentGroup(iid: {instanceId}, {nameof(wasCreated)}: {wasCreated}, guid: {guid})\");\n        // Remove Preview because it's not needed as soon Content is inserted\n        ClearPreview(instanceId);\n        // Update blockConfiguration Guid for this module\n        if (wasCreated)\n            UpdateInstanceSetting(instanceId, ModuleSettingNames.ContentGroup, guid.ToString(), Log);\n    }\n\n    public void UpdateTitle(IBlock block, IEntity titleItem)\n    {\n        Log.A(\"update title\");\n\n        // Module tile is stored in PageModule, so we need moduleId and pageId to update it.\n        var pageId = block.Context.Page.Id;\n        var moduleId = block.Context.Module.Id;\n        var pageModule = pageModuleRepository.GetPageModule(pageId, moduleId);\n        pageModule.Title = System.Net.WebUtility.HtmlEncode(titleItem.GetBestTitle());\n        pageModuleRepository.UpdatePageModule(pageModule);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtSecurity.cs",
    "content": "﻿using Microsoft.AspNetCore.Identity;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Security;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtSecurity(LazySvc<IUserRoleRepository> userRoleRepository, UserManager<IdentityUser> identityUserManager)\n    : ServiceBase($\"{OqtConstants.OqtLogPrefix}.User\", connect: [userRoleRepository, identityUserManager])\n{\n    public int Id(User user) => user?.UserId ?? -1;\n\n    public string Username(User user) => user?.Username;\n\n    public string Name(User user) => user?.DisplayName;\n\n    public string Email(User user) => user?.Email;\n\n    public Guid UserGuid(string username) => new(identityUserManager.FindByNameAsync(username).Result.Id);\n\n    public string UserIdentityToken(User user) => $\"{OqtConstants.UserTokenPrefix}{Id(user)}\";\n\n    public List<int> Roles(User user) => userRoleRepository.Value.GetUserRoles(Id(user), user.SiteId).Select(r => r.RoleId).ToList();\n    public List<UserRoleModel> Roles2(User user) => userRoleRepository.Value\n        .GetUserRoles(Id(user), user.SiteId)\n        .Select(r => new UserRoleModel\n        {\n            Id = r.RoleId,\n            Name = r.Role.Name,\n            Created = r.CreatedOn,\n            Modified = r.ModifiedOn,\n        })\n        .ToList();\n\n    public bool IsSystemAdmin(User user) => UserSecurity.IsAuthorized(user, RoleNames.Host);\n\n    public bool IsSiteAdmin(User user) => UserSecurity.IsAuthorized(user, RoleNames.Admin);\n\n    public bool IsAnonymous(User user) => Id(user) == -1;\n\n    public UserModel CmsUserBuilder(User user)\n    {\n        var isSiteAdmin = IsSiteAdmin(user);\n        return new()\n        {\n            Id = Id(user),\n            Guid = UserGuid(user.Username),\n            NameId = UserIdentityToken(user),\n            //RolesRaw = Roles(user),\n            Roles = Roles2(user),\n            IsSystemAdmin = IsSystemAdmin(user),\n            IsSiteAdmin = isSiteAdmin,\n            IsContentAdmin = isSiteAdmin,\n            IsContentEditor = isSiteAdmin,\n            IsAnonymous = IsAnonymous(user),\n            Created = user.CreatedOn,\n            Modified = user.ModifiedOn,\n            Username = Username(user),\n            Email = Email(user),\n            Name = Name(user),\n        };\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtServerPaths.cs",
    "content": "﻿using Microsoft.AspNetCore.Hosting;\nusing Oqtane.Repository;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\ninternal class OqtServerPaths(IWebHostEnvironment hostingEnvironment, LazySvc<IFileRepository> fileRepository)\n    : ServerPathsBase\n{\n    public override string FullAppPath(string virtualPath) => FullContentPath(virtualPath);\n\n\n    public override string FullContentPath(string virtualPath)\n    {\n        var path = virtualPath.Backslash().TrimPrefixSlash();\n        return Path.Combine(hostingEnvironment.ContentRootPath, path);\n    }\n\n\n    protected override string FullPathOfReference(int id)\n        => fileRepository.Value.GetFilePath(id);\n\n    public static string GetAppRootWithTenantAndSiteId(int tenantId, int siteId)\n        => string.Format(OqtConstants.AppRootTenantSiteBase, tenantId, siteId);\n\n    public static string GetAppPath(int tenantId, int siteId, string appFolder)\n        => Path.Combine(GetAppRootWithTenantAndSiteId(tenantId, siteId), appFolder);\n\n    public static string GetAppApiPath(int tenantId, int siteId, string appFolder, string apiPath)\n        => Path.Combine(GetAppPath(tenantId, siteId, appFolder), apiPath);\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtXmlExporter.cs",
    "content": "﻿using Microsoft.AspNetCore.Hosting;\nusing Oqtane.Repository;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.ImportExport.Sys.Xml;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.ExportImport.Sys;\nusing ToSic.Sxc.Oqt.Server.Adam;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\ninternal class OqtXmlExporter(\n    AdamManager adamManager,\n    ISxcCurrentContextService ctxService,\n    XmlSerializer xmlSerializer,\n    IWebHostEnvironment hostingEnvironment,\n    LazySvc<IFileRepository> fileRepositoryLazy,\n    LazySvc<IFolderRepository> folderRepositoryLazy,\n    LazySvc<ITenantResolver> oqtTenantResolverLazy,\n    IAppsCatalog appsCatalog,\n    LazySvc<OqtAssetsFileHelper> fileHelper)\n    : SxcXmlExporter(xmlSerializer, appsCatalog, ctxService, OqtConstants.OqtLogPrefix,\n        connect:\n        [\n            hostingEnvironment, fileRepositoryLazy, folderRepositoryLazy, oqtTenantResolverLazy, fileHelper, adamManager\n        ])\n{\n    #region Constructor / DI\n\n    protected override void PostContextInit(IContextOfApp appContext)\n    {\n        adamManager.Init(appContext, CompatibilityLevels.CompatibilityLevel10);\n    }\n\n\n    #endregion\n\n    public override void AddFilesToExportQueue()\n    {\n        // Add Adam Files To Export Queue\n        var exportList = new AdamExportListHelper<int, int>(adamManager);\n        var adamIds = exportList.AppFiles;\n        adamIds.ForEach(AddFileAndFolderToQueue);\n\n        // also add folders in adam - because empty folders may also have metadata assigned\n        var adamFolders = exportList.AppFolders;\n        adamFolders.ForEach(ReferencedFolderIds.Add);\n    }\n\n    protected override void AddFileAndFolderToQueue(int fileNum)\n    {\n        try\n        {\n            ReferencedFileIds.Add(fileNum);\n\n            // also try to remember the folder\n            try\n            {\n                var file = fileRepositoryLazy.Value.GetFile(fileNum, false);\n                if (file != null) ReferencedFolderIds.Add(file.FolderId);\n            }\n            catch\n            {\n                // don't do anything, because if the file doesn't exist, its FOLDER should also not land in the queue\n            }\n        }\n        catch\n        {\n            // don't do anything, because if the file doesn't exist, it should also not land in the queue\n        }\n    }\n\n    protected override string ResolveFolderId(int folderId)\n    {\n        var folderController = folderRepositoryLazy.Value;\n        var folder = folderController.GetFolder(folderId);\n        return folder?.Path;\n    }\n\n    protected override TenantFileItem ResolveFile(int fileId)\n    {\n        var fileController = fileRepositoryLazy.Value;\n        var file = fileController.GetFile(fileId);\n        if (file == null) return new()\n        {\n            Id = fileId,\n            RelativePath = null,\n            Path = null\n        };\n\n        var relativePath = Path.Combine(file?.Folder.Path.Backslash(), file?.Name);\n        var alias = oqtTenantResolverLazy.Value.GetAlias();\n        var path = fileHelper.Value.GetFilePath(hostingEnvironment.ContentRootPath, alias, relativePath);\n\n        return new()\n        {\n            Id = fileId,\n            RelativePath = relativePath,\n            Path = path\n        };\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Run/OqtZoneMapper.cs",
    "content": "﻿using Oqtane.Infrastructure;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Sxc.Cms;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.Run;\n\ninternal class OqtZoneMapper(\n    ISiteRepository siteRepository,\n    ISettingRepository settingRepository,\n    Generator<ISite> site,\n    LazySvc<ZoneCreator> zoneCreatorLazy,\n    OqtCulture oqtCulture,\n    IAppsCatalog appsCat,\n    LazySvc<ITenantManager> tenantManager)\n    : ZoneMapperBase(appsCat, $\"{OqtConstants.OqtLogPrefix}.ZoneMp\",\n        connect: [siteRepository, settingRepository, site, zoneCreatorLazy, oqtCulture, tenantManager])\n{\n    public override int GetZoneId(int siteId)\n    {\n        // additional protection against invalid portalId which may come from bad configs and execute in search-index mode\n        // see https://github.com/2sic/2sxc/issues/1054\n        if (siteId < 0)\n            throw new(\"Can't get zone for invalid portal ID: \" + siteId);\n\n        if (HasZoneId(siteId, out var existingZoneId))\n            return existingZoneId;\n\n        // Ensure the correct tenant/site is set in Oqtane SiteState before touching EAV/EF\n        // This makes SqlPlatformInfo/GlobalConfig resolve the tenant-specific connection string.\n        var portalSettings = siteRepository.GetSite(siteId);\n        tenantManager.Value.SetAlias(portalSettings.TenantId, siteId);\n\n        // Create new zone automatically, now using the proper tenant DB\n        var newZoneId = zoneCreatorLazy.Value.Create(portalSettings.Name + \" (Site \" + siteId + \")\");\n        settingRepository.AddSetting(new()\n        {\n            CreatedBy = \"2sxc\",\n            CreatedOn = DateTime.UtcNow,\n            EntityId = siteId,\n            EntityName = EntityNames.Site,\n            ModifiedBy = \"2sxc\",\n            ModifiedOn = DateTime.UtcNow,\n            SettingName = SiteSettingNames.SiteKeyForZoneId,\n            SettingValue = newZoneId.ToString()\n        });\n        return newZoneId;\n    }\n\n    private bool HasZoneId(int siteId, out int zoneId)\n    {\n        var settings = settingRepository.GetSettings(EntityNames.Site, siteId).ToList();\n\n        var zoneSetting = settings.FirstOrDefault(s => s.SettingName == SiteSettingNames.SiteKeyForZoneId);\n        if (zoneSetting is not null)\n        {\n            if (!int.TryParse(zoneSetting.SettingValue, out var parsedZoneId))\n            {\n                var msg = $\"Got value '{zoneSetting.SettingValue}' for ZoneId but can't convert to int\";\n                Log.A(msg);\n                throw new(msg);\n            }\n            zoneId = parsedZoneId;\n            return true;\n        }\n\n        zoneId = 0;\n        return false;\n    }\n\n    public override ISite SiteOfZone(int zoneId)\n    {\n        var sites = siteRepository.GetSites().ToList();\n        var found = sites.FirstOrDefault(p => HasZoneId(p.SiteId, out var zoneOfSite) && zoneOfSite == zoneId);\n        return found != null ? ((OqtSite)site.New()).Init(found) : null;\n    }\n\n    public override List<ISiteLanguageState> CulturesWithState(ISite site)\n    {\n        if (_supportedCultures != null) return _supportedCultures;\n        var availableEavLanguages = AppsCatalog.Zone(site.ZoneId).Languages;\n        _supportedCultures = oqtCulture.GetSupportedCultures(site.Id, availableEavLanguages);\n        return _supportedCultures;\n    }\n    private List<ISiteLanguageState> _supportedCultures;\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.12.00.00.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Apps]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_Apps](\n\t[AppID] [int] IDENTITY(1,1) NOT NULL,\n\t[ZoneID] [int] NOT NULL,\n\t[Name] [nvarchar](255) NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_Apps] PRIMARY KEY CLUSTERED\n(\n\t[AppID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_Apps] ON\nINSERT [dbo].[ToSIC_EAV_Apps] ([AppID], [ZoneID], [Name]) VALUES (1, 1, N'Default')\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_Apps] OFF\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AssignmentObjectTypes]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_AssignmentObjectTypes](\n\t[AssignmentObjectTypeID] [int] IDENTITY(1,1) NOT NULL,\n\t[Name] [nvarchar](50) NOT NULL,\n\t[Description] [nvarchar](max) NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_AssignmentObjectTypes] PRIMARY KEY CLUSTERED\n(\n\t[AssignmentObjectTypeID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ON\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (1, N'Default', N'Default')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (2, N'EAV Field Properties', N'EAV Field Properties')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (3, N'App', N'App')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (4, N'Entity', N'For Permissions, Data Pipelines with Pipeline Parts and Configurations')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (5, N'ContentType', N'Metadata for ContentTypes')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (6, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (7, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (8, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (9, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (10, N'CmsObject', N'References to CMS objects like files and pages')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (11, N'News?', N'News?')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (12, N'Contacts?', N'Contacts?')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (13, N'2SexyContent', N'2Sexy Contents data for the 2Sexy Content Module')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (14, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (15, N'2SexyContent-Template', N'2Sexy Content Template')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (16, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (17, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (18, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (19, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (20, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (21, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (22, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (23, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (24, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (25, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (26, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (27, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (28, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (29, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (30, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (31, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (32, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (33, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (34, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (35, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (36, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (37, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (38, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (39, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (40, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (41, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (42, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (43, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (44, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (45, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (46, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (47, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (48, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (49, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (50, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (51, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (52, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (53, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (54, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (55, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (56, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (57, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (58, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (59, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (60, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (61, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (62, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (63, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (64, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (65, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (66, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (67, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (68, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (69, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (70, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (71, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (72, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (73, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (74, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (75, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (76, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (77, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (78, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (79, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (80, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (81, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (82, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (83, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (84, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (85, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (86, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (87, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (88, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (89, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (90, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (91, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (92, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (93, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (94, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (95, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (96, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (97, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (98, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (99, N'Reserved', N'Reserved')\nINSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID], [Name], [Description]) VALUES (100, N'Reserved', N'Reserved')\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_AssignmentObjectTypes] OFF\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeGroups]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_AttributeGroups](\n\t[AttributeGroupID] [int] IDENTITY(1,1) NOT NULL,\n\t[Name] [nvarchar](50) NOT NULL,\n\t[SortOrder] [int] NOT NULL,\n\t[AttributeSetID] [int] NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_AttributeGroups] PRIMARY KEY CLUSTERED\n(\n\t[AttributeGroupID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_AttributeGroups] ON\nINSERT [dbo].[ToSIC_EAV_AttributeGroups] ([AttributeGroupID], [Name], [SortOrder], [AttributeSetID]) VALUES (1, N'Default', 0, 1)\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_AttributeGroups] OFF\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Attributes]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_Attributes](\n\t[AttributeID] [int] IDENTITY(1,1) NOT NULL,\n\t[StaticName] [nvarchar](50) NOT NULL,\n\t[Type] [nvarchar](50) NOT NULL,\n\t[ChangeLogCreated] [int] NOT NULL,\n\t[ChangeLogDeleted] [int] NULL,\n CONSTRAINT [PK_ToSIC_EAV_Attributes] PRIMARY KEY CLUSTERED\n(\n\t[AttributeID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_AttributeSets](\n\t[AttributeSetID] [int] IDENTITY(1,1) NOT NULL,\n\t[StaticName] [nvarchar](150) NULL,\n\t[Name] [nvarchar](150) NULL,\n\t[Scope] [nvarchar](50) NULL,\n\t[Description] [nvarchar](max) NOT NULL,\n\t[ChangeLogCreated] [int] NOT NULL,\n\t[ChangeLogDeleted] [int] NULL,\n\t[AppID] [int] NOT NULL,\n\t[UsesConfigurationOfAttributeSet] [int] NULL,\n\t[AlwaysShareConfiguration] [bit] NOT NULL,\n\t[Json] [nvarchar](max) NULL,\n CONSTRAINT [PK_ToSIC_EAV_AttributeSets] PRIMARY KEY CLUSTERED\n(\n\t[AttributeSetID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_AttributeSets] ON\nINSERT [dbo].[ToSIC_EAV_AttributeSets] ([AttributeSetID], [StaticName], [Name], [Scope], [Description], [ChangeLogCreated], [ChangeLogDeleted], [AppID], [UsesConfigurationOfAttributeSet], [AlwaysShareConfiguration], [Json]) VALUES (1, N'Default', N'Default (built in)', N'2SexyContent-System', N'Default', 1, NULL, 1, NULL, 1, NULL)\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_AttributeSets] OFF\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributesInSets]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_AttributesInSets](\n\t[AttributeID] [int] NOT NULL,\n\t[AttributeSetID] [int] NOT NULL,\n\t[AttributeGroupID] [int] NOT NULL,\n\t[SortOrder] [int] NOT NULL,\n\t[IsTitle] [bit] NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_AttributesInSets] PRIMARY KEY CLUSTERED\n(\n\t[AttributeID] ASC,\n\t[AttributeSetID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeTypes]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_AttributeTypes](\n\t[Type] [nvarchar](50) NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_AttributeTypes] PRIMARY KEY CLUSTERED\n(\n\t[Type] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nINSERT [dbo].[ToSIC_EAV_AttributeTypes] ([Type]) VALUES (N'Boolean')\nINSERT [dbo].[ToSIC_EAV_AttributeTypes] ([Type]) VALUES (N'Custom')\nINSERT [dbo].[ToSIC_EAV_AttributeTypes] ([Type]) VALUES (N'DateTime')\nINSERT [dbo].[ToSIC_EAV_AttributeTypes] ([Type]) VALUES (N'Empty')\nINSERT [dbo].[ToSIC_EAV_AttributeTypes] ([Type]) VALUES (N'Entity')\nINSERT [dbo].[ToSIC_EAV_AttributeTypes] ([Type]) VALUES (N'Hyperlink')\nINSERT [dbo].[ToSIC_EAV_AttributeTypes] ([Type]) VALUES (N'Number')\nINSERT [dbo].[ToSIC_EAV_AttributeTypes] ([Type]) VALUES (N'String')\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ChangeLog]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_ChangeLog](\n\t[ChangeID] [int] IDENTITY(1,1) NOT NULL,\n\t[Timestamp] [datetime] NOT NULL,\n\t[User] [nvarchar](255) NULL,\n CONSTRAINT [PK_ToSIC_EAV_ChangeLog] PRIMARY KEY CLUSTERED\n(\n\t[ChangeID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_ChangeLog] ON\nINSERT [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID], [Timestamp], [User]) VALUES (1, CAST(N'2012-05-02T08:31:35.297' AS DateTime), NULL)\nINSERT [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID], [Timestamp], [User]) VALUES (100, CAST(N'2020-10-20T00:00:00.000' AS DateTime), NULL)\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_ChangeLog] OFF\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ContextInfo]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_ContextInfo](\n\t[ContextInfo] [varbinary](128) NOT NULL,\n\t[ChangeID] [nvarchar](128) NOT NULL,\n\t[UpdatedAt] [datetime] NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_ContextInfo] PRIMARY KEY CLUSTERED\n(\n\t[ContextInfo] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nINSERT [dbo].[ToSIC_EAV_ContextInfo] ([ContextInfo], [ChangeID], [UpdatedAt]) VALUES (0x7398907A91C4BC4BBEEF94F97F76996E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, N'99', CAST(N'2020-09-14T08:29:21.173' AS DateTime))\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_DataTimeline]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_DataTimeline](\n\t[ID] [int] IDENTITY(1,1) NOT NULL,\n\t[SourceTable] [nvarchar](250) NOT NULL,\n\t[SourceID] [int] NULL,\n\t[SourceGuid] [uniqueidentifier] NULL,\n\t[SourceTextKey] [nvarchar](250) NULL,\n\t[Operation] [nchar](1) NOT NULL,\n\t[SysCreatedDate] [datetime] NOT NULL,\n\t[SysLogID] [int] NULL,\n\t[NewData] [xml] NOT NULL,\n\t[Json] [nvarchar](max) NULL,\n CONSTRAINT [PK_ToSIC_EAV_DataTimeline] PRIMARY KEY CLUSTERED\n(\n\t[ID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Dimensions]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_Dimensions](\n\t[DimensionID] [int] IDENTITY(1,1) NOT NULL,\n\t[Parent] [int] NULL,\n\t[Name] [nvarchar](100) NOT NULL,\n\t[SystemKey] [nvarchar](100) NULL,\n\t[ExternalKey] [nvarchar](100) NULL,\n\t[Active] [bit] NOT NULL,\n\t[ZoneID] [int] NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_Dimensions] PRIMARY KEY CLUSTERED\n(\n\t[DimensionID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_Dimensions] ON\nINSERT [dbo].[ToSIC_EAV_Dimensions] ([DimensionID], [Parent], [Name], [SystemKey], [ExternalKey], [Active], [ZoneID]) VALUES (1, NULL, N'Culture Root', N'Culture', NULL, 1, 1)\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_Dimensions] OFF\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_Entities](\n\t[EntityID] [int] IDENTITY(1,1) NOT NULL,\n\t[EntityGUID] [uniqueidentifier] NOT NULL,\n\t[AttributeSetID] [int] NOT NULL,\n\t[ConfigurationSet] [int] NULL,\n\t[AssignmentObjectTypeID] [int] NOT NULL,\n\t[KeyNumber] [int] NULL,\n\t[KeyGuid] [uniqueidentifier] NULL,\n\t[KeyString] [nvarchar](100) NULL,\n\t[SortOrder] [int] NOT NULL,\n\t[ChangeLogCreated] [int] NOT NULL,\n\t[ChangeLogDeleted] [int] NULL,\n\t[IsPublished] [bit] NOT NULL,\n\t[PublishedEntityId] [int] NULL,\n\t[ChangeLogModified] [int] NOT NULL,\n\t[Owner] [nvarchar](250) NULL,\n\t[Json] [nvarchar](max) NULL,\n\t[Version] [int] NOT NULL,\n\t[AppId] [int] NOT NULL,\n\t[ContentType] [nvarchar](250) NULL,\n CONSTRAINT [PK_ToSIC_EAV_Entities] PRIMARY KEY CLUSTERED\n(\n\t[EntityID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_EntityRelationships](\n\t[AttributeID] [int] NOT NULL,\n\t[ParentEntityID] [int] NOT NULL,\n\t[ChildEntityID] [int] NULL,\n\t[SortOrder] [int] NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_EntityRelationships] PRIMARY KEY CLUSTERED\n(\n\t[AttributeID] ASC,\n\t[ParentEntityID] ASC,\n\t[SortOrder] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_Values](\n\t[ValueID] [int] IDENTITY(1,1) NOT NULL,\n\t[EntityID] [int] NOT NULL,\n\t[AttributeID] [int] NOT NULL,\n\t[Value] [nvarchar](max) NOT NULL,\n\t[ChangeLogCreated] [int] NOT NULL,\n\t[ChangeLogDeleted] [int] NULL,\n\t[ChangeLogModified] [int] NULL,\n CONSTRAINT [PK_ToSIC_EAV_Values] PRIMARY KEY CLUSTERED\n(\n\t[ValueID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ValuesDimensions]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_ValuesDimensions](\n\t[ValueID] [int] NOT NULL,\n\t[DimensionID] [int] NOT NULL,\n\t[ReadOnly] [bit] NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_ValuesDimensions] PRIMARY KEY CLUSTERED\n(\n\t[ValueID] ASC,\n\t[DimensionID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Zones]') AND type in (N'U'))\nBEGIN\nCREATE TABLE [dbo].[ToSIC_EAV_Zones](\n\t[ZoneID] [int] IDENTITY(1,1) NOT NULL,\n\t[Name] [nvarchar](255) NOT NULL,\n CONSTRAINT [PK_ToSIC_EAV_Zones] PRIMARY KEY CLUSTERED\n(\n\t[ZoneID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_Zones] ON\nINSERT [dbo].[ToSIC_EAV_Zones] ([ZoneID], [Name]) VALUES (1, N'Default')\nSET IDENTITY_INSERT [dbo].[ToSIC_EAV_Zones] OFF\nEND\nGO\n\n\nSET ANSI_PADDING ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Apps]') AND name = N'ToSIC_EAV_Apps_PreventDuplicates')\nALTER TABLE [dbo].[ToSIC_EAV_Apps] ADD  CONSTRAINT [ToSIC_EAV_Apps_PreventDuplicates] UNIQUE NONCLUSTERED\n(\n\t[Name] ASC,\n\t[ZoneID] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n\n\nSET ANSI_PADDING ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AssignmentObjectTypes]') AND name = N'IX_ToSIC_EAV_AssignmentObjectTypes')\nCREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_AssignmentObjectTypes] ON [dbo].[ToSIC_EAV_AssignmentObjectTypes]\n(\n\t[Name] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]') AND name = N'IX_KeyNumber')\nCREATE NONCLUSTERED INDEX [IX_KeyNumber] ON [dbo].[ToSIC_EAV_Entities]\n(\n\t[KeyNumber] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]') AND name = N'IX_EAV_Values1')\nCREATE NONCLUSTERED INDEX [IX_EAV_Values1] ON [dbo].[ToSIC_EAV_Values]\n(\n\t[AttributeID] ASC,\n\t[EntityID] ASC,\n\t[ChangeLogDeleted] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]') AND name = N'IX_EAV_Values2')\nCREATE NONCLUSTERED INDEX [IX_EAV_Values2] ON [dbo].[ToSIC_EAV_Values]\n(\n\t[EntityID] ASC,\n\t[ChangeLogDeleted] ASC,\n\t[AttributeID] ASC,\n\t[ValueID] ASC\n)\nINCLUDE([Value],[ChangeLogCreated]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_ToSIC_EAV_AttributeSets_StaticName]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] ADD  CONSTRAINT [DF_ToSIC_EAV_AttributeSets_StaticName]  DEFAULT (newid()) FOR [StaticName]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] ADD  CONSTRAINT [DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration]  DEFAULT ((0)) FOR [AlwaysShareConfiguration]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_ToSIC_EAV_AttributesInSets_IsTitle]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets] ADD  CONSTRAINT [DF_ToSIC_EAV_AttributesInSets_IsTitle]  DEFAULT ((0)) FOR [IsTitle]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_ToSIC_EAV_ChangeLog_Timestamp]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_ChangeLog] ADD  CONSTRAINT [DF_ToSIC_EAV_ChangeLog_Timestamp]  DEFAULT (getdate()) FOR [Timestamp]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_DataTimeline_Operation]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_DataTimeline] ADD  CONSTRAINT [DF_DataTimeline_Operation]  DEFAULT (N'I') FOR [Operation]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_ToSIC_EAV_Dimensions_Active]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_Dimensions] ADD  CONSTRAINT [DF_ToSIC_EAV_Dimensions_Active]  DEFAULT ((1)) FOR [Active]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_ToSIC_EAV_Entities_EntityGUID]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_Entities] ADD  CONSTRAINT [DF_ToSIC_EAV_Entities_EntityGUID]  DEFAULT (newid()) FOR [EntityGUID]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_ToSIC_EAV_Entities_IsPublished]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_Entities] ADD  CONSTRAINT [DF_ToSIC_EAV_Entities_IsPublished]  DEFAULT ((1)) FOR [IsPublished]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF_ToSIC_EAV_ValuesDimensions_ReadOnly]') AND type = 'D')\nBEGIN\nALTER TABLE [dbo].[ToSIC_EAV_ValuesDimensions] ADD  CONSTRAINT [DF_ToSIC_EAV_ValuesDimensions_ReadOnly]  DEFAULT ((0)) FOR [ReadOnly]\nEND\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Apps]'))\nALTER TABLE [dbo].[ToSIC_EAV_Apps]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones] FOREIGN KEY([ZoneID])\nREFERENCES [dbo].[ToSIC_EAV_Zones] ([ZoneID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Apps]'))\nALTER TABLE [dbo].[ToSIC_EAV_Apps] CHECK CONSTRAINT [FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeGroups_ToSIC_EAV_AttributeSets]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeGroups]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeGroups]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_AttributeGroups_ToSIC_EAV_AttributeSets] FOREIGN KEY([AttributeSetID])\nREFERENCES [dbo].[ToSIC_EAV_AttributeSets] ([AttributeSetID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeGroups_ToSIC_EAV_AttributeSets]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeGroups]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeGroups] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeGroups_ToSIC_EAV_AttributeSets]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nALTER TABLE [dbo].[ToSIC_EAV_Attributes]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated] FOREIGN KEY([ChangeLogCreated])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nALTER TABLE [dbo].[ToSIC_EAV_Attributes] CHECK CONSTRAINT [FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nALTER TABLE [dbo].[ToSIC_EAV_Attributes]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted] FOREIGN KEY([ChangeLogDeleted])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nALTER TABLE [dbo].[ToSIC_EAV_Attributes] CHECK CONSTRAINT [FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nALTER TABLE [dbo].[ToSIC_EAV_Attributes]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types] FOREIGN KEY([Type])\nREFERENCES [dbo].[ToSIC_EAV_AttributeTypes] ([Type])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nALTER TABLE [dbo].[ToSIC_EAV_Attributes] CHECK CONSTRAINT [FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps] FOREIGN KEY([AppID])\nREFERENCES [dbo].[ToSIC_EAV_Apps] ([AppID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets] FOREIGN KEY([UsesConfigurationOfAttributeSet])\nREFERENCES [dbo].[ToSIC_EAV_AttributeSets] ([AttributeSetID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated] FOREIGN KEY([ChangeLogCreated])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted] FOREIGN KEY([ChangeLogDeleted])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeGroups]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributesInSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeGroups] FOREIGN KEY([AttributeGroupID])\nREFERENCES [dbo].[ToSIC_EAV_AttributeGroups] ([AttributeGroupID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeGroups]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributesInSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeGroups]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_Attributes]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributesInSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_Attributes] FOREIGN KEY([AttributeID])\nREFERENCES [dbo].[ToSIC_EAV_Attributes] ([AttributeID])\nON DELETE CASCADE\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_Attributes]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributesInSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_Attributes]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeSets]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributesInSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeSets] FOREIGN KEY([AttributeSetID])\nREFERENCES [dbo].[ToSIC_EAV_AttributeSets] ([AttributeSetID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeSets]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_AttributesInSets]'))\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeSets]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Dimensions]'))\nALTER TABLE [dbo].[ToSIC_EAV_Dimensions]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1] FOREIGN KEY([Parent])\nREFERENCES [dbo].[ToSIC_EAV_Dimensions] ([DimensionID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Dimensions]'))\nALTER TABLE [dbo].[ToSIC_EAV_Dimensions] CHECK CONSTRAINT [FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Dimensions]'))\nALTER TABLE [dbo].[ToSIC_EAV_Dimensions]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones] FOREIGN KEY([ZoneID])\nREFERENCES [dbo].[ToSIC_EAV_Zones] ([ZoneID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Dimensions]'))\nALTER TABLE [dbo].[ToSIC_EAV_Dimensions] CHECK CONSTRAINT [FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps] FOREIGN KEY([AppId])\nREFERENCES [dbo].[ToSIC_EAV_Apps] ([AppID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes] FOREIGN KEY([AssignmentObjectTypeID])\nREFERENCES [dbo].[ToSIC_EAV_AssignmentObjectTypes] ([AssignmentObjectTypeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets] FOREIGN KEY([AttributeSetID])\nREFERENCES [dbo].[ToSIC_EAV_AttributeSets] ([AttributeSetID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified] FOREIGN KEY([ChangeLogModified])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated] FOREIGN KEY([ChangeLogCreated])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted] FOREIGN KEY([ChangeLogDeleted])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities] FOREIGN KEY([ConfigurationSet])\nREFERENCES [dbo].[ToSIC_EAV_Entities] ([EntityID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]'))\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes] FOREIGN KEY([AttributeID])\nREFERENCES [dbo].[ToSIC_EAV_Attributes] ([AttributeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]'))\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships] CHECK CONSTRAINT [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]'))\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities] FOREIGN KEY([ChildEntityID])\nREFERENCES [dbo].[ToSIC_EAV_Entities] ([EntityID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]'))\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships] CHECK CONSTRAINT [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]'))\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities] FOREIGN KEY([ParentEntityID])\nREFERENCES [dbo].[ToSIC_EAV_Entities] ([EntityID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]'))\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships] CHECK CONSTRAINT [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes] FOREIGN KEY([AttributeID])\nREFERENCES [dbo].[ToSIC_EAV_Attributes] ([AttributeID])\nON DELETE CASCADE\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated] FOREIGN KEY([ChangeLogCreated])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted] FOREIGN KEY([ChangeLogDeleted])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified] FOREIGN KEY([ChangeLogModified])\nREFERENCES [dbo].[ToSIC_EAV_ChangeLog] ([ChangeID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_Entities]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_Entities] FOREIGN KEY([EntityID])\nREFERENCES [dbo].[ToSIC_EAV_Entities] ([EntityID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_Entities]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_Values]'))\nALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_ToSIC_EAV_Entities]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ValuesDimensions]'))\nALTER TABLE [dbo].[ToSIC_EAV_ValuesDimensions]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions] FOREIGN KEY([DimensionID])\nREFERENCES [dbo].[ToSIC_EAV_Dimensions] ([DimensionID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ValuesDimensions]'))\nALTER TABLE [dbo].[ToSIC_EAV_ValuesDimensions] CHECK CONSTRAINT [FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions]\nGO\n\n\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ValuesDimensions]'))\nALTER TABLE [dbo].[ToSIC_EAV_ValuesDimensions]  WITH CHECK ADD  CONSTRAINT [FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values] FOREIGN KEY([ValueID])\nREFERENCES [dbo].[ToSIC_EAV_Values] ([ValueID])\nGO\n\n\nIF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values]') AND parent_object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ValuesDimensions]'))\nALTER TABLE [dbo].[ToSIC_EAV_ValuesDimensions] CHECK CONSTRAINT [FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values]\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ChangeLogAdd]') AND type in (N'P', N'PC'))\nBEGIN\nEXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[ToSIC_EAV_ChangeLogAdd] AS'\nEND\nGO\n\nALTER PROCEDURE [dbo].[ToSIC_EAV_ChangeLogAdd]\n\t-- Add the parameters for the stored procedure here\n\t@User nvarchar(255) = null\nAS\nBEGIN\n\t-- SET NOCOUNT ON added to prevent extra result sets from\n\t-- interfering with SELECT statements.\n\t--SET NOCOUNT ON;\n\n\t-- Insert statements for procedure here\n\tINSERT INTO [dbo].[ToSIC_EAV_ChangeLog] ([Timestamp] ,[User])\n\tVALUES (GetDate(), @user)\n\n\tDECLARE @ChangeID int\n\tSET @ChangeID = scope_identity()\n\tEXEC ToSIC_EAV_ChangeLogSet @ChangeID\n\n\tSELECT *\n\tFROM [dbo].[ToSIC_EAV_ChangeLog]\n\tWHERE [ChangeID] = @ChangeID\nEND\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ChangeLogGet]') AND type in (N'P', N'PC'))\nBEGIN\nEXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[ToSIC_EAV_ChangeLogGet] AS'\nEND\nGO\n\nALTER PROCEDURE [dbo].[ToSIC_EAV_ChangeLogGet]\nAS\n\tSET NOCOUNT ON\n\tDECLARE @ContextInfo varbinary(128)\n\tSELECT @ContextInfo = CONTEXT_INFO()\n\n\tDECLARE @ChangeID int\n\tSET @ChangeID = 0\n\n\tSELECT @ChangeID = [ChangeID]\n\tFROM [dbo].[ToSIC_EAV_ContextInfo]\n\tWHERE [ContextInfo] = @ContextInfo\n\n\tRETURN @ChangeID\n\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_ChangeLogSet]') AND type in (N'P', N'PC'))\nBEGIN\nEXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[ToSIC_EAV_ChangeLogSet] AS'\nEND\nGO\n\n\nALTER PROCEDURE [dbo].[ToSIC_EAV_ChangeLogSet]\n  @ChangeID int\nAS\n\nSET NOCOUNT ON\n\n-- Remove all context items older than an 5 minutes ago\nDELETE FROM [dbo].[ToSIC_EAV_ContextInfo] WHERE [UpdatedAt] < DATEADD(mi, -5, GETUTCDATE())\n\nIF SERVERPROPERTY('edition') <> 'SQL Azure' OR CAST(SERVERPROPERTY('ProductVersion') AS CHAR(2)) >= '12'\nBEGIN\n\tDECLARE @b varbinary(128)\n\tSET @b = CONVERT(varbinary(128),newid())\n\tEXEC sp_executesql @statement=N'SET CONTEXT_INFO @b',@params=N'@b varbinary(128)',@b=@b\n\tprint @b\nEND\n\nDECLARE @ContextInfo varbinary(128)\nSELECT @ContextInfo = CONTEXT_INFO()\n\nIF EXISTS (SELECT * FROM [dbo].[ToSIC_EAV_ContextInfo] WHERE [ContextInfo] = @ContextInfo)\n\tUPDATE [dbo].[ToSIC_EAV_ContextInfo]\n\tSET\n\t\t[ChangeID] = @ChangeID,\n\t\t[UpdatedAt] = GETUTCDATE()\n\tWHERE\n\t\tContextInfo = @ContextInfo\nELSE\n\tINSERT INTO [dbo].[ToSIC_EAV_ContextInfo] ([ContextInfo], [ChangeID], [UpdatedAt]) VALUES (@ContextInfo, @ChangeID, GETUTCDATE());\n\n\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_DeleteApp]') AND type in (N'P', N'PC'))\nBEGIN\nEXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[ToSIC_EAV_DeleteApp] AS'\nEND\nGO\n\n\n-- =============================================\n-- Author:\t\tBenjamin Gemperle\n-- Create date: 2014-02-26\n-- Description:\tDelete an App in the 2sic EAV System\n-- =============================================\nALTER PROCEDURE [dbo].[ToSIC_EAV_DeleteApp]\n\t@AppId int\nAS\nBEGIN\n\t-- SET NOCOUNT ON added to prevent extra result sets from\n\t-- interfering with SELECT statements.\n\tSET NOCOUNT ON;\n\n\t-- Delete Value-Dimensions\n\tDELETE FROM ToSIC_EAV_ValuesDimensions\n\tFROM            ToSIC_EAV_Values INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_Entities ON ToSIC_EAV_Values.EntityID = ToSIC_EAV_Entities.EntityID INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributeSets ON ToSIC_EAV_Entities.AttributeSetID = ToSIC_EAV_AttributeSets.AttributeSetID INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_ValuesDimensions ON ToSIC_EAV_Values.ValueID = ToSIC_EAV_ValuesDimensions.ValueID\n\tWHERE        (ToSIC_EAV_AttributeSets.AppID = @AppID)\n\n\t-- Delete Values\n\tDELETE FROM ToSIC_EAV_Values\n\tFROM            ToSIC_EAV_Values INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_Entities ON ToSIC_EAV_Values.EntityID = ToSIC_EAV_Entities.EntityID INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributeSets ON ToSIC_EAV_Entities.AttributeSetID = ToSIC_EAV_AttributeSets.AttributeSetID\n\tWHERE        (ToSIC_EAV_AttributeSets.AppID = @AppID)\n\n\t-- Delete Parent-EntityRelationships\n\tDELETE FROM ToSIC_EAV_EntityRelationships\n\tFROM            ToSIC_EAV_Entities INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributeSets ON ToSIC_EAV_Entities.AttributeSetID = ToSIC_EAV_AttributeSets.AttributeSetID INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_EntityRelationships ON ToSIC_EAV_Entities.EntityID = ToSIC_EAV_EntityRelationships.ParentEntityID\n\tWHERE        (ToSIC_EAV_AttributeSets.AppID = @AppID)\n\n\t-- Delete Child-EntityRelationships\n\tDELETE FROM ToSIC_EAV_EntityRelationships\n\tFROM            ToSIC_EAV_Entities INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributeSets ON ToSIC_EAV_Entities.AttributeSetID = ToSIC_EAV_AttributeSets.AttributeSetID INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_EntityRelationships ON ToSIC_EAV_Entities.EntityID = ToSIC_EAV_EntityRelationships.ChildEntityID\n\tWHERE        (ToSIC_EAV_AttributeSets.AppID = @AppID)\n\n\t-- Delete Entities\n\tDELETE FROM ToSIC_EAV_Entities\n\tFROM            ToSIC_EAV_Entities INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributeSets ON ToSIC_EAV_Entities.AttributeSetID = ToSIC_EAV_AttributeSets.AttributeSetID\n\tWHERE        (ToSIC_EAV_AttributeSets.AppID = @AppId)\n\n\t-- Delete Attributes\n\tDELETE FROM ToSIC_EAV_Attributes\n\tFROM            ToSIC_EAV_Attributes INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributesInSets ON ToSIC_EAV_Attributes.AttributeID = ToSIC_EAV_AttributesInSets.AttributeID INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributeSets ON ToSIC_EAV_AttributesInSets.AttributeSetID = ToSIC_EAV_AttributeSets.AttributeSetID\n\tWHERE        (ToSIC_EAV_AttributeSets.AppID = @AppID)\n\n\n\t-- Delete Attributes not in use anywhere (Attribute not in any Set, no Values/Related Entities)\n\tDELETE FROM ToSIC_EAV_Attributes\n\tFROM            ToSIC_EAV_Attributes LEFT OUTER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributesInSets ON ToSIC_EAV_Attributes.AttributeID = ToSIC_EAV_AttributesInSets.AttributeID LEFT OUTER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_EntityRelationships ON ToSIC_EAV_Attributes.AttributeID = ToSIC_EAV_EntityRelationships.AttributeID LEFT OUTER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_Values ON ToSIC_EAV_Attributes.AttributeID = ToSIC_EAV_Values.AttributeID\n\tWHERE        (ToSIC_EAV_Values.ValueID IS NULL) AND (ToSIC_EAV_EntityRelationships.AttributeID IS NULL) AND (ToSIC_EAV_AttributesInSets.AttributeID IS NULL)\n\n\t-- Delete Attribute-In-Sets\n\tDELETE FROM ToSIC_EAV_AttributesInSets\n\tFROM            ToSIC_EAV_AttributeSets INNER JOIN\n\t\t\t\t\t\t\t ToSIC_EAV_AttributesInSets ON ToSIC_EAV_AttributeSets.AttributeSetID = ToSIC_EAV_AttributesInSets.AttributeSetID\n\tWHERE        (ToSIC_EAV_AttributeSets.AppID = @AppId)\n\n\t-- Delete AttributeSets\n\tDELETE FROM ToSIC_EAV_AttributeSets WHERE AppID = @AppId\n\n\t-- Delete App\n\tDELETE FROM ToSIC_EAV_Apps WHERE AppID = @AppId\n\n\nEND\n\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ToSIC_EAV_LogToTimeline]') AND type in (N'P', N'PC'))\nBEGIN\nEXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[ToSIC_EAV_LogToTimeline] AS'\nEND\nGO\n\nALTER PROCEDURE [dbo].[ToSIC_EAV_LogToTimeline]\n\t-- Add the parameters for the stored procedure here\n\t@table nvarchar(250) = '',\n\t@sourceID int = null,\n\t@sourceGuid uniqueidentifier = null,\n\t@sourceTextKey nvarchar(250) = null,\n\t@operation nchar(1),\n\t@sysCreated datetime = null,\n\t@sysChangeLogId int = null,\n\t@newData xml\n\nAS\nBEGIN\n\t-- SET NOCOUNT ON added to prevent extra result sets from\n\t-- interfering with SELECT statements.\n\tSET NOCOUNT ON;\n\tSet @operation = Lower(@operation)\t-- convert D-->d, U-->u, I-->i\n\n\tif @operation = 'd'\n\t\tBegin\n\t\t\tSelect @newData = '<d/>'\n\t\tEnd\n\n\t-- Insert statements for procedure here\n\tINSERT INTO [ToSIC_EAV_DataTimeline]\n\t\t   ([SourceTable]\n\t\t   ,[SourceID]\n\t\t   ,[SourceGuid]\n\t\t   ,[SourceTextKey]\n\t\t   ,[Operation]\n\t\t   ,[SysCreatedDate]\n\t\t   ,[SysLogID]\n\t\t   ,[NewData])\n\t VALUES\n\t\t   (@table\n\t\t   ,@sourceID\n\t\t   ,@sourceGuid\n\t\t   ,@sourceTextKey\n\t\t   ,@operation\n\t\t   ,@sysCreated\n\t\t   ,@sysChangeLogId\n\t\t   ,@newData)\nEND\n\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[AutoLogAllChangesToTimeline_EntityRelationships]'))\nEXEC dbo.sp_executesql @statement = N'\n-- =============================================\n-- Author:\t\tDaniel Mettler\n-- Create date: 2013-01-28\n-- Description:\tAutomatically log all changes to the DataTimeline\n-- =============================================\nCREATE TRIGGER [dbo].[AutoLogAllChangesToTimeline_EntityRelationships]\n   ON  [dbo].[ToSIC_EAV_EntityRelationships]\n   AFTER INSERT,DELETE,UPDATE\nAS\nBEGIN\n\t-- SET NOCOUNT ON added to prevent extra result sets from\n\t-- interfering with SELECT statements.\n\tSET NOCOUNT ON;\n\n\t-- Insert statements for trigger here\n\tDeclare @table nvarchar(250)\n\t\t,@rowID int\n\t\t,@rowGuid uniqueidentifier\n\t\t,@rowTextKey nvarchar(250)\n\t\t,@operation nchar(1)\n\t\t,@sysCreated datetime\n\t\t,@sysLogID int\n\t\t,@newData xml\n\n\tEXEC @sysLogId = [dbo].[ToSIC_EAV_ChangeLogGet]\n\tIF @sysLogId = 0\n\tBEGIN\n\t\tRAISERROR (''ChangeLogID is not set'', 0, 1)\n\t\tRETURN\n\tEND\n\n\t-- Automatically get the table name where this trigger is attached\n\tSelect @table = OBJECT_NAME(parent_id) FROM sys.triggers WHERE object_id=@@PROCID\n\tSelect @sysCreated = GetDate()\n\n\t-- Find out if insert, update or delete\n\t-- Note: here you would adapt things to our table if you re-use this trigger\n\t-- 1. Ensure you use a valid field in both IF EXISTS queries (the SysCreated might not exist everywhere)\n\t-- 2. Ensure you get the right keys (this example uses @rowID, but you could also use @rowGuid, @rowTextKey)\n\t-- 3. if you have a logid, also set the @sysLogId\n\t-- Note: don''t know how to get the LogID in there when deleting...\n\tIF EXISTS (SELECT * FROM Inserted)\n\t\tBEGIN\n\t\t\tSelect @rowID = ParentEntityID From inserted\n\t\t\tSelect @newData = (Select * From Inserted For XML Auto)\n\t\t\tSet @operation = ''I''\n\t\t\tIF EXISTS (SELECT * FROM deleted)\n\t\t\t\tBegin\n\t\t\t\t\tSET @operation = ''U''\n\t\t\t\tEnd\n\t\tEND\n\tELSE\n\t\tBEGIN\n\t\t\tSelect @rowID = ParentEntityID From deleted\n\t\t\tSET @operation = ''D''\n\t\tEND\n\n\t-- Add the stuff...\n\tExec dbo.ToSIC_EAV_LogToTimeline @table, @rowID, @rowGuid, @rowTextKey, @operation, @sysCreated, @sysLogId, @newData\nEND\n'\nGO\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships] ENABLE TRIGGER [AutoLogAllChangesToTimeline_EntityRelationships]\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[AutoLogAllChangesToTimeline_Values]'))\nEXEC dbo.sp_executesql @statement = N'\n-- =============================================\n-- Author:\t\tDaniel Mettler\n-- Create date: 2013-01-28\n-- Description:\tAutomatically log all changes to the DataTimeline\n-- =============================================\nCREATE TRIGGER [dbo].[AutoLogAllChangesToTimeline_Values]\n   ON  [dbo].[ToSIC_EAV_Values]\n   AFTER INSERT,DELETE,UPDATE\nAS\nBEGIN\n\t-- SET NOCOUNT ON added to prevent extra result sets from\n\t-- interfering with SELECT statements.\n\tSET NOCOUNT ON;\n\n\t-- Insert statements for trigger here\n\tDeclare @table nvarchar(250)\n\t\t,@rowID int\n\t\t,@rowGuid uniqueidentifier\n\t\t,@rowTextKey nvarchar(250)\n\t\t,@operation nchar(1)\n\t\t,@sysCreated datetime\n\t\t,@sysLogID int\n\t\t,@newData xml\n\n\tEXEC @sysLogId = [dbo].[ToSIC_EAV_ChangeLogGet]\n\tIF @sysLogId = 0\n\tBEGIN\n\t\tRAISERROR (''ChangeLogID is not set'', 0, 1)\n\t\tRETURN\n\tEND\n\n\t-- Automatically get the table name where this trigger is attached\n\tSelect @table = OBJECT_NAME(parent_id) FROM sys.triggers WHERE object_id=@@PROCID\n\tSelect @sysCreated = GetDate()\n\n\t-- Find out if insert, update or delete\n\t-- Note: here you would adapt things to our table if you re-use this trigger\n\t-- 1. Ensure you use a valid field in both IF EXISTS queries (the SysCreated might not exist everywhere)\n\t-- 2. Ensure you get the right keys (this example uses @rowID, but you could also use @rowGuid, @rowTextKey)\n\t-- 3. if you have a logid, also set the @sysLogId\n\t-- Note: don''t know how to get the LogID in there when deleting...\n\tIF EXISTS (SELECT * FROM Inserted)\n\t\tBEGIN\n\t\t\tSelect @rowID = ValueID From inserted\n\t\t\tSelect @newData = (Select * From Inserted For XML Auto)\n\t\t\tSet @operation = ''I''\n\t\t\tIF EXISTS (SELECT * FROM deleted)\n\t\t\t\tBegin\n\t\t\t\t\tSET @operation = ''U''\n\t\t\t\tEnd\n\t\tEND\n\tELSE\n\t\tBEGIN\n\t\t\tSelect @rowID = ValueID From deleted\n\t\t\tSET @operation = ''D''\n\t\tEND\n\n\t-- Add the stuff...\n\tExec dbo.ToSIC_EAV_LogToTimeline @table, @rowID, @rowGuid, @rowTextKey, @operation, @sysCreated, @sysLogId, @newData\nEND\n'\nGO\nALTER TABLE [dbo].[ToSIC_EAV_Values] ENABLE TRIGGER [AutoLogAllChangesToTimeline_Values]\nGO\n\n\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nIF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[AutoLogAllChangesToTimeline_ValuesDimensions]'))\nEXEC dbo.sp_executesql @statement = N'\n-- =============================================\n-- Author:\t\tDaniel Mettler\n-- Create date: 2013-01-28\n-- Description:\tAutomatically log all changes to the DataTimeline\n-- =============================================\nCREATE TRIGGER [dbo].[AutoLogAllChangesToTimeline_ValuesDimensions]\n   ON  [dbo].[ToSIC_EAV_ValuesDimensions]\n   AFTER INSERT,DELETE,UPDATE\nAS\nBEGIN\n\t-- SET NOCOUNT ON added to prevent extra result sets from\n\t-- interfering with SELECT statements.\n\tSET NOCOUNT ON;\n\n\t-- Insert statements for trigger here\n\tDeclare @table nvarchar(250)\n\t\t,@rowID int\n\t\t,@rowGuid uniqueidentifier\n\t\t,@rowTextKey nvarchar(250)\n\t\t,@operation nchar(1)\n\t\t,@sysCreated datetime\n\t\t,@sysLogID int\n\t\t,@newData xml\n\n\tEXEC @sysLogId = [dbo].[ToSIC_EAV_ChangeLogGet]\n\tIF @sysLogId = 0\n\tBEGIN\n\t\tRAISERROR (''ChangeLogID is not set'', 0, 1)\n\t\tRETURN\n\tEND\n\n\t-- Automatically get the table name where this trigger is attached\n\tSelect @table = OBJECT_NAME(parent_id) FROM sys.triggers WHERE object_id=@@PROCID\n\tSelect @sysCreated = GetDate()\n\n\t-- Find out if insert, update or delete\n\t-- Note: here you would adapt things to our table if you re-use this trigger\n\t-- 1. Ensure you use a valid field in both IF EXISTS queries (the SysCreated might not exist everywhere)\n\t-- 2. Ensure you get the right keys (this example uses @rowID, but you could also use @rowGuid, @rowTextKey)\n\t-- 3. if you have a logid, also set the @sysLogId\n\t-- Note: don''t know how to get the LogID in there when deleting...\n\tIF EXISTS (SELECT * FROM Inserted)\n\t\tBEGIN\n\t\t\tSelect @rowID = ValueID From inserted\n\t\t\tSelect @newData = (Select * From Inserted For XML Auto)\n\t\t\tSet @operation = ''I''\n\t\t\tIF EXISTS (SELECT * FROM deleted)\n\t\t\t\tBegin\n\t\t\t\t\tSET @operation = ''U''\n\t\t\t\tEnd\n\t\tEND\n\tELSE\n\t\tBEGIN\n\t\t\tSelect @rowID = ValueID From deleted\n\t\t\tSET @operation = ''D''\n\t\tEND\n\n\t-- Add the stuff...\n\tExec dbo.ToSIC_EAV_LogToTimeline @table, @rowID, @rowGuid, @rowTextKey, @operation, @sysCreated, @sysLogId, @newData\nEND\n'\nGO\nALTER TABLE [dbo].[ToSIC_EAV_ValuesDimensions] ENABLE TRIGGER [AutoLogAllChangesToTimeline_ValuesDimensions]\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.12.05.00.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n\n-- Update Folder settings\nUPDATE [dbo].[Folder] SET [IsSystem] = 0, [Type] = 'Private' WHERE [Path] LIKE 'adam%' AND [IsSystem] = 1\nGO\n\n-- Inser missing Browse permissions for All Users\nINSERT INTO [dbo].[Permission]\n\t([SiteId]\n\t,[EntityName]\n\t,[EntityId]\n\t,[PermissionName]\n\t,[RoleId]\n\t,[UserId]\n\t,[IsAuthorized]\n\t,[CreatedBy]\n\t,[CreatedOn]\n\t,[ModifiedBy]\n\t,[ModifiedOn])\nSELECT \n\t[SiteId] = f.[SiteId]\n\t,[EntityName] = 'Folder'\n\t,[FolderId] = f.[FolderId]\n\t,[PermissionName] = 'Browse'\n\t,[RoleId] = 1 -- All Users\n\t,[UserId] = null\n\t,[IsAuthorized] = 1\n\t,[CreatedBy] = f.[CreatedBy]\n\t,[CreatedOn] = f.[CreatedOn]\n\t,[ModifiedBy] = f.[ModifiedBy]\n\t,[ModifiedOn] = f.[ModifiedOn]\nFROM \n\t[dbo].[Folder] AS f\n\tLEFT JOIN [dbo].[Permission] AS p ON p.[EntityId] = f.[FolderId] AND p.[EntityName] = 'Folder' AND p.[PermissionName] = 'Browse'\nWHERE\n\tf.[Path] LIKE 'adam%'\n\tAND p.[PermissionId] IS NULL\nGO\n\n-- Insert missing View permissions for All Users\nINSERT INTO [dbo].[Permission]\n\t([SiteId]\n\t,[EntityName]\n\t,[EntityId]\n\t,[PermissionName]\n\t,[RoleId]\n\t,[UserId]\n\t,[IsAuthorized]\n\t,[CreatedBy]\n\t,[CreatedOn]\n\t,[ModifiedBy]\n\t,[ModifiedOn])\nSELECT \n\t[SiteId] = f.[SiteId]\n\t,[EntityName] = 'Folder'\n\t,[FolderId] = f.[FolderId]\n\t,[PermissionName] = 'View'\n\t,[RoleId] = 1 -- All Users\n\t,[UserId] = null\n\t,[IsAuthorized] = 1\n\t,[CreatedBy] = f.[CreatedBy]\n\t,[CreatedOn] = f.[CreatedOn]\n\t,[ModifiedBy] = f.[ModifiedBy]\n\t,[ModifiedOn] = f.[ModifiedOn]\nFROM \n\t[dbo].[Folder] AS f\n\tLEFT JOIN [dbo].[Permission] AS p ON p.[EntityId] = f.[FolderId] AND p.[EntityName] = 'Folder' AND p.[PermissionName] = 'View'\nWHERE\n\tf.[Path] LIKE 'adam%'\n\tAND p.[PermissionId] IS NULL\nGO\n\n-- Inser missing Browse permissions for Administrators\nINSERT INTO [dbo].[Permission]\n\t([SiteId]\n\t,[EntityName]\n\t,[EntityId]\n\t,[PermissionName]\n\t,[RoleId]\n\t,[UserId]\n\t,[IsAuthorized]\n\t,[CreatedBy]\n\t,[CreatedOn]\n\t,[ModifiedBy]\n\t,[ModifiedOn])\nSELECT \n\t[SiteId] = f.[SiteId]\n\t,[EntityName] = 'Folder'\n\t,[FolderId] = f.[FolderId]\n\t,[PermissionName] = 'Browse'\n\t,[RoleId] = r.RoleId\n\t,[UserId] = null\n\t,[IsAuthorized] = 1\n\t,[CreatedBy] = f.[CreatedBy]\n\t,[CreatedOn] = f.[CreatedOn]\n\t,[ModifiedBy] = f.[ModifiedBy]\n\t,[ModifiedOn] = f.[ModifiedOn]\nFROM \n\t[dbo].[Folder] AS f\n\tINNER JOIN [dbo].[Role] AS r ON f.SiteId = r.SiteId AND r.[Name] = 'Administrators'\n\tLEFT JOIN [dbo].[Permission] AS p ON p.[EntityId] = f.[FolderId] AND p.[EntityName] = 'Folder' AND p.[PermissionName] = 'Browse' AND r.RoleId = p.RoleId\nWHERE\n\tf.[Path] LIKE 'adam%'\n\tAND p.[PermissionId] IS NULL\nGO\n\n-- Inser missing View permissions for Administrators\nINSERT INTO [dbo].[Permission]\n\t([SiteId]\n\t,[EntityName]\n\t,[EntityId]\n\t,[PermissionName]\n\t,[RoleId]\n\t,[UserId]\n\t,[IsAuthorized]\n\t,[CreatedBy]\n\t,[CreatedOn]\n\t,[ModifiedBy]\n\t,[ModifiedOn])\nSELECT \n\t[SiteId] = f.[SiteId]\n\t,[EntityName] = 'Folder'\n\t,[FolderId] = f.[FolderId]\n\t,[PermissionName] = 'View'\n\t,[RoleId] = r.RoleId\n\t,[UserId] = null\n\t,[IsAuthorized] = 1\n\t,[CreatedBy] = f.[CreatedBy]\n\t,[CreatedOn] = f.[CreatedOn]\n\t,[ModifiedBy] = f.[ModifiedBy]\n\t,[ModifiedOn] = f.[ModifiedOn]\nFROM \n\t[dbo].[Folder] AS f\n\tINNER JOIN [dbo].[Role] AS r ON f.SiteId = r.SiteId AND r.[Name] = 'Administrators'\n\tLEFT JOIN [dbo].[Permission] AS p ON p.[EntityId] = f.[FolderId] AND p.[EntityName] = 'Folder' AND p.[PermissionName] = 'View' AND r.RoleId = p.RoleId\nWHERE\n\tf.[Path] LIKE 'adam%'\n\tAND p.[PermissionId] IS NULL\nGO\n\n-- Inser missing Edit permissions for Administrators\nINSERT INTO [dbo].[Permission]\n\t([SiteId]\n\t,[EntityName]\n\t,[EntityId]\n\t,[PermissionName]\n\t,[RoleId]\n\t,[UserId]\n\t,[IsAuthorized]\n\t,[CreatedBy]\n\t,[CreatedOn]\n\t,[ModifiedBy]\n\t,[ModifiedOn])\nSELECT \n\t[SiteId] = f.[SiteId]\n\t,[EntityName] = 'Folder'\n\t,[FolderId] = f.[FolderId]\n\t,[PermissionName] = 'Edit'\n\t,[RoleId] = r.RoleId\n\t,[UserId] = null\n\t,[IsAuthorized] = 1\n\t,[CreatedBy] = f.[CreatedBy]\n\t,[CreatedOn] = f.[CreatedOn]\n\t,[ModifiedBy] = f.[ModifiedBy]\n\t,[ModifiedOn] = f.[ModifiedOn]\nFROM \n\t[dbo].[Folder] AS f\n\tINNER JOIN [dbo].[Role] AS r ON f.SiteId = r.SiteId AND r.[Name] = 'Administrators'\n\tLEFT JOIN [dbo].[Permission] AS p ON p.[EntityId] = f.[FolderId] AND p.[EntityName] = 'Folder' AND p.[PermissionName] = 'Edit' AND r.RoleId = p.RoleId\nWHERE\n\tf.[Path] LIKE 'adam%'\n\tAND p.[PermissionId] IS NULL\nGO\n\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.13.00.00.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n\n/* TargetTypes Metadata for ..., Custom and Custom1-9 */\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'Zone' ,[Description] = 'Metadata for Zone' WHERE [AssignmentObjectTypeID] = 6\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'System' ,[Description] = 'Metadata for System' WHERE [AssignmentObjectTypeID] = 11\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'Site' ,[Description] = 'Metadata for Site' WHERE [AssignmentObjectTypeID] = 12\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'SiteVariant' ,[Description] = 'Metadata for SiteVariant' WHERE [AssignmentObjectTypeID] = 13\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'Page' ,[Description] = 'Metadata for Page' WHERE [AssignmentObjectTypeID] = 14\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'PageVariant' ,[Description] = 'Metadata for PageVariant' WHERE [AssignmentObjectTypeID] = 15\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'Module' ,[Description] = 'Metadata for Module' WHERE [AssignmentObjectTypeID] = 16\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'ModuleVariant' ,[Description] = 'Metadata for ModuleVariant' WHERE [AssignmentObjectTypeID] = 17\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'User' ,[Description] = 'Metadata for User' WHERE [AssignmentObjectTypeID] = 18\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'Custom' + IIF ([AssignmentObjectTypeID] = 90, '', LTRIM(STR([AssignmentObjectTypeID]-90))),\n\t[Description] = 'Custom' + IIF ([AssignmentObjectTypeID] = 90, '', LTRIM(STR([AssignmentObjectTypeID]-90)))\n\tWHERE [AssignmentObjectTypeID] > 89 AND [AssignmentObjectTypeID] < 100\nGO"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.13.01.00.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\nBEGIN TRANSACTION SexyContentUpdate;\n\nIF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'ToSIC_EAV_Apps' AND COLUMN_NAME = 'SysSettings')\nBEGIN\n  ALTER TABLE ToSIC_EAV_Apps\n    ADD SysSettings nvarchar(max) NULL\nEND\n\nCOMMIT TRANSACTION SexyContentUpdate;\n--ROLLBACK TRANSACTION SexyContentUpdate;\nGO\n\n/* TargetTypes Metadata for ... */\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'Scope' ,[Description] = 'Metadata for Scope' WHERE [AssignmentObjectTypeID] = 7\nUPDATE [dbo].[ToSIC_EAV_AssignmentObjectTypes] SET [Name] = 'Dimension' ,[Description] = 'Metadata for Dimension' WHERE [AssignmentObjectTypeID] = 8\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.15.00.00.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\n-- 1. remove sql trigger functionality that store data in 'ToSIC_EAV_DataTimeline' table \n-- min Sql Server 2016\nDROP TRIGGER IF EXISTS [dbo].[AutoLogAllChangesToTimeline_EntityRelationships];\nDROP TRIGGER IF EXISTS [dbo].[AutoLogAllChangesToTimeline_Values];\nDROP TRIGGER IF EXISTS [dbo].[AutoLogAllChangesToTimeline_ValuesDimensions];\nDROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_LogToTimeline]\nGO\n\n-- 2. remove trigger generated data from 'ToSIC_EAV_DataTimeline' in batches\nWHILE (SELECT COUNT(*) FROM [dbo].[ToSIC_EAV_DataTimeline] WHERE [SourceTable] IN ('ToSIC_EAV_Values', 'ToSIC_EAV_EntityRelationships', 'ToSIC_EAV_ValuesDimensions')) > 0\nBEGIN\n    ;WITH CTE AS\n    (\n\tSELECT TOP 100000 * \n\tFROM [dbo].[ToSIC_EAV_DataTimeline] \n\tWHERE [SourceTable] IN ('ToSIC_EAV_Values', 'ToSIC_EAV_EntityRelationships', 'ToSIC_EAV_ValuesDimensions')\n\t)\n    DELETE FROM CTE;\nEND\nGO\n\n-- 3. drop NewData column from 'ToSIC_EAV_DataTimeline'\nALTER TABLE [dbo].[ToSIC_EAV_DataTimeline] DROP COLUMN IF EXISTS [NewData];\nGO\n\n-- 4. add CJson column to 'ToSIC_EAV_DataTimeline'\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'CJson' AND Object_ID = OBJECT_ID('ToSIC_EAV_DataTimeline'))\nBEGIN\n    ALTER TABLE [dbo].[ToSIC_EAV_DataTimeline] ADD [CJson] varbinary(max) NULL;\nEND\nGO\n\n-- 5. remove columns that are not in use\nALTER TABLE [dbo].[ToSIC_EAV_AttributeGroups] DROP COLUMN IF EXISTS [SortOrder];\nALTER TABLE [dbo].[ToSIC_EAV_Entities] DROP COLUMN IF EXISTS [SortOrder];\nALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] DROP COLUMN IF EXISTS [Description];\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.16.07.01.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\n-- add [Guid], [SysSettings] columns to 'ToSIC_EAV_Attributes'\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'Guid' AND Object_ID = OBJECT_ID('ToSIC_EAV_Attributes'))\nBEGIN\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] ADD [Guid] uniqueidentifier NULL,\n    [SysSettings] nvarchar(MAX) NULL;\nEND\nGO\n\n-- add [SysSettings] column to 'ToSIC_EAV_AttributeSets'\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'SysSettings' AND Object_ID = OBJECT_ID('ToSIC_EAV_AttributeSets'))\nBEGIN\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] ADD [SysSettings] nvarchar(MAX) NULL;\nEND\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.18.03.00.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\n-- Remove AttributeGroups SQL table and related:\n-- Drop the foreign key constraint before dropping the column.\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets] \nDROP CONSTRAINT IF EXISTS [FK_ToSIC_EAV_AttributesInSets_ToSIC_EAV_AttributeGroups];\nGO\n\n-- Now it's safe to drop the column.\nALTER TABLE [dbo].[ToSIC_EAV_AttributesInSets] \nDROP COLUMN IF EXISTS [AttributeGroupID];\nGO\n\n-- Drop the foreign key constraint in another table before dropping the table.\nALTER TABLE [dbo].[ToSIC_EAV_AttributeGroups] \nDROP CONSTRAINT IF EXISTS [FK_ToSIC_EAV_AttributeGroups_ToSIC_EAV_AttributeSets];\nGO\n\n-- Now it's safe to drop the table.\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AttributeGroups];\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.19.00.00.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\n-- Drop the existing foreign key constraint\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships]\n    DROP CONSTRAINT IF EXISTS [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes];\nGO\n\n-- Add the foreign key constraint with ON DELETE CASCADE\nALTER TABLE [dbo].[ToSIC_EAV_EntityRelationships]\n    ADD CONSTRAINT [FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes]\n    FOREIGN KEY ([AttributeID])\n    REFERENCES [dbo].[ToSIC_EAV_Attributes] ([AttributeID])\n    ON UPDATE NO ACTION\n    ON DELETE CASCADE;\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.20.00.00.sql",
    "content": "﻿SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\nPRINT '*** Starting migration script.';\nGO\n\n-- Preflight check 1: Ensure no AttributeID appears more than once in ToSIC_EAV_AttributesInSets\nIF OBJECT_ID('[dbo].[ToSIC_EAV_AttributesInSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT 'Running Preflight check 1: Checking for duplicate AttributeIDs in ToSIC_EAV_AttributesInSets';\n\n    IF EXISTS (\n        SELECT AttributeID\n        FROM [dbo].[ToSIC_EAV_AttributesInSets]\n        GROUP BY AttributeID\n        HAVING COUNT(*) > 1\n    )\n    BEGIN\n        THROW 50001, 'Preflight check failed: Duplicate AttributeID found in ToSIC_EAV_AttributesInSets. Migration stopped.', 1;\n        RETURN;\n    END\nEND\nGO\n\n-- Preflight check 2: Remove orphaned Attributes and related data\nIF OBJECT_ID('[dbo].[ToSIC_EAV_AttributesInSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT 'Running Preflight check 2: Removing orphaned Attributes and related data';\n\n    -- 2.1 Find orphaned AttributeIDs\n    PRINT '... Finding orphaned AttributeIDs';\n    DECLARE @OrphanedAttributes TABLE (AttributeID INT);\n    INSERT INTO @OrphanedAttributes (AttributeID)\n    SELECT a.AttributeID\n    FROM [dbo].[ToSIC_EAV_Attributes] a\n    LEFT JOIN [dbo].[ToSIC_EAV_AttributesInSets] ais ON a.AttributeID = ais.AttributeID\n    WHERE ais.AttributeID IS NULL;\n\n    -- 2.2 Find ValueIDs related to orphaned AttributeIDs\n    PRINT '... Finding related ValueIDs';\n    DECLARE @OrphanedValueIDs TABLE (ValueID INT);\n    INSERT INTO @OrphanedValueIDs (ValueID)\n    SELECT v.ValueID\n    FROM [dbo].[ToSIC_EAV_Values] v\n    INNER JOIN @OrphanedAttributes oa ON v.AttributeID = oa.AttributeID;\n\n    -- 2.3 Delete from ToSIC_EAV_ValuesDimensions (child of Values)\n    PRINT '... Deleting orphaned ValuesDimensions';\n    DELETE vd\n    FROM [dbo].[ToSIC_EAV_ValuesDimensions] vd\n    INNER JOIN @OrphanedValueIDs ov ON vd.ValueID = ov.ValueID;\n\n    -- 2.4 Delete from ToSIC_EAV_Values (child of Attributes)\n    PRINT '... Deleting orphaned Values';\n    DELETE v\n    FROM [dbo].[ToSIC_EAV_Values] v\n    INNER JOIN @OrphanedValueIDs ov ON v.ValueID = ov.ValueID;\n\n    -- 2.5 Delete from ToSIC_EAV_EntityRelationships (child of Attributes)\n    PRINT '... Deleting orphaned EntityRelationships';\n    DELETE er\n    FROM [dbo].[ToSIC_EAV_EntityRelationships] er\n    INNER JOIN @OrphanedAttributes oa ON er.AttributeID = oa.AttributeID;\n\n    -- 2.6 Delete orphaned Attributes\n    PRINT '... Deleting orphaned Attributes';\n    DELETE a\n    FROM [dbo].[ToSIC_EAV_Attributes] a\n    INNER JOIN @OrphanedAttributes oa ON a.AttributeID = oa.AttributeID;\nEND\nGO\n\nPRINT '1. Upgrade script started.';\n\n-- 1.1. Add new columns to ToSIC_EAV_Attributes if they do not exist yet.\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'ContentTypeId' AND Object_ID = OBJECT_ID('ToSIC_EAV_Attributes'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 1.1. Adding new columns (ContentTypeId, SortOrder, IsTitle) to ToSIC_EAV_Attributes';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] ADD\n        [ContentTypeId] [int] NOT NULL CONSTRAINT DF_ToSIC_EAV_Attributes_ContentTypeId DEFAULT (0),\n        [SortOrder] [int] NOT NULL CONSTRAINT DF_ToSIC_EAV_Attributes_SortOrder DEFAULT (0),\n        [IsTitle] [bit] NOT NULL CONSTRAINT DF_ToSIC_EAV_Attributes_IsTitle DEFAULT (0);\nEND\nGO\n\n-- 1.2. Migrate data from ToSIC_EAV_AttributesInSets to new columns in ToSIC_EAV_Attributes\nIF OBJECT_ID('[dbo].[ToSIC_EAV_AttributesInSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 1.2. Migrating data from ToSIC_EAV_AttributesInSets to ToSIC_EAV_Attributes';\n    UPDATE a\n    SET\n        a.ContentTypeId = ais.AttributeSetID,\n        a.SortOrder = ais.SortOrder,\n        a.IsTitle = ais.IsTitle\n    FROM [dbo].[ToSIC_EAV_Attributes] a\n    INNER JOIN [dbo].[ToSIC_EAV_AttributesInSets] ais\n        ON a.AttributeID = ais.AttributeID;\nEND\nGO\n\n-- 1.3. Add Index on ContentTypeId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_ContentTypeId' AND Object_ID = OBJECT_ID('ToSIC_EAV_Attributes'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 1.3. Adding index IX_ToSIC_EAV_Attributes_ContentTypeId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Attributes_ContentTypeId] ON [dbo].[ToSIC_EAV_Attributes] ([ContentTypeId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 1.4. Add foreign key constraint from ContentTypeId to AttributeSets.AttributeSetID\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 1.4. Adding foreign key FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes]\n    ADD CONSTRAINT FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets\n    FOREIGN KEY ([ContentTypeId]) REFERENCES [dbo].[ToSIC_EAV_AttributeSets] ([AttributeSetID]);\nEND\nGO\n\n\n\n-- 2. Remove Stored Procedures and Tables\nPRINT '2. Removing obsolete Stored Procedures and Tables';\nGO\n\nIF OBJECT_ID('[dbo].[ToSIC_EAV_ChangeLogSet]', 'P') IS NOT NULL\nBEGIN\n    PRINT '... 2.1. Removing obsolete Stored Procedures';\n    DROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogSet];\n    DROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogGet];\n    DROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogAdd];\n    DROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_DeleteApp];\nEND\nGO\n\n-- Remove Tables\nIF OBJECT_ID('[dbo].[ToSIC_EAV_ContextInfo]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 2.2. Removing obsolete Tables';\n    DROP TABLE IF EXISTS [dbo].[ToSIC_EAV_ContextInfo];\n    DROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AttributesInSets];\nEND\nGO\n\n\n\n-- *** 3. Rename AssignmentObjectTypes to TsDynDataTargetType\nPRINT '3. Renaming table ToSIC_EAV_AssignmentObjectTypes to TsDynDataTargetType and related objects';\n\n-- 3.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_AssignmentObjectTypes' AND type = 'U')\nBEGIN\n    PRINT '... 3.1. Renaming table ToSIC_EAV_AssignmentObjectTypes to TsDynDataTargetType';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AssignmentObjectTypes]', N'TsDynDataTargetType';\nEND\nGO\n\n-- 3.2. Rename the primary key column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AssignmentObjectTypeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataTargetType]'))\nBEGIN\n    PRINT '... 3.2. Renaming column AssignmentObjectTypeID to TargetTypeId in TsDynDataTargetType';\n    EXEC sp_rename N'[dbo].[TsDynDataTargetType].[AssignmentObjectTypeID]', N'TargetTypeId', N'COLUMN';\nEND\nGO\n\n-- 3.3. Rename the primary key constraint\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_AssignmentObjectTypes' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataTargetType]'))\nBEGIN\n    PRINT '... 3.3.Renaming PK_ToSIC_EAV_AssignmentObjectTypes to PK_TsDynDataTargetType';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_AssignmentObjectTypes]', N'PK_TsDynDataTargetType', N'OBJECT';\nEND\nGO\n\n-- 3.4. Rename the index\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AssignmentObjectTypes')\nBEGIN\n    PRINT '... 3.4. Renaming index IX_ToSIC_EAV_AssignmentObjectTypes to IX_TsDynDataTargetType_Name';\n    EXEC sp_rename N'[dbo].[TsDynDataTargetType].[IX_ToSIC_EAV_AssignmentObjectTypes]', N'IX_TsDynDataTargetType_Name', N'INDEX';\nEND\nGO\n\n-- 3.5. Rename the foreign key column in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AssignmentObjectTypeID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 3.5.Renaming column AssignmentObjectTypeID to TargetTypeId in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[AssignmentObjectTypeID]', N'TargetTypeId', N'COLUMN';\nEND\nGO\n\n-- 3.6. Rename foreign key constraint on ToSIC_EAV_Entities\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes')\nBEGIN\n    PRINT '... 3.6. Rename FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_AssignmentObjectTypes]', N'FK_ToSIC_EAV_Entities_TsDynDataTargetType', N'OBJECT';\nEND\nGO\n\n-- 3.7. Add Index on TargetTypeId if it doesn't exist\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TargetTypeId' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 3.7. Adding index IX_ToSIC_EAV_Entities_TargetTypeId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_TargetTypeId] ON [dbo].[ToSIC_EAV_Entities] ([TargetTypeId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 3.8. Recreate the foreign key constraint on ToSIC_EAV_Entities with the new names\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTargetType')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 3.8. Recreating foreign key FK_ToSIC_EAV_Entities_TsDynDataTargetType';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTargetType]\n    FOREIGN KEY([TargetTypeId])\n    REFERENCES [dbo].[TsDynDataTargetType] ([TargetTypeId]);\nEND\nGO\n\n-- 3.9. Check the constraint FK_ToSIC_EAV_Entities_TsDynDataTargetType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTargetType')\nBEGIN\n    PRINT '... 3.9. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataTargetType';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTargetType];\nEND\nGO\n\n\n\n-- *** 4. Rename ToSIC_EAV_ChangeLog to TsDynDataTransaction\nPRINT '4. Renaming table ToSIC_EAV_ChangeLog to TsDynDataTransaction and related objects';\n\n-- 4.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_ChangeLog' AND type = 'U')\nBEGIN\n    PRINT '... 4.1. Renaming table ToSIC_EAV_ChangeLog to TsDynDataTransaction';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_ChangeLog]', N'TsDynDataTransaction';\nEND\nGO\n\n-- 4.2. Rename the primary key column in the renamed table\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataTransaction]'))\nBEGIN\n    PRINT '... 4.2. Renaming column ChangeID to TransactionId in TsDynDataTransaction';\n    EXEC sp_rename N'[dbo].[TsDynDataTransaction].[ChangeID]', N'TransactionId', N'COLUMN';\nEND\nGO\n\n-- 4.3. Rename the primary key constraint\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_ChangeLog' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataTransaction]'))\nBEGIN\n    PRINT '... 4.3. Renaming PK_ToSIC_EAV_ChangeLog to PK_TsDynDataTransaction';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_ChangeLog]', N'PK_TsDynDataTransaction', N'OBJECT';\nEND\nGO\n\n-- 4.4. Rename the default constraint for the Timestamp column\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_ChangeLog_Timestamp' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataTransaction]'))\nBEGIN\n    PRINT '... 4.4. Renaming default constraint DF_ToSIC_EAV_ChangeLog_Timestamp';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_ChangeLog_Timestamp]', N'DF_TsDynDataTransaction_Timestamp', N'OBJECT';\nEND\nGO\n\n-- 4.5. Rename the foreign key column ChangeLogCreated in the referencing table (ToSIC_EAV_Attributes)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nBEGIN\n    PRINT '... 4.5. Renaming ChangeLogCreated columns in ToSIC_EAV_Attributes';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Attributes].[ChangeLogCreated]', N'TransactionIdCreated', N'COLUMN';\nEND\nGO\n\n-- 4.6. Rename the foreign key column ChangeLogDeleted in the referencing table (ToSIC_EAV_Attributes)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Attributes]'))\nBEGIN\n    PRINT '... 4.6. Renaming ChangeLogDeleted columns in ToSIC_EAV_Attributes';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Attributes].[ChangeLogDeleted]', N'TransactionIdDeleted', N'COLUMN';\nEND\nGO\n\n-- 4.7. Rename the foreign key column ChangeLogCreated in the referencing table (ToSIC_EAV_AttributeSets)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nBEGIN\n    PRINT '... 4.7. Renaming ChangeLogCreated columns in ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeSets].[ChangeLogCreated]', N'TransactionIdCreated', N'COLUMN';\nEND\nGO\n\n-- 4.8. Rename the foreign key column ChangeLogDeleted in the referencing table (ToSIC_EAV_AttributeSets)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nBEGIN\n    PRINT '... 4.8. Renaming ChangeLogDeleted columns in ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeSets].[ChangeLogDeleted]', N'TransactionIdDeleted', N'COLUMN';\nEND\nGO\n\n-- 4.9. Rename the foreign key column ChangeLogCreated in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 4.9. Renaming ChangeLogCreated columns in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[ChangeLogCreated]', N'TransactionIdCreated', N'COLUMN';\nEND\nGO\n\n-- 4.10. Rename the foreign key column ChangeLogModified in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogModified' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 4.10. Renaming ChangeLogModified columns in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[ChangeLogModified]', N'TransactionIdModified', N'COLUMN';\nEND\nGO\n\n-- 4.11. Rename the foreign key column ChangeLogDeleted in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 4.11. Renaming ChangeLogDeleted columns in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[ChangeLogDeleted]', N'TransactionIdDeleted', N'COLUMN';\nEND\nGO\n\n-- 4.12. Rename the foreign key column ChangeLogCreated in the referencing table (ToSIC_EAV_Values)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 4.12. Renaming ChangeLogCreated columns in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[ChangeLogCreated]', N'TransactionIdCreated', N'COLUMN';\nEND\nGO\n\n-- 4.12b. Rename the foreign key column ChangeLogModified in the referencing table (ToSIC_EAV_Values)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogModified' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 4.12b. Renaming ChangeLogModified columns in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[ChangeLogModified]', N'TransactionIdModified', N'COLUMN';\nEND\nGO\n\n-- 4.14. Rename the foreign key column ChangeLogDeleted in the referencing table (ToSIC_EAV_Values)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ChangeLogDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 4.14. Renaming ChangeLogDeleted columns in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[ChangeLogDeleted]', N'TransactionIdDeleted', N'COLUMN';\nEND\nGO\n\n-- 4.15. Rename the foreign key constraint FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated')\nBEGIN\n    PRINT '... 4.15. Rename the foreign key constraint FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogCreated]', N'FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated', N'OBJECT';\nEND\nGO\n\n-- 4.16. Add Index on IX_ToSIC_EAV_Attributes_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.16. Adding index IX_ToSIC_EAV_Attributes_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Attributes_TransactionIdCreated] ON [dbo].[ToSIC_EAV_Attributes] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.17. Create the foreign key constraint FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.17. Creating foreign key FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.18. Check constraint FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 4.18. Checking foreign key constraints on FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] CHECK CONSTRAINT [FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated];\nEND\nGO\n\n-- 4.19. Rename the foreign key constraint FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted')\nBEGIN\n    PRINT '... 4.19. Rename the foreign key constraint FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_ChangeLogDeleted]', N'FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted', N'OBJECT';\nEND\nGO\n\n-- 4.20. Add Index on IX_ToSIC_EAV_Attributes_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]'))\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.20. Adding index IX_ToSIC_EAV_Attributes_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Attributes_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_Attributes] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.21. Create the foreign key constraint FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Attributes]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.21. Creating foreign key FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.22. Check constraint FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 4.22. Checking foreign key constraints on FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Attributes] CHECK CONSTRAINT [FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted];\nEND\nGO\n\n-- 4.23. Rename the foreign key constraint FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated')\nBEGIN\n    PRINT '... 4.23. Renaming FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogCreated]', N'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated', N'OBJECT';\nEND\nGO\n\n-- 4.24. Add Index on IX_ToSIC_EAV_AttributeSets_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.24. Adding index IX_ToSIC_EAV_AttributeSets_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_AttributeSets_TransactionIdCreated] ON [dbo].[ToSIC_EAV_AttributeSets] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.25. Create foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.25. Creating foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.26. Check constraint FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 4.26. Checking foreign key constraints on FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated];\nEND\nGO\n\n-- 4.27. Rename the foreign key constraint FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted')\nBEGIN\n    PRINT '... 4.27. Renaming FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_ChangeLogDeleted]', N'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted', N'OBJECT';\nEND\nGO\n\n-- 4.28. Add Index on TransactionIdDeleted if it doesn't exist\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.28. Adding index IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_AttributeSets] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.29. Create foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.29. Creating foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.30. Check constraint FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 4.30. Checking foreign key constraints on FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted];\nEND\nGO\n\n-- 4.31. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated')\nBEGIN\n    PRINT '... 4.31. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogCreated]', N'FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated', N'OBJECT';\nEND\nGO\n\n-- 4.32. Add Index IX_ToSIC_EAV_Entities_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.32. Adding index IX_ToSIC_EAV_Entities_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_TransactionIdCreated] ON [dbo].[ToSIC_EAV_Entities] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.33. Create foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.33. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.34. Check constraint FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 4.34. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated];\nEND\nGO\n\n-- 4.35. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified')\nBEGIN\n    PRINT '... 4.35. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLog_Modified]', N'FK_ToSIC_EAV_Entities_TsDynDataTransactionModified', N'OBJECT';\nEND\nGO\n\n-- 4.36. Add Index IX_ToSIC_EAV_Entities_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.36. Adding index IX_ToSIC_EAV_Entities_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_TransactionIdModified] ON [dbo].[ToSIC_EAV_Entities] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.37. Create foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.37. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.38. Check constraint FK_ToSIC_EAV_Entities_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 4.38. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionModified];\nEND\nGO\n\n-- 4.39. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted')\nBEGIN\n    PRINT '... 4.39. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_ChangeLogDeleted]', N'FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted', N'OBJECT';\nEND\nGO\n\n-- 4.40. Add Index IX_ToSIC_EAV_Entities_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.40. Adding index IX_ToSIC_EAV_Entities_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_Entities] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.41. Create foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.41. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.42. Check constraint FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 4.42. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted];\nEND\nGO\n\n-- 4.43. Rename the foreign key constraint FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated')\nBEGIN\n    PRINT '... 4.43. Renaming FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogCreated]', N'FK_ToSIC_EAV_Values_TsDynDataTransactionCreated', N'OBJECT';\nEND\nGO\n\n-- 4.44. Add Index IX_ToSIC_EAV_Values_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.44. Adding index IX_ToSIC_EAV_Values_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Values_TransactionIdCreated] ON [dbo].[ToSIC_EAV_Values] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.45. Create foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.45. Creating foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.46. Check constraint FK_ToSIC_EAV_Values_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 4.46. Checking foreign key constraints on FK_ToSIC_EAV_Values_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionCreated];\nEND\nGO\n\n-- 4.47. Rename the foreign key constraint FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified')\nBEGIN\n    PRINT '... 4.47. Renaming FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogModified]', N'FK_ToSIC_EAV_Values_TsDynDataTransactionModified', N'OBJECT';\nEND\nGO\n\n-- 4.48. Add Index IX_ToSIC_EAV_Values_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.48. Adding index IX_ToSIC_EAV_Values_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Values_TransactionIdModified] ON [dbo].[ToSIC_EAV_Values] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.49. Create foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.49. Creating foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.50. Check constraint FK_ToSIC_EAV_Values_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 4.50. Checking foreign key constraints on FK_ToSIC_EAV_Values_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionModified];\nEND\nGO\n\n-- 4.51. Rename the foreign key constraint FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted')\nBEGIN\n    PRINT '... 4.51. Renaming FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_ChangeLogDeleted]', N'FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted', N'OBJECT';\nEND\nGO\n\n-- 4.52. Add Index IX_ToSIC_EAV_Values_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.52. Adding index IX_ToSIC_EAV_Values_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Values_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_Values] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 4.53. Create foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Values]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 4.53. Creating foreign key FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 4.54. Check constraint FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 4.54. Checking foreign key constraints on FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] CHECK CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted];\nEND\nGO\n\n\n\n-- *** 5. Rename ToSIC_EAV_DataTimeline to TsDynDataHistory and update related objects\nPRINT '5. Renaming table ToSIC_EAV_DataTimeline to TsDynDataHistory and related objects';\n\n-- 5.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_DataTimeline' AND type = 'U')\nBEGIN\n    PRINT '... 5.1. Renaming table ToSIC_EAV_DataTimeline to TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_DataTimeline]', N'TsDynDataHistory';\nEND\nGO\n\n-- 5.2. Rename the primary key column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'Id' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.2. Renaming column ID to HistoryId in TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[TsDynDataHistory].[ID]', N'HistoryId', N'COLUMN';\nEND\nGO\n\n-- 5.3. Rename the primary key constraint\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_DataTimeline' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.3. Renaming PK_ToSIC_EAV_DataTimeline to PK_TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_DataTimeline]', N'PK_TsDynDataHistory', N'OBJECT';\nEND\nGO\n\n-- 5.4. Drop unused/obsolete column SourceTextKey\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'SourceTextKey' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.4. Dropping obsolete column SourceTextKey';\n    ALTER TABLE [dbo].[TsDynDataHistory] DROP COLUMN [SourceTextKey];\nEND\nGO\n\n-- 5.5. Drop unused/obsolete column NewData\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'NewData' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.5. Dropping obsolete column NewData';\n    ALTER TABLE [dbo].[TsDynDataHistory] DROP COLUMN [NewData];\nEND\nGO\n\n-- 5.6. Rename SysCreatedDate column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'SysCreatedDate' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.6. Renaming column SysCreatedDate to Timestamp in TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[TsDynDataHistory].[SysCreatedDate]', N'Timestamp', N'COLUMN';\nEND\nGO\n\n-- 5.7. Rename SourceID column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'SourceID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.7. Renaming column SourceID to SourceId in TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[TsDynDataHistory].[SourceID]', N'SourceId', N'COLUMN';\nEND\nGO\n\n-- 5.8. Rename SysLogId column (the foreign key column)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'SysLogId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataHistory]'))\nBEGIN\n    PRINT '... 5.8. Renaming column SysLogId to TransactionId in TsDynDataHistory';\n    EXEC sp_rename N'[dbo].[TsDynDataHistory].[SysLogId]', N'TransactionId', N'COLUMN';\nEND\nGO\n\n-- 5.9. Clean up orphaned history entries before adding FK constraint\nIF EXISTS (SELECT 1 FROM [dbo].[TsDynDataHistory] hist\n    LEFT JOIN [dbo].[TsDynDataTransaction] trans ON hist.TransactionId = trans.TransactionId\n    WHERE trans.TransactionId IS NULL AND hist.TransactionId IS NOT NULL)\nBEGIN\n    PRINT '... 5.9. Cleaning up orphaned history entries in TsDynDataHistory';\n    DELETE hist\n    FROM [dbo].[TsDynDataHistory] hist\n    LEFT JOIN [dbo].[TsDynDataTransaction] trans ON hist.TransactionId = trans.TransactionId\n    WHERE trans.TransactionId IS NULL AND hist.TransactionId IS NOT NULL; -- Only delete if TransactionId was set but is now invalid\nEND\nGO\n\n-- 5.10. Add Index IX_TsDynDataHistory_TransactionId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataHistory_TransactionId' AND object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\n    AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 5.10.Adding index IX_TsDynDataHistory_TransactionId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_TransactionId] ON [dbo].[TsDynDataHistory] ([TransactionId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 5.11. Create the foreign key constraint referencing TsDynDataTransaction\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataHistory_TsDynDataTransaction')\n   AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 5.11. Creating foreign key FK_TsDynDataHistory_TsDynDataTransaction';\n    ALTER TABLE [dbo].[TsDynDataHistory] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataHistory_TsDynDataTransaction]\n    FOREIGN KEY([TransactionId])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 5.12. Check the constraint FK_TsDynDataHistory_TsDynDataTransaction\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataHistory_TsDynDataTransaction')\nBEGIN\n    PRINT '... 5.12. Checking foreign key constraints on FK_TsDynDataHistory_TsDynDataTransaction';\n    ALTER TABLE [dbo].[TsDynDataHistory] CHECK CONSTRAINT [FK_TsDynDataHistory_TsDynDataTransaction];\nEND\nGO\n\n-- 5.12b. Add Index IX_TsDynDataHistory_SourceId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataHistory_SourceId' AND object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\n    AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 5.12b. Adding index IX_TsDynDataHistory_SourceId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_SourceId] ON [dbo].[TsDynDataHistory]\n    (\n        [SourceId] ASC\n    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 5.14. Add Index IX_TsDynDataHistory_SourceGuid\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataHistory_SourceGuid' AND object_id = OBJECT_ID('[dbo].[TsDynDataHistory]'))\n    AND OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 5.14. Adding index IX_TsDynDataHistory_SourceGuid';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_SourceGuid] ON [dbo].[TsDynDataHistory]\n    (\n        [SourceGuid] ASC\n    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 5.15. Rename constraint DF_DataTimeline_Operation\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_DataTimeline_Operation')\nBEGIN\n    PRINT '... 5.15. Renaming constraint DF_DataTimeline_Operation';\n    EXEC sp_rename N'[dbo].[DF_DataTimeline_Operation]', N'DF_TsDynDataHistory_Operation', N'OBJECT';\nEND\nGO\n\n\n\n-- *** 6. Rename ToSIC_EAV_Zones to TsDynDataZone and update related objects\nPRINT '6. Renaming table ToSIC_EAV_Zones to TsDynDataZone and related objects';\n\n-- 6.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Zones' AND type = 'U')\nBEGIN\n    PRINT '... 6.1. Renaming table ToSIC_EAV_Zones to TsDynDataZone';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Zones]', N'TsDynDataZone';\nEND\nGO\n\n-- 6.2. Rename the primary key column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ZoneID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 6.2. Renaming column ZoneID to ZoneId in TsDynDataZone';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[ZoneID]', N'ZoneId', N'COLUMN';\nEND\nGO\n\n-- 6.3. Rename the primary key constraint PK_ToSIC_EAV_Zones\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Zones' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 6.3. Renaming PK_ToSIC_EAV_Zones to PK_TsDynDataZone';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Zones]', N'PK_TsDynDataZone', N'OBJECT';\nEND\nGO\n\n-- 6.4. Add new column TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdCreated' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('TsDynDataZone', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.4. Adding TransactionIdCreated column to TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataZone] ADD [TransactionIdCreated] INT NULL;\nEND\nGO\n\n-- 6.5. Add new column TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdModified' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('TsDynDataZone', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.5. Adding TransactionIdModified column to TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataZone] ADD [TransactionIdModified] INT NULL;\nEND\nGO\n\n-- 6.6. Add new column TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdDeleted' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('TsDynDataZone', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.6. Adding TransactionIdDeleted column to TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataZone] ADD [TransactionIdDeleted] INT NULL;\nEND\nGO\n\n-- 6.7. Rename the foreign key column in the referencing table (ToSIC_EAV_Apps)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ZoneID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Apps]'))\nBEGIN\n    PRINT '... 6.7. Renaming column ZoneID to ZoneId in ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Apps].[ZoneID]', N'ZoneId', N'COLUMN';\nEND\nGO\n\n-- 6.8. Rename the foreign key column in the referencing table (ToSIC_EAV_Dimensions)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ZoneID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Dimensions]'))\nBEGIN\n    PRINT '... 6.8. Renaming column ZoneID to ZoneId in ToSIC_EAV_Dimensions';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Dimensions].[ZoneID]', N'ZoneId', N'COLUMN';\nEND\nGO\n\n-- 6.9. Rename the foreign key constraint FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones')\nBEGIN\n    PRINT '... 6.9. Renaming Zone foreign key from ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Apps_ToSIC_EAV_Zones]', N'FK_ToSIC_EAV_Apps_TsDynDataZone', N'OBJECT';\nEND\nGO\n\n-- 6.10. Rename the foreign key constraint FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones')\nBEGIN\n    PRINT '... 6.10. Renaming Zone foreign key from ToSIC_EAV_Dimensions';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Zones]', N'FK_ToSIC_EAV_Dimensions_TsDynDataZone', N'OBJECT';\nEND\nGO\n\n-- 6.11. Add Index IX_ToSIC_EAV_Dimensions_ZoneId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Dimensions_ZoneId' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Dimensions]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Dimensions]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.11. Adding index IX_ToSIC_EAV_Dimensions_ZoneId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Dimensions_ZoneId] ON [dbo].[ToSIC_EAV_Dimensions] ([ZoneId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 6.12. Create the foreign key constraint referencing TsDynDataZone\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_TsDynDataZone')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Dimensions]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.12. Creating foreign key FK_ToSIC_EAV_Dimensions_TsDynDataZone';\n    ALTER TABLE [dbo].[ToSIC_EAV_Dimensions] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Dimensions_TsDynDataZone]\n    FOREIGN KEY([ZoneId])\n    REFERENCES [dbo].[TsDynDataZone] ([ZoneId]);\nEND\nGO\n\n-- 6.12b. Check constraint FK_ToSIC_EAV_Dimensions_TsDynDataZone\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_TsDynDataZone')\nBEGIN\n    PRINT '... 6.12b. Checking foreign key constraints on FK_ToSIC_EAV_Dimensions_TsDynDataZone';\n    ALTER TABLE [dbo].[ToSIC_EAV_Dimensions] CHECK CONSTRAINT [FK_ToSIC_EAV_Dimensions_TsDynDataZone];\nEND\nGO\n\n-- 6.14. Add Index IX_TsDynDataZone_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransCreatedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.14. Adding index IX_TsDynDataZone_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransactionIdCreated] ON [dbo].[TsDynDataZone] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 6.15. Create foreign key FK_TsDynDataZone_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.15. Creating foreign key FK_TsDynDataZone_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[TsDynDataZone] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 6.16. Check constraint FK_TsDynDataZone_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 6.16. Checking foreign key constraints on FK_TsDynDataZone_TsDynDataTransactionCreated';  \n    ALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionCreated];\nEND\nGO\n\n-- 6.17. Add Index IX_TsDynDataZone_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransModifiedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.17. Adding index IX_TsDynDataZone_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransactionIdModified] ON [dbo].[TsDynDataZone] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 6.18. Create foreign key FK_TsDynDataZone_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.18. Creating foreign key FK_TsDynDataZone_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataZone] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 6.19. Check constraint FK_TsDynDataZone_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 6.19. Checking foreign key constraints on FK_TsDynDataZone_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionModified];\nEND\nGO\n\n-- 6.20. Add Index IX_TsDynDataZone_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransDeletedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataZone]'))\n    AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.20. Adding index IX_TsDynDataZone_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransactionIdDeleted] ON [dbo].[TsDynDataZone] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 6.21. Create foreign key FK_TsDynDataZone_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[TsDynDataZone]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 6.21. Creating foreign key FK_TsDynDataZone_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[TsDynDataZone] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 6.22. Check the constraints FK_TsDynDataZone_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataZone_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 6.22. Checking foreign key constraints on FK_TsDynDataZone_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionDeleted];\nEND\n\n\n\n-- *** 7. Rename ToSIC_EAV_Apps to TsDynDataApp and update related objects\nPRINT '7. Renaming table ToSIC_EAV_Apps to TsDynDataApp and related objects';\n\n-- 7.1. Rename the table\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Apps' AND type = 'U')\nBEGIN\n    PRINT '... 7.1. Renaming table ToSIC_EAV_Apps to TsDynDataApp';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Apps]', N'TsDynDataApp';\nEND\nGO\n\n-- 7.2. Rename the primary key column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AppID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 7.2. Renaming column AppID to AppId in TsDynDataApp';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[AppID]', N'AppId', N'COLUMN';\nEND\nGO\n\n-- 7.3. Rename the primary key constraint\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Apps' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 7.3. Renaming PK_ToSIC_EAV_Apps to PK_TsDynDataApp';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Apps]', N'PK_TsDynDataApp', N'OBJECT';\nEND\nGO\n\n-- 7.4. Rename the unique constraint ToSIC_EAV_Apps_PreventDuplicates\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Apps_PreventDuplicates' AND type = 'UQ')\nBEGIN\n    PRINT '... 7.4. Renaming unique constraint ToSIC_EAV_Apps_PreventDuplicates to UQ_TsDynDataApp_Name_ZoneId';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Apps_PreventDuplicates]', N'UQ_TsDynDataApp_Name_ZoneId', N'OBJECT';\nEND\nGO\n\n-- 7.5. Add new column TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdCreated' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('TsDynDataApp', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.5. Adding TransactionIdCreated column to TsDynDataApp';\n    ALTER TABLE [dbo].[TsDynDataApp] ADD [TransactionIdCreated] INT NULL;\nEND\nGO\n\n-- 7.6. Add new column TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdModified' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('TsDynDataApp', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.6. Adding TransactionIdModified column to TsDynDataApp';\n    ALTER TABLE [dbo].[TsDynDataApp] ADD [TransactionIdModified] INT NULL;\nEND\nGO\n\n-- 7.7. Add new column TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdDeleted' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('TsDynDataApp', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.7. Adding TransactionIdDeleted column to TsDynDataApp';\n    ALTER TABLE [dbo].[TsDynDataApp] ADD [TransactionIdDeleted] INT NULL;\nEND\nGO\n\n-- 7.8. Rename the foreign key column in the referencing table (ToSIC_EAV_AttributeSets)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AppID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_AttributeSets]'))\nBEGIN\n    PRINT '... 7.8. Renaming column AppID to AppId in ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeSets].[AppID]', N'AppId', N'COLUMN';\nEND\nGO\n\n-- 7.9. Rename the foreign key column in the referencing table (ToSIC_EAV_Entities)\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AppID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 7.9. Renaming column AppID to AppId in ToSIC_EAV_Entities';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[AppID]', N'AppId', N'COLUMN';\nEND\nGO\n\n-- 7.10. Rename the foreign key constraint FK_ToSIC_EAV_Apps_TsDynDataZone\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Apps_TsDynDataZone')\nBEGIN\n\n    PRINT '... 7.10. Renaming Zone foreign key from ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Apps_TsDynDataZone]', N'FK_TsDynDataApp_TsDynDataZone', N'OBJECT';\nEND\nGO\n\n-- 7.11. Add Index IX_TsDynDataApp_ZoneId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_ZoneId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.11. Adding index IX_TsDynDataApp_ZoneId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataApp_ZoneId] ON [dbo].[TsDynDataApp] ([ZoneId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 7.12. Create the foreign key constraint FK_TsDynDataApp_TsDynDataZone\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataZone')\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.12. Creating foreign key FK_TsDynDataApp_TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataApp] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataApp_TsDynDataZone]\n    FOREIGN KEY([ZoneId])\n    REFERENCES [dbo].[TsDynDataZone] ([ZoneId]);\nEND\nGO\n\n-- 7.12b. Check constraint FK_TsDynDataApp_TsDynDataZone\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataZone')\nBEGIN\n    PRINT '... 7.12b. Checking foreign key constraints on FK_TsDynDataApp_TsDynDataZone';\n    ALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataZone];\nEND\nGO\n\n-- 7.14. Rename the foreign key constraint FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps')\nBEGIN\n    PRINT '... 7.14. Renaming foreign key FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_Apps]', N'FK_ToSIC_EAV_AttributeSets_TsDynDataApp', N'OBJECT';\nEND\nGO\n\n-- 7.15. Add Index IX_ToSIC_EAV_AttributeSets_AppId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_AppId' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.15. Adding index IX_ToSIC_EAV_AttributeSets_AppId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_AttributeSets_AppId] ON [dbo].[ToSIC_EAV_AttributeSets] ([AppId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 7.16. Create the foreign key constraint FK_ToSIC_EAV_AttributeSets_TsDynDataApp\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataApp')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_AttributeSets]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.16. Creating foreign key FK_ToSIC_EAV_AttributeSets_TsDynDataApp';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataApp]\n    FOREIGN KEY([AppId])\n    REFERENCES [dbo].[TsDynDataApp] ([AppId]);\nEND\nGO\n\n-- 7.17. Check constraint FK_ToSIC_EAV_AttributeSets_TsDynDataApp\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataApp')\nBEGIN\n    PRINT '... 7.17. Checking foreign key constraints on FK_ToSIC_EAV_AttributeSets_TsDynDataApp';\n    ALTER TABLE [dbo].[ToSIC_EAV_AttributeSets] CHECK CONSTRAINT [FK_ToSIC_EAV_AttributeSets_TsDynDataApp];\nEND\nGO\n\n-- 7.18. Rename the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps')\nBEGIN\n    PRINT '... 7.18. Renaming foreign key FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_Apps]', N'FK_ToSIC_EAV_Entities_TsDynDataApp', N'OBJECT';\nEND\nGO\n\n-- 7.19. Add Index IX_ToSIC_EAV_Entities_AppId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_AppId' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Entities]'))\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.19. Adding index IX_ToSIC_EAV_Entities_AppId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_AppId] ON [dbo].[ToSIC_EAV_Entities] ([AppId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 7.20. Create the foreign key constraint FK_ToSIC_EAV_Entities_TsDynDataApp\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataApp')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.20. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataApp';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataApp]\n    FOREIGN KEY([AppId])\n    REFERENCES [dbo].[TsDynDataApp] ([AppId]);\nEND\nGO\n\n-- 7.21. Check constraint FK_ToSIC_EAV_Entities_TsDynDataApp\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataApp')\nBEGIN\n    PRINT '... 7.21. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataApp';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataApp];\nEND\nGO\n\n-- 7.22. Add Index IX_TsDynDataApp_TransactionIdCreated\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransCreatedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.22. Adding index IX_TsDynDataApp_TransactionIdCreated';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransactionIdCreated] ON [dbo].[TsDynDataApp] ([TransactionIdCreated] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 7.23. Create foreign key FK_TsDynDataApp_TsDynDataTransactionCreated\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionCreated')\n   AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.23. Recreating foreign key FK_TsDynDataApp_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[TsDynDataApp] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionCreated]\n    FOREIGN KEY([TransactionIdCreated])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 7.24. Check constraint FK_TsDynDataApp_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 7.24. Checking foreign key constraints on FK_TsDynDataApp_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionCreated];\nEND\nGO\n\n-- 7.25. Add Index IX_TsDynDataApp_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransModifiedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.25. Adding index IX_TsDynDataApp_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransactionIdModified] ON [dbo].[TsDynDataApp] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 7.26. Create foreign key FK_TsDynDataApp_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.26. Creating foreign key FK_TsDynDataApp_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataApp] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 7.27. Check constraint FK_TsDynDataApp_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 7.27. Checking foreign key constraints on FK_TsDynDataApp_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionModified];\nEND\nGO\n\n-- 7.28. Add Index IX_TsDynDataApp_TransactionIdDeleted\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransDeletedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.28. Adding index IX_TsDynDataApp_TransactionIdDeleted';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransactionIdDeleted] ON [dbo].[TsDynDataApp] ([TransactionIdDeleted] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 7.29. Create foreign key FK_TsDynDataApp_TsDynDataTransactionDeleted\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionDeleted')\n   AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.29. Recreating foreign key FK_TsDynDataApp_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[TsDynDataApp] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionDeleted]\n    FOREIGN KEY([TransactionIdDeleted])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 7.30. Check the constraints FK_TsDynDataApp_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataApp_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 7.30. Checking foreign key constraints on FK_TsDynDataApp_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionDeleted];\nEND\nGO\n\n-- 7.31. Rename index IX_ToSIC_EAV_Apps_ZoneId to IX_TsDynDataApp_ZoneId if exists\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Apps_ZoneId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_ZoneId' AND object_id = OBJECT_ID('[dbo].[TsDynDataApp]'))\n    AND OBJECT_ID('[dbo].[TsDynDataApp]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 7.31. Renaming index IX_ToSIC_EAV_Apps_ZoneId to IX_TsDynDataApp_ZoneId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[IX_ToSIC_EAV_Apps_ZoneId]', N'IX_TsDynDataApp_ZoneId', N'INDEX';\nEND\nGO\n\n\n\n-- *** 8. Renaming table ToSIC_EAV_AttributeSets to TsDynDataContentType and update related objects\nPRINT '8. Renaming table ToSIC_EAV_AttributeSets to TsDynDataContentType and related objects';\n\n-- 8.1. Rename table ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_AttributeSets' AND type = 'U')\nBEGIN\n    PRINT '... 8.1. Renaming table ToSIC_EAV_AttributeSets to TsDynDataContentType';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeSets]', N'TsDynDataContentType';\nEND\nGO\n\n-- 8.2. Rename PK column AttributeSetID to ContentTypeId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AttributeSetID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.2. Renaming column AttributeSetID to ContentTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[AttributeSetID]', N'ContentTypeId', N'COLUMN';\nEND\nGO\n\n-- 8.3. Rename PK_ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_AttributeSets' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.3. Rename PK_ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_AttributeSets]', N'PK_TsDynDataContentType', N'OBJECT';\nEND\nGO\n\n-- 8.4. Rename columns UsesConfigurationOfAttributeSet to InheritContentTypeId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'UsesConfigurationOfAttributeSet' AND Object_ID = Object_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.4. Renaming column UsesConfigurationOfAttributeSet to InheritContentTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[UsesConfigurationOfAttributeSet]', N'InheritContentTypeId', N'COLUMN';\nEND\nGO\n\n-- 8.5. Rename columns AlwaysShareConfiguration to IsGlobal\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AlwaysShareConfiguration' AND Object_ID = Object_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.5. Renaming column AlwaysShareConfiguration to IsGlobal';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[AlwaysShareConfiguration]', N'IsGlobal', N'COLUMN';\nEND\nGO\n\n-- 8.6. Add column TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = 'TransactionIdModified' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND OBJECT_ID('TsDynDataContentType', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.6. Adding TransactionIdModified column to TsDynDataContentType';\n    ALTER TABLE [dbo].[TsDynDataContentType] ADD [TransactionIdModified] INT NULL;\nEND\nGO\n\n-- 8.7. Rename columns AttributeSetID to ContentTypeId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'AttributeSetID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Entities]'))\nBEGIN\n    PRINT '... 8.7.Renaming column AttributeSetID to ContentTypeId';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities].[AttributeSetID]', N'ContentTypeId', N'COLUMN';\nEND\nGO\n\n-- 8.8. Rename FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets')\nBEGIN\n    PRINT '... 8.8. Rename FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_ToSIC_EAV_AttributeSets]', N'FK_TsDynDataContentType_TsDynDataContentType' , N'OBJECT';\nEND\nGO\n\n-- 8.9. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataApp\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataApp')\nBEGIN\n    PRINT '... 8.9. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataApp';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_TsDynDataApp]', N'FK_TsDynDataContentType_TsDynDataApp' , N'OBJECT';\nEND\nGO\n\n-- 8.10. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated')\nBEGIN\n    PRINT '... 8.10. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionCreated]', N'FK_TsDynDataContentType_TsDynDataTransactionCreated' , N'OBJECT';\nEND\nGO\n\n-- 8.11. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted')\nBEGIN\n    PRINT '... 8.11. Rename FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_AttributeSets_TsDynDataTransactionDeleted]', N'FK_TsDynDataContentType_TsDynDataTransactionDeleted' , N'OBJECT';\nEND\nGO\n\n-- 8.12. Rename FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets')\nBEGIN\n    PRINT '... 8.12. Rename FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_ContentTypeId_ToSIC_EAV_AttributeSets]', N'FK_ToSIC_EAV_Attributes_TsDynDataContentType' , N'OBJECT';\nEND\nGO\n\n-- 8.12b. Rename FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets')\nBEGIN\n    PRINT '... 8.12b. Rename FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_ToSIC_EAV_AttributeSets]', N'FK_ToSIC_EAV_Entities_TsDynDataContentType' , N'OBJECT';\nEND\nGO\n\n-- 8.14. Add Index on ContentTypeId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_ContentTypeId')\n    AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.14. Adding index IX_ToSIC_EAV_Entities_ContentTypeId';\n    CREATE NONCLUSTERED INDEX [IX_ToSIC_EAV_Entities_ContentTypeId] ON [dbo].[ToSIC_EAV_Entities] ([ContentTypeId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 8.15. Create foreign key FK_ToSIC_EAV_Entities_TsDynDataContentType\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataContentType')\n   AND OBJECT_ID('[dbo].[ToSIC_EAV_Entities]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.15. Creating foreign key FK_ToSIC_EAV_Entities_TsDynDataContentType';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] WITH NOCHECK\n    ADD CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataContentType]\n    FOREIGN KEY([ContentTypeId])\n    REFERENCES [dbo].[TsDynDataContentType] ([ContentTypeId]);\nEND\nGO\n\n-- 8.16. Check the constraints FK_ToSIC_EAV_Entities_TsDynDataContentType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataContentType')\nBEGIN\n    PRINT '... 8.16. Checking foreign key constraints on FK_ToSIC_EAV_Entities_TsDynDataContentType';\n    ALTER TABLE [dbo].[ToSIC_EAV_Entities] CHECK CONSTRAINT [FK_ToSIC_EAV_Entities_TsDynDataContentType];\nEND\nGO\n\n-- 8.17. Add Index IX_TsDynDataContentType_TransactionIdModified\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransModifiedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND OBJECT_ID('[dbo].[TsDynDataContentType]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.17. Adding index IX_TsDynDataContentType_TransactionIdModified';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_TransactionIdModified] ON [dbo].[TsDynDataContentType] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 8.18. Create foreign key FK_TsDynDataContentType_TsDynDataTransactionModified\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataContentType_TsDynDataTransactionModified')\n   AND OBJECT_ID('[dbo].[TsDynDataContentType]', 'U') IS NOT NULL\nBEGIN\n    PRINT '... 8.18. Creating foreign key FK_TsDynDataContentType_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataContentType] WITH NOCHECK\n    ADD CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified])\n    REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 8.19. Check constraint FK_TsDynDataContentType_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataContentType_TsDynDataTransactionModified')\nBEGIN\n    PRINT '... 8.19. Checking foreign key constraints on FK_TsDynDataContentType_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionModified];\nEND\nGO\n\n-- 8.20. Rename index IX_ToSIC_EAV_AttributeSets_TransactionIdCreated\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.20. Renaming index IX_ToSIC_EAV_AttributeSets_TransactionIdCreated';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_ToSIC_EAV_AttributeSets_TransactionIdCreated]', N'IX_TsDynDataContentType_TransactionIdCreated', N'INDEX';\nEND\nGO\n\n-- 8.21. Rename index IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.21. Renaming index IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_ToSIC_EAV_AttributeSets_TransactionIdDeleted]', N'IX_TsDynDataContentType_TransactionIdDeleted', N'INDEX';\nEND\nGO\n\n-- 8.22. Rename index IX_ToSIC_EAV_AttributeSets_AppId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_AttributeSets_AppId' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 8.22. Renaming index IX_ToSIC_EAV_AttributeSets_AppId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_ToSIC_EAV_AttributeSets_AppId]', N'IX_TsDynDataContentType_AppId', N'INDEX';\nEND\nGO\n\n-- 8.23. Add Index IX_TsDynDataContentType_AppId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_AppId' AND object_id = OBJECT_ID('[dbo].[TsDynDataContentType]'))\n    AND OBJECT_ID('[dbo].[TsDynDataContentType]', 'U') IS NOT NULL \nBEGIN\n    PRINT '... 8.23. Adding index IX_TsDynDataContentType_AppId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_AppId] ON [dbo].[TsDynDataContentType] ([AppId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 8.24. Rename constraint DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration')\nBEGIN\n    PRINT '... 8.24. Renaming constraint DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_AttributeSets_AlwaysShareConfiguration]', N'DF_TsDynDataContentType_IsGlobal', N'OBJECT';\nEND\nGO\n\n-- 8.25. Rename constraint DF_ToSIC_EAV_AttributeSets_StaticName\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_AttributeSets_StaticName')\nBEGIN\n    PRINT '... 8.25. Renaming constraint DF_ToSIC_EAV_AttributeSets_StaticName';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_AttributeSets_StaticName]', N'DF_TsDynDataContentType_StaticName', N'OBJECT';\nEND\nGO\n\n\n\n-- *** 9. Rename table ToSIC_EAV_Attributes to TsDynDataAttribute and related objects\nPRINT '9. Renaming table ToSIC_EAV_Attributes to TsDynDataAttribute and related objects';\n\n-- 9.1. Rename the table ToSIC_EAV_Attributes to TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Attributes' AND type = 'U')\nBEGIN\n    PRINT '... 9.1. Renaming table ToSIC_EAV_Attributes to TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Attributes]', N'TsDynDataAttribute';\nEND\nGO\n\n-- 9.2. Rename the primary key column AttributeID to AttributeId in TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.2. Renaming column AttributeID to AttributeId in TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\nGO\n\n-- 9.3. Rename the primary key constraint PK_ToSIC_EAV_Attributes to PK_TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Attributes' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.3. Renaming PK_ToSIC_EAV_Attributes to PK_TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Attributes]', N'PK_TsDynDataAttribute', N'OBJECT';\nEND\nGO\n\n-- 9.4. Add new column TransactionIdModified to TsDynDataAttribute\nIF NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = Object_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.4. Adding column TransactionIdModified to TsDynDataAttribute';\n    ALTER TABLE [dbo].[TsDynDataAttribute] ADD [TransactionIdModified] INT NULL;\nEND\nGO\n\n-- 9.5. Rename FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.5. Renaming FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types to FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_ToSIC_EAV_Types]', N'FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes', N'OBJECT';\nEND\nGO\n\n-- 9.6. Rename FK_ToSIC_EAV_Attributes_TsDynDataContentType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataContentType' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.6. Renaming FK_ToSIC_EAV_Attributes_TsDynDataContentType to FK_TsDynDataAttribute_TsDynDataContentType';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_TsDynDataContentType]', N'FK_TsDynDataAttribute_TsDynDataContentType', N'OBJECT';\nEND\nGO\n\n-- 9.7. Rename FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.7. Renaming FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated to FK_TsDynDataAttribute_TsDynDataTransactionCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_TsDynDataTransactionCreated]', N'FK_TsDynDataAttribute_TsDynDataTransactionCreated', N'OBJECT';\nEND\nGO\n\n-- 9.8. Rename FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.8. Renaming FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted to FK_TsDynDataAttribute_TsDynDataTransactionDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Attributes_TsDynDataTransactionDeleted]', N'FK_TsDynDataAttribute_TsDynDataTransactionDeleted', N'OBJECT';\nEND\nGO\n\n-- 9.9. Add new Foreign Key for TransactionIdModified on TsDynDataAttribute\nIF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataAttribute_TsDynDataTransactionModified' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.9. Adding FK_TsDynDataAttribute_TsDynDataTransactionModified to TsDynDataAttribute';\n    ALTER TABLE [dbo].[TsDynDataAttribute] WITH CHECK\n    ADD CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionModified]\n    FOREIGN KEY([TransactionIdModified]) REFERENCES [dbo].[TsDynDataTransaction] ([TransactionId]);\nEND\nGO\n\n-- 9.10. Renaming index IX_ToSIC_EAV_Attributes_ContentTypeId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_ContentTypeId' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.10. Renaming index IX_ToSIC_EAV_Attributes_ContentTypeId to IX_TsDynDataAttribute_ContentTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_ToSIC_EAV_Attributes_ContentTypeId]', N'IX_TsDynDataAttribute_ContentTypeId', N'INDEX';\nEND\nGO\n\n-- 9.11. Renaming index IX_ToSIC_EAV_Attributes_TransactionIdCreated\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.11. Renaming index IX_ToSIC_EAV_Attributes_TransactionIdCreated to IX_TsDynDataAttribute_TransactionIdCreated';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_ToSIC_EAV_Attributes_TransactionIdCreated]', N'IX_TsDynDataAttribute_TransactionIdCreated', N'INDEX';\nEND\nGO\n\n-- 9.12. Renaming index IX_ToSIC_EAV_Attributes_TransactionIdDeleted\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Attributes_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.12. Renaming index IX_ToSIC_EAV_Attributes_TransactionIdDeleted to IX_TsDynDataAttribute_TransactionIdDeleted';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_ToSIC_EAV_Attributes_TransactionIdDeleted]', N'IX_TsDynDataAttribute_TransactionIdDeleted', N'INDEX';\nEND\nGO\n\n-- 9.12b. Add new Index for TransactionIdModified on TsDynDataAttribute\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransModifiedId' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.12b. Adding index IX_TsDynDataAttribute_TransactionIdModified on TsDynDataAttribute';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_TransactionIdModified] ON [dbo].[TsDynDataAttribute] ([TransactionIdModified] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 9.14. Add new Index for AttributeId inc. StaticName on TsDynDataAttribute\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_AttributeId_StaticName' AND object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.14. Adding index IX_TsDynDataAttribute_AttributeId_StaticName';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_AttributeId_StaticName] ON [dbo].[TsDynDataAttribute] ([AttributeId] ASC) INCLUDE([StaticName])\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 9.15. Rename Default Constraints DF_ToSIC_EAV_Attributes_ContentTypeId\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Attributes_ContentTypeId' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.15. Renaming default constraint DF_ToSIC_EAV_Attributes_ContentTypeId to DF_TsDynDataAttribute_ContentTypeId';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Attributes_ContentTypeId]', N'DF_TsDynDataAttribute_ContentTypeId', N'OBJECT';\nEND\nGO\n\n-- 9.16. Rename Default Constraints DF_ToSIC_EAV_Attributes_SortOrder\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Attributes_SortOrder' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.16. Renaming default constraint DF_ToSIC_EAV_Attributes_SortOrder to DF_TsDynDataAttribute_SortOrder';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Attributes_SortOrder]', N'DF_TsDynDataAttribute_SortOrder', N'OBJECT';\nEND\nGO\n\n-- 9.17. Rename Default Constraints DF_ToSIC_EAV_Attributes_IsTitle\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Attributes_IsTitle' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 9.17. Renaming default constraint DF_ToSIC_EAV_Attributes_IsTitle to DF_TsDynDataAttribute_IsTitle';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Attributes_IsTitle]', N'DF_TsDynDataAttribute_IsTitle', N'OBJECT';\nEND\nGO\n\n-- 9.18. Renaming column AttributeID to AttributeId in ToSIC_EAV_EntityRelationships\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_EntityRelationships]'))\nBEGIN\n    PRINT '... 9.18. Renaming column AttributeID to AttributeId in ToSIC_EAV_EntityRelationships';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_EntityRelationships].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\nGO\n\n-- 9.19. Renaming column AttributeID to AttributeId in ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 9.19. Renaming column AttributeID to AttributeId in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\nGO\n\n-- 9.20. Rename FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes')\nBEGIN\n    PRINT '... 9.20. Rename FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_Attributes]', N'FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute' , N'OBJECT';\nEND\nGO\n\n-- 9.21. Rename FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes')\nBEGIN\n    PRINT '... 9.21. Rename FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_Attributes]', N'FK_ToSIC_EAV_Values_TsDynDataAttribute' , N'OBJECT';\nEND\nGO\n\n\n\n-- *** 10. Renaming table ToSIC_EAV_AttributeTypes to TsDynDataAttributeType and related objects \nPRINT '10. Renaming table ToSIC_EAV_AttributeTypes to TsDynDataAttributeType and related objects';\nGO\n\n-- 10.1. Rename the table ToSIC_EAV_AttributeTypes to TsDynDataAttributeType\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_AttributeTypes' AND type = 'U')\nBEGIN\n    PRINT '... 10.1. Renaming table ToSIC_EAV_AttributeTypes to TsDynDataAttributeType';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_AttributeTypes]', N'TsDynDataAttributeType';\nEND\nGO\n\n-- 10.2. Rename the primary key constraint PK_ToSIC_EAV_AttributeTypes to PK_TsDynDataAttributeType\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_AttributeTypes' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttributeType]'))\nBEGIN\n    PRINT '... 10.2. Renaming PK_ToSIC_EAV_AttributeTypes to PK_TsDynDataAttributeType';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_AttributeTypes]', N'PK_TsDynDataAttributeType', N'OBJECT';\nEND\nGO\n\n-- 10.3. Rename the foreign key constraint in TsDynDataAttribute that references this table.\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 10.3. Renaming FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes to FK_TsDynDataAttribute_TsDynDataAttributeType';\n    EXEC sp_rename N'[dbo].[FK_TsDynDataAttribute_ToSIC_EAV_AttributeTypes]', N'FK_TsDynDataAttribute_TsDynDataAttributeType', N'OBJECT';\nEND\nGO\n\n\n\n-- *** 11. Renaming table ToSIC_EAV_Entities to TsDynDataEntity and related objects\nPRINT '11. Renaming table ToSIC_EAV_Entities to TsDynDataEntity and related objects';\n\n-- 11.1. Rename table ToSIC_EAV_Entities to TsDynDataEntity\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Entities' AND type = 'U')\nBEGIN\n    PRINT '... 11.1. Renaming table ToSIC_EAV_Entities to TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Entities]', N'TsDynDataEntity';\nEND\nGO\n\n-- 11.2. Rename the primary key column EntityID to EntityId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'EntityID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.2. Renaming PK column EntityID to EntityId in TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[EntityID]', N'EntityId', N'COLUMN';\nEND\nGO\n\n-- 11.3. Rename column EntityGUID to EntityGuid\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'EntityGUID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.3. Renaming column EntityGUID to EntityGuid in TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[EntityGUID]', N'EntityGuid', N'COLUMN';\nEND\nGO\n\n-- 11.4. Rename the primary key constraint PK_ToSIC_EAV_Entities to PK_TsDynDataEntity\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Entities' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.4. Renaming PK_ToSIC_EAV_Entities to PK_TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Entities]', N'PK_TsDynDataEntity', N'OBJECT';\nEND\nGO\n\n-- 11.5. Drop the foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities')\nBEGIN\n    PRINT '... 11.5. Dropping foreign key constraint FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities';\n    ALTER TABLE [dbo].[TsDynDataEntity] DROP CONSTRAINT [FK_ToSIC_EAV_Entities_ToSIC_EAV_Entities];\nEND\nGO\n\n-- 11.6. Drop the ConfigurationSet column\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'ConfigurationSet' AND Object_ID = Object_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.6. Dropping column ConfigurationSet from TsDynDataEntity';\n    ALTER TABLE [dbo].[TsDynDataEntity] DROP COLUMN [ConfigurationSet];\nEND\nGO\n\n-- 11.7. Rename the column EntityID to EntityId in ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'EntityID' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 11.7. Renaming column EntityID to EntityId in ToSIC_EAV_Values';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values].[EntityID]', N'EntityId', N'COLUMN';\nEND\nGO\n\n-- 11.8. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataApp to FK_TsDynDataEntity_TsDynDataApp\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataApp' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.8. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataApp to FK_TsDynDataEntity_TsDynDataApp';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataApp]', N'FK_TsDynDataEntity_TsDynDataApp', N'OBJECT';\nEND\nGO\n\n-- 11.9. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataContentType to FK_TsDynDataEntity_TsDynDataContentType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataContentType' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.9. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataContentType to FK_TsDynDataEntity_TsDynDataContentType';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataContentType]', N'FK_TsDynDataEntity_TsDynDataContentType', N'OBJECT';\nEND\nGO\n\n-- 11.10. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTargetType to FK_TsDynDataEntity_TsDynDataTargetType\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTargetType' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.10. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTargetType to FK_TsDynDataEntity_TsDynDataTargetType';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataTargetType]', N'FK_TsDynDataEntity_TsDynDataTargetType', N'OBJECT';\nEND\nGO\n\n-- 11.11. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated to FK_TsDynDataEntity_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.11. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated to FK_TsDynDataEntity_TsDynDataTransactionCreated';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataTransactionCreated]', N'FK_TsDynDataEntity_TsDynDataTransactionCreated', N'OBJECT';\nEND\nGO\n\n-- 11.12. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionModified to FK_TsDynDataEntity_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionModified' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.12. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionModified to FK_TsDynDataEntity_TsDynDataTransactionModified';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataTransactionModified]', N'FK_TsDynDataEntity_TsDynDataTransactionModified', N'OBJECT';\nEND\nGO\n\n-- 11.12b. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted to FK_TsDynDataEntity_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.12b. Renaming FK FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted to FK_TsDynDataEntity_TsDynDataTransactionDeleted';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Entities_TsDynDataTransactionDeleted]', N'FK_TsDynDataEntity_TsDynDataTransactionDeleted', N'OBJECT';\nEND\nGO\n\n-- 11.14. Renaming Default Constraint DF_ToSIC_EAV_Entities_EntityGUID to DF_TsDynDataEntity_EntityGuid\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Entities_EntityGUID' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.14. Renaming Default Constraint DF_ToSIC_EAV_Entities_EntityGUID to DF_TsDynDataEntity_EntityGuid';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Entities_EntityGUID]', N'DF_TsDynDataEntity_EntityGuid', N'OBJECT';\nEND\nGO\n\n-- 11.15. Renaming Default Constraint DF_ToSIC_EAV_Entities_IsPublished to DF_TsDynDataEntity_IsPublished\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Entities_IsPublished' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.15. Renaming Default Constraint DF_ToSIC_EAV_Entities_IsPublished to DF_TsDynDataEntity_IsPublished';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Entities_IsPublished]', N'DF_TsDynDataEntity_IsPublished', N'OBJECT';\nEND\nGO\n\n-- 11.16. Renaming Index IX_KeyNumber to IX_TsDynDataEntity_KeyNumber\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_KeyNumber' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.16. Renaming Index IX_KeyNumber to IX_TsDynDataEntity_KeyNumber';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_KeyNumber]', N'IX_TsDynDataEntity_KeyNumber', N'INDEX';\nEND\nGO\n\n-- 11.17. Renaming Index IX_ToSIC_EAV_Entities_AppId to IX_TsDynDataEntity_AppId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_AppId' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.17. Renaming Index IX_ToSIC_EAV_Entities_AppId to IX_TsDynDataEntity_AppId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_AppId]', N'IX_TsDynDataEntity_AppId', N'INDEX';\nEND\nGO\n\n-- 11.18. Renaming Index IX_ToSIC_EAV_Entities_ContentTypeId to IX_TsDynDataEntity_ContentTypeId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_ContentTypeId' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.18. Renaming Index IX_ToSIC_EAV_Entities_ContentTypeId to IX_TsDynDataEntity_ContentTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_ContentTypeId]', N'IX_TsDynDataEntity_ContentTypeId', N'INDEX';\nEND\nGO\n\n-- 11.19. Renaming Index IX_ToSIC_EAV_Entities_TargetTypeId to IX_TsDynDataEntity_TargetTypeId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TargetTypeId' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.19. Renaming Index IX_ToSIC_EAV_Entities_TargetTypeId to IX_TsDynDataEntity_TargetTypeId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_TargetTypeId]', N'IX_TsDynDataEntity_TargetTypeId', N'INDEX';\nEND\nGO\n\n-- 11.20. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdCreated to IX_TsDynDataEntity_TransactionIdCreated\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.20. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdCreated to IX_TsDynDataEntity_TransactionIdCreated';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_TransactionIdCreated]', N'IX_TsDynDataEntity_TransactionIdCreated', N'INDEX';\nEND\nGO\n\n-- 11.21. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdModified to IX_TsDynDataEntity_TransactionIdModified\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.21. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdModified to IX_TsDynDataEntity_TransactionIdModified';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_TransactionIdModified]', N'IX_TsDynDataEntity_TransactionIdModified', N'INDEX';\nEND\nGO\n\n-- 11.22. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdDeleted to IX_TsDynDataEntity_TransactionIdDeleted\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Entities_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 11.22. Renaming Index IX_ToSIC_EAV_Entities_TransactionIdDeleted to IX_TsDynDataEntity_TransactionIdDeleted';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_ToSIC_EAV_Entities_TransactionIdDeleted]', N'IX_TsDynDataEntity_TransactionIdDeleted', N'INDEX';\nEND\nGO\n\n\n\n-- *** 12. Rename ToSIC_EAV_EntityRelationships to TsDynDataRelationship and related objects\nPRINT '12. Renaming table ToSIC_EAV_EntityRelationships to TsDynDataRelationship and related objects';\n\n-- 12.1. Rename table ToSIC_EAV_EntityRelationships to TsDynDataRelationship\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_EntityRelationships' AND type = 'U')\nBEGIN\n    PRINT '... 12.1. Renaming table ToSIC_EAV_EntityRelationships to TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_EntityRelationships]', N'TsDynDataRelationship';\nEND\nGO\n\n-- 12.2. Rename column AttributeID to AttributeId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.2. Renaming column AttributeID to AttributeId in TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[TsDynDataRelationship].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\nGO\n\n-- 12.3. Rename column ParentEntityID to ParentEntityId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ParentEntityID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.3. Renaming column ParentEntityID to ParentEntityId in TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[TsDynDataRelationship].[ParentEntityID]', N'ParentEntityId', N'COLUMN';\nEND\nGO\n\n-- 12.4. Rename column ChildEntityID to ChildEntityId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ChildEntityID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.4. Renaming column ChildEntityID to ChildEntityId in TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[TsDynDataRelationship].[ChildEntityID]', N'ChildEntityId', N'COLUMN';\nEND\nGO\n\n-- 12.5. Rename the primary key constraint PK_ToSIC_EAV_EntityRelationships to PK_TsDynDataRelationship\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_EntityRelationships' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.5. Renaming PK_ToSIC_EAV_EntityRelationships to PK_TsDynDataRelationship';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_EntityRelationships]', N'PK_TsDynDataRelationship', N'OBJECT';\nEND\nGO\n\n-- 12.6. Renaming FK FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute to FK_TsDynDataRelationship_TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.6. Renaming FK FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute to FK_TsDynDataRelationship_TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_EntityRelationships_TsDynDataAttribute]', N'FK_TsDynDataRelationship_TsDynDataAttribute', N'OBJECT';\nEND\nGO\n\n-- 12.7. Renaming FK FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities to FK_TsDynDataRelationship_TsDynDataEntityParent\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.7. Renaming FK FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities to FK_TsDynDataRelationship_TsDynDataEntityParent';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ParentEntities]', N'FK_TsDynDataRelationship_TsDynDataEntityParent', N'OBJECT';\nEND\nGO\n\n-- 12.8. Renaming FK FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities to FK_TsDynDataRelationship_TsDynDataEntityChild\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\nBEGIN\n    PRINT '... 12.8. Renaming FK FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities to FK_TsDynDataRelationship_TsDynDataEntityChild';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_EntityRelationships_ToSIC_EAV_ChildEntities]', N'FK_TsDynDataRelationship_TsDynDataEntityChild', N'OBJECT';\nEND\nGO\n\n-- 12.9. Adding index IX_TsDynDataRelationship_ParentEntityId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataRelationship_ParentEntityId' AND object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\n    AND OBJECT_ID('[dbo].[TsDynDataRelationship]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'ParentEntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]')) -- Ensure column exists\nBEGIN\n    PRINT '... 12.9. Adding index IX_TsDynDataRelationship_ParentEntityId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataRelationship_ParentEntityId] ON [dbo].[TsDynDataRelationship] ([ParentEntityId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 12.10. Adding index IX_TsDynDataRelationship_ChildEntityId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataRelationship_ChildEntityId' AND object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]'))\n    AND OBJECT_ID('[dbo].[TsDynDataRelationship]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'ChildEntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataRelationship]')) -- Ensure column exists\nBEGIN\n    PRINT '... 12.10. Adding index IX_TsDynDataRelationship_ChildEntityId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataRelationship_ChildEntityId] ON [dbo].[TsDynDataRelationship] ([ChildEntityId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n\n\n-- *** 12b. Rename ToSIC_EAV_Values to TsDynDataValue and related objects\nPRINT '12b. Renaming table ToSIC_EAV_Values to TsDynDataValue and related objects';\n\n-- 12b.1. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionCreated\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionCreated' AND parent_object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.1. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionCreated';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionCreated];\nEND\nGO\n\n-- 12b.2. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionModified\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionModified' AND parent_object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.2. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionModified';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionModified];\nEND\nGO\n\n-- 12b.3. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted' AND parent_object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.3. Dropping FK FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP CONSTRAINT [FK_ToSIC_EAV_Values_TsDynDataTransactionDeleted];\nEND\nGO\n\n-- 12b.4. Drop old complex index IX_EAV_Values1 from ToSIC_EAV_Values (as they included TransactionId columns)\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_EAV_Values1' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.4. Dropping Index IX_EAV_Values1';\n    DROP INDEX [IX_EAV_Values1] ON [dbo].[ToSIC_EAV_Values];\nEND\nGO\n\n-- 12b.5. Drop old complex index IX_EAV_Values2 from ToSIC_EAV_Values (as they included TransactionId columns)\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_EAV_Values2' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.5. Dropping Index IX_EAV_Values2';\n    DROP INDEX [IX_EAV_Values2] ON [dbo].[ToSIC_EAV_Values];\nEND\nGO\n\n-- 12b.6. Dropping Index IX_ToSIC_EAV_Values_TransactionIdCreated\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdCreated' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.6. Dropping Index IX_ToSIC_EAV_Values_TransactionIdCreated';\n    DROP INDEX [IX_ToSIC_EAV_Values_TransactionIdCreated] ON [dbo].[ToSIC_EAV_Values];\nEND\nGO\n\n-- 12b.7. Dropping Index IX_ToSIC_EAV_Values_TransactionIdModified\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdModified' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.7. Dropping Index IX_ToSIC_EAV_Values_TransactionIdModified';\n    DROP INDEX [IX_ToSIC_EAV_Values_TransactionIdModified] ON [dbo].[ToSIC_EAV_Values];\nEND\nGO\n\n-- 12b.8. Dropping Index IX_ToSIC_EAV_Values_TransactionIdDeleted\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Values_TransactionIdDeleted' AND object_id = OBJECT_ID('[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.8. Dropping Index IX_ToSIC_EAV_Values_TransactionIdDeleted';\n    DROP INDEX [IX_ToSIC_EAV_Values_TransactionIdDeleted] ON [dbo].[ToSIC_EAV_Values];\nEND\nGO\n\n-- 12b.9. Dropping column TransactionIdCreated from ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.9. Dropping column TransactionIdCreated from ToSIC_EAV_Values';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP COLUMN [TransactionIdCreated];\nEND\nGO\n\n-- 12b.10. Dropping column TransactionIdModified from ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.10. Dropping column TransactionIdModified from ToSIC_EAV_Values';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP COLUMN [TransactionIdModified];\nEND\nGO\n\n-- 12b.11. Dropping column TransactionIdDeleted from ToSIC_EAV_Values\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = Object_ID(N'[dbo].[ToSIC_EAV_Values]'))\nBEGIN\n    PRINT '... 12b.11. Dropping column TransactionIdDeleted from ToSIC_EAV_Values';\n    ALTER TABLE [dbo].[ToSIC_EAV_Values] DROP COLUMN [TransactionIdDeleted];\nEND\nGO\n\n-- 12b.12. Renaming table ToSIC_EAV_Values to TsDynDataValue\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Values' AND type = 'U')\nBEGIN\n    PRINT '... 12b.12. Renaming table ToSIC_EAV_Values to TsDynDataValue';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Values]', N'TsDynDataValue';\nEND\nGO\n\n-- 12b.12b. Renaming column ValueID to ValueId in TsDynDataValue\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ValueID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.12b.Renaming column ValueID to ValueId in TsDynDataValue';\n    EXEC sp_rename N'[dbo].[TsDynDataValue].[ValueID]', N'ValueId', N'COLUMN';\nEND\nGO\n\n-- 12b.14. Renaming column EntityID to EntityId in TsDynDataValue\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'EntityID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.14. Renaming column EntityID to EntityId in TsDynDataValue';\n    EXEC sp_rename N'[dbo].[TsDynDataValue].[EntityID]', N'EntityId', N'COLUMN';\nEND\nGO\n\n-- 12b.15. Renaming column AttributeID to AttributeId in TsDynDataValue\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'AttributeID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.15. Renaming column AttributeID to AttributeId in TsDynDataValue (defensive)';\n    EXEC sp_rename N'[dbo].[TsDynDataValue].[AttributeID]', N'AttributeId', N'COLUMN';\nEND\nGO\n\n-- 12b.16. Renaming PK_ToSIC_EAV_Values to PK_TsDynDataValue\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Values' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.16. Renaming PK_ToSIC_EAV_Values to PK_TsDynDataValue';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Values]', N'PK_TsDynDataValue', N'OBJECT';\nEND\nGO\n\n-- 12b.17. Renaming FK FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values to FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values' AND parent_object_id = OBJECT_ID('[dbo].[ToSIC_EAV_ValuesDimensions]'))\nBEGIN\n    PRINT '... 12b.17. Renaming FK FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values to FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Values]', N'FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue', N'OBJECT';\nEND\nGO\n\n-- 12b.18. Renaming FK FK_ToSIC_EAV_Values_ToSIC_EAV_Entities to FK_TsDynDataValue_TsDynDataEntity\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_ToSIC_EAV_Entities' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.18. Renaming FK FK_ToSIC_EAV_Values_ToSIC_EAV_Entities to FK_TsDynDataValue_TsDynDataEntity';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_ToSIC_EAV_Entities]', N'FK_TsDynDataValue_TsDynDataEntity', N'OBJECT';\nEND\nGO\n\n-- 12b.19. Renaming FK FK_ToSIC_EAV_Values_TsDynDataAttribute to FK_TsDynDataValue_TsDynDataAttribute\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Values_TsDynDataAttribute' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.19. Renaming FK FK_ToSIC_EAV_Values_TsDynDataAttribute to FK_TsDynDataValue_TsDynDataAttribute';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Values_TsDynDataAttribute]', N'FK_TsDynDataValue_TsDynDataAttribute', N'OBJECT';\nEND\nGO\n\n-- 12b.20. Adding index IX_TsDynDataValue_EntityId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataValue_EntityId' AND object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\n    AND OBJECT_ID('[dbo].[TsDynDataValue]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'EntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.20. Adding index IX_TsDynDataValue_EntityId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataValue_EntityId] ON [dbo].[TsDynDataValue] ([EntityId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 12b.21. Adding index IX_TsDynDataValue_AttributeId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataValue_AttributeId' AND object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\n    AND OBJECT_ID('[dbo].[TsDynDataValue]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'AttributeId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.21. Adding index IX_TsDynDataValue_AttributeId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataValue_AttributeId] ON [dbo].[TsDynDataValue] ([AttributeId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 12b.22. Adding index IX_TsDynDataValue_AttributeId_EntityId\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataValue_AttributeId_EntityId' AND object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\n    AND OBJECT_ID('[dbo].[TsDynDataValue]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'AttributeId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'EntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.22. Adding index IX_TsDynDataValue_AttributeId_EntityId';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataValue_AttributeId_EntityId] ON [dbo].[TsDynDataValue] ([AttributeId] ASC, [EntityId] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- 12b.23. Adding index IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value\nIF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value' AND object_id = OBJECT_ID('[dbo].[TsDynDataValue]'))\n    AND OBJECT_ID('[dbo].[TsDynDataValue]', 'U') IS NOT NULL\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'EntityId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'AttributeId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'ValueId' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\n    AND EXISTS (SELECT * FROM sys.columns WHERE Name = 'Value' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValue]'))\nBEGIN\n    PRINT '... 12b.23. Adding index IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value] ON [dbo].[TsDynDataValue] ([EntityId] ASC, [AttributeId] ASC, [ValueId] ASC)\n    INCLUDE([Value])\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n\n\n-- *** 14. Renaming table ToSIC_EAV_Dimensions to TsDynDataDimension and related objects\nPRINT '14. Renaming table ToSIC_EAV_Dimensions to TsDynDataDimension and related objects';\n\n-- 14.1. Rename table ToSIC_EAV_Dimensions to TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_Dimensions' AND type = 'U')\nBEGIN\n    PRINT '... 14.1. Renaming table ToSIC_EAV_Dimensions to TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_Dimensions]', N'TsDynDataDimension';\nEND\nGO\n\n-- 14.2. Rename column DimensionID to DimensionId in TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'DimensionID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.2. Renaming column DimensionID to DimensionId in TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[TsDynDataDimension].[DimensionID]', N'DimensionId', N'COLUMN';\nEND\nGO\n\n-- 14.3. Rename Primary Key constraint for TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_Dimensions' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.3. Renaming PK_ToSIC_EAV_Dimensions to PK_TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_Dimensions]', N'PK_TsDynDataDimension', N'OBJECT';\nEND\nGO\n\n-- 14.4. Renaming FK FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1 to FK_TsDynDataDimension_TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.4. Renaming FK FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1 to FK_TsDynDataDimension_TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Dimensions_ToSIC_EAV_Dimensions1]', N'FK_TsDynDataDimension_TsDynDataDimension', N'OBJECT';\nEND\nGO\n\n-- 14.5. Renaming FK FK_ToSIC_EAV_Dimensions_TsDynDataZone to FK_TsDynDataDimension_TsDynDataZone\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_Dimensions_TsDynDataZone' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.5. Renaming FK FK_ToSIC_EAV_Dimensions_TsDynDataZone to FK_TsDynDataDimension_TsDynDataZone';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_Dimensions_TsDynDataZone]', N'FK_TsDynDataDimension_TsDynDataZone', N'OBJECT';\nEND\nGO\n\n-- 14.6. Renaming Default Constraint DF_ToSIC_EAV_Dimensions_Active to DF_TsDynDataDimension_Active\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_Dimensions_Active' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.6. Renaming Default Constraint DF_ToSIC_EAV_Dimensions_Active to DF_TsDynDataDimension_Active';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_Dimensions_Active]', N'DF_TsDynDataDimension_Active', N'OBJECT';\nEND\nGO\n\n-- 14.7. Renaming Index IX_ToSIC_EAV_Dimensions_ZoneId to IX_TsDynDataDimension_ZoneId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ToSIC_EAV_Dimensions_ZoneId' AND object_id = OBJECT_ID('[dbo].[TsDynDataDimension]'))\nBEGIN\n    PRINT '... 14.7. Renaming Index IX_ToSIC_EAV_Dimensions_ZoneId to IX_TsDynDataDimension_ZoneId';\n    EXEC sp_rename N'[dbo].[TsDynDataDimension].[IX_ToSIC_EAV_Dimensions_ZoneId]', N'IX_TsDynDataDimension_ZoneId', N'INDEX';\nEND\nGO\n\n\n\n-- *** 15. Renaming table ToSIC_EAV_ValuesDimensions to TsDynDataValueDimension and related objects\nPRINT '15. Renaming table ToSIC_EAV_ValuesDimensions to TsDynDataValueDimension and related objects';\n\n-- 15.1. Rename table ToSIC_EAV_ValuesDimensions to TsDynDataValueDimension\nIF EXISTS (SELECT * FROM sys.objects WHERE name = 'ToSIC_EAV_ValuesDimensions' AND type = 'U')\nBEGIN\n    PRINT '... 15.1. Renaming table ToSIC_EAV_ValuesDimensions to TsDynDataValueDimension';\n    EXEC sp_rename N'[dbo].[ToSIC_EAV_ValuesDimensions]', N'TsDynDataValueDimension';\nEND\nGO\n\n-- 15.2. Rename column ValueID to ValueId in TsDynDataValueDimension\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'ValueID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.2. Renaming column ValueID to ValueId in TsDynDataValueDimension';\n    EXEC sp_rename N'[dbo].[TsDynDataValueDimension].[ValueID]', N'ValueId', N'COLUMN';\nEND\nGO\n\n-- 15.3. Rename column DimensionID to DimensionId in TsDynDataValueDimension\nIF EXISTS (SELECT * FROM sys.columns WHERE Name COLLATE Latin1_General_CS_AS = N'DimensionID' AND Object_ID = Object_ID(N'[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.3. Renaming column DimensionID to DimensionId in TsDynDataValueDimension';\n    EXEC sp_rename N'[dbo].[TsDynDataValueDimension].[DimensionID]', N'DimensionId', N'COLUMN';\nEND\nGO\n\n-- 15.4. Rename Primary Key constraint for TsDynDataValueDimension\nIF EXISTS (SELECT * FROM sys.key_constraints WHERE name = 'PK_ToSIC_EAV_ValuesDimensions' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.4. Renaming PK_ToSIC_EAV_ValuesDimensions to PK_TsDynDataValueDimension';\n    EXEC sp_rename N'[dbo].[PK_ToSIC_EAV_ValuesDimensions]', N'PK_TsDynDataValueDimension', N'OBJECT';\nEND\nGO\n\n-- 15.5. Renaming FK FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions to FK_TsDynDataValueDimension_TsDynDataDimension\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.5. Renaming FK FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions to FK_TsDynDataValueDimension_TsDynDataDimension';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_ToSIC_EAV_Dimensions]', N'FK_TsDynDataValueDimension_TsDynDataDimension', N'OBJECT';\nEND\nGO\n\n-- 15.6. Renaming FK FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue to FK_TsDynDataValueDimension_TsDynDataValue\nIF EXISTS (SELECT * FROM sys.foreign_keys WHERE name = 'FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.6. Renaming FK FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue to FK_TsDynDataValueDimension_TsDynDataValue';\n    EXEC sp_rename N'[dbo].[FK_ToSIC_EAV_ValuesDimensions_TsDynDataValue]', N'FK_TsDynDataValueDimension_TsDynDataValue', N'OBJECT';\nEND\nGO\n\n-- 15.7. Renaming Default Constraint DF_ToSIC_EAV_ValuesDimensions_ReadOnly to DF_TsDynDataValueDimension_ReadOnly\nIF EXISTS (SELECT * FROM sys.default_constraints WHERE name = 'DF_ToSIC_EAV_ValuesDimensions_ReadOnly' AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataValueDimension]'))\nBEGIN\n    PRINT '... 15.7. Renaming Default Constraint DF_ToSIC_EAV_ValuesDimensions_ReadOnly to DF_TsDynDataValueDimension_ReadOnly';\n    EXEC sp_rename N'[dbo].[DF_ToSIC_EAV_ValuesDimensions_ReadOnly]', N'DF_TsDynDataValueDimension_ReadOnly', N'OBJECT';\nEND\nGO\n\n\n\n-- *** 16. TransactionId column => TransId migration script for all tables\nPRINT '16. TransactionId column => TransId migration script for all tables';\nGO\n\n-- 16.1. Processing table TsDynDataApp\n-- 16.1.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.1. Renaming column TsDynDataApp.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\nGO\n\n-- 16.1.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.2. Renaming column TsDynDataApp.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\nGO\n\n-- 16.1.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.3. Renaming column TsDynDataApp.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\nGO\n\n-- 16.1.4. Rename index IX_TsDynDataApp_TransactionIdCreated to IX_TsDynDataApp_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.4. Renaming index IX_TsDynDataApp_TransactionIdCreated to IX_TsDynDataApp_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[IX_TsDynDataApp_TransactionIdCreated]', N'IX_TsDynDataApp_TransCreatedId', N'INDEX';\nEND\nGO\n\n-- 16.1.5. Rename index IX_TsDynDataApp_TransactionIdModified to IX_TsDynDataApp_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.5. Renaming index IX_TsDynDataApp_TransactionIdModified to IX_TsDynDataApp_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[IX_TsDynDataApp_TransactionIdModified]', N'IX_TsDynDataApp_TransModifiedId', N'INDEX';\nEND\nGO\n\n-- 16.1.6. Rename index IX_TsDynDataApp_TransactionIdDeleted to IX_TsDynDataApp_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataApp_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataApp]'))\nBEGIN\n    PRINT '... 16.1.6. Renaming index IX_TsDynDataApp_TransactionIdDeleted to IX_TsDynDataApp_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataApp].[IX_TsDynDataApp_TransactionIdDeleted]', N'IX_TsDynDataApp_TransDeletedId', N'INDEX';\nEND\nGO\n\n-- 16.2. Processing table TsDynDataAttribute\n-- 16.2.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.1. Renaming column TsDynDataAttribute.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\nGO\n\n-- 16.2.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.2. Renaming column TsDynDataAttribute.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\nGO\n\n-- 16.2.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.3. Renaming column TsDynDataAttribute.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\nGO\n\n-- 16.2.4. Rename index IX_TsDynDataAttribute_TransactionIdCreated to IX_TsDynDataAttribute_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.4. Renaming index IX_TsDynDataAttribute_TransactionIdCreated to IX_TsDynDataAttribute_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_TsDynDataAttribute_TransactionIdCreated]', N'IX_TsDynDataAttribute_TransCreatedId', N'INDEX';\nEND\nGO\n\n-- 16.2.5. Rename index IX_TsDynDataAttribute_TransactionIdModified to IX_TsDynDataAttribute_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.5. Renaming index IX_TsDynDataAttribute_TransactionIdModified to IX_TsDynDataAttribute_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_TsDynDataAttribute_TransactionIdModified]', N'IX_TsDynDataAttribute_TransModifiedId', N'INDEX';\nEND\nGO\n\n-- 16.2.6. Rename index IX_TsDynDataAttribute_TransactionIdDeleted to IX_TsDynDataAttribute_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataAttribute_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataAttribute]'))\nBEGIN\n    PRINT '... 16.2.6. Renaming index IX_TsDynDataAttribute_TransactionIdDeleted to IX_TsDynDataAttribute_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataAttribute].[IX_TsDynDataAttribute_TransactionIdDeleted]', N'IX_TsDynDataAttribute_TransDeletedId', N'INDEX';\nEND\nGO\n\n-- 16.3. Processing table TsDynDataContentType\n-- 16.3.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.1. Renaming column TsDynDataContentType.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\nGO\n\n-- 16.3.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.2. Renaming column TsDynDataContentType.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\nGO\n\n-- 16.3.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.3. Renaming column TsDynDataContentType.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\nGO\n\n-- 16.3.4. Rename index IX_TsDynDataContentType_TransactionIdCreated to IX_TsDynDataContentType_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.4. Renaming index IX_TsDynDataContentType_TransactionIdCreated to IX_TsDynDataContentType_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_TsDynDataContentType_TransactionIdCreated]', N'IX_TsDynDataContentType_TransCreatedId', N'INDEX';\nEND\nGO\n\n-- 16.3.5. Rename index IX_TsDynDataContentType_TransactionIdModified to IX_TsDynDataContentType_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.5. Renaming index IX_TsDynDataContentType_TransactionIdModified to IX_TsDynDataContentType_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_TsDynDataContentType_TransactionIdModified]', N'IX_TsDynDataContentType_TransModifiedId', N'INDEX';\nEND\nGO\n\n-- 16.3.6. Rename index IX_TsDynDataContentType_TransactionIdDeleted to IX_TsDynDataContentType_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataContentType_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataContentType]'))\nBEGIN\n    PRINT '... 16.3.6. Renaming index IX_TsDynDataContentType_TransactionIdDeleted to IX_TsDynDataContentType_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataContentType].[IX_TsDynDataContentType_TransactionIdDeleted]', N'IX_TsDynDataContentType_TransDeletedId', N'INDEX';\nEND\nGO\n\n-- 16.4. Processing table TsDynDataEntity\n-- 16.4.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.1. Renaming column TsDynDataEntity.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\nGO\n\n-- 16.4.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.2. Renaming column TsDynDataEntity.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\nGO\n\n-- 16.4.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.3. Renaming column TsDynDataEntity.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\nGO\n\n-- 16.4.4. Rename index IX_TsDynDataEntity_TransactionIdCreated to IX_TsDynDataEntity_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.4. Renaming index IX_TsDynDataEntity_TransactionIdCreated to IX_TsDynDataEntity_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_TsDynDataEntity_TransactionIdCreated]', N'IX_TsDynDataEntity_TransCreatedId', N'INDEX';\nEND\nGO\n\n-- 16.4.5. Rename index IX_TsDynDataEntity_TransactionIdModified to IX_TsDynDataEntity_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.5. Renaming index IX_TsDynDataEntity_TransactionIdModified to IX_TsDynDataEntity_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_TsDynDataEntity_TransactionIdModified]', N'IX_TsDynDataEntity_TransModifiedId', N'INDEX';\nEND\nGO\n\n-- 16.4.6. Rename index IX_TsDynDataEntity_TransactionIdDeleted to IX_TsDynDataEntity_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataEntity_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataEntity]'))\nBEGIN\n    PRINT '... 16.4.6. Renaming index IX_TsDynDataEntity_TransactionIdDeleted to IX_TsDynDataEntity_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataEntity].[IX_TsDynDataEntity_TransactionIdDeleted]', N'IX_TsDynDataEntity_TransDeletedId', N'INDEX';\nEND\nGO\n\n-- 16.5. Processing table TsDynDataZone\n-- 16.5.1. Rename column TransactionIdCreated to TransCreatedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdCreated' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransCreatedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.1. Renaming column TsDynDataZone.TransactionIdCreated to TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[TransactionIdCreated]', N'TransCreatedId', N'COLUMN';\nEND\nGO\n\n-- 16.5.2. Rename column TransactionIdModified to TransModifiedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdModified' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransModifiedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.2. Renaming column TsDynDataZone.TransactionIdModified to TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[TransactionIdModified]', N'TransModifiedId', N'COLUMN';\nEND\nGO\n\n-- 16.5.3. Rename column TransactionIdDeleted to TransDeletedId\nIF EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransactionIdDeleted' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.columns WHERE Name = N'TransDeletedId' AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.3. Renaming column TsDynDataZone.TransactionIdDeleted to TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[TransactionIdDeleted]', N'TransDeletedId', N'COLUMN';\nEND\nGO\n\n-- 16.5.4. Rename index IX_TsDynDataZone_TransactionIdCreated to IX_TsDynDataZone_TransCreatedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdCreated' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransCreatedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.4. Renaming index IX_TsDynDataZone_TransactionIdCreated to IX_TsDynDataZone_TransCreatedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[IX_TsDynDataZone_TransactionIdCreated]', N'IX_TsDynDataZone_TransCreatedId', N'INDEX';\nEND\nGO\n\n-- 16.5.5. Rename index IX_TsDynDataZone_TransactionIdModified to IX_TsDynDataZone_TransModifiedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdModified' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransModifiedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.5. Renaming index IX_TsDynDataZone_TransactionIdModified to IX_TsDynDataZone_TransModifiedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[IX_TsDynDataZone_TransactionIdModified]', N'IX_TsDynDataZone_TransModifiedId', N'INDEX';\nEND\nGO\n\n-- 16.5.6. Rename index IX_TsDynDataZone_TransactionIdDeleted to IX_TsDynDataZone_TransDeletedId\nIF EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransactionIdDeleted' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\n    AND NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_TsDynDataZone_TransDeletedId' AND object_id = OBJECT_ID(N'[dbo].[TsDynDataZone]'))\nBEGIN\n    PRINT '... 16.5.6. Renaming index IX_TsDynDataZone_TransactionIdDeleted to IX_TsDynDataZone_TransDeletedId';\n    EXEC sp_rename N'[dbo].[TsDynDataZone].[IX_TsDynDataZone_TransactionIdDeleted]', N'IX_TsDynDataZone_TransDeletedId', N'INDEX';\nEND\nGO\n\n\n-- 17. Adding new table type TsDynDataIntList\n-- 2025-05-12, stv, test alternative strategy to load values\n-- DROP TYPE IF EXISTS [dbo].[TsDynDataIntList];\n-- GO\n--IF TYPE_ID(N'[dbo].[TsDynDataIntList]') IS NULL\n--BEGIN\n--    PRINT '... 17.1. Creating new table type TsDynDataIntList for TVP';\n--    CREATE TYPE [dbo].[TsDynDataIntList] AS TABLE\n--    (\n--        Id int NOT NULL\n--    );\n--END\n-- GO\n\nPRINT '*** Finished migration script.';\nGO\n\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.20.00.05.sql",
    "content": "-- =====================================================================\n-- Switch default value from GETDATE() to GETUTCDATE() on [dbo].[TsDynDataTransaction].[Timestamp] if the current default uses GETDATE()\n-- =====================================================================\n\nDECLARE @Definition nvarchar(max);\n\nSELECT @Definition = dc.definition\nFROM sys.default_constraints dc\n         JOIN sys.columns c ON c.default_object_id = dc.object_id\n         JOIN sys.tables t ON t.object_id = c.object_id\n         JOIN sys.schemas s ON s.schema_id = t.schema_id\nWHERE s.name = 'dbo'\n  AND t.name = 'TsDynDataTransaction'\n  AND c.name = 'Timestamp'\n  AND dc.name = 'DF_TsDynDataTransaction_Timestamp';\n\nIF @Definition IS NOT NULL AND UPPER(REPLACE(@Definition, ' ', '')) LIKE '%GETDATE()%'\n    BEGIN\n        ALTER TABLE [dbo].[TsDynDataTransaction]\n            DROP CONSTRAINT [DF_TsDynDataTransaction_Timestamp];\n\n        ALTER TABLE [dbo].[TsDynDataTransaction]\n            ADD CONSTRAINT [DF_TsDynDataTransaction_Timestamp]\n                DEFAULT (GETUTCDATE()) FOR [Timestamp];\n    END\nGO\n\n\n-- =====================================================================\n-- Update legacy SettingName values (Eav*) to new names (TsDynData*)\n-- =====================================================================\n\nUPDATE Setting\nSET SettingName = 'TsDynDataZoneId'\nWHERE SettingName = 'EavZone';\nGO\n\nUPDATE Setting\nSET SettingName = 'TsDynDataApp'\nWHERE SettingName = 'EavApp';\nGO\n\nUPDATE Setting\nSET SettingName = 'TsDynDataContentGroup'\nWHERE SettingName = 'EavContentGroup';\nGO\n\nUPDATE Setting\nSET SettingName = 'TsDynDataPreview'\nWHERE SettingName = 'EavPreview';\nGO\n\n\n-- =====================================================================\n-- Drop all tables and stored procedures in the old ToSIC EAV schema\n-- =====================================================================\n\n-- Stored procedures (no dependencies)\nDROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_LogToTimeline];\nGO\nDROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_DeleteApp];\nGO\nDROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogSet];\nGO\nDROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogGet];\nGO\nDROP PROCEDURE IF EXISTS [dbo].[ToSIC_EAV_ChangeLogAdd];\nGO\n\n/* \n   Tables drop order:\n   - Drop most dependent children first.\n   - Core parents (Apps, Zones, AttributeTypes, ChangeLog) last.\n*/\n\n-- Child of Values & Dimensions\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_ValuesDimensions];      -- FK -> Values, Dimensions\nGO\n\n-- Child of Entities, Attributes, ChangeLog\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_Values];                 -- FK -> Entities, Attributes, ChangeLog\nGO\n\n-- Child of Entities (parent/child) and Attributes\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_EntityRelationships];    -- FK -> Entities, Attributes\nGO\n\n-- Child of AttributeSets, Attributes, AttributeGroups\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AttributesInSets];       -- FK -> AttributeSets, Attributes, AttributeGroups\nGO\n\n-- Child of AttributeSets\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AttributeGroups];        -- FK -> AttributeSets\nGO\n\n-- Child of AttributeSets, AssignmentObjectTypes, Apps, ChangeLog (also self-FK)\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_Entities];               -- FK -> AttributeSets, AssignmentObjectTypes, Apps, ChangeLog\nGO\n\n-- Child of Zones (also self-FK)\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_Dimensions];             -- FK -> Zones\nGO\n\n-- Not referenced in your FK list (drop early to be safe)\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_DataTimeline];\nGO\n\n-- Not referenced in your FK list (drop early to be safe)\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_ContextInfo];\nGO\n\n-- Child of AttributeTypes and ChangeLog\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_Attributes];             -- FK -> AttributeTypes, ChangeLog\nGO\n\n-- Child of Apps and ChangeLog (also self-FK)\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AttributeSets];          -- FK -> Apps, ChangeLog\nGO\n\n-- Parent of Entities\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AssignmentObjectTypes];  -- parent only\nGO\n\n-- Parent of Entities & AttributeSets\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_Apps];                   -- parent only\nGO\n\n-- Parent of Dimensions\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_Zones];                  -- parent only\nGO\n\n-- Parent of Attributes\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_AttributeTypes];         -- parent only\nGO\n\n-- Root parent of many (Values, Entities, AttributeSets, Attributes, )\nDROP TABLE IF EXISTS [dbo].[ToSIC_EAV_ChangeLog];              -- drop last\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.21.00.00.sql",
    "content": "SET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\n-- make sure sql rolls back automatically in case of error.\nSET XACT_ABORT ON\nGO\n\n-- =====================================================================\n-- TsDynDataHistory: add ParentRef so history can be grouped by app\n-- ParentRef format example: \"app-42\"\n-- =====================================================================\n\n-- Add ParentRef column on existing installations\nIF OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\n    AND NOT EXISTS (\n        SELECT *\n        FROM sys.columns\n        WHERE Name = N'ParentRef'\n          AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataHistory]')\n    )\nBEGIN\n    PRINT '... Adding column [ParentRef] to [dbo].[TsDynDataHistory]';\n    ALTER TABLE [dbo].[TsDynDataHistory] ADD [ParentRef] [nvarchar](250) NULL;\nEND\nGO\n\n-- Add index for ParentRef\nIF OBJECT_ID('[dbo].[TsDynDataHistory]', 'U') IS NOT NULL\n    AND NOT EXISTS (\n        SELECT *\n        FROM sys.indexes\n        WHERE name = 'IX_TsDynDataHistory_ParentRef'\n          AND object_id = OBJECT_ID('[dbo].[TsDynDataHistory]')\n    )\nBEGIN\n    PRINT '... Adding index IX_TsDynDataHistory_ParentRef';\n    CREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_ParentRef] ON [dbo].[TsDynDataHistory] ([ParentRef] ASC)\n    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY];\nEND\nGO\n\n-- =====================================================================\n-- TsDynDataRelationship: add ChildExternalId to support undelete\n-- =====================================================================\n\n-- Add ChildExternalId column on existing installations\nIF OBJECT_ID('[dbo].[TsDynDataRelationship]', 'U') IS NOT NULL\n    AND NOT EXISTS (\n        SELECT *\n        FROM sys.columns\n        WHERE Name = N'ChildExternalId'\n          AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataRelationship]')\n    )\nBEGIN\n    PRINT '... Adding column [ChildExternalId] to [dbo].[TsDynDataRelationship]';\n    ALTER TABLE [dbo].[TsDynDataRelationship] ADD [ChildExternalId] [uniqueidentifier] NULL;\nEND\nGO\n\n-- Remove TransDeletedId (was a short-lived experiment)\nIF OBJECT_ID('[dbo].[TsDynDataRelationship]', 'U') IS NOT NULL\nBEGIN\n    IF EXISTS (\n        SELECT *\n        FROM sys.foreign_keys\n        WHERE name = 'FK_TsDynDataRelationship_TsDynDataTransactionDeleted'\n          AND parent_object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]')\n    )\n    BEGIN\n        PRINT '... Dropping FK FK_TsDynDataRelationship_TsDynDataTransactionDeleted';\n        ALTER TABLE [dbo].[TsDynDataRelationship] DROP CONSTRAINT [FK_TsDynDataRelationship_TsDynDataTransactionDeleted];\n    END\n\n    IF EXISTS (\n        SELECT *\n        FROM sys.indexes\n        WHERE name = 'IX_TsDynDataRelationship_TransDeletedId'\n          AND object_id = OBJECT_ID('[dbo].[TsDynDataRelationship]')\n    )\n    BEGIN\n        PRINT '... Dropping index IX_TsDynDataRelationship_TransDeletedId';\n        DROP INDEX [IX_TsDynDataRelationship_TransDeletedId] ON [dbo].[TsDynDataRelationship];\n    END\n\n    IF EXISTS (\n        SELECT *\n        FROM sys.columns\n        WHERE Name = N'TransDeletedId'\n          AND Object_ID = OBJECT_ID(N'[dbo].[TsDynDataRelationship]')\n    )\n    BEGIN\n        PRINT '... Dropping column [TransDeletedId] from [dbo].[TsDynDataRelationship]';\n        ALTER TABLE [dbo].[TsDynDataRelationship] DROP COLUMN [TransDeletedId];\n    END\nEND\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.Install.sql",
    "content": "/************************************************************/\n/*****              SqlDataProvider                     *****/\n/*****                                                  *****/\n/*****                                                  *****/\n/***** Note: To manually execute this script you must   *****/\n/*****       perform a search and replace operation     *****/\n/*****       for {databaseOwner} and {objectQualifier}  *****/\n/*****                                                  *****/\n/************************************************************/\n-- Set session language to english to ensure DateTime format is correct (all following insert statements in this script expect that)\nSET LANGUAGE English\n\n-- Start of install procedure which replaces all install scripts and code updates until and including version 20.00.05 -------------------------------------------------\n\n/****** Object:  Table [dbo].[TsDynDataApp]    Script Date: 15.5.2025. 13:42:07 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataApp](\n    [AppId] [int] IDENTITY(1,1) NOT NULL,\n    [ZoneId] [int] NOT NULL,\n    [Name] [nvarchar](255) NOT NULL,\n    [SysSettings] [nvarchar](max) NULL,\n    [TransCreatedId] [int] NULL,\n    [TransModifiedId] [int] NULL,\n    [TransDeletedId] [int] NULL,\n CONSTRAINT [PK_TsDynDataApp] PRIMARY KEY CLUSTERED \n(\n    [AppId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataAttribute]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataAttribute](\n    [AttributeId] [int] IDENTITY(1,1) NOT NULL,\n    [StaticName] [nvarchar](50) NOT NULL,\n    [Type] [nvarchar](50) NOT NULL,\n    [TransCreatedId] [int] NOT NULL,\n    [TransDeletedId] [int] NULL,\n    [Guid] [uniqueidentifier] NULL,\n    [SysSettings] [nvarchar](max) NULL,\n    [ContentTypeId] [int] NOT NULL,\n    [SortOrder] [int] NOT NULL,\n    [IsTitle] [bit] NOT NULL,\n    [TransModifiedId] [int] NULL,\n CONSTRAINT [PK_TsDynDataAttribute] PRIMARY KEY CLUSTERED \n(\n    [AttributeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataAttributeType]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataAttributeType](\n    [Type] [nvarchar](50) NOT NULL,\n CONSTRAINT [PK_TsDynDataAttributeType] PRIMARY KEY CLUSTERED \n(\n    [Type] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataContentType]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataContentType](\n    [ContentTypeId] [int] IDENTITY(1,1) NOT NULL,\n    [StaticName] [nvarchar](150) NULL,\n    [Name] [nvarchar](150) NULL,\n    [Scope] [nvarchar](50) NULL,\n    [TransCreatedId] [int] NOT NULL,\n    [TransDeletedId] [int] NULL,\n    [AppId] [int] NOT NULL,\n    [InheritContentTypeId] [int] NULL,\n    [IsGlobal] [bit] NOT NULL,\n    [Json] [nvarchar](max) NULL,\n    [SysSettings] [nvarchar](max) NULL,\n    [TransModifiedId] [int] NULL,\n CONSTRAINT [PK_TsDynDataContentType] PRIMARY KEY CLUSTERED \n(\n    [ContentTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataDimension]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataDimension](\n    [DimensionId] [int] IDENTITY(1,1) NOT NULL,\n    [Parent] [int] NULL,\n    [Name] [nvarchar](100) NOT NULL,\n    [SystemKey] [nvarchar](100) NULL,\n    [ExternalKey] [nvarchar](100) NULL,\n    [Active] [bit] NOT NULL,\n    [ZoneId] [int] NOT NULL,\n CONSTRAINT [PK_TsDynDataDimension] PRIMARY KEY CLUSTERED \n(\n    [DimensionId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataEntity]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataEntity](\n    [EntityId] [int] IDENTITY(1,1) NOT NULL,\n    [EntityGuid] [uniqueidentifier] NOT NULL,\n    [ContentTypeId] [int] NOT NULL,\n    [TargetTypeId] [int] NOT NULL,\n    [KeyNumber] [int] NULL,\n    [KeyGuid] [uniqueidentifier] NULL,\n    [KeyString] [nvarchar](100) NULL,\n    [TransCreatedId] [int] NOT NULL,\n    [TransDeletedId] [int] NULL,\n    [IsPublished] [bit] NOT NULL,\n    [PublishedEntityId] [int] NULL,\n    [TransModifiedId] [int] NOT NULL,\n    [Owner] [nvarchar](250) NULL,\n    [Json] [nvarchar](max) NULL,\n    [Version] [int] NOT NULL,\n    [AppId] [int] NOT NULL,\n    [ContentType] [nvarchar](250) NULL,\n CONSTRAINT [PK_TsDynDataEntity] PRIMARY KEY CLUSTERED \n(\n    [EntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataHistory]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataHistory](\n    [HistoryId] [int] IDENTITY(1,1) NOT NULL,\n    [SourceTable] [nvarchar](250) NOT NULL,\n    [SourceId] [int] NULL,\n    [SourceGuid] [uniqueidentifier] NULL,\n    [Operation] [nchar](1) NOT NULL,\n    [Timestamp] [datetime] NOT NULL,\n    [TransactionId] [int] NULL,\n    [Json] [nvarchar](max) NULL,\n    [CJson] [varbinary](max) NULL,\n CONSTRAINT [PK_TsDynDataHistory] PRIMARY KEY CLUSTERED \n(\n    [HistoryId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataRelationship]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataRelationship](\n    [AttributeId] [int] NOT NULL,\n    [ParentEntityId] [int] NOT NULL,\n    [ChildEntityId] [int] NULL,\n    [SortOrder] [int] NOT NULL,\n CONSTRAINT [PK_TsDynDataRelationship] PRIMARY KEY CLUSTERED \n(\n    [AttributeId] ASC,\n    [ParentEntityId] ASC,\n    [SortOrder] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataTargetType]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataTargetType](\n    [TargetTypeId] [int] IDENTITY(1,1) NOT NULL,\n    [Name] [nvarchar](50) NOT NULL,\n    [Description] [nvarchar](max) NOT NULL,\n CONSTRAINT [PK_TsDynDataTargetType] PRIMARY KEY CLUSTERED \n(\n    [TargetTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataTransaction]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataTransaction](\n    [TransactionId] [int] IDENTITY(1,1) NOT NULL,\n    [Timestamp] [datetime] NOT NULL,\n    [User] [nvarchar](255) NULL,\n CONSTRAINT [PK_TsDynDataTransaction] PRIMARY KEY CLUSTERED \n(\n    [TransactionId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataValue]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataValue](\n    [ValueId] [int] IDENTITY(1,1) NOT NULL,\n    [EntityId] [int] NOT NULL,\n    [AttributeId] [int] NOT NULL,\n    [Value] [nvarchar](max) NOT NULL,\n CONSTRAINT [PK_TsDynDataValue] PRIMARY KEY CLUSTERED \n(\n    [ValueId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataValueDimension]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataValueDimension](\n    [ValueId] [int] NOT NULL,\n    [DimensionId] [int] NOT NULL,\n    [ReadOnly] [bit] NOT NULL,\n CONSTRAINT [PK_TsDynDataValueDimension] PRIMARY KEY CLUSTERED \n(\n    [ValueId] ASC,\n    [DimensionId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nGO\n/****** Object:  Table [dbo].[TsDynDataZone]    Script Date: 15.5.2025. 13:42:08 ******/\nSET ANSI_NULLS ON\nGO\nSET QUOTED_IDENTIFIER ON\nGO\nCREATE TABLE [dbo].[TsDynDataZone](\n    [ZoneId] [int] IDENTITY(1,1) NOT NULL,\n    [Name] [nvarchar](255) NOT NULL,\n    [TransCreatedId] [int] NULL,\n    [TransModifiedId] [int] NULL,\n    [TransDeletedId] [int] NULL,\n CONSTRAINT [PK_TsDynDataZone] PRIMARY KEY CLUSTERED \n(\n    [ZoneId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n) ON [PRIMARY]\nGO\n\n\n\nSET IDENTITY_INSERT [dbo].[TsDynDataApp] ON;\nINSERT [dbo].[TsDynDataApp] ([AppId], [ZoneId], [Name], [SysSettings], [TransCreatedId], [TransModifiedId], [TransDeletedId]) VALUES (1, 1, N'Default', NULL, NULL, NULL, NULL);\nSET IDENTITY_INSERT [dbo].[TsDynDataApp] OFF;\nGO\n\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Boolean');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Custom');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'DateTime');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Empty');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Entity');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Hyperlink');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'Number');\nINSERT [dbo].[TsDynDataAttributeType] ([Type]) VALUES (N'String');\nGO\n\nSET IDENTITY_INSERT [dbo].[TsDynDataContentType] ON; \nINSERT [dbo].[TsDynDataContentType] ([ContentTypeId], [StaticName], [Name], [Scope], [TransCreatedId], [TransDeletedId], [AppId], [InheritContentTypeId], [IsGlobal], [Json], [SysSettings], [TransModifiedId]) VALUES (1, N'Default', N'Default (built in)', N'2SexyContent-System', 1, NULL, 1, NULL, 1, NULL, NULL, NULL);\nSET IDENTITY_INSERT [dbo].[TsDynDataContentType] OFF;\nGO\n\nSET IDENTITY_INSERT [dbo].[TsDynDataDimension] ON;\nINSERT [dbo].[TsDynDataDimension] ([DimensionId], [Parent], [Name], [SystemKey], [ExternalKey], [Active], [ZoneId]) VALUES (1, NULL, N'Culture Root', N'Culture', NULL, 1, 1);\nSET IDENTITY_INSERT [dbo].[TsDynDataDimension] OFF;\nGO\n\nSET IDENTITY_INSERT [dbo].[TsDynDataTargetType] ON; \nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (1, N'Default', N'Default');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (2, N'EAV Field Properties', N'EAV Field Properties');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (3, N'App', N'App');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (4, N'Entity', N'For Permissions, Data Pipelines with Pipeline Parts and Configurations');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (5, N'ContentType', N'Metadata for ContentTypes');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (6, N'Zone', N'Metadata for Zone');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (7, N'Scope', N'Metadata for Scope');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (8, N'Dimension', N'Metadata for Dimension');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (9, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (10, N'CmsObject', N'References to CMS objects like files and pages');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (11, N'System', N'Metadata for System');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (12, N'Site', N'Metadata for Site');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (13, N'SiteVariant', N'Metadata for SiteVariant');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (14, N'Page', N'Metadata for Page');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (15, N'PageVariant', N'Metadata for PageVariant');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (16, N'Module', N'Metadata for Module');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (17, N'ModuleVariant', N'Metadata for ModuleVariant');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (18, N'User', N'Metadata for User');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (19, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (20, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (21, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (22, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (23, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (24, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (25, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (26, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (27, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (28, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (29, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (30, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (31, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (32, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (33, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (34, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (35, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (36, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (37, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (38, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (39, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (40, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (41, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (42, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (43, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (44, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (45, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (46, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (47, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (48, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (49, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (50, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (51, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (52, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (53, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (54, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (55, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (56, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (57, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (58, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (59, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (60, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (61, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (62, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (63, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (64, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (65, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (66, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (67, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (68, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (69, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (70, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (71, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (72, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (73, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (74, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (75, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (76, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (77, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (78, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (79, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (80, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (81, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (82, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (83, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (84, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (85, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (86, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (87, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (88, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (89, N'Reserved', N'Reserved');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (90, N'Custom', N'Custom');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (91, N'Custom1', N'Custom1');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (92, N'Custom2', N'Custom2');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (93, N'Custom3', N'Custom3');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (94, N'Custom4', N'Custom4');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (95, N'Custom5', N'Custom5');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (96, N'Custom6', N'Custom6');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (97, N'Custom7', N'Custom7');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (98, N'Custom8', N'Custom8');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (99, N'Custom9', N'Custom9');\nINSERT [dbo].[TsDynDataTargetType] ([TargetTypeId], [Name], [Description]) VALUES (100, N'Reserved', N'Reserved');\nSET IDENTITY_INSERT [dbo].[TsDynDataTargetType] OFF;\nGO\n\nSET IDENTITY_INSERT [dbo].[TsDynDataTransaction] ON;\nINSERT [dbo].[TsDynDataTransaction] ([TransactionId], [Timestamp], [User]) VALUES (1, CAST(N'2012-05-02T08:31:35.297' AS DateTime), NULL);\nINSERT [dbo].[TsDynDataTransaction] ([TransactionId], [Timestamp], [User]) VALUES (100, CAST(N'2020-10-20T00:00:00.000' AS DateTime), NULL);\nSET IDENTITY_INSERT [dbo].[TsDynDataTransaction] OFF;\nGO\n\nSET IDENTITY_INSERT [dbo].[TsDynDataZone] ON ;\nINSERT [dbo].[TsDynDataZone] ([ZoneId], [Name], [TransCreatedId], [TransModifiedId], [TransDeletedId]) VALUES (1, N'Default', NULL, NULL, NULL);\nSET IDENTITY_INSERT [dbo].[TsDynDataZone] OFF;\nGO\n\n\n\nSET ANSI_PADDING ON\nGO\n/****** Object:  Index [UQ_TsDynDataApp_Name_ZoneId]    Script Date: 15.5.2025. 13:42:08 ******/\nALTER TABLE [dbo].[TsDynDataApp] ADD  CONSTRAINT [UQ_TsDynDataApp_Name_ZoneId] UNIQUE NONCLUSTERED \n(\n    [Name] ASC,\n    [ZoneId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataApp_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransCreatedId] ON [dbo].[TsDynDataApp]\n(\n    [TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataApp_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransDeletedId] ON [dbo].[TsDynDataApp]\n(\n    [TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataApp_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataApp_TransModifiedId] ON [dbo].[TsDynDataApp]\n(\n    [TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataApp_ZoneId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataApp_ZoneId] ON [dbo].[TsDynDataApp]\n(\n    [ZoneId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataAttribute_AttributeId_StaticName]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_AttributeId_StaticName] ON [dbo].[TsDynDataAttribute]\n(\n    [AttributeId] ASC\n)\nINCLUDE([StaticName]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataAttribute_ContentTypeId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_ContentTypeId] ON [dbo].[TsDynDataAttribute]\n(\n    [ContentTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataAttribute_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_TransCreatedId] ON [dbo].[TsDynDataAttribute]\n(\n    [TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataAttribute_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_TransDeletedId] ON [dbo].[TsDynDataAttribute]\n(\n    [TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataAttribute_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataAttribute_TransModifiedId] ON [dbo].[TsDynDataAttribute]\n(\n    [TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataContentType_AppId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_AppId] ON [dbo].[TsDynDataContentType]\n(\n    [AppId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataContentType_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_TransCreatedId] ON [dbo].[TsDynDataContentType]\n(\n    [TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataContentType_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_TransDeletedId] ON [dbo].[TsDynDataContentType]\n(\n    [TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataContentType_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataContentType_TransModifiedId] ON [dbo].[TsDynDataContentType]\n(\n    [TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataDimension_ZoneId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataDimension_ZoneId] ON [dbo].[TsDynDataDimension]\n(\n    [ZoneId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataEntity_AppId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_AppId] ON [dbo].[TsDynDataEntity]\n(\n    [AppId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataEntity_ContentTypeId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_ContentTypeId] ON [dbo].[TsDynDataEntity]\n(\n    [ContentTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataEntity_KeyNumber]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_KeyNumber] ON [dbo].[TsDynDataEntity]\n(\n    [KeyNumber] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataEntity_TargetTypeId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_TargetTypeId] ON [dbo].[TsDynDataEntity]\n(\n    [TargetTypeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataEntity_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_TransCreatedId] ON [dbo].[TsDynDataEntity]\n(\n    [TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataEntity_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_TransDeletedId] ON [dbo].[TsDynDataEntity]\n(\n    [TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataEntity_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataEntity_TransModifiedId] ON [dbo].[TsDynDataEntity]\n(\n    [TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataHistory_SourceGuid]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_SourceGuid] ON [dbo].[TsDynDataHistory]\n(\n    [SourceGuid] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataHistory_SourceId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_SourceId] ON [dbo].[TsDynDataHistory]\n(\n    [SourceId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataHistory_TransactionId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataHistory_TransactionId] ON [dbo].[TsDynDataHistory]\n(\n    [TransactionId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataRelationship_ChildEntityId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataRelationship_ChildEntityId] ON [dbo].[TsDynDataRelationship]\n(\n    [ChildEntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataRelationship_ParentEntityId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataRelationship_ParentEntityId] ON [dbo].[TsDynDataRelationship]\n(\n    [ParentEntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\nSET ANSI_PADDING ON\nGO\n/****** Object:  Index [IX_TsDynDataTargetType_Name]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataTargetType_Name] ON [dbo].[TsDynDataTargetType]\n(\n    [Name] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataValue_AttributeId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataValue_AttributeId] ON [dbo].[TsDynDataValue]\n(\n    [AttributeId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataValue_AttributeId_EntityId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataValue_AttributeId_EntityId] ON [dbo].[TsDynDataValue]\n(\n    [AttributeId] ASC,\n    [EntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataValue_EntityId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataValue_EntityId] ON [dbo].[TsDynDataValue]\n(\n    [EntityId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataValue_EntityId_AttributeId_ValueId_Include_Value] ON [dbo].[TsDynDataValue]\n(\n    [EntityId] ASC,\n    [AttributeId] ASC,\n    [ValueId] ASC\n)\nINCLUDE([Value]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataZone_TransCreatedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransCreatedId] ON [dbo].[TsDynDataZone]\n(\n    [TransCreatedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataZone_TransDeletedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransDeletedId] ON [dbo].[TsDynDataZone]\n(\n    [TransDeletedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\n/****** Object:  Index [IX_TsDynDataZone_TransModifiedId]    Script Date: 15.5.2025. 13:42:08 ******/\nCREATE NONCLUSTERED INDEX [IX_TsDynDataZone_TransModifiedId] ON [dbo].[TsDynDataZone]\n(\n    [TransModifiedId] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\nGO\nALTER TABLE [dbo].[TsDynDataAttribute] ADD  CONSTRAINT [DF_TsDynDataAttribute_ContentTypeId]  DEFAULT ((0)) FOR [ContentTypeId]\nGO\nALTER TABLE [dbo].[TsDynDataAttribute] ADD  CONSTRAINT [DF_TsDynDataAttribute_SortOrder]  DEFAULT ((0)) FOR [SortOrder]\nGO\nALTER TABLE [dbo].[TsDynDataAttribute] ADD  CONSTRAINT [DF_TsDynDataAttribute_IsTitle]  DEFAULT ((0)) FOR [IsTitle]\nGO\nALTER TABLE [dbo].[TsDynDataContentType] ADD  CONSTRAINT [DF_TsDynDataContentType_StaticName]  DEFAULT (newid()) FOR [StaticName]\nGO\nALTER TABLE [dbo].[TsDynDataContentType] ADD  CONSTRAINT [DF_TsDynDataContentType_IsGlobal]  DEFAULT ((0)) FOR [IsGlobal]\nGO\nALTER TABLE [dbo].[TsDynDataDimension] ADD  CONSTRAINT [DF_TsDynDataDimension_Active]  DEFAULT ((1)) FOR [Active]\nGO\nALTER TABLE [dbo].[TsDynDataEntity] ADD  CONSTRAINT [DF_TsDynDataEntity_EntityGuid]  DEFAULT (newid()) FOR [EntityGuid]\nGO\nALTER TABLE [dbo].[TsDynDataEntity] ADD  CONSTRAINT [DF_TsDynDataEntity_IsPublished]  DEFAULT ((1)) FOR [IsPublished]\nGO\nALTER TABLE [dbo].[TsDynDataHistory] ADD  CONSTRAINT [DF_TsDynDataHistory_Operation]  DEFAULT (N'I') FOR [Operation]\nGO\nALTER TABLE [dbo].[TsDynDataTransaction] ADD  CONSTRAINT [DF_TsDynDataTransaction_Timestamp]  DEFAULT (getutcdate()) FOR [Timestamp]\nGO\nALTER TABLE [dbo].[TsDynDataValueDimension] ADD  CONSTRAINT [DF_TsDynDataValueDimension_ReadOnly]  DEFAULT ((0)) FOR [ReadOnly]\nGO\nALTER TABLE [dbo].[TsDynDataApp]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionCreated]\nGO\nALTER TABLE [dbo].[TsDynDataApp]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionDeleted]\nGO\nALTER TABLE [dbo].[TsDynDataApp]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataTransactionModified]\nGO\nALTER TABLE [dbo].[TsDynDataApp]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataApp_TsDynDataZone] FOREIGN KEY([ZoneId])\nREFERENCES [dbo].[TsDynDataZone] ([ZoneId])\nGO\nALTER TABLE [dbo].[TsDynDataApp] CHECK CONSTRAINT [FK_TsDynDataApp_TsDynDataZone]\nGO\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataAttributeType] FOREIGN KEY([Type])\nREFERENCES [dbo].[TsDynDataAttributeType] ([Type])\nGO\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataAttributeType]\nGO\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataContentType] FOREIGN KEY([ContentTypeId])\nREFERENCES [dbo].[TsDynDataContentType] ([ContentTypeId])\nGO\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataContentType]\nGO\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionCreated]\nGO\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionDeleted]\nGO\nALTER TABLE [dbo].[TsDynDataAttribute]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataAttribute] CHECK CONSTRAINT [FK_TsDynDataAttribute_TsDynDataTransactionModified]\nGO\nALTER TABLE [dbo].[TsDynDataContentType]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataApp] FOREIGN KEY([AppId])\nREFERENCES [dbo].[TsDynDataApp] ([AppId])\nGO\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataApp]\nGO\nALTER TABLE [dbo].[TsDynDataContentType]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataContentType] FOREIGN KEY([InheritContentTypeId])\nREFERENCES [dbo].[TsDynDataContentType] ([ContentTypeId])\nGO\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataContentType]\nGO\nALTER TABLE [dbo].[TsDynDataContentType]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionCreated]\nGO\nALTER TABLE [dbo].[TsDynDataContentType]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionDeleted]\nGO\nALTER TABLE [dbo].[TsDynDataContentType]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataContentType] CHECK CONSTRAINT [FK_TsDynDataContentType_TsDynDataTransactionModified]\nGO\nALTER TABLE [dbo].[TsDynDataDimension]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataDimension_TsDynDataDimension] FOREIGN KEY([Parent])\nREFERENCES [dbo].[TsDynDataDimension] ([DimensionId])\nGO\nALTER TABLE [dbo].[TsDynDataDimension] CHECK CONSTRAINT [FK_TsDynDataDimension_TsDynDataDimension]\nGO\nALTER TABLE [dbo].[TsDynDataDimension]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataDimension_TsDynDataZone] FOREIGN KEY([ZoneId])\nREFERENCES [dbo].[TsDynDataZone] ([ZoneId])\nGO\nALTER TABLE [dbo].[TsDynDataDimension] CHECK CONSTRAINT [FK_TsDynDataDimension_TsDynDataZone]\nGO\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataApp] FOREIGN KEY([AppId])\nREFERENCES [dbo].[TsDynDataApp] ([AppId])\nGO\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataApp]\nGO\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataContentType] FOREIGN KEY([ContentTypeId])\nREFERENCES [dbo].[TsDynDataContentType] ([ContentTypeId])\nGO\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataContentType]\nGO\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataTargetType] FOREIGN KEY([TargetTypeId])\nREFERENCES [dbo].[TsDynDataTargetType] ([TargetTypeId])\nGO\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataTargetType]\nGO\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionCreated]\nGO\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionDeleted]\nGO\nALTER TABLE [dbo].[TsDynDataEntity]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataEntity] CHECK CONSTRAINT [FK_TsDynDataEntity_TsDynDataTransactionModified]\nGO\nALTER TABLE [dbo].[TsDynDataHistory]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataHistory_TsDynDataTransaction] FOREIGN KEY([TransactionId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataHistory] CHECK CONSTRAINT [FK_TsDynDataHistory_TsDynDataTransaction]\nGO\nALTER TABLE [dbo].[TsDynDataRelationship]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataRelationship_TsDynDataAttribute] FOREIGN KEY([AttributeId])\nREFERENCES [dbo].[TsDynDataAttribute] ([AttributeId])\nON DELETE CASCADE\nGO\nALTER TABLE [dbo].[TsDynDataRelationship] CHECK CONSTRAINT [FK_TsDynDataRelationship_TsDynDataAttribute]\nGO\nALTER TABLE [dbo].[TsDynDataRelationship]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataRelationship_TsDynDataEntityChild] FOREIGN KEY([ChildEntityId])\nREFERENCES [dbo].[TsDynDataEntity] ([EntityId])\nGO\nALTER TABLE [dbo].[TsDynDataRelationship] CHECK CONSTRAINT [FK_TsDynDataRelationship_TsDynDataEntityChild]\nGO\nALTER TABLE [dbo].[TsDynDataRelationship]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataRelationship_TsDynDataEntityParent] FOREIGN KEY([ParentEntityId])\nREFERENCES [dbo].[TsDynDataEntity] ([EntityId])\nGO\nALTER TABLE [dbo].[TsDynDataRelationship] CHECK CONSTRAINT [FK_TsDynDataRelationship_TsDynDataEntityParent]\nGO\nALTER TABLE [dbo].[TsDynDataValue]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataValue_TsDynDataAttribute] FOREIGN KEY([AttributeId])\nREFERENCES [dbo].[TsDynDataAttribute] ([AttributeId])\nON DELETE CASCADE\nGO\nALTER TABLE [dbo].[TsDynDataValue] CHECK CONSTRAINT [FK_TsDynDataValue_TsDynDataAttribute]\nGO\nALTER TABLE [dbo].[TsDynDataValue]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataValue_TsDynDataEntity] FOREIGN KEY([EntityId])\nREFERENCES [dbo].[TsDynDataEntity] ([EntityId])\nGO\nALTER TABLE [dbo].[TsDynDataValue] CHECK CONSTRAINT [FK_TsDynDataValue_TsDynDataEntity]\nGO\nALTER TABLE [dbo].[TsDynDataValueDimension]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataValueDimension_TsDynDataDimension] FOREIGN KEY([DimensionId])\nREFERENCES [dbo].[TsDynDataDimension] ([DimensionId])\nGO\nALTER TABLE [dbo].[TsDynDataValueDimension] CHECK CONSTRAINT [FK_TsDynDataValueDimension_TsDynDataDimension]\nGO\nALTER TABLE [dbo].[TsDynDataValueDimension]  WITH CHECK ADD  CONSTRAINT [FK_TsDynDataValueDimension_TsDynDataValue] FOREIGN KEY([ValueId])\nREFERENCES [dbo].[TsDynDataValue] ([ValueId])\nGO\nALTER TABLE [dbo].[TsDynDataValueDimension] CHECK CONSTRAINT [FK_TsDynDataValueDimension_TsDynDataValue]\nGO\nALTER TABLE [dbo].[TsDynDataZone]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionCreated] FOREIGN KEY([TransCreatedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionCreated]\nGO\nALTER TABLE [dbo].[TsDynDataZone]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionDeleted] FOREIGN KEY([TransDeletedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionDeleted]\nGO\nALTER TABLE [dbo].[TsDynDataZone]  WITH NOCHECK ADD  CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionModified] FOREIGN KEY([TransModifiedId])\nREFERENCES [dbo].[TsDynDataTransaction] ([TransactionId])\nGO\nALTER TABLE [dbo].[TsDynDataZone] CHECK CONSTRAINT [FK_TsDynDataZone_TsDynDataTransactionModified]\nGO\n\n\n\n-- Insert rows into __EFMigrationsHistory to mark specific migrations as already applied,\n-- preventing Oqtane from running unnecessary or redundant upgrade migrations.\n-- This install script ensure that database schema 20.00.05 is up-to-date so older migrations\n-- are not required for clean install case.\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.Install')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.Install', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.12.00.00')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.12.00.00', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.12.05.00')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.12.05.00', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.13.00.00')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.13.00.00', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.13.01.00')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.13.01.00', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.15.00.00')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.15.00.00', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.16.07.01')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.16.07.01', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.18.03.00')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.18.03.00', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.19.00.00')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.19.00.00', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.20.00.00')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.20.00.00', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\nIF NOT EXISTS (SELECT 1 FROM __EFMigrationsHistory WHERE MigrationId = 'ToSic.Sxc.20.00.05')\n    INSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion, AppliedDate, AppliedVersion)\n    VALUES ('ToSic.Sxc.20.00.05', '20.00.05', SYSDATETIME(), '6.1.5');\nGO\n\n\n\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Scripts/ToSic.Sxc.Uninstall.sql",
    "content": "-- Remove Tables\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataRelationship]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataValueDimension]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataDimension]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataValue]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataEntity]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataHistory]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataAttribute]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataAttributeType]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataContentType]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataTargetType]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataApp]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataZone]\nGO\n\nDROP TABLE IF EXISTS [dbo].[TsDynDataTransaction]\nGO\n\nDELETE FROM ModuleDefinition WHERE ModuleDefinitionName LIKE 'ToSic.Sxc.Oqt.%, ToSic.Sxc.Oqtane.Client'\nGO\n\nDELETE FROM __EFMigrationsHistory WHERE MigrationId LIKE 'ToSic.Sxc.%'\nGO\n\nDELETE FROM Setting WHERE SettingName IN ('TsDynDataZoneId', 'TsDynDataApp', 'TsDynDataContentGroup', 'TsDynDataPreview', 'EavZone', 'EavApp', 'EavContentGroup', 'EavPreview')\nGO\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/OqtDebugStateService.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\n\nnamespace ToSic.Sxc.Oqt.Server.Services;\n\ninternal class OqtDebugStateService(IHttpContextAccessor httpContextAccessor) : IOqtDebugStateService\n{\n    public bool IsDebugEnabled => (httpContextAccessor?.HttpContext?.Items[DebugKey] as bool?) ?? false;\n\n    async public Task<bool> GetDebugAsync() => IsDebugEnabled;\n\n    public void SetDebug(bool value)\n    {\n        if (httpContextAccessor?.HttpContext != null)\n            httpContextAccessor.HttpContext.Items[DebugKey] = value;\n    }\n\n    private const string DebugKey = \"2sxcDebug\";\n\n    public string Platform => \"Server\";\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/OqtLinkService.cs",
    "content": "﻿using Custom.Hybrid;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Link.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sys.Utils;\nusing Page = Oqtane.Models.Page;\n\nnamespace ToSic.Sxc.Oqt.Server.Services;\n\n/// <summary>\n/// The Oqtane implementation of the <see cref=\"ILinkService\"/>.\n/// </summary>\n[PrivateApi]\ninternal class OqtLinkService(\n    IPageRepository pageRepository,\n    AliasResolver aliasResolver,\n    ImgResizeLinker imgLinker,\n    LazySvc<ILinkPaths> linkPathsLazy)\n    : LinkServiceBase(imgLinker, linkPathsLazy, connect: [pageRepository, aliasResolver])\n{\n    public Razor12 RazorPage { get; set; }\n    private IContextOfBlock _blockCtx;\n\n    private new OqtLinkPaths LinkPaths => (OqtLinkPaths) base.LinkPaths;\n\n    public override void ConnectToRoot(IExecutionContext exCtx)\n    {\n        base.ConnectToRoot(exCtx);\n        _blockCtx = exCtx.GetContextOfBlock();\n    }\n\n    protected override string ToApi(string api, string parameters = null) => ApiNavigateUrl(api, parameters);\n\n    protected override string ToPage(int? pageId, string parameters = null, string language = null) =>\n        PageNavigateUrl(pageId, parameters);\n\n    // Prepare Api link.\n    private string ApiNavigateUrl(string api, string parameters)\n    {\n        var alias = aliasResolver.Alias;\n\n        var pathWithQueryString = CombineApiWithQueryString(\n            LinkPaths.ApiFromSiteRoot(AppFolder, api),\n            parameters);\n\n        var relativePath = string.IsNullOrEmpty(alias.Path)\n            ? pathWithQueryString\n            : $\"/{alias.Path}{pathWithQueryString}\";\n\n        return relativePath;\n    }\n\n    // Prepare Page link.\n    private string PageNavigateUrl(int? pageId, string parameters, bool absoluteUrl = true)\n    {\n        var currentPageId = _blockCtx?.Page?.Id;\n\n        if ((pageId ?? currentPageId) == null)\n            throw new($\"Error, PageId is unknown, pageId: {pageId}, currentPageId: {currentPageId} .\");\n\n        if (pageId.HasValue)\n        {\n            var page = pageRepository.GetPage(pageId.Value, false);\n            if (page != null) return PageUrlBuilder(page, parameters, absoluteUrl);\n        }\n\n        // if pageId is invalid, fallback to currentPageId\n        var currentPage = pageRepository.GetPage(currentPageId.Value, false);\n        var currentPageUrl = PageUrlBuilder(currentPage, parameters, absoluteUrl);\n\n        return CurrentPageUrlWithEventualHashError(pageId, currentPageUrl);\n    }\n\n    private string PageUrlBuilder(Page page, string parameters, bool absoluteUrl)\n    {\n        aliasResolver.InitIfEmpty(page.SiteId);\n        var alias = aliasResolver.Alias \n            ?? throw new($\"Error, Alias is unknown, pageId: {page.PageId}, siteId: {page.SiteId}.\"); \n\n        // for invalid page numbers just skip that part \n        var relativePath =\n            Utilities.NavigateUrl(alias.Path, page?.Path ?? string.Empty, QueryParametersForOqtane(parameters)) // NavigateUrl do not works with absolute links\n            .PrefixSlash(); // fix for Oqt v5.1.0+ NavigateUrl returns relative path without leading slash\n\n        return absoluteUrl ? $\"{LinkPaths.GetCurrentLinkRoot()}{relativePath}\" : relativePath;\n    }\n\n    /// <summary>\n    /// Oqtane Utilities.NavigateUrl and Utilities.ParseParameters\n    /// expects queryParameters that starts with '?' so we need to add it.\n    /// This is to ensure that that oqtane will work with / in query string,\n    /// or oqtane will recognize it as special oqtane UrlParameters\n    /// that starts with /!/ separator in page route part of url and\n    /// that is currently not expected in 2sxc apps.\n    /// </summary>\n    /// <param name=\"queryParameters\"></param>\n    /// <returns>query params that starts with ?</returns>\n    private static string QueryParametersForOqtane(string queryParameters) \n        => string.IsNullOrEmpty(queryParameters) ? string.Empty : $\"?{queryParameters?.TrimStart('?')}\";\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/OqtLogService.cs",
    "content": "﻿using Oqtane.Enums;\nusing Oqtane.Infrastructure;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Oqt.Server.Services;\n\ninternal class OqtSystemLogService(ILogManager logManager) : ISystemLogService\n{\n    public void Add(string title, string message)\n    {\n        logManager.Log(LogLevel.Information, title, LogFunction.Other, message);\n    }\n}\n\n// TODO: WIP, need to enhance Logging in Oqtane using LogManager, but find better method (like prefill new Log())\n// because \"Title\" is not stored log as expected \n\n//public class SxcAppEventLogHost\n//{\n//    public SxcAppEventLogHost(string title)\n//    {\n//        Title = title;\n//    }\n\n//    public string Title { get; }\n\n//    public override string? ToString()\n//    {\n//        return Title;\n//    }\n//}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/OqtMailService.cs",
    "content": "﻿using Oqtane.Repository;\nusing Oqtane.Shared;\nusing System.Configuration;\nusing System.Net;\nusing System.Net.Mail;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Services.Mail.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Oqt.Server.Services;\n\ninternal class OqtMailService(LazySvc<ISettingRepository> settingRepositoryLazy, LazySvc<IUser> userLazy)\n    : MailServiceBase(userLazy, connect: [settingRepositoryLazy])\n{\n    protected override SmtpClient SmtpClient()\n    {\n        var settings = GetSettings();\n        if (!settings.ContainsKey(\"SMTPHost\") || settings[\"SMTPHost\"] == \"\" \n                                              || !settings.ContainsKey(\"SMTPPort\") || settings[\"SMTPPort\"] == \"\" \n                                              || !settings.ContainsKey(\"SMTPSSL\") || settings[\"SMTPSSL\"] == \"\" \n                                              || !settings.ContainsKey(\"SMTPSender\") || settings[\"SMTPSender\"] == \"\") \n            throw new ConfigurationErrorsException(\"SMTP configuration problem. Some settings are missing. Please configure 'SMTP Settings' in 'Site Settings'.\");\n\n        try\n        {\n            // construct SMTP Client\n            var client = new SmtpClient\n            {\n                DeliveryMethod = SmtpDeliveryMethod.Network,\n                UseDefaultCredentials = false,\n                Host = settings[\"SMTPHost\"],\n                Port = int.Parse(settings[\"SMTPPort\"]),\n                EnableSsl = bool.Parse(settings[\"SMTPSSL\"])\n            };\n\n            if (settings[\"SMTPUsername\"] != \"\" && settings[\"SMTPPassword\"] != \"\")\n            {\n                client.Credentials = new NetworkCredential(settings[\"SMTPUsername\"], settings[\"SMTPPassword\"]);\n            }\n\n            return client;\n        }\n        catch (Exception ex)\n        {\n            throw new ConfigurationErrorsException(\"SMTP configuration problem.\", ex);\n        }\n    }\n\n    private Dictionary<string, string> GetSettings()\n    {\n        var site = ExCtx.GetContextOfBlock().Site;\n        var settings = settingRepositoryLazy.Value\n            .GetSettings(EntityNames.Site, site.Id)\n            .ToList();\n        return settings\n            .OrderBy(item => item.SettingName)\n            .ToList()\n            .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/OqtPageChangesOnServerService.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Oqt.Server.Services;\n\ninternal class OqtPageChangesOnServerService(\n    IHttpContextAccessor httpContextAccessor,\n    LazySvc<IFeaturesService> featuresService,\n    Generator<CspOfPage> cspOfPage)\n    : ServiceBase($\"{SxcLogging.SxcLogName}.OqtPgChService\",\n        connect: [httpContextAccessor, featuresService, cspOfPage]), IOqtPageChangesOnServerService\n{\n    public int ApplyHttpHeaders(OqtViewResultsDto result, IOqtHybridLog page)\n    {\n        var logPrefix = $\"{nameof(ApplyHttpHeaders)}(...) - \";\n\n        #region initial request and parameters validation\n        page?.Log($\"{logPrefix}validate parameters\");\n\n        if (httpContextAccessor?.HttpContext == null)\n        {\n            page?.Log($\"{logPrefix}missing http context\");\n            return -1;\n        }\n\n        if (httpContextAccessor.HttpContext.Request?.Path.HasValue != true)\n        {\n            page?.Log($\"{logPrefix}not a page because no path, so no headers\");\n            return -1;\n        }\n\n        if (httpContextAccessor.HttpContext.Request.Path.Value!.Contains(\"/_blazor\"))\n        {\n            page?.Log($\"{logPrefix}no headers for blazor\");\n            return -1;\n        }\n\n        if (!(result?.CspParameters?.Any() ?? false))\n        {\n            page?.Log($\"{logPrefix}no headers if there are no CSP parameters\");\n            return -1;\n        }\n        #endregion\n\n        // Register CSP changes for applying once all modules have been prepared\n        // Note that in cached scenarios, CspEnabled is true, but it may have been turned off since\n        if (result!.CspEnabled && featuresService.Value.IsEnabled(\"ContentSecurityPolicy\" /*BuiltInFeatures.ContentSecurityPolicy.NameId*/))\n        {\n            page?.Log($\"{logPrefix}Register CSP changes\");\n            PageCsp(result.CspEnforced, page).Add(result.CspParameters.Select(p => new CspParameters(UrlHelpers.ParseQueryString(p))).ToList());\n        }\n\n        #region response and headers validation\n        if (httpContextAccessor.HttpContext.Response.HasStarted)\n        {\n            page?.Log($\"{logPrefix}error, to late for adding http headers\");\n            return 0;\n        }\n\n        var httpHeaders = result.HttpHeaders;\n        if (httpHeaders?.Any() == true)\n        {\n            page?.Log($\"{logPrefix}ok, no headers to add\");\n            return 0;\n        } \n        #endregion\n\n        // Register event to attach headers\n        httpContextAccessor.HttpContext.Response.OnStarting(() =>\n        {\n            try\n            {\n                foreach (var httpHeader in httpHeaders!)\n                {\n                    if (string.IsNullOrWhiteSpace(httpHeader.Name)) continue;\n\n                    // TODO: The CSP header can only exist once\n                    // So to do this well, we'll need to merge them in future, \n                    // Ideally combining the existing one with any additional ones added here\n                    httpContextAccessor.HttpContext.Response.Headers[httpHeader.Name] = httpHeader.Value;\n                    page?.Log($\"{logPrefix}{httpHeader.Name}={httpHeader.Value}\");\n                }\n            }\n            catch (Exception e)\n            {\n                page?.Log($\"{logPrefix}Exception: {e.Message}\");\n            }\n\n            return Task.CompletedTask;\n        });\n\n        page?.Log($\"{logPrefix}httpHeaders.Count: {httpHeaders!.Count}\");\n        return httpHeaders!.Count;\n    }\n\n    private CspOfPage PageCsp(bool enforced, IOqtHybridLog page)\n    {\n        var logPrefix = $\"{nameof(PageCsp)}(enforced:{enforced}) - \";\n\n        var key = \"2sxcPageLevelCsp\";\n\n        // If it's already registered, then the add-on-sending has already been added too\n        // So we shouldn't repeat it, just return the cache which will be used later\n        if (httpContextAccessor.HttpContext!.Items.ContainsKey(key))\n        {\n            var result = (CspOfPage)httpContextAccessor.HttpContext.Items[key];\n            page?.Log($\"already registered {logPrefix}{key}={result}\");\n            return result;\n        }\n\n        // Not yet registered. Create, and register for on-end of request\n        var pageLevelCsp = cspOfPage.New();\n        httpContextAccessor.HttpContext.Items[key] = pageLevelCsp;\n\n        // Register event to attach headers once the request is done and all Apps have registered their Csp\n        if (!httpContextAccessor.HttpContext.Response.HasStarted)\n            httpContextAccessor.HttpContext.Response.OnStarting(() =>\n            {\n                try\n                {\n                    var headers = pageLevelCsp.CspHttpHeader();\n                    if (headers != null)\n                    {\n                        var key = pageLevelCsp.HeaderName(enforced);\n                        httpContextAccessor.HttpContext.Response.Headers[key] = headers;\n                        page?.Log($\"{logPrefix}have headers {key}={headers}\");\n                    }\n\n                }\n                catch (Exception e)\n                {\n                    page?.Log($\"{logPrefix}Exception: {e.Message}\");\n                }\n\n                return Task.CompletedTask;\n            });\n        page?.Log($\"not yet registered {logPrefix}{key}={pageLevelCsp}\");\n        return pageLevelCsp;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/OqtPrerenderService.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\nusing HtmlHelper = ToSic.Sxc.Oqt.Shared.Helpers.HtmlHelper;\n\nnamespace ToSic.Sxc.Oqt.Server.Services;\n\ninternal class OqtPrerenderService(IHttpContextAccessor httpContextAccessor, IThemeRepository themes)\n    : ServiceBase($\"Oqt.PrerndSrv\"), IOqtPrerenderService\n{\n    public string GetPrerenderHtml(bool isPrerendered, OqtViewResultsDto viewResults, SiteState siteState, string themeType)\n    {\n        try\n        {\n            if (!isPrerendered || !UsePrerender) return string.Empty;\n\n            var prerenderHtmlFragment = string.Empty;\n            prerenderHtmlFragment = HtmlHelper.ManageStyleSheets(prerenderHtmlFragment, viewResults, siteState.Alias, Theme(themeType).Name, Html);\n            prerenderHtmlFragment = HtmlHelper.ManageScripts(prerenderHtmlFragment, viewResults, siteState.Alias, Html);\n            prerenderHtmlFragment = HtmlHelper.ManageInlineScripts(prerenderHtmlFragment, viewResults, siteState.Alias, Html);\n            prerenderHtmlFragment = SystemHtml(prerenderHtmlFragment);\n            Html += prerenderHtmlFragment;\n            return prerenderHtmlFragment;\n        }\n        catch (Exception e)\n        {\n            Log.Ex(e);\n            return string.Empty;\n        }\n    }\n\n    #region Validation\n    public bool UsePrerender => _usePrerender ??= (HasUserAgentSignature() || CheckForKeyInQueryString(\"prerender\"));\n    private bool? _usePrerender;\n\n    private bool HasUserAgentSignature()\n    {\n        var userAgent = httpContextAccessor.HttpContext?.Request.Headers[\"User-Agent\"];\n        return userAgent.HasValue && _userAgentSignatures.Exists(x => userAgent.Value.ToString().Contains(x, StringComparison.InvariantCultureIgnoreCase));\n    }\n\n    public bool CheckForKeyInQueryString(string key)\n    {\n        var queryCollection = httpContextAccessor.HttpContext?.Request.Query;\n        return queryCollection != null && queryCollection.ContainsKey(key);\n    }\n\n    // based on https://raw.githubusercontent.com/monperrus/crawler-user-agents/master/crawler-user-agents.json\n    private readonly List<string> _userAgentSignatures = new() // used for production\n    {\n        // ReSharper disable StringLiteralTypo\n        @\"Googlebot\",\n        @\"AdsBot-Google\",\n        @\"Feedfetcher-Google\",\n        @\"Mediapartners\",\n        @\"APIs-Google\",\n        @\"bingbot\",\n        @\"Slurp\",\n        @\"wget\",\n        @\"LinkedInBot\",\n        @\"Python-urllib\",\n        @\"python-requests\",\n        @\"aiohttp\",\n        @\"httpx\",\n        @\"libwww-perl\",\n        @\"httpunit\",\n        @\"nutch\",\n        @\"Go-http-client\",\n        @\"phpcrawl\",\n        @\"msnbot\",\n        @\"jyxobot\",\n        @\"FAST-WebCrawler\",\n        @\"FAST Enterprise Crawler\",\n        @\"BIGLOTRON\",\n        @\"Teoma\",\n        @\"convera\",\n        @\"seekbot\",\n        @\"Gigabot\",\n        @\"Gigablast\",\n        @\"exabot\",\n        @\"ia_archiver\",\n        @\"GingerCrawler\",\n        @\"webmon\",\n        @\"HTTrack\",\n        @\"grub.org\",\n        @\"UsineNouvelleCrawler\",\n        @\"antibot\",\n        @\"netresearchserver\",\n        @\"speedy\",\n        @\"fluffy\",\n        @\"findlink\",\n        @\"msrbot\",\n        @\"panscient\",\n        @\"yacybot\",\n        @\"AISearchBot\",\n        @\"ips-agent\",\n        @\"tagoobot\",\n        @\"MJ12bot\",\n        @\"woriobot\",\n        @\"yanga\",\n        @\"buzzbot\",\n        @\"mlbot\",\n        @\"YandexBot\",\n        @\"YandexImages\",\n        @\"YandexAccessibilityBot\",\n        @\"YandexMobileBot\",\n        @\"YandexMetrika\",\n        @\"YandexTurbo\",\n        @\"YandexImageResizer\",\n        @\"YandexVideo\",\n        @\"YandexAdNet\",\n        @\"YandexBlogs\",\n        @\"YandexCalendar\",\n        @\"YandexDirect\",\n        @\"YandexFavicons\",\n        @\"YaDirectFetcher\",\n        @\"YandexForDomain\",\n        @\"YandexMarket\",\n        @\"YandexMedia\",\n        @\"YandexMobileScreenShotBot\",\n        @\"YandexNews\",\n        @\"YandexOntoDB\",\n        @\"YandexPagechecker\",\n        @\"YandexPartner\",\n        @\"YandexRCA\",\n        @\"YandexSearchShop\",\n        @\"YandexSitelinks\",\n        @\"YandexSpravBot\",\n        @\"YandexTracker\",\n        @\"YandexVertis\",\n        @\"YandexVerticals\",\n        @\"YandexWebmaster\",\n        @\"YandexScreenshotBot\",\n        @\"purebot\",\n        @\"Linguee Bot\",\n        @\"CyberPatrol\",\n        @\"voilabot\",\n        @\"Baiduspider\",\n        @\"citeseerxbot\",\n        @\"spbot\",\n        @\"twengabot\",\n        @\"postrank\",\n        @\"TurnitinBot\",\n        @\"scribdbot\",\n        @\"page2rss\",\n        @\"sitebot\",\n        @\"linkdex\",\n        @\"Adidxbot\",\n        @\"ezooms\",\n        @\"dotbot\",\n        @\"Mail.RU_Bot\",\n        @\"discobot\",\n        @\"heritrix\",\n        @\"findthatfile\",\n        @\"europarchive.org\",\n        @\"NerdByNature.Bot\",\n        @\"sistrix crawler\",\n        @\"Ahrefs\",\n        @\"fuelbot\",\n        @\"CrunchBot\",\n        @\"IndeedBot\",\n        @\"mappydata\",\n        @\"woobot\",\n        @\"ZoominfoBot\",\n        @\"PrivacyAwareBot\",\n        @\"Multiviewbot\",\n        @\"SWIMGBot\",\n        @\"Grobbot\",\n        @\"eright\",\n        @\"Apercite\",\n        @\"semanticbot\",\n        @\"Aboundex\",\n        @\"domaincrawler\",\n        @\"wbsearchbot\",\n        @\"summify\",\n        @\"CCBot\",\n        @\"edisterbot\",\n        @\"seznambot\",\n        @\"ec2linkfinder\",\n        @\"gslfbot\",\n        @\"aiHitBot\",\n        @\"intelium_bot\",\n        @\"facebookexternalhit\",\n        @\"Yeti\",\n        @\"RetrevoPageAnalyzer\",\n        @\"lb-spider\",\n        @\"Sogou\",\n        @\"lssbot\",\n        @\"careerbot\",\n        @\"wotbox\",\n        @\"wocbot\",\n        @\"ichiro\",\n        @\"DuckDuckBot\",\n        @\"lssrocketcrawler\",\n        @\"drupact\",\n        @\"webcompanycrawler\",\n        @\"acoonbot\",\n        @\"openindexspider\",\n        @\"gnam gnam spider\",\n        @\"web-archive-net.com.bot\",\n        @\"backlinkcrawler\",\n        @\"coccoc\",\n        @\"integromedb\",\n        @\"content crawler spider\",\n        @\"toplistbot\",\n        @\"it2media-domain-crawler\",\n        @\"ip-web-crawler.com\",\n        @\"siteexplorer.info\",\n        @\"elisabot\",\n        @\"proximic\",\n        @\"changedetection\",\n        @\"arabot\",\n        @\"WeSEE:Search\",\n        @\"niki-bot\",\n        @\"CrystalSemanticsBot\",\n        @\"rogerbot\",\n        @\"360Spider\",\n        @\"psbot\",\n        @\"InterfaxScanBot\",\n        @\"CC Metadata Scaper\",\n        @\"g00g1e.net\",\n        @\"GrapeshotCrawler\",\n        @\"urlappendbot\",\n        @\"brainobot\",\n        @\"fr-crawler\",\n        @\"binlar\",\n        @\"SimpleCrawler\",\n        @\"Twitterbot\",\n        @\"cXensebot\",\n        @\"smtbot\",\n        @\"bnf.fr_bot\",\n        @\"A6-Indexer\",\n        @\"ADmantX\",\n        @\"Facebot\",\n        @\"OrangeBot\",\n        @\"memorybot\",\n        @\"AdvBot\",\n        @\"MegaIndex\",\n        @\"SemanticScholarBot\",\n        @\"ltx71\",\n        @\"nerdybot\",\n        @\"xovibot\",\n        @\"BUbiNG\",\n        @\"Qwantify\",\n        @\"archive.org_bot\",\n        @\"Applebot\",\n        @\"TweetmemeBot\",\n        @\"crawler4j\",\n        @\"findxbot\",\n        @\"SemrushBot\",\n        @\"yoozBot\",\n        @\"lipperhey\",\n        @\"Y!J\",\n        @\"Domain Re-Animator Bot\",\n        @\"AddThis\",\n        @\"Screaming Frog SEO Spider\",\n        @\"MetaURI\",\n        @\"Scrapy\",\n        @\"Livelapbot\",\n        @\"OpenHoseBot\",\n        @\"CapsuleChecker\",\n        @\"collection@infegy.com\",\n        @\"IstellaBot\",\n        @\"DeuSu\",\n        @\"betaBot\",\n        @\"Cliqzbot\",\n        @\"MojeekBot\",\n        @\"netEstate NE Crawler\",\n        @\"SafeSearch microdata crawler\",\n        @\"Gluten Free Crawler\",\n        @\"Sonic\",\n        @\"Sysomos\",\n        @\"Trove\",\n        @\"deadlinkchecker\",\n        @\"Slack-ImgProxy\",\n        @\"Embedly\",\n        @\"RankActiveLinkBot\",\n        @\"iskanie\",\n        @\"SafeDNSBot\",\n        @\"SkypeUriPreview\",\n        @\"Veoozbot\",\n        @\"Slackbot\",\n        @\"redditbot\",\n        @\"datagnionbot\",\n        @\"Google-Adwords-Instant\",\n        @\"adbeat_bot\",\n        @\"WhatsApp\",\n        @\"contxbot\",\n        @\"pinterest.com.bot\",\n        @\"electricmonk\",\n        @\"GarlikCrawler\",\n        @\"BingPreview\",\n        @\"vebidoobot\",\n        @\"FemtosearchBot\",\n        @\"Yahoo Link Preview\",\n        @\"MetaJobBot\",\n        @\"DomainStatsBot\",\n        @\"mindUpBot\",\n        @\"Daum\",\n        @\"Jugendschutzprogramm-Crawler\",\n        @\"Xenu Link Sleuth\",\n        @\"Pcore-HTTP\",\n        @\"moatbot\",\n        @\"KosmioBot\",\n        @\"pingdom\",\n        @\"AppInsights\",\n        @\"PhantomJS\",\n        @\"Gowikibot\",\n        @\"PiplBot\",\n        @\"Discordbot\",\n        @\"TelegramBot\",\n        @\"Jetslide\",\n        @\"newsharecounts\",\n        @\"James BOT\",\n        @\"Barkrowler\",\n        @\"TinEye\",\n        @\"SocialRankIOBot\",\n        @\"trendictionbot\",\n        @\"Ocarinabot\",\n        @\"epicbot\",\n        @\"Primalbot\",\n        @\"DuckDuckGo-Favicons-Bot\",\n        @\"GnowitNewsbot\",\n        @\"Leikibot\",\n        @\"LinkArchiver\",\n        @\"YaK\",\n        @\"PaperLiBot\",\n        @\"Digg Deeper\",\n        @\"dcrawl\",\n        @\"Snacktory\",\n        @\"AndersPinkBot\",\n        @\"Fyrebot\",\n        @\"EveryoneSocialBot\",\n        @\"Mediatoolkitbot\",\n        @\"Luminator-robots\",\n        @\"ExtLinksBot\",\n        @\"SurveyBot\",\n        @\"NING\",\n        @\"okhttp\",\n        @\"Nuzzel\",\n        @\"omgili\",\n        @\"PocketParser\",\n        @\"YisouSpider\",\n        @\"um-LN\",\n        @\"ToutiaoSpider\",\n        @\"MuckRack\",\n        @\"Jamie's Spider\",\n        @\"AHC\",\n        @\"NetcraftSurveyAgent\",\n        @\"Laserlikebot\",\n        @\"Apache-HttpClient\",\n        @\"AppEngine-Google\",\n        @\"Jetty\",\n        @\"Upflow\",\n        @\"Thinklab\",\n        @\"Traackr.com\",\n        @\"Twurly\",\n        @\"Mastodon\",\n        @\"http_get\",\n        @\"DnyzBot\",\n        @\"botify\",\n        @\"007ac9 Crawler\",\n        @\"BehloolBot\",\n        @\"BrandVerity\",\n        @\"check_http\",\n        @\"BDCbot\",\n        @\"ZumBot\",\n        @\"EZID\",\n        @\"ICC-Crawler\",\n        @\"ArchiveBot\",\n        @\"LCC\",\n        @\"filterdb.iss.netcrawler\",\n        @\"BLP_bbot\",\n        @\"BomboraBot\",\n        @\"Buck\",\n        @\"Companybook-Crawler\",\n        @\"Genieo\",\n        @\"magpie-crawler\",\n        @\"MeltwaterNews\",\n        @\"Moreover\",\n        @\"newspaper\",\n        @\"ScoutJet\",\n        @\"sentry\",\n        @\"StorygizeBot\",\n        @\"UptimeRobot\",\n        @\"OutclicksBot\",\n        @\"seoscanners\",\n        @\"Hatena\",\n        @\"Google Web Preview\",\n        @\"MauiBot\",\n        @\"AlphaBot\",\n        @\"SBL-BOT\",\n        @\"IAS crawler\",\n        @\"adscanner\",\n        @\"Netvibes\",\n        @\"acapbot\",\n        @\"Baidu-YunGuanCe\",\n        @\"bitlybot\",\n        @\"blogmuraBot\",\n        @\"Bot.AraTurka.com\",\n        @\"bot-pge.chlooe.com\",\n        @\"BoxcarBot\",\n        @\"BTWebClient\",\n        @\"ContextAd Bot\",\n        @\"Digincore bot\",\n        @\"Disqus\",\n        @\"Feedly\",\n        @\"Fetch\",\n        @\"Fever\",\n        @\"Flamingo_SearchEngine\",\n        @\"FlipboardProxy\",\n        @\"g2reader-bot\",\n        @\"G2 Web Services\",\n        @\"imrbot\",\n        @\"K7MLWCBot\",\n        @\"Kemvibot\",\n        @\"Landau-Media-Spider\",\n        @\"linkapediabot\",\n        @\"vkShare\",\n        @\"Siteimprove.com\",\n        @\"BLEXBot\",\n        @\"DareBoost\",\n        @\"ZuperlistBot\",\n        @\"Miniflux\",\n        @\"Feedspot\",\n        @\"Diffbot\",\n        @\"SEOkicks\",\n        @\"tracemyfile\",\n        @\"Nimbostratus-Bot\",\n        @\"zgrab\",\n        @\"PR-CY.RU\",\n        @\"AdsTxtCrawler\",\n        @\"Datafeedwatch\",\n        @\"Zabbix\",\n        @\"TangibleeBot\",\n        @\"google-xrawler\",\n        @\"axios\",\n        @\"Amazon CloudFront\",\n        @\"Pulsepoint\",\n        @\"CloudFlare-AlwaysOnline\",\n        @\"Google-Structured-Data-Testing-Tool\",\n        @\"WordupInfoSearch\",\n        @\"WebDataStats\",\n        @\"HttpUrlConnection\",\n        @\"Seekport Crawler\",\n        @\"ZoomBot\",\n        @\"VelenPublicWebCrawler\",\n        @\"MoodleBot\",\n        @\"jpg-newsbot\",\n        @\"outbrain\",\n        @\"W3C_Validator\",\n        @\"Validator.nu\",\n        @\"W3C-checklink\",\n        @\"W3C-mobileOK\",\n        @\"W3C_I18n-Checker\",\n        @\"FeedValidator\",\n        @\"W3C_CSS_Validator\",\n        @\"W3C_Unicorn\",\n        @\"Google-PhysicalWeb\",\n        @\"Blackboard\",\n        @\"ICBot\",\n        @\"BazQux\",\n        @\"Twingly\",\n        @\"Rivva\",\n        @\"Experibot\",\n        @\"awesomecrawler\",\n        @\"Dataprovider.com\",\n        @\"GroupHigh\",\n        @\"theoldreader.com\",\n        @\"AnyEvent\",\n        @\"Uptimebot.org\",\n        @\"Nmap Scripting Engine\",\n        @\"2ip.ru\",\n        @\"Clickagy\",\n        @\"Caliperbot\",\n        @\"MBCrawler\",\n        @\"online-webceo-bot\",\n        @\"B2B Bot\",\n        @\"AddSearchBot\",\n        @\"Google Favicon\",\n        @\"HubSpot\",\n        @\"Chrome-Lighthouse\",\n        @\"HeadlessChrome\",\n        @\"CheckMarkNetwork\",\n        @\"www.uptime.com\",\n        @\"Streamline3Bot\",\n        @\"serpstatbot\",\n        @\"MixnodeCache\",\n        @\"curl\",\n        @\"SimpleScraper\",\n        @\"RSSingBot\",\n        @\"Jooblebot\",\n        @\"fedoraplanet\",\n        @\"Friendica\",\n        @\"NextCloud\",\n        @\"Tiny Tiny RSS\",\n        @\"RegionStuttgartBot\",\n        @\"Bytespider\",\n        @\"Datanyze\",\n        @\"Google-Site-Verification\",\n        @\"TrendsmapResolver\",\n        @\"tweetedtimes\",\n        @\"NTENTbot\",\n        @\"Gwene\",\n        @\"SimplePie\",\n        @\"SearchAtlas\",\n        @\"Superfeedr\",\n        @\"feedbot\",\n        @\"UT-Dorkbot\",\n        @\"Amazonbot\",\n        @\"SerendeputyBot\",\n        @\"Eyeotabot\",\n        @\"officestorebot\",\n        @\"Neticle Crawler\",\n        @\"SurdotlyBot\",\n        @\"LinkisBot\",\n        @\"AwarioSmartBot\",\n        @\"AwarioRssBot\",\n        @\"RyteBot\",\n        @\"FreeWebMonitoring SiteChecker\",\n        @\"AspiegelBot\",\n        @\"NAVER Blog Rssbot\",\n        @\"zenback bot\",\n        @\"SentiBot\",\n        @\"Domains Project\",\n        @\"Pandalytics\",\n        @\"VKRobot\",\n        @\"bidswitchbot\",\n        @\"tigerbot\",\n        @\"NIXStatsbot\",\n        @\"Atom Feed Robot\",\n        @\"Curebot\",\n        @\"PagePeeker\",\n        @\"Vigil\",\n        @\"rssbot\",\n        @\"startmebot\",\n        @\"JobboerseBot\",\n        @\"seewithkids\",\n        @\"NINJA bot\",\n        @\"Cutbot\",\n        @\"BublupBot\",\n        @\"BrandONbot\",\n        @\"RidderBot\",\n        @\"Taboolabot\",\n        @\"Dubbotbot\",\n        @\"FindITAnswersbot\",\n        @\"infoobot\",\n        @\"Refindbot\",\n        @\"BlogTraffic\",\n        @\"SeobilityBot\",\n        @\"Cincraw\",\n        @\"Dragonbot\",\n        @\"VoluumDSP-content-bot\",\n        @\"FreshRSS\",\n        @\"BitBot\",\n        @\"PHP-Curl-Class\",\n        @\"Google-Certificates-Bridge\",\n        @\"centurybot\",\n        @\"Viber\",\n        @\"e.ventures Investment Crawler\",\n        @\"evc-batch\",\n        @\"PetalBot\",\n        @\"virustotal\",\n        @\"PTST\",\n        @\"minicrawler\",\n        // ReSharper restore StringLiteralTypo\n    }; \n    #endregion\n\n    #region Theme\n    private Theme Theme(string themeType) => _theme ??= themes.GetThemes().FirstOrDefault(item => item.Themes.Any(item => item.TypeName == themeType));\n    private Theme _theme;\n\n    #endregion\n\n    #region SystemHtml\n    private string SystemHtml(string html)\n    {\n        if (Executed) return html;\n        var systemHtml =\n            $\"<style> {(OqtaneVersion >= new Version(3, 0, 2) ? \"body\" : \"app\")} > div:first-of-type {{ display: block !important }} </style>\";\n        if (!html.Contains(systemHtml, StringComparison.OrdinalIgnoreCase) && !Html.Contains(systemHtml, StringComparison.OrdinalIgnoreCase))\n            html += systemHtml + Environment.NewLine;\n        Executed = true;\n        return html;\n    }\n\n    private Version OqtaneVersion => _oqtaneVersion ??= GetOqtaneVersion();\n    private Version _oqtaneVersion;\n\n    private static Version GetOqtaneVersion()\n        => Version.TryParse(Oqtane.Shared.Constants.Version, out var ver) ? ver : new Version(1, 0);\n\n    private bool Executed // for execution once per request\n    {\n        get => (httpContextAccessor?.HttpContext?.Items[ExecutedKey] as bool?) ?? false;\n        set\n        {\n            if (httpContextAccessor?.HttpContext != null)\n                httpContextAccessor.HttpContext.Items[ExecutedKey] = value;\n        }\n    }\n    private const string ExecutedKey = \"PrerenderServiceExecuted\";\n    #endregion\n\n    #region Html\n    private string Html // for execution once per request\n    {\n        get => (httpContextAccessor?.HttpContext?.Items[PrerenderHtmlFragmentKey] as string) ?? string.Empty;\n        set\n        {\n            if (httpContextAccessor?.HttpContext != null)\n                httpContextAccessor.HttpContext.Items[PrerenderHtmlFragmentKey] = value;\n        }\n    }\n    private const string PrerenderHtmlFragmentKey = \"PrerenderHtmlFragment\"; \n    #endregion\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/OqtSxcRenderService.cs",
    "content": "using Microsoft.AspNetCore.Http;\nusing Oqtane.Enums;\nusing Oqtane.Infrastructure;\nusing Oqtane.Repository;\nusing Oqtane.Security;\nusing Oqtane.Shared;\nusing System.Globalization;\nusing Oqtane.Services;\nusing ToSic.Sxc.Oqt.Server.Blocks;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Shared.Helpers;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Server.Services;\n\npublic class OqtSxcRenderService(\n    IHttpContextAccessor accessor,\n    Generator<IOqtSxcViewBuilder> oqtSxcViewBuilder,\n    AliasResolver aliasResolver,\n    ISiteService sites,\n    IPageRepository pages,\n    IModuleRepository modules,\n    IModuleDefinitionRepository definitions,\n    ISettingRepository settings,\n    IUserPermissions userPermissions,\n    ILogManager logger) : IOqtSxcRenderService\n{\n    public Task<OqtViewResultsDto> RenderAsync(RenderParameters @params) => Task.FromResult(Render(@params));\n\n    public OqtViewResultsDto Render(RenderParameters @params)\n    {\n        try\n        {\n            var alias = aliasResolver.GetAndStoreAlias(@params.AliasId);\n            if (alias == null)\n                return Forbidden(\"Unauthorized Alias Get Attempt {AliasId}\", @params.AliasId);\n\n            // Set User culture\n            if (@params.Culture != CultureInfo.CurrentUICulture.Name) OqtCulture.SetCulture(@params.Culture);\n\n            var site = sites.GetSiteAsync(alias.SiteId).GetAwaiter().GetResult();\n            if (site == null)\n                return Forbidden(\"Unauthorized Site Get Attempt {SiteId}\", alias.SiteId);\n\n            var page = pages.GetPage(@params.PageId);\n            if (page == null || page.SiteId != alias.SiteId || !userPermissions.IsAuthorized(accessor?.HttpContext?.User, alias.SiteId, EntityNames.Page, @params.PageId, PermissionNames.View))\n                return Forbidden(\"Unauthorized Page Get Attempt {pageId}\", @params.PageId);\n\n            var module = modules.GetModule(@params.ModuleId);\n            if (module == null || module.SiteId != alias.SiteId || !userPermissions.IsAuthorized(accessor?.HttpContext?.User, \"View\", module.PermissionList)) \n                return Forbidden(\"Unauthorized Module Get Attempt {ModuleId}\", @params.ModuleId);\n\n            var moduleDefinitions = definitions.GetModuleDefinitions(module.SiteId).ToList();\n            module.ModuleDefinition = moduleDefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);\n\n            module.Settings = settings.GetSettings(EntityNames.Module, @params.ModuleId).ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);\n\n            return oqtSxcViewBuilder.New().Render(alias, site, page, module, @params.PreRender);\n        }\n        catch (Exception ex)\n        {\n            return Error(ex);\n        }\n    }\n\n    private OqtViewResultsDto Forbidden(string message, params object[] args)\n    {\n        logger.Log(LogLevel.Error, this, LogFunction.Security, message, args);\n        //if (accessor?.HttpContext != null) \n        //    accessor.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;\n        return null;\n    }\n\n    private OqtViewResultsDto Error(Exception ex)\n    {\n        logger.Log(LogLevel.Error, this, LogFunction.Read, ex, $\"exception in {nameof(Render)}\");\n        return new() { \n            ErrorMessage = ErrorHelper.ErrorMessage(ex, IsSuperUser)\n        };\n    }\n\n    private bool IsSuperUser => \n        (accessor?.HttpContext?.User.IsInRole(RoleNames.Host) ?? false)\n        || (accessor?.HttpContext?.User.IsInRole(RoleNames.Admin) ?? false);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/OqtTurnOnService.cs",
    "content": "﻿using System.Text;\nusing ToSic.Oqt.Coding;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Oqt.Server.Services;\n\ninternal class OqtTurnOnService(LazySvc<IHtmlTagsService> htmlTagsService) : TurnOnService(htmlTagsService), IOqtTurnOnService\n{\n    protected override string TagName => base.TagName + GenerateRandomHtmlTag();\n\n    // ReSharper disable once StringLiteralTypo\n    private static readonly char[] Characters = \"abcdefghijklmnopqrstuvwxyz\".ToCharArray();\n\n    private static readonly Random Random = new();\n\n    private static string GenerateRandomHtmlTag()\n    {\n        var tagLength = Random.Next(7, 14); // Length of the tag name between 7 and 14 characters\n        var tagBuilder = new StringBuilder(tagLength);\n\n        for (var i = 0; i < tagLength; i++)\n            tagBuilder.Append(Characters[Random.Next(Characters.Length)]);\n\n        return tagBuilder.ToString();\n    }\n\n    public string Run(object runOrSpecs, NoParamOrderOqtane noParamOrder = default, object require = null, object data = null,\n        IEnumerable<object> args = default, string addContext = default) =>\n        base.Run(runOrSpecs, require: require, data: data, args: args, addContext: addContext).ToString();\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/Services/RenderInfoService.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\n\nnamespace ToSic.Sxc.Oqt.Server.Services\n{\n    /// <inheritdoc />\n    public class RenderInfoService(IHttpContextAccessor httpContextAccessor) : IRenderInfoService\n    {\n        private readonly List<string> _enhancedNavValues = [\"allow\", \"on\"];\n        private const string BlazorEnhancedNav = \"blazor-enhanced-nav\";\n        private const string SsrFraming = \"ssr-framing\";\n\n        /// <inheritdoc />\n        public bool IsStaticSsr(string renderMode = RenderModes.Interactive)\n          => string.Equals($\"{renderMode}\", RenderModes.Static, StringComparison.OrdinalIgnoreCase);\n\n        /// <inheritdoc />\n        public bool IsBlazorEnhancedNav(string renderMode)\n        {\n            if (!IsStaticSsr(renderMode))\n                return false;\n\n            var context = httpContextAccessor.HttpContext;\n            if (context != null && context.Response.Headers.TryGetValue(BlazorEnhancedNav, out var enhancedNav))\n                return _enhancedNavValues.Contains($\"{enhancedNav}\", StringComparer.OrdinalIgnoreCase);\n\n            return false;\n        }\n\n        /// <inheritdoc />\n        public bool IsSsrFraming(string renderMode)\n        {\n            if (!IsBlazorEnhancedNav(renderMode))\n                return false;\n\n            var context = httpContextAccessor.HttpContext;\n            return context != null && context.Response.Headers.TryGetValue(SsrFraming, out _);\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Oqt.Server.Controllers;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\ninternal static partial class OqtRegisterServices\n{\n    public static IServiceCollection AddSxcOqtane(this IServiceCollection services)\n    {\n        services\n            .AddOqtanePlumbing()                        // Helpers to make State work etc.\n            .AddSxcOqtPathsAndPlatform()                // Paths and PlatformInfo\n            .AddOqtGlobalConfiguration()                // Global config override (per-tenant ConnectionString)\n            .AddSxcOqtContext()                         // Context objects like ISite etc.\n            .AddSxcOqtAppPermissionsAndImportExport()   // App stuff\n            .AddOqtaneLookUpsAndSources()               // Lookups / LookUp Engine\n            .AddSxcOqtIntegratedServices()              // Oqtane Integration like Logging & Send-Mail\n            .AddOqtaneInstallation()                    // Installation-complete checks and similar\n            .AddOqtaneBlazorWebAssemblySupport()        // Oqtane client Blazor WebAssembly support on Oqtane server\n            .AddOqtaneApiPlumbingAndHelpers()           // Things to make Oqtane APIs work\n            .AddSxcOqtApiParts()                        // Overrides etc. for Sxc Objects in the APIs\n            .AddSxcOqtDynCodeAndViews()                 // Stuff so the Dyn-Code and views work\n            .AddSxcOqtModule()                          // Module capabilities\n            .AddSxcOqtLookUps()\n            .AddRazorDependencies()                     // Razor functionality\n            .AddSxcOqtAdam()                            // Adam\n            ;\n\n        services.TryAddTransient<IUiContextBuilder, OqtUiContextBuilder>();\n\n        return services;\n    }\n        \n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices_App.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.ImportExport.Integration;\n\nusing ToSic.Eav.ImportExport.Sys.XmlExport;\nusing ToSic.Sxc.Adam.Sys.FileSystem;\nusing ToSic.Sxc.Adam.Sys.Paths;\nusing ToSic.Sxc.Oqt.Server.Adam;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\ninternal static partial class OqtRegisterServices\n{\n\n\n    private static IServiceCollection AddOqtaneLookUpsAndSources(this IServiceCollection services)\n    {\n        // 2023-11-28 This looks faulty - they are already registered as ILookup elsewhere\n        //services.TryAddTransient<OqtSiteLookUp>();\n        //services.TryAddTransient<OqtPageLookUp>();\n        //services.TryAddTransient<OqtModuleLookUp>();\n        //services.TryAddScoped<OqtUserLookUp>();\n\n        // New v15 for better DI/Logging\n        services.TryAddTransient<OqtAssetsFileHelper>();\n        return services;\n    }\n        \n\n    private static IServiceCollection AddSxcOqtAdam(this IServiceCollection services)\n    {\n        // ADAM stuff\n        services.TryAddTransient<IAdamPaths, OqtAdamPaths>();\n        services.TryAddTransient<IAdamFileSystem, OqtAdamFileSystem>();\n        return services;\n    }\n\n    private static IServiceCollection AddSxcOqtAppPermissionsAndImportExport(this IServiceCollection services)\n    {\n        // Permissions\n        //services.TryAddTransient<AppPermissionCheck, OqtPermissionCheck>();\n        services.TryAddTransient<IEnvironmentPermission, OqtEnvironmentPermission>();\n\n        // Import / Export\n        services.TryAddTransient<XmlExporter, OqtXmlExporter>();\n        services.TryAddTransient<IImportExportEnvironment, OqtImportExportEnvironment>();\n\n        return services;\n    }\n        \n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices_AppApi.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Oqt.Server.Code.Sys;\nusing ToSic.Sxc.Oqt.Server.Controllers.AppApi;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\n// ReSharper disable once InconsistentNaming\npartial class OqtRegisterServices\n{\n    public static IServiceCollection AddOqtAppWebApi(this IServiceCollection services)\n    {\n        // App WebApi: .net specific code compiler\n        services.TryAddTransient<CodeCompiler, CodeCompilerNetCore>();\n        services.TryAddTransient<IClassCompiler, CodeCompilerNetCore>();\n        services.TryAddTransient<AppCodeCompiler, AppCodeCompilerNetCore>();\n\n        // Shared assembly disk cache infrastructure (for both Razor and AppCode)\n        services.TryAddTransient<AssemblyDiskCache>();\n\n        services.AddSingleton<IActionDescriptorChangeProvider>(AppApiActionDescriptorChangeProvider.Instance);\n        services.AddSingleton(AppApiActionDescriptorChangeProvider.Instance);\n        services.AddSingleton<AppApiFileSystemWatcher>();\n        services.AddScoped<AppApiDynamicRouteValueTransformer>();\n        services.AddScoped<AppApiControllerManager>();\n        services.AddScoped<AppApiActionContext>();\n        services.AddScoped<AppApiAuthorization>();\n        services.AddScoped<AppApiActionInvoker>();\n        services.AddScoped<IAuthorizationHandler, AppApiPermissionHandler>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices_Context.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Oqt.Server.Blocks.Output;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\npartial class OqtRegisterServices\n{\n\n    /// <summary>\n    /// Context information like the ISite, IUser etc.\n    /// </summary>\n    private static IServiceCollection AddSxcOqtContext(this IServiceCollection services)\n    {\n        // Context: Things which are relevant for determining the context\n        services.TryAddScoped<IOqtTenantContext, OqtTenantContext>();\n        services.TryAddScoped<ISite, OqtSite>();\n        services.TryAddScoped<IPage, OqtPage>();\n        services.TryAddScoped<IUser, OqtUser>();\n\n        services.TryAddTransient<IModule, OqtModule>();\n\n        // TODO: @STV - this could cause a bug - maybe better not to mix this? OqtSite transient?\n        services.TryAddTransient<IZoneCultureResolver, OqtSite>();\n        //services.TryAddTransient<IZoneCultureResolver>(x => x.GetRequiredService<ISite>()); // eventual alternative to line above\n\n        services.TryAddScoped<OqtSecurity>();\n        services.TryAddScoped<IJsApiService, OqtJsApiService>();\n\n        // must be Transient (scoped cause StackOverflowException infinite recursion)\n        services.TryAddTransient<IRuntimeKeyService, OqtRuntimeKeyService>();\n\n        return services;\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices_CoreAndPlumbing.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Apps.Sys.Installation;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Oqt.Server.Code.Sys;\nusing ToSic.Sxc.Oqt.Server.Configuration;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sxc.Oqt.Server.Installation;\nusing ToSic.Sxc.Oqt.Server.Integration;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sxc.Oqt.Server.Services;\nusing ToSic.Sxc.Oqt.Shared.Interfaces;\nusing ToSic.Sxc.Sys.Integration.Installation;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sxc.Web.Sys.Http;\nusing ToSic.Sys.Capabilities.Platform;\nusing ToSic.Sys.Configuration;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\npartial class OqtRegisterServices\n{\n    /// <summary>\n    /// Path resolvers and IPlatform information\n    /// </summary>\n    private static IServiceCollection AddSxcOqtPathsAndPlatform(this IServiceCollection services)\n    {\n        services.TryAddTransient<IServerPaths, OqtServerPaths>();\n        services.AddScoped<ILinkPaths, OqtLinkPaths>();\n        services.TryAddTransient<Compiler>();\n\n        // TODO: Review - it looks a bit fishy to have the same class as singleton and transient\n        services.AddSingleton<IPlatform, OqtPlatformContext>();\n        services.TryAddTransient<IPlatformInfo, OqtPlatformContext>();\n        return services;\n    }\n        \n    /// <summary>\n    /// Plumbing helpers to make sure everything can work, the context is ready etc.\n    /// </summary>\n    private static IServiceCollection AddOqtanePlumbing(this IServiceCollection services)\n    {\n        // Helper to access settings of a Site, Module etc.\n        services.TryAddTransient<SettingsHelper>();\n\n        // Helper to get header, query string and route information from current request\n        //services.TryAddScoped<RequestHelper>();\n\n        // Manage oqtane site culture info\n        services.TryAddTransient<OqtCulture>();\n\n        // Site State Initializer for APIs etc. to ensure that the SiteState exists and is correctly preloaded\n        services.TryAddTransient<AliasResolver>();\n\n        // Views / Templates / Razor: Get url params in the request\n        services.TryAddTransient<IHttp, HttpBlazor>();\n\n        // 2025-03-07 2dm disabled as not needed any more https://github.com/2sic/2sxc/issues/3594\n        // Special Key generator for security implementation, which doesn't exist in .net standard\n        // services.TryAddTransient<Rfc2898Generator, Rfc2898NetCoreGenerator>();\n\n        return services;\n    }\n        \n\n    private static IServiceCollection AddOqtaneInstallation(this IServiceCollection services)\n    {\n        // Installation: Helper to ensure the installation is complete\n        services.TryAddTransient<IEnvironmentInstaller, OqtEnvironmentInstaller>();\n        services.TryAddTransient<IPlatformAppInstaller, OqtEnvironmentInstaller>();\n\n        // Installation: Verify the Razor Helper DLLs are available\n        services.TryAddSingleton<GlobalTypesCheck>();\n\n        return services;\n    }\n    private static IServiceCollection AddOqtaneBlazorWebAssemblySupport(this IServiceCollection services)\n    {\n        // following registrations in the server project will override the previous one in client project\n        services.AddScoped<IOqtDebugStateService, OqtDebugStateService>();\n        services.AddScoped<IOqtPageChangesOnServerService, OqtPageChangesOnServerService>();\n        services.AddScoped<IOqtPrerenderService, OqtPrerenderService>();\n        services.AddScoped<IOqtSxcRenderService, OqtSxcRenderService>();\n        services.AddScoped<IRenderInfoService, RenderInfoService>();\n        services.AddScoped<IOqtTurnOnService, OqtTurnOnService>();\n\n        return services;\n    }\n\n    /// <summary>\n    /// Replace default IGlobalConfiguration with OqtGlobalConfiguration which resolves ConnectionString per tenant.\n    /// </summary>\n    private static IServiceCollection AddOqtGlobalConfiguration(this IServiceCollection services)\n    {\n        services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();\n        services.Replace(ServiceDescriptor.Transient<IGlobalConfiguration, OqtGlobalConfiguration>());\n\n        return services;\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices_LookUps.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.LookUp;\nusing ToSic.Sxc.Oqt.Server.LookUps;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\npartial class OqtRegisterServices\n{\n    /// <summary>\n    /// Mail, Logging and other services.\n    /// </summary>\n    private static IServiceCollection AddSxcOqtLookUps(this IServiceCollection services)\n    {\n        services.AddTransient<ILookUp, OqtModuleLookUp>();\n        services.AddTransient<ILookUp, OqtPageLookUp>();\n        services.AddTransient<ILookUp, OqtSiteLookUp>();\n        services.AddTransient<ILookUp, OqtUserLookUp>();\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices_ModuleAndRazor.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.AspNetCore.Mvc.Routing;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Sxc.Backend.Context;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Integration.Modules;\nusing ToSic.Sxc.Oqt.Server.Blocks;\nusing ToSic.Sxc.Oqt.Server.Cms;\nusing ToSic.Sxc.Oqt.Server.Data;\nusing ToSic.Sxc.Oqt.Server.Integration;\nusing ToSic.Sxc.Oqt.Server.Polymorphism;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sxc.Oqt.Server.Services;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Render.Sys.ResourceExtractor;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing OqtPageOutput = ToSic.Sxc.Oqt.Server.Blocks.Output.OqtPageOutput;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\npartial class OqtRegisterServices\n{\n    /// <summary>\n    /// Ensure that the module-concept works\n    /// </summary>\n    /// <param name=\"services\"></param>\n    /// <returns></returns>\n    private static IServiceCollection AddSxcOqtModule(this IServiceCollection services)\n    {\n        // Multi-Site Services\n        services.TryAddTransient<IZoneMapper, OqtZoneMapper>();\n\n        // Update title etc. when a module-content changes\n        services.TryAddTransient<IPlatformModuleUpdater, OqtModuleUpdater>();\n            \n        // Page publishing - ATM neutral objects which don't do much\n        services.TryAddTransient<IPagePublishing, OqtPagePublishing>();\n        services.AddTransient<IPagePublishingGetSettings, OqtPagePublishingGetGetSettings>(); // #SwitchServicePagePublishingResolver #2749\n\n        services.TryAddTransient<OqtModuleHelper>();\n\n        return services;\n    }\n        \n        \n\n    private static IServiceCollection AddSxcOqtDynCodeAndViews(this IServiceCollection services)\n    {\n        // 2022-03-29 2dm replaced this. As Oqtane is still very new, we don't need to support the old interface as nobody will have code ATM linking to exactly that interface\n        //services.TryAddTransient<ILinkHelper, OqtLinkHelper>();\n        services.TryAddTransient<ILinkService, OqtLinkService>();\n\n        services.TryAddTransient<OqtPageOutput>();\n        services.TryAddTransient<IBlockResourceExtractor, BlockResourceExtractorWithInline>();\n        services.TryAddTransient<IValueConverter, OqtValueConverter>();\n\n        // Views / Templates / Razor: View Builder\n        services.TryAddTransient<IOqtSxcViewBuilder, OqtSxcViewBuilder>();\n\n        services.TryAddTransient<ExecutionContext, OqtExecutionContext>();\n        services.TryAddTransient(typeof(ExecutionContext<,>), typeof(OqtExecutionContext<,>));\n        services.TryAddTransient<IWebApiContextBuilder, OqtGetBlock>();\n\n        // v13\n        services.TryAddTransient<IModuleAndBlockBuilder, OqtModuleAndBlockBuilder>();\n\n        // Views / Templates / Razor: Polymorphism Resolvers\n        services.TryAddTransient<Connect.Koi.Detectors.ICssFrameworkDetector, OqtKoiCssFrameworkDetector>();\n\n        return services;\n    }\n\n    private static IServiceCollection AddRazorDependencies(this IServiceCollection services)\n    {\n        // Microsoft Services used to run Razor?\n        // enable use of UrlHelper for AbsolutePath\n        services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();\n        services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();\n        return services;\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices_OqtaneIntegration.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Oqt.Server.Services;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.TurnOn.Sys;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\npartial class OqtRegisterServices\n{\n    /// <summary>\n    /// Mail, Logging and other services.\n    /// </summary>\n    private static IServiceCollection AddSxcOqtIntegratedServices(this IServiceCollection services)\n    {\n        services.TryAddTransient<ISystemLogService, OqtSystemLogService>();\n        services.TryAddTransient<IMailService, OqtMailService>();\n        services.AddTransient<ITurnOnService, OqtTurnOnService>();\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtRegisterServices_WebApi.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.WebApi.Sys.ApiExplorer;\nusing ToSic.Sxc.Oqt.Server.WebApi;\nusing ToSic.Sxc.Oqt.Server.WebApi.Admin;\nusing ToSic.Sxc.WebApi.Sys.ActionFilters;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\npartial class OqtRegisterServices\n{\n    /// <summary>\n    /// Things needed by the standard API Controllers to work\n    /// </summary>\n    private static IServiceCollection AddSxcOqtApiParts(this IServiceCollection services)\n    {\n        // ApiExplorer helper - inspects a custom WebApi class to figure out what it provides\n        services.TryAddTransient<IApiInspector, OqtApiInspector>();\n\n        return services;\n    }\n\n\n    private static IServiceCollection AddOqtaneApiPlumbingAndHelpers(this IServiceCollection services)\n    {\n        // action filter for exceptions\n        services.AddTransient<HttpResponseExceptionFilter>();\n\n        // action filter instead of global option AllowEmptyInputInBodyModelBinding = true\n        services.AddTransient<OptionalBodyFilter>();\n\n        services.TryAddTransient<AppAssetsControllerBase.Dependencies>();\n\n        // ViewController deps for AllModulesWithContent\n        services.TryAddTransient<Pages.Pages>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtStartup.cs",
    "content": "﻿using Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Oqtane.Infrastructure;\nusing ToSic.Eav;\nusing ToSic.Eav.Run.Startup;\nusing ToSic.Eav.Sys;\nusing ToSic.Razor.StartUp;\nusing ToSic.Sxc.Backend;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.DataSources;\nusing ToSic.Sxc.Oqt.Server.Adam.Imageflow;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.Oqt.Server.Controllers.AppApi;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Run.Startup;\nusing ToSic.Sys.Boot;\nusing ToSic.Sys.Configuration;\nusing ToSic.Sys.Security.Encryption;\nusing static ToSic.Sxc.Oqt.Server.WebApi.OqtWebApiConstants;\n\nnamespace ToSic.Sxc.Oqt.Server.StartUp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtStartup : IServerStartup\n{\n    internal IConfigurationRoot Configuration { get; }\n\n    public OqtStartup()\n    {\n        // Configuration is used to provide Master tenant sql connection string to 2sxc eav.\n        var builder = new ConfigurationBuilder()\n            .AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\n        Configuration = builder.Build();\n    }\n\n    public void ConfigureServices(IServiceCollection services)\n    {\n        // 1. Enable dynamic razor compiling\n        services.AddRazorPages()\n            .AddRazorRuntimeCompilation(options =>\n            {\n                var dllLocation = typeof(Oqtane.Server.Program).Assembly.Location;\n                var dllPath = Path.GetDirectoryName(dllLocation);\n                foreach (var dllFile in Directory.GetFiles(dllPath, \"*.dll\"))\n                    options.AdditionalReferencePaths.Add(dllFile);\n            });\n\n        // TODO: STV - MAKE SURE OUR CONTROLLERS RULES ONLY APPLY TO OURS, NOT TO override rules on normal Oqtane controllers\n\n        // 2. Register EAV & 2sxc\n        services\n            .AddSxcOqtane()                 // Always first add your override services\n            .AddOqtSxcDataSources()\n            .AddSxcRazor()                  // this is the .net core Razor compiler\n            .AddAdamWebApi<int, int>()      // This is used to enable ADAM WebAPIs\n            .AddSxcWebApi()                 // This adds all the standard backend services for WebAPIs to work\n            .AddSxcCustom()                 // Anything around custom code\n            .AddSxcCode()\n            .AddSxcCodeHotBuild()\n            .AddSxcEngines()\n            .AddSxcImages()\n            // Core 2sxc services\n            .AddSxcApps()\n            .AddSxcEdit()\n            .AddSxcData()\n            .AddSxcAdam()\n            .AddSxcAdamWork<int, int>()\n            .AddSxcBlocks()\n            .AddSxcRender()\n            .AddSxcCms()\n            .AddSxcServices()\n            .AddSxcServicesObsolete()\n            .AddSxcWeb()\n            .AddSxcLightSpeed()             // LightSpeed services\n            .AddSxcCodeGen()                // Code generation services\n            .AddSxcCore()\n            .AddSxcAppsFallbacks()\n            .AddSxcCoreFallbacks()\n            .AddEavAll()             // Core EAV services\n            .AddEavAllFallbacks()\n            .AddEavWebApiTypedAfterEav()\n            .AddOqtAppWebApi()              // Oqtane App WebAPI stuff\n            .AddRazorBlade();               // RazorBlade helpers for Razor in the edition used by Oqtane\n\n        // 2sxc Oqtane blob services for Imageflow and other customizations.\n        services.AddImageflowExtensions();\n    }\n\n    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n    {\n        var serviceProvider = app.ApplicationServices;\n\n        var globalConfig = serviceProvider.Build<IGlobalConfiguration>();\n        globalConfig.ConnectionString(Configuration.GetConnectionString(\"DefaultConnection\"));\n        globalConfig.GlobalFolder(Path.Combine(env.ContentRootPath, \"wwwroot\\\\Modules\", OqtConstants.PackageName));\n        globalConfig.AppDataTemplateFolder(Path.Combine(env.ContentRootPath, \"Content\", \"2sxc\", \"system\", FolderConstants.DataFolderProtected, FolderConstants.NewAppFolder));\n        globalConfig.DataFolder(Path.Combine(env.ContentRootPath, \"Content\", \"2sxc\", \"system\", FolderConstants.DataFolderProtected, FolderConstants.DataSubFolderSystem));\n        globalConfig.TemporaryFolder(Path.Combine(env.ContentRootPath, \"Content\", \"2sxc\", \"system\", FolderConstants.TemporaryFolder));\n        globalConfig.InstructionsFolder(Path.Combine(env.ContentRootPath, \"Content\", \"2sxc\", \"system\", FolderConstants.InstructionsFolder));\n        globalConfig.AssetsVirtualUrl($\"~/Modules/{OqtConstants.PackageName}/assets/\");\n        globalConfig.SharedAppsFolder($\"/{OqtConstants.AppRoot}/{OqtConstants.TenantsFolderName}/1/{OqtConstants.SitesFolderName}/{OqtConstants.SharedAppFolder}/\"); // \"/2sxc/Tenants/1/Sites/Shared\"\n        globalConfig.TempAssemblyFolder(Path.Combine(env.ContentRootPath, FolderConstants.DataFolderProtected, FolderConstants.TempAssemblyFolder)); // \".../App_Data/2sxc.bin\"\n        globalConfig.CshtmlAssemblyFolder(Path.Combine(env.ContentRootPath, FolderConstants.DataFolderProtected, FolderConstants.CshtmlAssemblyFolder)); // \".../App_Data/2sxc.bin.cshtml\"\n        globalConfig.CryptoFolder(Path.Combine(env.ContentRootPath, FolderConstants.DataFolderProtected, FolderConstants.CryptoFolder)); // \".../App_Data/2sxc.crypto\"\n\n        // ensure we have an instance\n        var assemblyResolver = serviceProvider.Build<AssemblyResolver>();\n\n        // Load features from configuration\n        // NOTE: On first installation of 2sxc module in oqtane, this code can not load all 2sxc global types\n        // because it has dependency on ToSic_Eav_* sql tables, before this tables are actually created by oqtane 2.3.x,\n        // but after next restart of oqtane application all is ok, and all 2sxc global types are loaded as expected\n\n        var bootCoordinator = serviceProvider.Build<BootCoordinator>();\n        bootCoordinator.StartUp();\n\n        // Clean the App_Data/2sxc.bin folder\n        serviceProvider.Build<Util>().CleanTempAssemblyFolder();\n\n        //if (env.IsDevelopment())\n        //    app.UsePageResponseRewriteMiddleware();\n\n        // Configure Sxc endpoints and dialogs\n        app.UseEndpoints(endpoints =>\n        {\n            // Sxc API Endpoints\n            // Mapped directly; these will be matched based on their patterns.\n            foreach (var pattern in SxcEndpointPatterns)\n                endpoints.Map(pattern, AppApiMiddleware.InvokeAsync);\n\n            // Sxc Dialogs\n            // Mapped as fallbacks for specific URL patterns.\n            foreach (var (url, page, setting) in SxcDialogs)\n                endpoints.MapFallback(url, context => EditUiMiddleware.PageOutputCached(context, env, page, setting));\n        });\n    }\n\n    public void ConfigureMvc(IMvcBuilder mvcBuilder)\n    {\n        // Do nothing\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/StartUp/OqtStartupHelper.cs",
    "content": "﻿//using static ToSic.Sxc.Oqt.Server.WebApi.OqtWebApiConstants;\n\n//namespace ToSic.Sxc.Oqt.Server.StartUp;\n\n//internal static class OqtStartupHelper\n//{\n\n//    public static bool IsSxcEndpoint(string path) => SxcEndpointPathRegex.IsMatch(path);\n\n//    public static bool IsSxcDialog(string path) => SxcDialogs.Any(p => path.Contains(p.url, StringComparison.OrdinalIgnoreCase));\n//}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/ToSic.Sxc.DataSources/OqtPagesDsProvider.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Oqtane.Repository;\nusing Oqtane.Security;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Cms.Pages.Sys;\nusing ToSic.Sxc.DataSources.Sys.Pages;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Deliver a list of pages from the current platform (Dnn or Oqtane)\n/// </summary>\n[PrivateApi]\ninternal class OqtPagesDsProvider(\n    IPageRepository pages,\n    SiteState siteState,\n    IUserPermissions userPermissions,\n    IHttpContextAccessor httpContextAccessor,\n    LazySvc<ILinkPaths> linkPathsLazy)\n    : PagesDataSourceProvider(\"Oqt.Pages\",\n        connect: [pages, siteState, userPermissions, httpContextAccessor, linkPathsLazy])\n{\n    private const int OqtLevelOffset = 1;\n\n    public override List<PageModelRaw> GetPagesInternal(\n        NoParamOrder npo = default,\n        bool includeHidden = default,\n        bool includeDeleted = default,\n        bool includeAdmin = default,\n        bool includeSystem = default,\n        bool includeLinks = default,\n        bool requireViewPermissions = true,\n        bool requireEditPermissions = true)\n    {\n        var l = Log.Fn<List<PageModelRaw>>();\n        var user = httpContextAccessor?.HttpContext?.User;\n        var allowed = pages\n            .GetPages(siteState.Alias.SiteId)\n            .Where(page => userPermissions.IsAuthorized(user, PermissionNames.View, page.PermissionList))\n            .ToList();\n\n        var parts = new UrlParts(linkPathsLazy.Value.GetCurrentRequestUrl());\n\n        var converted = allowed\n            .Select(p => new PageModelRaw\n            {\n                // In v14\n                Id = p.PageId,\n                Guid = Guid.Empty,\n                ParentId = p.ParentId ?? NoParent,\n                Title = p.Title.UseFallbackIfNoValue(p.Name),\n                Name = p.Name,\n                IsNavigation = p.IsNavigation,\n                Path = p.Path,\n                Url = $\"{parts.Protocol}{siteState.Alias.Name}/{p.Path}\".TrimLastSlash(),\n                Created = p.CreatedOn,\n                Modified = p.ModifiedOn,\n\n                // New in 15.01\n                IsClickable = p.IsClickable,\n                HasChildren = p.HasChildren,\n                IsDeleted = p.IsDeleted,\n                Level = p.Level + OqtLevelOffset,\n                Order = p.Order,\n                // New in 15.02\n                LinkTarget = \"\", // TODO\n            })\n            .ToList();\n\n        return l.ReturnAsOk(converted);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/ToSic.Sxc.DataSources/OqtRolesDsProvider.cs",
    "content": "﻿using Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Cms.Users.Sys;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Deliver a list of roles from the Oqtane\n/// </summary>\ninternal class OqtRolesDsProvider(IRoleRepository roles, SiteState siteState)\n    : ServiceBase(\"Oqt.Roles\", connect: [roles, siteState]),\n        IUserRolesProvider\n{\n    [PrivateApi]\n    public IEnumerable<UserRoleModel> GetRoles()\n    {\n        var l = Log.Fn<IEnumerable<UserRoleModel>>();\n        var siteId = siteState.Alias.SiteId;\n        l.A($\"Portal Id {siteId}\");\n        try\n        {\n            var roles1 = roles.GetRoles(siteId, includeGlobalRoles: true).ToList();\n            if (!roles1.Any())\n                return l.Return(new List<UserRoleModel>(), \"null/empty\");\n\n            var result = roles1\n                .Select(r => new UserRoleModel\n                {\n                    Id = r.RoleId,\n                    // Guid = r.\n                    Name = r.Name,\n                    Created = r.CreatedOn,\n                    Modified = r.ModifiedOn,\n                })\n                .ToList();\n            return l.Return(result, \"found\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return(new List<UserRoleModel>(), \"error\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/ToSic.Sxc.DataSources/OqtSitesDsProvider.cs",
    "content": "﻿using Oqtane.Repository;\nusing ToSic.Sxc.Cms.Sites.Sys;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sys.Utils;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Deliver a list of sites from the Oqtane\n/// </summary>\n[PrivateApi]\ninternal class OqtSitesDsProvider : SitesDataSourceProvider\n{\n    private readonly IAliasRepository _aliases;\n    private readonly ISiteRepository _sites;\n    private readonly LazySvc<OqtCulture> _oqtCulture;\n\n    #region Constructor / DI\n\n    public OqtSitesDsProvider(Dependencies services, IAliasRepository aliases, ISiteRepository sites, LazySvc<OqtCulture> oqtCulture)\n        :base(services, \"Oqt.Sites\")\n    {\n        ConnectLogs([\n            _aliases = aliases,\n            _sites = sites,\n            _oqtCulture = oqtCulture\n        ]);\n    }\n\n    #endregion\n\n    public override List<SiteModel> GetSitesInternal()\n    {\n        var l = Log.Fn<List<SiteModel>>();\n        var sites = _sites.GetSites().ToList();\n        return l.ReturnAsOk(sites.Select(s => new SiteModel\n        {\n            Id = s.SiteId,\n            Guid = new(s.SiteGuid),\n            Name = s.Name,\n            Url = GetUrl(s.SiteId),\n            Languages = GetLanguages(s.SiteId),\n            DefaultLanguage = _oqtCulture.Value.DefaultLanguageCode(s.SiteId),\n            Created = s.CreatedOn,\n            Modified = s.ModifiedOn,\n            ZoneId = GetZoneId(s.SiteId),\n            ContentAppId = GetDefaultAppId(s.SiteId),\n            PrimaryAppId = GetPrimaryAppId(s.SiteId)\n        }).ToList());\n    }\n\n    private string GetUrl(int siteId)\n    {\n        var alias = _aliases.GetAliases().FirstOrDefault(a => a.SiteId == siteId && a.IsDefault);\n        //?? _aliases.GetAliases().FirstOrDefault(a => a.SiteId == siteId);\n        return $\"{alias?.Protocol}{alias?.Name}/{alias?.Path}\".TrimLastSlash();\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/ToSic.Sxc.DataSources/OqtSqlPlatformInfo.cs",
    "content": "﻿using Oqtane.Infrastructure;\nusing Oqtane.Shared;\nusing ToSic.Eav.DataSources.Sys;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Oqt.Server.ToSic.Sxc.DataSources;\n\ninternal class OqtSqlPlatformInfo(\n    LazySvc<IConfigManager> configManager,\n    LazySvc<IOqtTenantContext> tenantContext) : SqlPlatformInfo\n{\n    // Make the default connection-string name tenant-aware.\n    // If the current tenant has a named connection, use that; otherwise fall back to Oqtane default.\n    public override string DefaultConnectionStringName\n        => tenantContext.Value.Get() is { } ctx && ctx.ConnectionStringName.HasValue()\n            ? ctx.ConnectionStringName\n            : SettingKeys.ConnectionStringKey;\n\n    public override string FindConnectionString(string name)\n    {\n        if (tenantContext.Value.Get() is { } tenantContextInfo && tenantContextInfo.ConnectionString.HasValue())\n        {\n            if (name.EqualsInsensitive(SettingKeys.ConnectionStringKey))\n                return tenantContextInfo.ConnectionString;\n\n            if (tenantContextInfo.ConnectionStringName.HasValue() && name.EqualsInsensitive(tenantContextInfo.ConnectionStringName))\n                return tenantContextInfo.ConnectionString;\n        }\n\n        var config = configManager.Value;\n        if (name.EqualsInsensitive(SettingKeys.ConnectionStringKey))\n        {\n            var defaultConnection = config.GetConnectionString();\n            if (defaultConnection.HasValue())\n                return defaultConnection;\n        }\n\n        var resolved = config.GetConnectionString(name);\n        if (resolved.HasValue())\n            return resolved;\n\n        resolved = config.GetSetting($\"ConnectionStrings:{name}\", \"\");\n        if (resolved.HasValue())\n            return resolved;\n\n        return base.FindConnectionString(name);\n    }\n\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/ToSic.Sxc.DataSources/OqtStartUpDataSources.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.DataSources.Sys;\nusing ToSic.Sxc.Cms.Sites.Sys;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.DataSources.Sys.Pages;\nusing ToSic.Sxc.Oqt.Server.ToSic.Sxc.DataSources;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\ninternal static class OqtStartUpDataSources\n{\n    public static IServiceCollection AddOqtSxcDataSources(this IServiceCollection services)\n    {\n        // DataSourceProvider model\n        services.TryAddTransient<IUserRolesProvider, OqtRolesDsProvider>();\n        services.TryAddTransient<IUsersProvider, OqtUsersProvider>();\n        services.TryAddTransient<SitesDataSourceProvider, OqtSitesDsProvider>();\n        services.TryAddTransient<PagesDataSourceProvider, OqtPagesDsProvider>();\n\n        // info class to ensure SQL knows about default connections\n        services.TryAddTransient<SqlPlatformInfo, OqtSqlPlatformInfo>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/ToSic.Sxc.DataSources/OqtUsersProvider.cs",
    "content": "﻿using Oqtane.Managers;\nusing Oqtane.Models;\nusing Oqtane.Repository;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sys.Utils;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\ninternal class OqtUsersProvider(\n    SiteState siteState,\n    LazySvc<OqtSecurity> oqtSecurity,\n    LazySvc<IUserRoleRepository> userRolesRepository,\n    LazySvc<UserManager> userManager)\n    : ServiceBase(\"Oqt.Users\", connect: [siteState, oqtSecurity, userRolesRepository, userManager]), IUsersProvider\n{\n    #region Configuration\n    private UsersGetSpecs _specs;\n\n    private UsersGetSpecsParsed SpecsParsed => field ??= new(_specs);\n\n    #endregion\n\n    public string PlatformIdentityTokenPrefix => OqtConstants.UserTokenPrefix;\n\n    public IUserModel? GetUser(int userId, int siteId)\n    {\n        var user = userManager.Value.GetUser(userId, SiteId);\n        return user == null \n            ? null \n            : oqtSecurity.Value.CmsUserBuilder(user);\n    }\n\n    public IEnumerable<UserModel> GetUsers(UsersGetSpecs specs)\n    {\n        var l = Log.Fn<List<UserModel>>();\n        _specs = specs;\n\n        l.A($\"Portal Id {SiteId}\");\n\n        try\n        {\n            var oqtUserRoles = new List<UserRole>();\n\n            // Include users\n            if (_specs.UserIds.IsEmpty() && _specs.RoleIds.IsEmpty())\n            {\n                oqtUserRoles.AddRange(OqtAllUserRoles);\n            }\n            else\n            {\n                // UserIds\n                oqtUserRoles.AddRange(SpecsParsed.UserIdFilter.Except(SpecsParsed.ExcludeUserIdsFilter)\n                    .SelectMany(userId => userRolesRepository.Value.GetUserRoles(userId, SiteId)));\n\n                oqtUserRoles.AddRange(SpecsParsed.UserGuidFilter.Except(SpecsParsed.ExcludeUserGuidsFilter)\n                    .SelectMany(membershipUserKey => OqtAllUserRoles.Where(ur => oqtSecurity.Value.UserGuid(ur.User.Username) == membershipUserKey)));\n\n                // RoleIds\n                oqtUserRoles.AddRange(SpecsParsed.RolesFilter.Except(SpecsParsed.ExcludeRolesFilter)\n                    .SelectMany(roleId => OqtAllUserRoles.Where(ur => ur.RoleId == roleId)));\n            }\n\n            // Excluded users\n            var excludedUsers = oqtUserRoles\n                .Where(ExcludeUser)\n                .Select(ur => ur.UserId)\n                .Distinct();\n\n            // results\n            var oqtUsers = oqtUserRoles\n                .Select(ur => ur.UserId)\n                .Where(userId => !excludedUsers.Contains(userId))\n                .Distinct()\n                .Select(userId => userManager.Value.GetUser(userId, SiteId))\n                .ToList();\n\n            if (!oqtUsers.Any())\n                return l.Return([], \"null/empty\");\n\n            var users = oqtUsers\n                //.Where(user => !user.IsDeleted)\n                .Select(u => oqtSecurity.Value.CmsUserBuilder(u))\n                .ToList();\n\n            return l.Return(users, \"found\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return([], \"error\");\n        }\n    }\n\n    private int SiteId => siteState.Alias.SiteId;\n\n    private IEnumerable<UserRole> OqtAllUserRoles => _oqtAllUserRoles.Get(() => userRolesRepository.Value.GetUserRoles(SiteId));\n    private readonly GetOnce<IEnumerable<UserRole>> _oqtAllUserRoles = new();\n\n    private bool ExcludeUser(UserRole userRole)\n    {\n        if (userRole == null) return true;\n        if (SpecsParsed.ExcludeUserIdsFilter.Contains(userRole.UserId)) return true;\n        if (SpecsParsed.ExcludeUserGuidsFilter.Contains(oqtSecurity.Value.UserGuid(userRole.User.Username))) return true;\n        if (SpecsParsed.ExcludeRolesFilter.Contains(userRole.RoleId)) return true;\n        if (_specs.IncludeSystemAdmins.EqualsInsensitive(UserConstants.IncludeForbidden) && IsSystemAdmin(userRole)) return true;\n        if (_specs.IncludeSystemAdmins.EqualsInsensitive(UserConstants.IncludeRequired) && !IsSystemAdmin(userRole)) return true;\n        return false;\n    }\n\n    private bool IsSystemAdmin(UserRole userRole) => userRole.RoleId == 2; // Host Users\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/ToSic.Sxc.Oqt.Server.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Razor\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-NetCore.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <PropertyGroup>\n    <RootNamespace>ToSic.Sxc.Oqt.Server</RootNamespace>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AddRazorSupportForMvc>true</AddRazorSupportForMvc>\n    <AssemblyName>ToSic.Sxc.Oqtane.Server</AssemblyName>\n    <!--2dm I think we need this to include DLLs-->\n    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>\n    <RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>\n    <AnalysisLevel>none</AnalysisLevel>\n\n    <!-- 2dm - this seems necessary to ensure that compiler DLLs are included in the output -->\n    <!-- See: https://github.com/toddams/RazorLight/issues/294 and https://stackoverflow.com/questions/40426665/what-is-the-use-of-preservecompilationcontext-under-build-option-in-project-json -->\n    <!-- also https://github.com/dotnet/aspnetcore/issues/14418 -->\n    <!-- but apparently we don't need it, bcause it's set when we activate dynamic razor compilation ... https://github.com/dotnet/aspnetcore/issues/20173 ??? -->\n    <!--<PreserveCompilationReferences>true</PreserveCompilationReferences>\n    <PreserveCompilationContext>true</PreserveCompilationContext>-->\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"Apps\\**\" />\n    <Compile Remove=\"Contents\\**\" />\n    <Compile Remove=\"Content\\**\" />\n    <Compile Remove=\"Engines\\**\" />\n    <Compile Remove=\"RazorPartialToString\\**\" />\n    <Compile Remove=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane.Install\\**\" />\n    <Compile Remove=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane\\**\" />\n    <Compile Remove=\"wwwroot\\Modules\\ToSic.Sxc\\**\" />\n    <Content Remove=\"Apps\\**\" />\n    <Content Remove=\"Contents\\**\" />\n    <Content Remove=\"Content\\**\" />\n    <Content Remove=\"Engines\\**\" />\n    <Content Remove=\"RazorPartialToString\\**\" />\n    <Content Remove=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane.Install\\**\" />\n    <Content Remove=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane\\**\" />\n    <Content Remove=\"wwwroot\\Modules\\ToSic.Sxc\\**\" />\n    <EmbeddedResource Remove=\"Apps\\**\" />\n    <EmbeddedResource Remove=\"Contents\\**\" />\n    <EmbeddedResource Remove=\"Content\\**\" />\n    <EmbeddedResource Remove=\"Engines\\**\" />\n    <EmbeddedResource Remove=\"RazorPartialToString\\**\" />\n    <EmbeddedResource Remove=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane.Install\\**\" />\n    <EmbeddedResource Remove=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane\\**\" />\n    <EmbeddedResource Remove=\"wwwroot\\Modules\\ToSic.Sxc\\**\" />\n    <None Remove=\"Apps\\**\" />\n    <None Remove=\"Contents\\**\" />\n    <None Remove=\"Content\\**\" />\n    <None Remove=\"Engines\\**\" />\n    <None Remove=\"RazorPartialToString\\**\" />\n    <None Remove=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane.Install\\**\" />\n    <None Remove=\"wwwroot\\Modules\\ToSic.Sxc.Oqtane\\**\" />\n    <None Remove=\"wwwroot\\Modules\\ToSic.Sxc\\**\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Remove=\"StartUp\\IIsSxcRazorPage.cs\" />\n    <Compile Remove=\"StartUp\\SxcRazorPage.cs\" />\n    <Compile Remove=\"StartUp\\SxcRazorPage_Block.cs\" />\n    <Compile Remove=\"StartUp\\SxcRazorPage_CreateInstance.cs\" />\n    <Compile Remove=\"StartUp\\SxcRazorPage_IDynamicCode.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <!-- stv - SQL scripts have to be included as embedded resources -->\n    <!-- to be executed as part of oqtane installation or upgrade procedure -->\n    <EmbeddedResource Include=\"Scripts\\*.sql\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Authentication.OpenIdConnect\" Version=\"9.0.5\" /><!-- from Oqtane.Server.csproj -->\n    <PackageReference Include=\"Microsoft.AspNetCore.Components.WebAssembly.Server\" Version=\"9.0.5\" /><!-- from Oqtane.Server.csproj -->\n    <PackageReference Include=\"Microsoft.AspNetCore.Identity.EntityFrameworkCore\" Version=\"9.0.5\" /><!-- from Oqtane.Server.csproj -->\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\" Version=\"9.0.5\" />\n    <PackageReference Include=\"Microsoft.AspNetCore.StaticFiles\" Version=\"2.2.0\" />\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore\" Version=\"9.0.5\" /><!-- from Oqtane.Server.csproj -->\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.SqlServer\" Version=\"9.0.5\" /><!-- from Oqtane.Database.SqlServer.csproj -->\n    <PackageReference Include=\"Microsoft.Extensions.Localization\" Version=\"9.0.5\" /><!-- from Oqtane.Server.csproj -->\n    <PackageReference Include=\"Oqtane.Client\" Version=\"6.1.3\" />\n    <PackageReference Include=\"Oqtane.Server\" Version=\"6.1.3\" />\n    <PackageReference Include=\"Oqtane.Shared\" Version=\"6.1.3\" />\n    <PackageReference Include=\"ToSic.Imageflow.Oqtane\" Version=\"1.12.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <!--<ProjectReference Include=\"..\\..\\..\\..\\oqtane\\oqtane.framework\\Oqtane.Server\\Oqtane.Server.csproj\" />-->\n    <!--<ProjectReference Include=\"..\\..\\..\\..\\oqtane\\oqtane.framework\\Oqtane.Shared\\Oqtane.Shared.csproj\" />-->\n    <ProjectReference Include=\"..\\..\\Razor\\ToSic.Sxc.Razor\\ToSic.Sxc.Razor.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Cms\\ToSic.Sxc.Cms.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Code.HotBuild\\ToSic.Sxc.Code.HotBuild.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Edit\\ToSic.Sxc.Edit.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Images\\ToSic.Sxc.Images.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.LightSpeed\\ToSic.Sxc.LightSpeed.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Web\\ToSic.Sxc.Web.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Oqt.Shared\\ToSic.Sxc.Oqt.Shared.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Reference Include=\"Connect.Koi\">\n      <HintPath>..\\..\\..\\Dependencies\\Koi\\net6.0\\Connect.Koi.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"wwwroot\\Modules\\\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/ToSic.Sxc.Oqt.Server.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=controllers_005Capp/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=controllers_005Ccms/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=controllers_005Csystem/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=webapi_005Csystem/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Adam/AdamController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ToSic.Eav.WebApi.PublicApi;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Adam.AdamControllerReal<int>;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Adam;\n\n/// <summary>\n/// Direct access to app-content items, simple manipulations etc.\n/// Should check for security at each standard call - to see if the current user may do this\n/// Then we can reduce security access level to anonymous, because each method will do the security check\n/// </summary>\n//[SupportedModules(\"2sxc,2sxc-app\")]\n//[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)] // use view, all methods must re-check permissions\n//[Authorize(Roles = RoleNames.Everyone)] commented because of http403 issue\n[ValidateAntiForgeryToken]\n\n// Release routes\n[Route(OqtWebApiConstants.AppRootNoLanguage + \"/{appName}/content/{contentType}/{guid:guid}/{field}\")]\n[Route(OqtWebApiConstants.AppRootPathOrLang + \"/{appName}/content/{contentType}/{guid:guid}/{field}\")]\n[Route(OqtWebApiConstants.AppRootPathAndLang + \"/{appName}/content/{contentType}/{guid:guid}/{field}\")]\n[Route(OqtWebApiConstants.AppRootNoLanguage + \"/{appName}/data/{contentType}/{guid:guid}/{field}\")] // new, v13\n[Route(OqtWebApiConstants.AppRootPathOrLang + \"/{appName}/data/{contentType}/{guid:guid}/{field}\")] // new, v13\n[Route(OqtWebApiConstants.AppRootPathAndLang + \"/{appName}/data/{contentType}/{guid:guid}/{field}\")] // new, v13\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamController() : OqtStatefulControllerBase(\"Adam\"), IAdamController<int>\n{\n    private RealController Real => GetService<RealController>();\n\n    // Note: #AdamItemDto - as of now, we must use object because System.Io.Text.Json will otherwise not convert the object correctly :(\n\n    [HttpPost]\n    [HttpPut]\n    public /*AdamItemDto*/object Upload(int appId, string contentType, Guid guid, string field, string subFolder = \"\", bool usePortalRoot = false) \n        => Real.Upload(new(Request), appId, contentType, guid, field, subFolder, usePortalRoot);\n\n    [HttpGet(\"items\")]\n    public IEnumerable</*AdamItemDto*/object> Items(int appId, string contentType, Guid guid, string field, string subfolder, bool usePortalRoot = false)\n        => Real.Items(appId, contentType, guid, field, subfolder, usePortalRoot)\n            // Fix bug with .net 7 so that we really return a fresh IEnumerable and not the initial list\n            // Otherwise System.Text.Json sees the List<AdamItemDto> and will not convert additional properties on the objects\n            .Select(e => e); \n\n    [HttpPost(\"folder\")]\n    public IEnumerable</*AdamItemDto*/object> Folder(int appId, string contentType, Guid guid, string field, string subfolder, string newFolder, bool usePortalRoot)\n        => Real.Folder(appId, contentType, guid, field, subfolder, newFolder, usePortalRoot)\n            // Fix bug with .net 7 so that we really return a fresh IEnumerable and not the initial list\n            // Otherwise System.Text.Json sees the List<AdamItemDto> and will not convert additional properties on the objects\n            .Select(e => e);\n\n    [HttpGet(\"delete\")]\n    public bool Delete(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, int id, bool usePortalRoot)\n        => Real.Delete(appId, contentType, guid, field, subfolder, isFolder, id, usePortalRoot );\n\n    [HttpGet(\"rename\")]\n    public bool Rename(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, int id, string newName, bool usePortalRoot)\n        => Real.Rename(appId, contentType, guid, field, subfolder, isFolder, id, newName, usePortalRoot);\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Adam/AppAssetsController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ToSic.Sxc.Oqt.Server.Adam;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Adam;\n\n// Release routes\n[Route(OqtWebApiConstants.AppRootNoLanguage + \"/{appName}/adam\")]\n[Route(OqtWebApiConstants.AppRootPathOrLang + \"/{appName}/adam\")]\n[Route(OqtWebApiConstants.AppRootPathAndLang + \"/{appName}/adam\")]\n\n// Beta routes\n//[Route(WebApiConstants.WebApiStateRoot + \"/adam/{appName}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppAssetsController(AppAssetsControllerBase.Dependencies services)\n    : WebApi.AppAssetsControllerBase(services, OqtAssetsFileHelper.RouteAdam, \"Assets\");"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/ApiExplorerController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing System.Reflection;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Eav.WebApi.Sys.ApiExplorer;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Oqt.Server.Code.Sys;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.Oqt.Server.Controllers.AppApi;\nusing ToSic.Sxc.Oqt.Server.Plumbing;\nusing ToSic.Sxc.Oqt.Server.Run;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Sxc.WebApi;\nusing ToSic.Sxc.WebApi.Sys;\nusing ToSic.Sys.Utils;\nusing RealController = ToSic.Eav.WebApi.Sys.ApiExplorer.ApiExplorerControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ValidateAntiForgeryToken]\n//[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[Authorize(Roles = RoleNames.Admin)]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ApiExplorerController() : OqtStatefulControllerBase(RealController.LogSuffix), IApiExplorerController\n{\n    private RealController Real => GetService<RealController>();\n    private Generator<Compiler> Compiler => GetService<Generator<Compiler>>();\n\n    [HttpGet]\n    public IActionResult Inspect(string path)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.Inspect(path, GetCompiledAssembly);\n    }\n\n    private Assembly GetCompiledAssembly(string path)\n    {\n        // get path from root\n        var alias = GetService<SiteState>()?.Alias ?? GetService<AliasResolver>().Alias;\n        var siteId = alias.SiteId;\n        var tenantId = alias.TenantId;\n        var appFolder = GetService<AppFolderLookupForWebApi>().GetAppFolder();\n        var pathFromRoot = OqtServerPaths.GetAppApiPath(tenantId, siteId, appFolder, path);\n\n        // Figure out the current edition\n        var blockOrNull = CtxHlp.BlockOptional;\n        var edition = blockOrNull\n            .NullOrGetWith(b => GetService<PolymorphConfigReader>().UseViewEditionOrGet(b));\n\n        var runtimeKey = blockOrNull?.Context.AppReaderRequired?.Specs.RuntimeKey;\n        var spec = new HotBuildSpec(blockOrNull?.AppId ?? KnownAppsConstants.AppIdEmpty, edition: edition, appName: blockOrNull?.AppOrNull?.Name, runtimeKey: runtimeKey);\n\n        Log.A($\"Controller path from root: {pathFromRoot}\");\n\n        // get full path\n        var oqtServerPaths = GetService<IServerPaths>();\n        var apiFile = oqtServerPaths.FullContentPath(pathFromRoot);\n\n        if (!System.IO.File.Exists(apiFile))\n            throw new($\"Error: can't find controller file: {pathFromRoot}\");\n\n        // get dll name\n        var controllerFolder = pathFromRoot.Substring(0, pathFromRoot.LastIndexOf(@\"\\\"));\n        var dllName = AppApiDynamicRouteValueTransformer.GetDllName(controllerFolder, apiFile);\n\n        return Compiler.New().Compile(apiFile, dllName, spec).Assembly;\n    }\n\n    [HttpGet]\n    [JsonFormatter(Casing = Casing.Camel)]\n    public AllApiFilesDto AppApiFiles(int appId) => Real.AppApiFiles(appId);\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/AppController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.DataSources.Sys;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.Oqt.Server.Installation;\nusing RealController = ToSic.Sxc.Backend.Admin.AppControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n// [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)] can't be used, because it forces the security\n// token, which fails in the cases where the url is called using get, which should result in a download\n// [ValidateAntiForgeryToken] because the exports are called by the browser directly (new tab)\n// we can't set this globally (only needed for imports)\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppController() : OqtStatefulControllerBase(RealController.LogSuffix), IAppController\n{\n    private RealController Real => GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ICollection<AppDto> List(int zoneId)\n        => Real.List(zoneId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Host)]\n    public ICollection<AppDto> InheritableApps()\n        => Real.InheritableApps();\n\n    /// <inheritdoc />\n    [HttpDelete]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public void App(int zoneId, int appId, bool fullDelete = true)\n        => Real.App(zoneId, appId, fullDelete);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public void App(int zoneId, string name, int? inheritAppId = null) => Real.App(zoneId, name, inheritAppId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ICollection<SiteLanguageDto> Languages(int appId)\n        => Real.Languages(appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public AppExportInfoDto Statistics(int zoneId, int appId)\n        => Real.Statistics(zoneId, appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool FlushCache(int zoneId, int appId)\n        => Real.FlushCache(zoneId, appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    public IActionResult Export(int zoneId, int appId, bool includeContentGroups, bool resetAppGuid, bool assetsAdam, bool assetsSite, bool assetAdamDeleted = true) \n        => Real.Export(new(zoneId, appId, includeContentGroups, resetAppGuid, assetsAdam, assetsSite, assetAdamDeleted))\n            .ToHttpResponse();\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [Authorize(Roles = RoleNames.Admin)]\n    [ValidateAntiForgeryToken]\n    public async Task<bool> SaveData(int zoneId, int appId, bool includeContentGroups, bool resetAppGuid, bool withPortalFiles = false)\n        => (await Real.SaveData(new(zoneId, appId, includeContentGroups, resetAppGuid, WithSiteFiles: withPortalFiles))).Data;\n\n    /// <inheritdoc />\n    [HttpPost]\n    [Authorize(Roles = RoleNames.Host)]\n    [ValidateAntiForgeryToken]\n    public Task<ImportResultDto> Reset(int zoneId, int appId, bool withPortalFiles = false) \n        => Real.Reset(zoneId, appId, CtxHlp.BlockOptional.Context.Site.DefaultCultureCode, withPortalFiles);\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public List<AppStackDataRaw> GetStack(int appId, string part, string key = null, Guid? view = null)\n        => Real.GetStack(appId, part, key, view);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ImportResultDto Import(int zoneId)\n    {\n        // Ensure that Hot Reload is not enabled or try to disable it.\n        HotReloadEnabledCheck.Check();\n        return Real.Import(new(Request), zoneId, Request.Form[\"Name\"]);\n    }\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<PendingAppDto> GetPendingApps(int zoneId)\n        => Real.GetPendingApps(zoneId);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ImportResultDto InstallPendingApps(int zoneId, [FromBody] IEnumerable<PendingAppDto> pendingApps)\n    {\n        // Ensure that Hot Reload is not enabled or try to disable it.\n        HotReloadEnabledCheck.Check();\n        return Real.InstallPendingApps(zoneId, pendingApps);\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/AppExtensionsController.cs",
    "content": "using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.Oqt.Server.Installation;\nusing RealController = ToSic.Sxc.Backend.Admin.AppExtensionsControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n// Release routes - same base routes as AppController\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppExtensionsController() : OqtStatefulControllerBase(RealController.LogSuffix), IAppExtensionsController\n{\n    private RealController Real => GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ExtensionsResultDto Extensions(int appId)\n        => Real.Extensions(appId);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public PreflightResultDto InstallPreflight(int appId, [FromQuery] string editions = \"\")\n    {\n        HotReloadEnabledCheck.Check();\n        return Real.InstallPreflight(new(Request), appId, editions);\n    }\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public PreflightResultDto InstallPreflightFrom(int appId, [FromBody] string[] urls, [FromQuery] string editions = \"\")\n    {\n        HotReloadEnabledCheck.Check();\n        return Real.InstallPreflightFrom(urls, appId, editions);\n    }\n\n    /// <inheritdoc />\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Install(int zoneId, int appId, [FromQuery] string editions = \"\", bool overwrite = false)\n    {\n        HotReloadEnabledCheck.Check();\n        return Real.Install(new(Request), zoneId, appId, editions, overwrite);\n    }\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool InstallFrom(int zoneId, int appId, [FromBody] string[] urls, [FromQuery] string editions = \"\", bool overwrite = false)\n    {\n        HotReloadEnabledCheck.Check();\n        return Real.InstallFrom(urls, zoneId, appId, editions, overwrite);\n    }\n\n    /// <inheritdoc />\n    [HttpGet]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ExtensionInspectResultDto Inspect(int appId, string name, string edition = null)\n        => Real.Inspect(appId, name, edition);\n\n    /// <inheritdoc />\n    //[HttpPut(\"{name}\")]\n    [HttpPost(\"{name}\")]\n    //[HttpPost(\"extensions\")]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Configuration(int appId, string name, [FromBody] ExtensionManifest configuration)\n        => Real.Configuration(appId, name, configuration);\n\n    ///// <summary>\n    ///// Alias POST endpoint for front-ends posting to /appExtensions/extensions with query parameters.\n    ///// Matches DNN plural POST behavior to avoid 405 errors if client uses POST instead of PUT.\n    ///// </summary>\n    //[HttpPost(\"extensions\")]\n    //[ValidateAntiForgeryToken]\n    //[Authorize(Roles = RoleNames.Admin)]\n    //public bool ExtensionsPostAlias(int appId, string name, [FromBody] ExtensionManifest configuration)\n    //    => Real.Extension(appId, name, configuration);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IActionResult Download(int appId, string name)\n        => Real.Download(appId, name).ToHttpResponse();\n\n    /// <inheritdoc />\n    [HttpDelete]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Delete(int appId, string name, string edition = null, bool force = false, bool withData = false)\n        => Real.Delete(appId, name, edition, force, withData);\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/AppFilesController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Apps.Sys.EditAssets;\nusing ToSic.Sxc.Backend.Admin.AppFiles;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Admin.AppFiles.AppFilesControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <summary>\n/// This one supplies portal-wide (or cross-portal) settings / configuration\n/// </summary>\n[ValidateAntiForgeryToken]\n[Authorize(Roles = RoleNames.Admin)]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppFilesController() : OqtStatefulControllerBase(RealController.LogSuffix), IAppFilesController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    [HttpGet]\n    public ICollection<string> All(\n        [FromQuery] int appId,\n        [FromQuery] bool global,\n        [FromQuery] string path = null,\n        [FromQuery] string mask = \"*.*\",\n        [FromQuery] bool withSubfolders = false,\n        [FromQuery] bool returnFolders = false\n    ) => Real.All(appId, global, path, mask, withSubfolders, returnFolders);\n\n    [HttpGet]\n    public AssetEditInfo Asset(\n        [FromQuery] int appId,\n        [FromQuery] int templateId = 0,\n        [FromQuery] string path = null, // identifier is always one of these two\n        [FromQuery] bool global = false\n    ) => Real.Asset(appId, templateId, path, global);\n\n    [HttpPost]\n    public bool Create(\n        [FromQuery] int appId,\n        [FromQuery] string path,\n        [FromQuery] bool global,\n        [FromQuery] string templateKey\n    ) => Real.Create(appId, path, global, templateKey);\n\n    [HttpPost]\n    public bool Asset(\n        [FromQuery] int appId,\n        [FromBody] AssetEditInfo template,\n        [FromQuery] int templateId = 0,\n        [FromQuery] string path = null, // identifier is either template Id or path\n        // todo w/SPM - global never seems to be used - must check why and if we remove or add to UI\n        [FromQuery] bool global = false\n    ) => Real.Asset(appId, template, templateId, path, global);\n\n    [HttpGet]\n    public TemplatesDto GetTemplates(string purpose = null, string type = null) => Real.GetTemplates(purpose, type);\n\n    [HttpGet]\n    public TemplatePreviewDto Preview(int appId, string path, string templateKey, bool global = false)\n        => Real.Preview(appId, path, templateKey, global);\n\n    [HttpGet]\n    public AllFilesDto AppFiles(int appId, [FromQuery] string path = null, [FromQuery] string mask = null) => Real.AppFiles(appId, path, mask);\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/AppInternalsController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.AppInternalsControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <summary>\n/// Proxy Class to the AppInternalsController (Web API Controller)\n/// </summary>\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppInternalsController() : OqtStatefulControllerBase(RealController.LogSuffix), IAppInternalsController\n{\n    private RealController Real => GetService<RealController>();\n\n    /// <inheritdoc/>\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public AppInternalsDto Get(int appId)\n        => Real.Get(appId);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/AppPartsController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Admin.AppPartsControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n// [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)] can't be used, because it forces the security\n// token, which fails in the cases where the url is called using get, which should result in a download\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppPartsController() : OqtStatefulControllerBase(RealController.LogSuffix), IAppPartsController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    #region Parts Export/Import\n\n    /// <inheritdoc />\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ExportPartsOverviewDto Get(int zoneId, int appId, string scope) => Real.Get(zoneId: zoneId, appId: appId, scope: scope);\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    public IActionResult Export(int zoneId, int appId, string contentTypeIdsString, string entityIdsString, string templateIdsString)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.Export(zoneId: zoneId, appId: appId, contentTypeIdsString: contentTypeIdsString, entityIdsString: entityIdsString, templateIdsString: templateIdsString);\n    }\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ImportResultDto Import(int zoneId, int appId) \n        => Real.Import(uploadInfo: new(Request), zoneId: zoneId, appId: appId);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/CodeController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Admin.CodeControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeController() : OqtControllerBase(false, RealController.LogSuffix)\n{\n    private RealController Real => GetService<RealController>();\n\n    [HttpGet]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<RealController.HelpItem> InlineHelp(string language)\n        => Real.InlineHelp(language);\n\n    [HttpGet]\n    [Authorize(Roles = RoleNames.Host)]\n    public RichResult GenerateDataModels(int appId, string generator, string edition = null, int configurationId = 0)\n        => Real.GenerateDataModels(appId, edition, generator: generator, configurationId: configurationId);\n\n    // #MigrateSimpleDataToSysDataAccess\n    //[HttpGet]\n    //[JsonFormatter]\n    //[Authorize(Roles = RoleNames.Host)]\n    //public EditionsDto GetEditions(int appId)\n    //    => Real.GetEditions(appId);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/DataController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Oqt.Server.Controllers;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <summary>\n/// Web API Controller for app data bundles etc.\n/// </summary>\n//[SupportedModules(\"2sxc,2sxc-app\")]\n//[DnnLogExceptions]\n[Authorize(Roles = RoleNames.Admin)]\n[AutoValidateAntiforgeryToken]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DataController() : OqtStatefulControllerBase(DataControllerReal.LogSuffix), IAdminDataController\n{\n    private DataControllerReal Real => GetService<DataControllerReal>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public IActionResult BundleExport(int appId, Guid exportConfiguration, int indentation = 0)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.BundleExport(appId, exportConfiguration, indentation);\n    }\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ImportResultDto BundleImport(int zoneId, int appId)\n        => Real.BundleImport(new(Request), zoneId, appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public bool BundleSave(int appId, Guid exportConfiguration, int indentation = 0)\n        => Real.BundleSave(appId, exportConfiguration, indentation);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public bool BundleRestore(string fileName, int zoneId, int appId)\n        => Real.BundleRestore(fileName, zoneId, appId);\n\n    ///// <inheritdoc />\n    //[HttpGet]\n    //[Authorize(Roles = RoleNames.Host)]\n    //public IReadOnlyList<WorkEntityRecycleBin.RecycleBinItem> GetRecycleBin(int appId)\n    //    => Real.GetRecycleBin(appId);\n\n    /// <inheritdoc />\n    [HttpPost]\n    [Authorize(Roles = RoleNames.Host)]\n    public void Recycle(int appId, int transactionId)\n        => Real.Recycle(appId, transactionId);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/DialogController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Admin.DialogControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <summary>\n/// This one supplies portal-wide (or cross-portal) settings / configuration\n/// </summary>\n//[SupportedModules(\"2sxc,2sxc-app\")]\n//[DnnLogExceptions]\n[Authorize(Roles = RoleNames.Admin)]\n[AutoValidateAntiforgeryToken]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ApiController]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DialogController() : OqtStatefulControllerBase(RealController.LogSuffix), IDialogController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    [HttpGet]\n    public DialogContextStandaloneDto Settings(int appId) => Real.Settings(appId);\n        \n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/EntityController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.ImportExport.Sys.Options;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.EntityControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <summary>\n/// Proxy Class to the EAV EntitiesController (Web API Controller)\n/// </summary>\n/// <remarks>\n/// Because the JSON call is made in a new window, they won't contain any http-headers like module-id or security token.\n/// So we can't use the classic protection attributes like:\n/// - [SupportedModules(\"2sxc,2sxc-app\")]\n/// - [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n/// - [ValidateAntiForgeryToken]\n/// Instead, the method itself must do additional security checking.\n/// Security checking is possible, because the cookie still contains user information\n/// </remarks>\n//[DnnLogExceptions]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EntityController() : OqtStatefulControllerBase(RealController.LogSuffix), IEntityController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    /// <inheritdoc/>\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<Dictionary<string, object>> List(int appId, string contentType) => Real.List(appId, contentType);\n\n\n    /// <inheritdoc/>\n    [HttpDelete]\n    [ValidateAntiForgeryToken]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public void Delete([FromQuery] string contentType,\n        [FromQuery] int appId,\n        [FromQuery] int? id = null,\n        [FromQuery] Guid? guid = null,\n        [FromQuery] bool force = false,\n        [FromQuery] int? parentId = null,\n        [FromQuery] string parentField = null) =>\n        Real.Delete(contentType, appId, id, guid, force, parentId, parentField);\n\n\n    /// <inheritdoc/>\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public IActionResult Json(int appId, int id, string prefix, bool withMetadata)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.Json(appId, id, prefix, withMetadata);\n    }\n\n\n    /// <inheritdoc/>\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public IActionResult Download(\n        int appId,\n        string language,\n        string defaultLanguage,\n        string contentType,\n        ExportSelection recordExport, \n        ExportResourceReferenceMode resourcesReferences,\n        ExportLanguageResolution languageReferences, \n        string selectedIds = null)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.Download(appId, language, defaultLanguage, contentType, recordExport, resourcesReferences,\n            languageReferences, selectedIds);\n    }\n\n\n    /// <inheritdoc/>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ContentImportResultDto XmlPreview(ContentImportArgsDto args) => Real.XmlPreview(args);\n\n\n    /// <inheritdoc/>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ContentImportResultDto XmlUpload(ContentImportArgsDto args) => Real.XmlUpload(args);\n\n\n    /// <inheritdoc/>\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Upload(EntityImportDto args) => Real.Upload(args);\n\n\n    //// New feature in 11.03 - Usage Statistics\n    //// not final yet, so no [HttpGet]\n    //public dynamic Usage(int appId, Guid guid) => Real.Usage(appId, guid);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/FeatureController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.WebApi.Sys.Admin.Features;\nusing ToSic.Eav.WebApi.Sys.Licenses;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sys.Capabilities.Features;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.Features.FeatureControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n[ValidateAntiForgeryToken]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class FeatureController() : OqtStatefulControllerBase(RealController.LogSuffix), IFeatureController\n{\n    private RealController Real => GetService<RealController>();\n\n    [HttpGet]\n    [Authorize(Roles = RoleNames.Admin)]\n    public FeatureStateDto Details(string nameId) => Real.Details(nameId);\n\n    /// <summary>\n    /// POST updated features JSON configuration.\n    /// </summary>\n    /// <remarks>\n    /// Added in 2sxc 13\n    /// </remarks>\n    [HttpPost]\n    [Authorize(Roles = RoleNames.Host)]\n    public bool SaveNew([FromBody] List<FeatureStateChange> changes) => Real.SaveNew(changes);\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/FieldController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.FieldControllerReal;\n// ReSharper disable RouteTemplates.MethodMissingRouteParameters\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n[ValidateAntiForgeryToken]\n[Authorize(Roles = RoleNames.Admin)]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class FieldController() : OqtStatefulControllerBase(RealController.LogSuffix), IFieldController\n{\n    private RealController Real => GetService<RealController>();\n\n    #region Fields - Get, Reorder, Data-Types (for dropdown), etc.\n\n    /// <summary>\n    /// Returns the configuration for a content type\n    /// </summary>\n    [HttpGet]\n    public IEnumerable<ContentTypeFieldDto> All(int appId, string staticName) => Real.All(appId, staticName);\n\n    /// <summary>\n    /// Used to be GET ContentType/DataTypes\n    /// </summary>\n    [HttpGet]\n    public string[] DataTypes(int appId) => Real.DataTypes(appId);\n\n    /// <summary>\n    /// Used to be GET ContentType/InputTypes\n    /// </summary>\n    [HttpGet]\n    public ICollection<InputTypeInfo> InputTypes(int appId) => Real.InputTypes(appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    public Dictionary<string, string> ReservedNames() => AttributeNames.ReservedNames;\n\n    /// <summary>\n    /// Used to be GET ContentType/AddField\n    /// </summary>\n    [HttpPost]\n    public int Add(int appId, int contentTypeId, string staticName, string type, string inputType, int index)\n        => Real.Add(appId, contentTypeId, staticName, type, inputType, index);\n\n    /// <summary>\n    /// Used to be GET ContentType/DeleteField\n    /// </summary>\n    [HttpDelete]\n    public bool Delete(int appId, int contentTypeId, int attributeId)\n        => Real.Delete(appId, contentTypeId, attributeId);\n\n    /// <summary>\n    /// Used to be GET ContentType/Reorder\n    /// </summary>\n    [HttpPost]\n    public bool Sort(int appId, int contentTypeId, string order)\n        => Real.Sort(appId, contentTypeId, order);\n\n\n    /// <summary>\n    /// Used to be GET ContentType/UpdateInputType\n    /// </summary>\n    [HttpPost]\n    public bool InputType(int appId, int attributeId, string inputType)\n        => Real.InputType(appId, attributeId, inputType);\n\n    #endregion\n\n    /// <summary>\n    /// Used to be GET ContentType/Rename\n    /// </summary>\n    [HttpPost]\n    public void Rename(int appId, int contentTypeId, int attributeId, string newName)\n        => Real.Rename(appId, contentTypeId, attributeId, newName);\n\n    #region Sharing and Inheriting\n\n    [HttpGet]\n    public IEnumerable<ContentTypeFieldDto> GetSharedFields(int appId, int attributeId = default)\n        => Real.GetSharedFields(appId, attributeId);\n\n    [HttpGet]\n    public IEnumerable<ContentTypeFieldDto> GetAncestors(int appId, int attributeId)\n        => Real.GetAncestors(appId, attributeId);\n\n    [HttpGet]\n    public IEnumerable<ContentTypeFieldDto> GetDescendants(int appId, int attributeId)\n        => Real.GetDescendants(appId, attributeId);\n\n    [HttpPost]\n    public bool Share(int appId, int attributeId, bool share, bool hide = false)\n        => Real.Share(appId, attributeId, share, hide);\n\n    [HttpPost]\n    public bool Inherit(int appId, int attributeId, Guid inheritMetadataOf)\n        => Real.Inherit(appId, attributeId, inheritMetadataOf);\n\n    [HttpPost]\n    public bool AddInheritedField(int appId, int contentTypeId, string sourceType, Guid sourceField, string name)\n        => Real.AddInheritedField(appId, contentTypeId, sourceType, sourceField, name);\n\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/MetadataController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.WebApi.Sys.Admin.Metadata;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.Metadata.MetadataControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <inheritdoc cref=\"IMetadataController\" />\n[ValidateAntiForgeryToken]\n[Authorize(Roles = RoleNames.Admin)]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class MetadataController() : OqtStatefulControllerBase(RealController.LogSuffix), IMetadataController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    [HttpGet]\n    public MetadataListDto Get(int appId, int targetType, string keyType, string key, string contentType = null)\n        => Real.Get(appId, targetType, keyType, key, contentType);\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/OqtApiInspector.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing System.Reflection;\nusing ToSic.Eav.WebApi.Sys.ApiExplorer;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtApiInspector() : ServiceBase(OqtConstants.OqtLogPrefix), IApiInspector\n{\n    public bool IsBody(ParameterInfo paramInfo)\n    {\n        return paramInfo.CustomAttributes.Any(ca => ca.AttributeType == typeof(FromBodyAttribute));\n    }\n\n    public List<string> GetHttpVerbs(MethodInfo methodInfo)\n    {\n        var httpMethods = new List<string>();\n\n        var getAtt = methodInfo.GetCustomAttribute<HttpGetAttribute>();\n        if (getAtt != null)\n            httpMethods.Add(getAtt.HttpMethods.First());\n\n        var postAtt = methodInfo.GetCustomAttribute<HttpPostAttribute>();\n        if (postAtt != null)\n            httpMethods.Add(postAtt.HttpMethods.First());\n\n        var putAtt = methodInfo.GetCustomAttribute<HttpPutAttribute>();\n        if (putAtt != null)\n            httpMethods.Add(putAtt.HttpMethods.First());\n\n        var deleteAtt = methodInfo.GetCustomAttribute<HttpDeleteAttribute>();\n        if (deleteAtt != null)\n            httpMethods.Add(deleteAtt.HttpMethods.First());\n\n        var acceptVerbsAtt = methodInfo.GetCustomAttribute<AcceptVerbsAttribute>();\n        if (acceptVerbsAtt != null)\n            httpMethods.AddRange(acceptVerbsAtt.HttpMethods);\n\n        return httpMethods;\n    }\n\n    public ApiSecurityDto GetSecurity(MemberInfo member)\n    {\n        var oqtAuthList = member.GetCustomAttributes<AuthorizeAttribute>().ToList();\n\n        return new()\n        {\n            ignoreSecurity = member.GetCustomAttribute<AllowAnonymousAttribute>() != null,\n            allowAnonymous = oqtAuthList.Any(a => a.Roles == RoleNames.Everyone),\n\n            requireVerificationToken = GetRequireVerificationToken(member),\n            _validateAntiForgeryToken = member.GetCustomAttribute<ValidateAntiForgeryTokenAttribute>() != null,\n            _autoValidateAntiforgeryToken = member.GetCustomAttribute<AutoValidateAntiforgeryTokenAttribute>() != null,\n            _ignoreAntiforgeryToken = member.GetCustomAttribute<IgnoreAntiforgeryTokenAttribute>() != null,\n\n            superUser = oqtAuthList.Any(a => a.Roles == RoleNames.Host),\n            admin = oqtAuthList.Any(a => a.Roles == RoleNames.Admin),\n            edit = oqtAuthList.Any(a => a.Policy == PolicyNames.EditModule),\n            view = oqtAuthList.Any(a => a.Policy == PolicyNames.ViewModule),\n                \n            // Supported-modules attribute do not exist in Oqtane\n            requireContext = oqtAuthList.Any(),\n        };\n    }\n\n    /// AntiForgery token validation is enabled or skipped based on:\n    /// - ValidateAntiForgeryToken attribute\n    /// - AutoValidateAntiforgeryToken attribute for unsafe HTTP methods\n    /// - IgnoreAntiforgeryToken attribute\n    private bool GetRequireVerificationToken(MemberInfo member)\n    {\n        var (validateAntiForgeryToken, autoValidateAntiforgeryToken, ignoreAntiforgeryToken) = GetLastAntiForgeryTokenAttribute(member);\n\n        // ValidateAntiForgeryToken attribute enables AntiForgery token validation,\n        // AutoValidateAntiforgeryToken attribute enables AntiForgery token validation for all unsafe HTTP methods.\n        // IgnoreAntiforgeryToken attribute skips AntiForgery token validation.\n        return !ignoreAntiforgeryToken && (validateAntiForgeryToken || (autoValidateAntiforgeryToken && IsUnsafeHttpMethod(member)));\n    }\n\n    private static (bool validateAntiForgeryToken, bool autoValidateAntiforgeryToken, bool ignoreAntiforgeryToken)\n        GetLastAntiForgeryTokenAttribute(MemberInfo member)\n    {\n        // All AntiForgeryToken attributes have the same attribute order (Order=1000).\n        // In practice only one AntiForgeryToken attribute should be used per member.\n        // If we have more than one, only the last AntiForgeryToken attribute prevails (other are ignored).\n        // This is the reason why we try to find only last of the AntiForgeryToken attributes on member.\n        var validateAntiForgeryToken = false;\n        var autoValidateAntiforgeryToken = false;\n        var ignoreAntiforgeryToken = false;\n\n        var orderedList = member.CustomAttributes.ToList();\n        for (var i = orderedList.Count - 1; i > 0; i--)\n        {\n            if (orderedList[i].AttributeType == typeof(ValidateAntiForgeryTokenAttribute))\n            {\n                validateAntiForgeryToken = true;\n                break;\n            }\n\n            if (orderedList[i].AttributeType == typeof(AutoValidateAntiforgeryTokenAttribute))\n            {\n                autoValidateAntiforgeryToken = true;\n                break;\n            }\n\n            if (orderedList[i].AttributeType == typeof(IgnoreAntiforgeryTokenAttribute))\n            {\n                ignoreAntiforgeryToken = true;\n                break;\n            }\n        }\n\n        return (validateAntiForgeryToken, autoValidateAntiforgeryToken, ignoreAntiforgeryToken);\n    }\n\n    // AutoValidateAntiforgeryTokenAttribute causes validation of antiforgery tokens for all unsafe HTTP methods.\n    // An antiforgery token is required for HTTP methods other than GET, HEAD, OPTIONS and TRACE.\n    private bool IsUnsafeHttpMethod(MemberInfo member)\n    {\n        // HttpVerbs cant be on class, so just return true.\n        if (member is not MethodInfo method) return true;\n        // Find unsafe HTTP methods.\n        var safeHttpMethods = new List<string>() { \"GET\", \"HEAD\", \"OPTIONS\", \"TRACE\" };\n        var httpVerbs = GetHttpVerbs(method);\n        httpVerbs.RemoveAll(t => safeHttpMethods.Contains(t));\n        return httpVerbs.Any();\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/QueryController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.WebApi.Sys.Admin.Query;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Admin.Query.QueryControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <summary>\n/// Proxy Class to the EAV PipelineDesignerController (Web API Controller)\n/// </summary>\n[ValidateAntiForgeryToken]\n[Authorize(Roles = RoleNames.Admin)]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class QueryController() : OqtStatefulControllerBase(RealController.LogSuffix), IQueryController\n{\n    private RealController Real => GetService<RealController>();\n\n    [HttpGet]\n    public QueryDefinitionDto Get(int appId, int? id = null) =>\n        Real.Get(appId, id);\n\n    [HttpGet]\n    public IEnumerable<DataSourceDto> DataSources(int zoneId, int appId) =>\n        Real.DataSources(new(zoneId, appId));\n\n    [HttpPost]\n    public QueryDefinitionDto Save([FromBody] QueryDefinitionDto data, int appId, int id) =>\n        Real.Save(data, appId, id);\n\n    [HttpGet]\n    public QueryRunDto RunDev(int appId, int id, int top = 0) =>\n        Real.RunDev(appId, id, top);\n\n    [HttpGet]\n    public QueryRunDto DebugStream(int appId, int id, string from, string @out, int top = 25) =>\n        Real.DebugStream(appId, id, @from, @out, top);\n\n    [HttpGet]\n    public void Clone(int appId, int id) =>\n        Real.Clone(appId, id);\n\n    [HttpDelete]\n    public bool Delete(int appId, int id) =>\n        Real.DeleteIfUnused(appId, id);\n\n    [HttpPost]\n    public bool Import(EntityImportDto args) =>\n        Real.Import(args);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/TypeController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Admin.TypeControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <summary>\n/// This one supplies portal-wide (or cross-portal) settings / configuration\n/// </summary>\n//[SupportedModules(\"2sxc,2sxc-app\")]\n//[DnnLogExceptions]\n[Authorize(Roles = RoleNames.Admin)]\n[AutoValidateAntiforgeryToken]\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class TypeController() : OqtStatefulControllerBase(RealController.LogSuffix), ITypeController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<ContentTypeDto> List(int appId, string scope = null, bool withStatistics = false) => Real.List(appId, scope, withStatistics);\n\n\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ScopesDto Scopes(int appId) => Real.Scopes(appId);\n\n\n    [HttpGet]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ContentTypeDto Get(int appId, string contentTypeId, string scope = null) => Real.Get(appId, contentTypeId, scope);\n\n\n    [HttpDelete]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Delete(int appId, string staticName) => Real.Delete(appId, staticName);\n\n\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Save(int appId, [FromBody] Dictionary<string, object> item) => Real.Save(appId, item);\n\n\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Host)]\n    public bool AddGhost(int appId, string sourceNameId) => Real.AddGhost(appId, sourceNameId);\n\n\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public void SetTitle(int appId, int contentTypeId, int attributeId) => Real.SetTitle(appId, contentTypeId, attributeId);\n\n\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public IActionResult Json(int appId, string name)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.Json(appId, name);\n    }\n\n\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ImportResultDto Import(int zoneId, int appId) => Real.Import(new(Request), zoneId, appId);\n\n\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public IActionResult JsonBundleExport(int appId, Guid exportConfiguration, int indentation = 0)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.JsonBundleExport(appId, exportConfiguration, indentation);\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/ViewController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Backend.Views;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Admin.ViewControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n[AllowAnonymous] // necessary at this level, because otherwise download would fail\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ViewController : OqtStatefulControllerBase, IViewController\n{\n    public ViewController(LazySvc<Pages.Pages> pages) : base(RealController.LogSuffix)\n    {\n        this.ConnectLogs([\n            _pages = pages\n        ]);\n    }\n    private readonly LazySvc<Pages.Pages> _pages;\n\n    private RealController Real => GetService<RealController>();\n\n    /// <inheritdoc />\n    [HttpGet]\n    //[SupportedModules(\"2sxc,2sxc-app\")]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<ViewDetailsDto> All(int appId) => Real.All(appId);\n\n    /// <inheritdoc />\n    [HttpGet, HttpDelete]\n    //[SupportedModules(\"2sxc,2sxc-app\")]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Delete(int appId, int id) => Real.Delete(appId, id);\n\n    /// <inheritdoc />\n    [HttpGet]\n    [AllowAnonymous] // will do security check internally\n    public IActionResult Json(int appId, int viewId)\n    {\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.Json(appId, viewId);\n    }\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ImportResultDto Import(int zoneId, int appId) => Real.Import(new(Request), zoneId, appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    //[SupportedModules(\"2sxc,2sxc-app\")]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<ViewDto> Usage(int appId, Guid guid) => Real.UsagePreparations((views, blocks) =>\n    {\n        // create list with all 2sxc modules in this site\n        var allMods = _pages.Value.AllModulesWithContent(Real.SiteId);\n        Log.A($\"Found {allMods.Count} modules\");\n\n        return views.Select(vwb => _pages.Value.ViewDtoBuilder(vwb, blocks, allMods));\n    }).Usage(appId, guid);\n\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Admin/ZoneController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.WebApi.Sys.Zone;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Eav.WebApi.Sys.Admin.ZoneControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Admin;\n\n/// <summary>\n/// This one supplies portal-wide (or cross-portal) settings / configuration\n/// </summary>\n[ValidateAntiForgeryToken]\n[Authorize(Roles = RoleNames.Admin)]\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Admin}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Admin}\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ZoneController() : OqtStatefulControllerBase(RealController.LogSuffix), IZoneController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    public IList<SiteLanguageDto> GetLanguages() => Real.GetLanguages();\n\n    /// <inheritdoc />\n    [HttpGet]\n    public void SwitchLanguage(string cultureCode, bool enable) => Real.SwitchLanguage(cultureCode, enable);\n\n    /// <inheritdoc />\n    [HttpGet]\n    public SystemInfoSetDto GetSystemInfo() => Real.GetSystemInfo();\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/App/AppAssetsController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ToSic.Sxc.Oqt.Server.Adam;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.App;\n//[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)] // use view, all methods must re-check permissions\n//[Authorize(Roles = RoleNames.Everyone)] commented because of http403 issue\n// TODO: 2DM please check permissions\n\n// Release routes\n[Route(OqtWebApiConstants.AppRootNoLanguage + \"/{appName}/assets\")]\n[Route(OqtWebApiConstants.AppRootPathOrLang + \"/{appName}/assets\")]\n[Route(OqtWebApiConstants.AppRootPathAndLang + \"/{appName}/assets\")]\n\n// Beta routes\n//[Route(WebApiConstants.WebApiStateRoot + \"/assets/{appName}\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppAssetsController(AppAssetsControllerBase.Dependencies services)\n    : AppAssetsControllerBase(services, OqtAssetsFileHelper.RouteAssets, \"Assets\");"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/App/AppDataController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Http.Extensions;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Eav.WebApi.Sys.App;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing static ToSic.Eav.WebApi.Sys.EavWebApiConstants;\nusing RealController = ToSic.Sxc.Backend.App.AppDataControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.App;\n\n/// <inheritdoc />\n[ApiController]\n\n// Release routes\n[Route(OqtWebApiConstants.AppRootNoLanguage+ \"/{appPath}/content\")]\n[Route(OqtWebApiConstants.AppRootPathOrLang+ \"/{appPath}/content\")]\n[Route(OqtWebApiConstants.AppRootPathAndLang + \"/{appPath}/content\")]\n[Route(OqtWebApiConstants.AppRootNoLanguage + \"/{appPath}/data\")] // new, v13\n[Route(OqtWebApiConstants.AppRootPathOrLang + \"/{appPath}/data\")] // new, v13\n[Route(OqtWebApiConstants.AppRootPathAndLang + \"/{appPath}/data\")] // new, v13\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppDataController() : OqtStatefulControllerBase(RealController.LogSuffix), IAppDataController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    #region Get List / all of a certain content-type\n\n    /// <inheritdoc />\n    [HttpGet(\"{contentType}\")]\n    [AllowAnonymous]   // will check security internally, so assume no requirements\n    public IEnumerable<IDictionary<string, object>> GetEntities(string contentType, string appPath = default, [FromQuery] IDictionary<string, string> queryParams = null)\n        => Real.GetEntities(contentType, appPath, new Uri(Request.GetDisplayUrl()));\n\n    #endregion\n\n\n    #region GetOne by ID / GUID\n\n    /// <inheritdoc />\n    [HttpGet(\"{contentType}/{id}\")]\n    [AllowAnonymous] // will check security internally, so assume no requirements\n    public IDictionary<string, object> GetOne(string contentType, string id, string appPath = default, [FromQuery] IDictionary<string, string> queryParams = null) \n        => Real.GetOne(contentType, id, appPath, new Uri(Request.GetDisplayUrl()));\n\n    #endregion\n\n    #region Create\n\n    /// <inheritdoc />\n    [HttpPost(\"{contentType}\")]\n    [HttpPost(\"{contentType}/{id}\")]\n    [AllowAnonymous] // will check security internally, so assume no requirements\n    public IDictionary<string, object> CreateOrUpdate(\n        string contentType,\n        [FromBody] Dictionary<string, object> newContentItem,\n        int? id = null,\n        string appPath = null)\n        =>Real.CreateOrUpdate(contentType, newContentItem, id, appPath);\n\n    #endregion\n\n    #region Delete\n\n    /// <inheritdoc />\n    [HttpDelete(\"{contentType}/{id}\")]\n    [AllowAnonymous]   // will check security internally, so assume no requirements\n    public void Delete(string contentType, string id, string appPath = null) \n        => Real.Delete(contentType, id, appPath);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/App/AppQueryController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.WebApi.Sys.Admin.App;\nusing ToSic.Eav.WebApi.Sys.Admin.Query;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.App.AppQueryControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.App;\n\n// Release routes\n[Route(OqtWebApiConstants.AppRootNoLanguage)]\n[Route(OqtWebApiConstants.AppRootPathOrLang)]\n[Route(OqtWebApiConstants.AppRootPathAndLang)]\n\n[AllowAnonymous] // All functions will check security internally, so assume no requirements\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppQueryController() : OqtStatefulControllerBase(RealController.LogSuffix), IAppQueryController\n{\n    private RealController Real => GetService<RealController>();\n\n    // GET is separated from POST to solve HttpResponseException that happens when\n    // 'content-type' header is missing (or in GET request) on the endpoint that has [FromBody] in signature\n\n    [HttpGet(\"{appPath}/\" + AppParts.Query + \"/{name}\")]\n    [HttpGet(\"{appPath}/\" + AppParts.Query + \"/{name}/{stream}\")]\n    public IDictionary<string, IEnumerable<EavLightEntity>> PublicQuery(\n        [FromRoute] string appPath,\n        [FromRoute] string name,\n        [FromRoute] string stream = null\n    ) => Real.PublicQuery(appPath, name, stream);\n\n    [HttpPost(\"{appPath}/\" + AppParts.Query + \"/{name}\")]\n    [HttpPost(\"{appPath}/\" + AppParts.Query + \"/{name}/{stream}\")]\n    public IDictionary<string, IEnumerable<EavLightEntity>> PublicQueryPost(\n        [FromRoute] string appPath,\n        [FromRoute] string name,\n        QueryParametersDtoFromClient more,\n        [FromRoute] string stream = null\n    ) => Real.PublicQueryPost(appPath, name, more, stream);\n\n    [HttpGet($\"{AppParts.Auto}/{AppParts.Query}\" + \"/{name}\")]\n    [HttpGet($\"{AppParts.Auto}/{AppParts.Query}\" + \"/{name}/{stream?}\")]\n    public IDictionary<string, IEnumerable<EavLightEntity>> Query(\n        [FromRoute] string name,\n        [FromQuery] int? appId = null,\n        [FromRoute] string stream = null,\n        [FromQuery] bool? includeGuid = false\n    ) => Real.Query(name, appId, stream, includeGuid);\n\n    [HttpPost($\"{AppParts.Auto}/{AppParts.Query}\" + \"/{name}\")]\n    [HttpPost($\"{AppParts.Auto}/{AppParts.Query}\" + \"/{name}/{stream?}\")]\n    public IDictionary<string, IEnumerable<EavLightEntity>> QueryPost(\n        [FromRoute] string name,\n        QueryParametersDtoFromClient more,\n        [FromQuery] int? appId = null,\n        [FromRoute] string stream = null,\n        [FromQuery] bool? includeGuid = false\n    ) => Real.QueryPost(name, more, appId, stream, includeGuid);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/App/AppSharedController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ToSic.Sxc.Oqt.Server.Adam;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.App;\n//[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)] // use view, all methods must re-check permissions\n//[Authorize(Roles = RoleNames.Everyone)] commented because of http403 issue\n// TODO: 2DM please check permissions\n\n// Release routes\n[Route(OqtWebApiConstants.SharedRootNoLanguage + \"/{appName}/\")]\n[Route(OqtWebApiConstants.SharedRootPathOrLang + \"/{appName}/\")]\n[Route(OqtWebApiConstants.SharedRootPathAndLang + \"/{appName}/\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppSharedController(AppAssetsControllerBase.Dependencies services)\n    : AppAssetsControllerBase(services, OqtAssetsFileHelper.RouteShared, \"Shared\");"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/App/CacheController.cs",
    "content": "using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Oqt.Server.Controllers;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.App;\n\n[Route(OqtWebApiConstants.AppRootNoLanguage)]\n[Route(OqtWebApiConstants.AppRootPathOrLang)]\n[Route(OqtWebApiConstants.AppRootPathAndLang)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CacheController() : OqtStatefulControllerBase(CacheControllerReal.LogSuffix)\n{\n    private CacheControllerReal Real => GetService<CacheControllerReal>();\n\n    [HttpPost(\"{appPath}/{controller}/{action}\")]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Flush([FromRoute] string appPath, [FromBody] AppCacheFlushSpecs specs)\n        => Real.Flush(appPath, specs);\n\n    [HttpPost($\"{AppParts.Auto}/{{controller}}/{{action}}\")]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Flush([FromBody] AppCacheFlushSpecs specs, [FromQuery] int? appId = null)\n        => Real.FlushAuto(appId, specs);\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/AppAssetsControllerBase.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Server.Adam;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.WebApi.Sys;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class AppAssetsControllerBase : OqtControllerBase\n{\n    private string Route { get; }\n\n    #region Dependencies\n\n    public record Dependencies(\n        IWebHostEnvironment HostingEnvironment,\n        LazySvc<AppFolderLookupForWebApi> AppFolder,\n        SiteState SiteState,\n        LazySvc<OqtAssetsFileHelper> FileHelper)\n        : DependenciesRecord(connect: [HostingEnvironment, AppFolder, SiteState, FileHelper]);\n\n    #endregion\n\n\n    protected AppAssetsControllerBase(Dependencies services, string route, string logSuffix): base(false, logSuffix)\n    {\n        Deps = services.ConnectServices(Log);\n        Route = route;\n    }\n\n    private Dependencies Deps;\n\n    [HttpGet(\"{*filePath}\")]\n    public IActionResult GetFile([FromRoute] string appName, [FromRoute] string filePath)\n    {\n        var l = Log.Fn<IActionResult>($\"{nameof(appName)}: {appName}; {nameof(filePath)}: {filePath}\");\n        try\n        {\n            if (appName == OqtWebApiConstants.Auto) appName = Deps.AppFolder.Value.GetAppFolder();\n\n            var alias = Deps.SiteState.Alias;\n            var fullFilePath = Deps.FileHelper.Value.GetFilePath(Deps.HostingEnvironment.ContentRootPath, alias, Route, appName, filePath);\n            if (string.IsNullOrEmpty(fullFilePath))\n                return l.Return(NotFound(), \"empty path\");\n\n            var fileBytes = System.IO.File.ReadAllBytes(fullFilePath);\n            var mimeType = OqtAssetsFileHelper.GetMimeType(fullFilePath);\n\n            var result = mimeType.StartsWith(\"image\") ? File(fileBytes, mimeType) :\n                new(fileBytes, mimeType) { FileDownloadName = Path.GetFileName(fullFilePath) };\n\n            return l.Return(result, \"found\");\n        }\n        catch\n        {\n            return l.Return(NotFound(), \"error\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Cms/BlockController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Apps.Sys.Ui;\nusing ToSic.Sxc.Backend.Cms;\nusing ToSic.Sxc.Backend.InPage;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.Oqt.Shared;\nusing RealController = ToSic.Sxc.Backend.Cms.BlockControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Cms;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Cms}\")]\n\n[ValidateAntiForgeryToken]\n[ApiController]\n// cannot use this, as most requests now come from a lone page [SupportedModules(\"2sxc,2sxc-app\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockController() : OqtStatefulControllerBase(RealController.LogSuffix), IBlockController\n{\n    private RealController Real => GetService<RealController>();\n\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public string Block(int parentId, string field, int index, string app = \"\", Guid? guid = null)\n        => Real.Block(parentId, field, index, app, guid);\n\n    /// <inheritdoc />\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public void Item(int? index = null) => Real.Item(index);\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public void App(int? appId) => Real.App(appId);\n\n    /// <inheritdoc />\n    [HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<AppUiInfo> Apps(string apps = null) => Real.Apps(apps);\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<ContentTypeUiInfo> ContentTypes() => Real.ContentTypes();\n\n    /// <inheritdoc />\n    [HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public IEnumerable<TemplateUiInfo> Templates() => Real.Templates();\n\n    /// <inheritdoc />\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n    //[Authorize(Roles = RoleNames.Registered)]\n    [Authorize(Roles = RoleNames.Admin)]\n    // TODO: 2DM please check permissions\n    public Guid? Template(int templateId, bool forceCreateContentGroup) => Real.Template(templateId, forceCreateContentGroup);\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public AjaxRenderDto Render(int templateId, string lang, string edition) => Real.Set(OqtConstants.UiRoot).Render(templateId, lang, edition);\n\n    /// <inheritdoc />\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Publish(string part, int index) => Real.Publish(part, index);\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Cms/ContentGroupController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Sxc.Backend.Cms;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Cms.ContentGroupControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Cms;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Cms}\")]\n\n[ValidateAntiForgeryToken]\n[ApiController]\n// cannot use this, as most requests now come from a lone page [SupportedModules(\"2sxc,2sxc-app\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentGroupController() : OqtStatefulControllerBase(RealController.LogSuffix), IContentGroupController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    [HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public EntityInListDto Header(Guid guid)\n        => Real.Header(guid);\n\n\n    // TODO: shouldn't be part of ContentGroupController any more, as it's generic now\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public void Replace(Guid guid, string part, int index, int entityId, bool add = false)\n        => Real.Replace(guid, part, index, entityId, add);\n\n\n    // TODO: WIP changing this from ContentGroup editing to any list editing\n    [HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public ReplacementListDto Replace(Guid guid, string part, int index)\n        => Real.Replace(guid, part, index);\n\n    [HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public List<EntityInListDto> ItemList(Guid guid, string part)\n        => Real.ItemList(guid, part);\n\n\n    // TODO: part should be handed in with all the relevant names! atm it's \"content\" in the content-block scenario\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool ItemList([FromQuery] Guid guid, List<EntityInListDto> list, [FromQuery] string part = null)\n        => Real.ItemList(guid, list, part);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Cms/EditController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Cms.EditControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Cms;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Cms}\")]\n\n[ValidateAntiForgeryToken]\n\n[ApiController]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EditController() : OqtStatefulControllerBase(RealController.LogSuffix), IEditController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    [HttpPost]\n    // [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n    [AllowAnonymous]   // will check security internally, so assume no requirements\n    public async Task<EditLoadDto> Load([FromBody] List<ItemIdentifier> items, int appId)\n        => await Real.Load(items, appId);\n\n    [HttpPost]\n    // [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public async Task<Dictionary<Guid, int>> Save([FromBody] EditSaveDto package, int appId, bool partOfPage)\n        => await Real.Save(package, appId, partOfPage);\n\n    /// <inheritdoc />\n    [HttpGet]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n    //[Authorize(Roles = RoleNames.Everyone)] commented because of http403 issue\n    // TODO: 2DM please check permissions\n    public LinkInfoDto LinkInfo(string link, int appId, string contentType = default, Guid guid = default, string field = default)\n        => Real.LinkInfo(link, appId, contentType, guid, field);\n\n    /// <inheritdoc />\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Publish(int id)\n        => Real.Publish(id);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Cms/HistoryController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.Persistence.Versions;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Cms.HistoryControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Cms;\n\n/// <summary>\n/// Controller for history of entities\n/// </summary>\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Cms}\")]\n[PrivateApi]\n[ValidateAntiForgeryToken]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HistoryController() : OqtStatefulControllerBase(RealController.LogSuffix), IHistoryController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public List<ItemHistory> Get(int appId, [FromBody] ItemIdentifier item)\n        => Real.Get(appId, item);\n\n    /// <inheritdoc />\n    [HttpPost]\n    //[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n    [Authorize(Roles = RoleNames.Admin)]\n    public bool Restore(int appId, [FromQuery(Name = \"changeId\")] int transactionId, [FromBody] ItemIdentifier item) \n        => Real.Restore(appId, transactionId, item);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Cms/ListController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Sxc.Backend.Cms.ListControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Cms;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + $\"/{AreaRoutes.Cms}\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + $\"/{AreaRoutes.Cms}\")]\n\n[ValidateAntiForgeryToken]\n//[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]\n[Authorize(Roles = RoleNames.Admin)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ListController() : OqtStatefulControllerBase(RealController.LogSuffix), IListController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    /// <inheritdoc />\n    /// <summary>\n    /// used to be GET Module/ChangeOrder\n    /// </summary>\n    [HttpPost]\n    public void Move(Guid? parent, string fields, int index, int toIndex) \n        => Real.Move(parent, fields, index, toIndex);\n\n    /// <inheritdoc />\n    /// <summary>\n    /// Used to be Get Module/RemoveFromList\n    /// </summary>\n    [HttpDelete]\n    public void Delete(Guid? parent, string fields, int index) \n        => Real.Delete(parent, fields, index);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/OqtWebApiConstants.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Shared;\nusing ToSic.Sxc.Web.Sys.EditUi;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static class OqtWebApiConstants\n{\n    public const string Auto = \"auto\";\n\n    // Release routes\n    // Names are a bit strange so they are the same length\n    // Which helps align values when they are used together later on\n\n    private const string RootNoLanguage = \"\";\n    private const string RootPathOrLang = \"{path-or-language}/\";\n    private const string RootPathAndLang = \"{path}/{subpath-or-language}/\";\n\n    public const string ApiRootNoLanguage = RootNoLanguage + \"api/sxc\";\n    public const string ApiRootPathOrLang = RootPathOrLang + \"api/sxc\";\n    public const string ApiRootPathAndLang = RootPathAndLang + \"api/sxc\";\n        \n    public const string AppRootNoLanguage = RootNoLanguage + \"app\";\n    public const string AppRootPathOrLang = RootPathOrLang + \"app\";\n    public const string AppRootPathAndLang = RootPathAndLang + \"app\";\n\n    public const string SharedRootNoLanguage = RootNoLanguage + \"2sxc/shared\";\n    public const string SharedRootPathOrLang = RootPathOrLang + \"2sxc/shared\";\n    public const string SharedRootPathAndLang = RootPathAndLang + \"2sxc/shared\";\n\n    // Beta routes\n    //public const string WebApiStateRoot = \"{alias:int}/api/sxc\";\n\n    // Endpoint mappings\n    public static readonly string[] SxcEndpointPatterns =\n    [\n        // Release routes\n        AppRootNoLanguage + \"/{appFolder}/api/{controller}/{action}\",\n        AppRootNoLanguage + \"/{appFolder}/{edition}/api/{controller}/{action}\",\n        AppRootPathOrLang + \"/{appFolder}/api/{controller}/{action}\",\n        AppRootPathOrLang + \"/{appFolder}/{edition}/api/{controller}/{action}\",\n        AppRootPathAndLang + \"/{appFolder}/api/{controller}/{action}\",\n        AppRootPathAndLang + \"/{appFolder}/{edition}/api/{controller}/{action}\"\n        //// Beta routes\n        //WebApiStateRoot + \"/app/{appFolder}/api/{controller}/{action}\",\n        //WebApiStateRoot + \"/app/{appFolder}/{edition}/api/{controller}/{action}\"\n    ];\n\n    //// Regex patterns to match endpoint mappings\n    //// This regular expression is for matching URL paths to 2sxc app custom endpoints.\n    //// For example, URL like this: \"/subportal/language/app/custom-2sxc-app-name/edition-name/api/MyCtr/Method\".\n    //// The given regular expression, `(.*/)?app/([\\w-]+)(/([\\w-]+))?/api/(.+)`, can be broken down as follows:\n    //// 1. `(.*/)?` : Optional 'alias' and/or 'language' (path ending with /)\n    ////               This captures zero or one occurrence of any characters (except a new line), ending with a forward slash('/').\n    ////               This part is optional because of the '?' after the group, which means it could match strings like \"subportal/\" or\n    ////               \"subportal/language/\" etc. and also an empty string.\n    //// 2. `app/` : This simply matches the exact string 'app/'.\n    //// 3. `([\\w -]+)` : 'custom 2sxc app name'\n    ////                  This captures zero or more word characters (letters, numbers, underscores) or hyphens.\n    ////                  This part could match strings like \"example-app\", \"blog6\", \"app3\", etc., but not an empty string.\n    //// 4. `(/([\\w -]+))?` : Optional one path segement with 2sxc app '/edition name',\n    ////                      This is an optional part, meaning it could match an empty string.\n    ////                      If present, it must start with a forward slash('/') followed by one or more word characters(letters, numbers, underscores) or hyphens.\n    ////                      This part could match strings like \"/live\", \"/bd5\", etc., but not a single '/'.\n    //// 5. `/api/` : This simply matches the exact string '/api/'.\n    //// 6. `(.+)` : API endpoint path 'controller/action'\n    ////             This captures one or more of any characters (except a new line).\n    ////             This part must be present and could match strings like \"get-data\", \"123\", \"user/data\", etc.\n    //public static readonly Regex SxcEndpointPathRegex = new(@\"(.*/)?app/([\\w-]+)(/([\\w-]+))?/api/(.+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n\n    // Regex patterns to match endpoint mappings\n    //public static readonly string[] SxcEndpointPathRegexPatterns = new[]\n    //{\n    //    // Release routes\n    //    @\"(.*/)?app/([\\w-]*)(/([\\w-]*))?/api/(.+)\",\n    //    //// Beta routes\n    //    //@\"(\\d+)/api/sxc/app/([\\w-]*)/api/([\\w-]*)/([\\w-]*)\",\n    //    //@\"(\\d+)/api/sxc/app/([\\w-]*)/([\\w-]*)/api/([\\w-]*)/([\\w-]*)\"\n    //};\n\n    // Dialogs for 2sxc UI\n    public static readonly List<(string url, string page, EditUiResourceSettings setting)> SxcDialogs =\n    [\n        ($\"/Modules/{OqtConstants.PackageName}/dist/quick-dialog/\",\n            $@\"Modules\\{OqtConstants.PackageName}\\dist\\quick-dialog\\index-raw.html\",\n            EditUiResourceSettings.QuickDialog),\n        ($\"/Modules/{OqtConstants.PackageName}/dist/ng-edit/\",\n            $@\"Modules\\{OqtConstants.PackageName}\\dist\\ng-edit\\index-raw.html\", EditUiResourceSettings.EditUi)\n    ];\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Sys/InsightsController.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Eav.Sys.Insights.InsightsControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Sys;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + \"/sys/[controller]/\")]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + \"/sys/[controller]/\")]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + \"/sys/[controller]/\")]\n    \n[ApiController]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class InsightsController() : OqtControllerBase(false, RealController.LogSuffix)\n{\n    private RealController Real => GetService<RealController>();\n\n\n    private ContentResult Wrap(string contents) => base.Content(contents, \"text/html\");\n\n    [HttpGet(\"{view}\")]\n    public ContentResult Details([FromRoute] string view, \n        [FromQuery] int? appId = null, [FromQuery] string key = null, [FromQuery] int? position = null,\n        [FromQuery] string type = null, [FromQuery] bool? toggle = null, string nameId = null, string filter = default)\n        => Wrap(Real.Details(view, appId, key, position, type, toggle, nameId, filter));\n\n    #region Logging aspects\n\n    /// <summary>\n    /// Make sure that these requests don't land in the normal api-log.\n    /// Otherwise each log-access would re-number what item we're looking at\n    /// </summary>\n    protected override string HistoryLogGroup => \"web-api.insights\";\n\n    /// <summary>\n    /// Enable/disable logging of access to insights\n    /// Only enable this if you have trouble developing insights, otherwise it clutters our logs\n    /// </summary>\n    internal const bool InsightsLoggingEnabled = false;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Sys/InstallController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.WebApi.Sys.Install;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.Oqt.Server.Installation;\nusing RealController = ToSic.Sxc.Backend.Sys.InstallControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Sys;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + \"/\" + AreaRoutes.Sys)]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + \"/\" + AreaRoutes.Sys)]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + \"/\" + AreaRoutes.Sys)]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class InstallController()\n    : OqtStatefulControllerBase(RealController.LogSuffix), IInstallController\n{\n    private RealController Real => GetService<RealController>();\n\n\n    /// <summary>\n    /// Make sure that these requests don't land in the normal api-log.\n    /// Otherwise each log-access would re-number what item we're looking at\n    /// </summary>\n    protected override string HistoryLogGroup { get; } = \"web-api.install\";\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    // [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    [Authorize(Roles = RoleNames.Host)]\n    public bool Resume() => Real.Resume();\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    [Authorize(Roles = RoleNames.Admin)]\n    // [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    public InstallAppsDto InstallSettings(bool isContentApp)\n        => Real.InstallSettings(isContentApp, CtxHlp.BlockOptional.Context.Module);\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    // [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n    [Authorize(Roles = RoleNames.Admin)]\n    [ValidateAntiForgeryToken]\n    public IActionResult RemotePackage(string packageUrl, string newName = null)\n    {\n        HotReloadEnabledCheck.Check(); // Ensure that Hot Reload is not enabled or try to disable it.\n        // Make sure the Scoped ResponseMaker has this controller context\n        CtxHlp.SetupResponseMaker();\n        return Real.RemotePackage(packageUrl, CtxHlp.BlockOptional?.Context.Module, newName);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Sys/LicenseController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.WebApi.Sys.Licenses;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing RealController = ToSic.Eav.WebApi.Sys.Licenses.LicenseControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Sys;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + \"/\" + AreaRoutes.Sys)]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + \"/\" + AreaRoutes.Sys)]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + \"/\" + AreaRoutes.Sys)]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LicenseController() : OqtStatefulControllerBase(\"License\"), ILicenseController\n{\n    private RealController Real => GetService<RealController>();\n\n\n\n    /// <summary>\n    /// Make sure that these requests don't land in the normal api-log.\n    /// Otherwise each log-access would re-number what item we're looking at\n    /// </summary>\n    protected override string HistoryLogGroup { get; } = \"web-api.license\";\n\n    #region License\n\n    /// <inheritdoc />\n    [HttpGet]\n    // [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    [Authorize(Roles = RoleNames.Host)]\n    public IEnumerable<LicenseDto> Summary() => Real.Summary();\n\n\n    /// <inheritdoc />\n    [HttpPost]\n    [ValidateAntiForgeryToken]\n    [Authorize(Roles = RoleNames.Host)]\n    public LicenseFileResultDto Upload() => Real.Upload(new(Request));\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    // [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Host)]\n    [Authorize(Roles = RoleNames.Host)]\n    public LicenseFileResultDto Retrieve() => Real.Retrieve();\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/WebApi/Sys/LogController.cs",
    "content": "﻿using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\nusing Oqtane.Shared;\nusing ToSic.Eav.WebApi.Sys.Logs;\nusing ToSic.Sxc.Oqt.Server.Controllers;\nusing ToSic.Sxc.Oqt.Server.Integration;\nusing RealController = ToSic.Eav.WebApi.Sys.Logs.LogControllerReal;\n\nnamespace ToSic.Sxc.Oqt.Server.WebApi.Sys;\n\n// Release routes\n[Route(OqtWebApiConstants.ApiRootNoLanguage + \"/\" + AreaRoutes.Sys)]\n[Route(OqtWebApiConstants.ApiRootPathOrLang + \"/\" + AreaRoutes.Sys)]\n[Route(OqtWebApiConstants.ApiRootPathAndLang + \"/\" + AreaRoutes.Sys)]\n\n// [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n[Authorize(Roles = RoleNames.Admin)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LogController() : OqtStatefulControllerBase(RealController.LogSuffix), ILogController\n{\n    private RealController Real => GetService<RealController>();\n\n\n\n    /// <inheritdoc />\n    [HttpGet]\n    public string EnableDebug(int duration = 1) => Real.EnableDebug(OqtLogging.ActivateForDuration, duration);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane/Module.css",
    "content": "/* Module Custom Styles */"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane/Module.js",
    "content": "var ToSic = window.ToSic = window.ToSic || {};\n\nToSic.Sxc = ToSic.Sxc || {};\n\nToSic.Sxc.Oqtane = ToSic.Sxc.Oqtane || {\n\n    registeredModules: new Map(),\n\n    registerReloadModule: function (dotNetObjectReference, moduleId) {\n        const debug = window?.$2sxc?.urlParams?.isDebug() ?? false;\n        if (debug) console.log('registerReloadModule', dotNetObjectReference, moduleId);\n        this.registeredModules.set(moduleId, dotNetObjectReference);\n    },\n\n    unregisterReloadModule: function (moduleId) {\n        const debug = window?.$2sxc?.urlParams?.isDebug() ?? false;\n        if (debug) console.log('unregisterReloadModule', moduleId)\n        if (this.registeredModules.has(moduleId)) {\n            this.registeredModules.get(moduleId).dispose();\n            this.registeredModules.delete(moduleId);\n        }\n    },\n\n    reloadModule: async function (moduleId) {\n        const debug = window?.$2sxc?.urlParams?.isDebug() ?? false;\n        if (debug) console.log('oqt: reloadModule', moduleId);\n        // 2024-07-04 stv, we had different strategy for Interactive and SSR to refresh module content on page after edit using 2sxc Edit UI\n        // Interactive use our blazor 'ReloadModule' method to update DOM, but this breaks from Oqtane 5.1.2 because of blazor.web.js\n        // so fix was just to reload page with window.location.reload()\n        if (this.registeredModules.has(moduleId)) {\n            if (debug) console.log('oqt: interactive');\n            window.location.reload(); // quick fix for Oqtane 5.1.2\n            // await this.registeredModules.get(moduleId).invokeMethodAsync('ReloadModule'); // not working in Oqtane 5.1.2\n            return Promise.resolve(true);\n        } else {\n            if (debug) console.log('oqt: static SSR');\n            return Promise.resolve(false);\n        }\n    },\n\n    getTitleValue: function (title) {\n        return document.title;\n    },\n\n    getMetaTagContentByName: function (name) {\n        var elements = document.getElementsByName(name);\n        if (elements.length) {\n            return elements[0].content;\n        } else {\n            return \"\";\n        }\n    },\n\n    includeInlineScripts: function (inlineScripts) {\n        const debug = window?.$2sxc?.urlParams?.isDebug() ?? false;\n        if (debug) console.log('includeInlineScripts:', inlineScripts);\n        for (let i = 0; i < inlineScripts.length; i++) {\n          Oqtane.Interop.includeScript(inlineScripts[i].id, inlineScripts[i].src, inlineScripts[i].integrity, inlineScripts[i].crossorigin, inlineScripts[i].type, inlineScripts[i].content, inlineScripts[i].location, inlineScripts[i].dataAttributes)\n        }\n    }\n};\n\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/Modules/ToSic.Sxc.Oqtane/NativeModule.js",
    "content": "/* native JavaScript module */\n\n/**\n * copy of Oqtane.Interop.includeScripts from Oqtane v3.1.0\n * https://github.com/oqtane/oqtane.framework/blob/v3.1.0/Oqtane.Server/wwwroot/js/interop.js#L195..L243\n * with addition of httpAttributes support\n * @param {any} scripts\n */\nasync function includeScriptsWithAttributes(scripts) {\n  // 2022-08-20 2dm debug some more\n  const debug = window?.$2sxc?.urlParams?.isDebug() ?? false;\n  if (debug) console.log('includeScriptsWithAttributes', scripts);\n\n  //// remove existing scripts\n  //for (let s = 0; s < scripts.length; s++) {\n  //  const src = scripts[s].href;\n  //  if (src !== \"\") {\n  //    let script = document.querySelector(\"script[src=\\\"\" + CSS.escape(src) + \"\\\"]\");\n  //    if (script !== null) script.remove();\n  //  }\n  //}\n\n  const bundles = [];\n  for (let s = 0; s < scripts.length; s++) {\n    if (scripts[s].bundle === '') {\n      scripts[s].bundle = scripts[s].href;\n    }\n    if (!bundles.includes(scripts[s].bundle)) {\n      bundles.push(scripts[s].bundle);\n    }\n  }\n  const promises = [];\n  for (let b = 0; b < bundles.length; b++) {\n    const urls = [];\n    for (let s = 0; s < scripts.length; s++) {\n      if (scripts[s].bundle === bundles[b]) {\n        urls.push(scripts[s].href);\n      }\n    }\n    promises.push(new window.Promise((resolve, reject) => {\n      if (loadjs.isDefined(bundles[b])) {\n        resolve(true);\n      }\n      else {\n        loadjs(urls, bundles[b], {\n          async: false,\n          returnPromise: true,\n          before: function (path, element) {\n            for (let s = 0; s < scripts.length; s++) {\n              // 2022-03-10 start - httpAttributes support\n              if (path === scripts[s].href && !!scripts[s].htmlAttributes) {\n                for (var key in scripts[s].htmlAttributes)\n                  element.setAttribute(key, scripts[s].htmlAttributes[key]);\n              }\n              // 2022-03-10 end - httpAttributes support\n              if (path === scripts[s].href && scripts[s].integrity !== '') {\n                element.integrity = scripts[s].integrity;\n              }\n              if (path === scripts[s].href && scripts[s].crossorigin !== '') {\n                element.crossOrigin = scripts[s].crossorigin;\n              }\n              if (path === scripts[s].href && scripts[s].es6module === true) {\n                element.type = \"module\";\n              }\n            }\n          }\n        })\n          .then(function () { resolve(true) })\n          .catch(function (pathsNotFound) { reject(false) });\n      }\n    }));\n  }\n  if (promises.length !== 0) {\n    await window.Promise.all(promises);\n  }\n}\n\nexport { includeScriptsWithAttributes };"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server/wwwroot/readme.md",
    "content": "﻿# wwwroot in 2sxc Oqtane Server Project\n\nThis folder contains the `Modules/ToSic.Sxc.Oqtane/` folder and more\n\nIt has module CSS and JS scripts etc. which are part of the distribution. \n\nBut it's not shown in Visual Studio, because search and the compiler/debugger would show too many hits / errors. "
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server.Tests/Configuration/OqtGlobalConfigurationTests.cs",
    "content": "using System;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing ToSic.Sxc.Oqt.Server.Configuration;\nusing ToSic.Sxc.Oqt.Server.Context;\nusing ToSic.Sys.Configuration;\n\nnamespace ToSic.Sxc.Oqt.Configuration;\n\npublic class OqtGlobalConfigurationTests\n{\n    #region ConnectionString Resolution\n    [Fact]\n    public void GetThis_ReturnsTenantConnectionString_WhenTenantContextAvailable()\n    {\n        // Arrange\n        const string expected = \"Data Source=.;Initial Catalog=TenantDb;Integrated Security=True;\";\n\n        var services = new ServiceCollection()\n            .AddScoped<IOqtTenantContext>(_ => new FakeOqtTenantContext(\n                new OqtTenantContextInfo(\n                    TenantId: 7,\n                    SiteId: 1,\n                    ConnectionStringName: \"TenantDb\",\n                    ConnectionString: expected\n                )));\n\n        using var serviceProvider = services.BuildServiceProvider();\n        using var scope = serviceProvider.CreateScope();\n        var httpContext = new DefaultHttpContext { RequestServices = scope.ServiceProvider };\n        var httpContextAccessor = new HttpContextAccessor { HttpContext = httpContext };\n\n        var sut = new OqtGlobalConfiguration(httpContextAccessor);\n\n        // Act\n        var result = ((IGlobalConfiguration)sut).GetThis(nameof(GlobalConfigDb.ConnectionString));\n\n        // Assert\n        Equal(expected, result);\n    }\n    #endregion\n\n    private sealed class FakeOqtTenantContext(OqtTenantContextInfo? context) : IOqtTenantContext\n    {\n        public OqtTenantContextInfo? Get() => context;\n\n        public OqtTenantContextInfo GetRequired()\n            => context ?? throw new InvalidOperationException(\"Test context not configured.\");\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server.Tests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using static Xunit.Assert;"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server.Tests/Imageflow/OqtaneBlobServiceTests.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Server.Adam.Imageflow;\nusing ToSic.Sxc.Oqt.Shared;\n\nnamespace ToSic.Sxc.Oqt.Imageflow;\n\npublic class OqtaneBlobServiceTests\n{\n    private static readonly OqtaneBlobService OqtaneBlobService = new(null);\n    private static bool SupportsPath(string virtualPath) =>\n        OqtaneBlobService.SupportsPath(virtualPath);\n\n    private static bool GetAppNameAndFilePath(string virtualPath, out string appName, out string filePath) =>\n        OqtaneBlobService.GetAppNameAndFilePath(virtualPath, out appName, out filePath);\n\n    private static bool ContainsSxcPath(string virtualPath) =>\n        OqtaneBlobService.ContainsSxcPath(virtualPath);\n\n    [Theory]\n    [InlineData(\"app/Content/adam/2aUKYsXls0KCeVH-XnHmRQ/Image/Demo-1.jpg?w=600&h=370&quality=75&mode=crop&scale=both\")]\n    [InlineData(\"app/Gallery7/adam/0jPONC8CT0i06sp3dybtCw/Images/boris-baldinger-eUFfY6cwjSU-unsplash.jpg\")]\n    [InlineData(\"app/Content/adam/2aUKYsXls0KCeVH-XnHmRQ/Image/Demo-1.jpg?w=2000&amp;h=1500&amp;quality=75&amp;mode=max&amp;scale=downscaleonly\")]\n    //[InlineData(\"app/Gallery7/adam/0jPONC8CT0i06sp3dybtCw/Images/boris-baldinger-eUFfY6cwjSU-unsplash.jpg\")]\n    public void SupportsPathTest(string virtualPath) =>\n        True(SupportsPath(virtualPath));\n\n    [Theory]\n    [InlineData($\"Modules/{OqtConstants.PackageName}/assets/app-primary.png\")]\n    public void NotSupportsPathTest(string virtualPath) =>\n        False(SupportsPath(virtualPath));\n\n    [Theory]\n    [InlineData(\"app/Tutorial-Razor/assets/app-icon.png\", \"Tutorial-Razor\", \"app-icon.png\")]\n    [InlineData(\"child-site/en-uk/app/Tutorial-Razor/assets/folder/app/subfolder/assets/app-icon.png\", \"Tutorial-Razor\", \"folder/app/subfolder/assets/app-icon.png\")]\n    public void GetAppNameAndFilePathTest(string virtualPath, string expectedAppName, string expectedFilePath)\n    {\n        True(GetAppNameAndFilePath(virtualPath, out var actualAppName, out var actualFilePath));\n        Equal(expectedAppName, actualAppName);\n        Equal(expectedFilePath, actualFilePath);\n    }\n\n    [Theory]\n    [InlineData($\"Modules/{OqtConstants.PackageName}/assets/app-primary.png\")]\n    public void NotSupportedGetAppNameAndFilePathTest(string virtualPath) => False(GetAppNameAndFilePath(virtualPath, out var actualAppName, out var actualFilePath));\n\n    [Theory]\n    [InlineData(\"app/Tutorial-Razor/assets/app-icon.png\")]\n    [InlineData(\"1/app/Tutorial_-1230Razor/assets/1/app-icon.png\")]\n    [InlineData(\"1/2/app/Tutorial-Razor/assets/1/2/asset/app/app-icon.png\")]\n    public void ContainsSxcPathPathTest(string virtualPath) => True(ContainsSxcPath(virtualPath));\n\n    [Theory]\n    [InlineData($\"Modules/{OqtConstants.PackageName}/assets/app-primary.png\")]\n    [InlineData(\"app/Tutori/al/Ra/zor/assets/app-icon.png\")]\n    [InlineData(\"app/Content/adam/2aUKYsXls0KCeVH-XnHmRQ/Image/Demo-1.jpg?w=2000&h=1500&quality=75&mode=max&scale=downscaleonly\")]\n    public void NotContainsSxcPathTest(string virtualPath) => False(ContainsSxcPath(virtualPath));\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server.Tests/Security/Encryption/AesCryptographyServiceTests.cs",
    "content": "﻿\nusing ToSic.Sys.Security.Encryption;\n\nnamespace ToSic.Sxc.Oqt.Security.Encryption;\n\npublic class AesCryptographyServiceTests\n{\n    [Fact]\n    public void DecryptTest()\n    {\n#pragma warning disable CS0219\n        var x = \"secure:pycbhspVSBHE662IjdEfFG8rwwCdxN9jCQaMJK6/QfLl/JxaDhAk+6q1WU4BSXw4;iv:HUyYDwdMhsuiaxZo3TG4Zg==\";\n        var v = \"pycbhspVSBHE662IjdEfFG8rwwCdxN9jCQaMJK6/QfLl/JxaDhAk+6q1WU4BSXw4\";\n#pragma warning restore CS0219\n        var r = new Rfc2898Generator();\n        var aes = new AesCryptographyService(r);\n        var ret = aes.DecryptFromBase64(v, new() { InitializationVector64 = \"HUyYDwdMhsuiaxZo3TG4Zg==\" } );\n        Equal(\"AIzaSyAKEFBVw7SddUQR0YnAuTam5wpXvDomzts\", ret);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server.Tests/StartUp/OqtStartupHelperTests.cs",
    "content": "﻿//using ToSic.Sxc.Oqt.Server.StartUp;\n//using ToSic.Sxc.Oqt.Shared;\n\n//namespace ToSic.Sxc.Oqt.StartUp;\n\n//public class OqtStartupHelperTests\n//{\n//    //private static bool IsSxcEndpoint(string path) => OqtStartupHelper.IsSxcEndpoint(path);\n//    //private static bool IsSxcDialog(string path) => OqtStartupHelper.IsSxcDialog(path);\n\n//    [Theory]\n//    [InlineData(\"app/testApp/api/testController/testAction\")]\n//    [InlineData(\"app/testApp/edition/api/testController/testAction\")]\n//    [InlineData(\"path/app/testApp/api/testController/testAction\")]\n//    [InlineData(\"path/app/testApp/edition/api/testController/testAction\")]\n//    [InlineData(\"path/subpath/app/testApp/api/testController/testAction\")]\n//    [InlineData(\"path/subpath/app/testApp/edition/api/testController/testAction\")]\n//    [InlineData(\"subsite/path/subpath/app/testApp/api/testController/testAction\")]\n//    [InlineData(\"subsite/path/subpath/app/testApp/edition/api/testController/testAction\")]\n//    public void IsSxcEndpoint_ShouldReturnTrue_ForValidPath(string validPath)\n//        => True(IsSxcEndpoint(validPath));\n\n//    [Theory]\n//    [InlineData(\"invalid/path/to/api\")]\n//    [InlineData(\"app/testApp/api\")]\n//    [InlineData(\"path/app/testApp/api/\")]\n//    [InlineData(\"path/app/api/testController/testAction\")]\n//    [InlineData(\"path/app//api/testController/testAction\")]\n//    [InlineData(\"testApp/api/testController/testAction\")]\n//    [InlineData(\"app/testApp/not-api/testController/testAction\")]\n//    [InlineData(\"app/testApp/edition/not-api/testController/testAction\")]\n//    [InlineData(\"path/app/testApp//api/testController/testAction\")]\n//    [InlineData(\"path/app/testApp/not-api/testController/testAction\")]\n//    [InlineData(\"path/app/testApp/edition/not-api/testController/testAction\")]\n//    [InlineData(\"path/subpath/app/testApp/not-api/testController/testAction\")]\n//    [InlineData(\"path/subpath/app/testApp/edition/not-api/testController/testAction\")]\n//    [InlineData(\"subsite/path/subpath/app/testApp/not-api/testController/testAction\")]\n//    [InlineData(\"subsite/path/subpath/app/testApp/edition/not-api/testController/testAction\")]\n//    [InlineData(\"not-only-app/testApp/api\")]\n//    public void IsSxcEndpoint_ShouldReturnFalse_ForInvalidPath(string invalidPath)\n//        => False(IsSxcEndpoint(invalidPath));\n\n//    [Theory]\n//    [InlineData(\"/Modules/\" + OqtConstants.PackageName + \"/dist/quick-dialog/\")]\n//    [InlineData(\"/Modules/\" + OqtConstants.PackageName + \"/dist/ng-edit/\")]\n//    public void IsSxcDialog_ShouldReturnTrue_ForValidPath(string validPath)\n//        => True(IsSxcDialog(validPath));\n\n//    [Theory]\n//    [InlineData(\"/invalid/path/to/dialog\")]\n//    [InlineData(\"/Modules/InvalidPackageName/dist/quick-dialog/\")]\n//    [InlineData(\"/Modules/InvalidPackageName/dist/ng-edit/\")]\n//    public void IsSxcDialog_ShouldReturnFalse_ForInvalidPath(string invalidPath)\n//        => False(IsSxcDialog(invalidPath));\n//}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Server.Tests/ToSic.Sxc.Oqt.Server.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net9.0</TargetFramework>\n    <Nullable>enable</Nullable>\n    <IsPackable>false</IsPackable>\n    <LangVersion>preview</LangVersion>\n    <RootNamespace>ToSic.Sxc.Oqt</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"Xunit.DependencyInjection\" Version=\"9.9.0\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.0\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Oqt.Server\\ToSic.Sxc.Oqt.Server.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Oqt.Shared\\ToSic.Sxc.Oqt.Shared.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Using Include=\"Xunit\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/CspConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CspConstants\n{\n    public const string LogPrefix = \"Csp\";\n    public const string AllSrcName = \"all-src\";\n    public const string DefaultSrcName = \"default-src\";\n    public const string SuffixSrc = \"-src\";\n\n    public const string CspHeaderNamePolicy = \"Content-Security-Policy\";\n    public const string CspHeaderNameReport = \"Content-Security-Policy-Report-Only\";\n    public const string CspUrlParameter = \"csp\";\n    public const string CspUrlTrue = \"true\";\n    public const string CspUrlDev = \"dev\";\n\n    public const string CspWhitelistAttribute = \"csp-whitelist\";\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Dev/WipConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Dev;\n\n/// <summary>\n/// Temporary constants which should be removed soon\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WipConstants\n{\n    // ADAM\n    public const int ParentFolderNotFound = 0;\n    public static void AdamNotImplementedYet() { }\n        \n    public static void DontDoAnythingImplementLater() { }\n\n    // Settings\n    public const string SettingsChangeUserId = \"sxc-auto\";\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using Oqtane.Documentation;"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Helpers/ErrorHelper.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Helpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ErrorHelper\n{\n    public static string ErrorMessage(Exception ex, bool isSuperUser = false)\n    {\n        var errorMessage = ex.Message;\n\n        if (!isSuperUser) return errorMessage;\n\n        errorMessage += \" - \" + ex.StackTrace;\n        if (ex.InnerException == null) return errorMessage;\n\n        errorMessage += \" - \" + ex.InnerException.Message;\n        errorMessage += \" - \" + ex.InnerException.StackTrace;\n\n        return errorMessage;\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Helpers/HtmlHelper.cs",
    "content": "﻿using Oqtane.Models;\nusing Oqtane.Shared;\nusing System.Collections;\nusing System.Net;\nusing System.Text.RegularExpressions;\nusing ToSic.Sxc.Oqt.Shared.Models;\nusing ResourceLevel = Oqtane.Shared.ResourceLevel;\n\nnamespace ToSic.Sxc.Oqt.Shared.Helpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HtmlHelper\n{\n    private static readonly string Timestamp = DateTime.UtcNow.ToString(\"yyyyMMddHHmmssfff\");\n\n    //public string Link(string id) => $\"<link id=\\\"{id}\\\" rel=\\\"shortcut icon\\\" type=\\\"image/{favicontype}\\\" href=\\\"{favicon}\\\" />\\n\";\n\n    //public static string SetMetaTag(string id, string name, string content)\n    //{\n    //    var rez = \"<meta\";\n    //    if (!string.IsNullOrEmpty(id)) rez += $\" id=\\\"{WebUtility.HtmlEncode(id)}\\\"\";\n    //    if (!string.IsNullOrEmpty(name)) rez += $\" name=\\\"{WebUtility.HtmlEncode(name)}\\\"\";\n    //    if (!string.IsNullOrEmpty(content)) rez += $\" content=\\\"{WebUtility.HtmlEncode(content)}\\\"\";\n    //    rez += \" />\\n\";\n    //    return rez;\n    //}\n\n    //public static string GetAttribute(string element, string attribute) \n    //    => XElement.Parse(element).Attribute(attribute)?.Value;\n\n\n    //public void AddHeadContent(SiteState siteState, string content)\n    //{\n    //    if (!string.IsNullOrEmpty(content))\n    //    {\n    //        // format html content, remove scripts, and filter duplicate elements\n    //        var elements = (\">\" + content.Replace(\"\\n\", \"\") + \"<\").Split(\"><\");\n    //        foreach (var element in elements)\n    //        {\n    //            if (!string.IsNullOrEmpty(element) && !element.ToLower().StartsWith(\"script\"))\n    //            {\n    //                if (!siteState.Properties.HeadContent.Contains(\"<\" + element + \">\"))\n    //                {\n    //                    siteState.Properties.HeadContent += \"<\" + element + \">\" + \"\\n\";\n    //                }\n    //            }\n    //        }\n    //    }\n    //}\n\n    //public void GetHeadContent(SiteState siteState, string attribute)\n    //{\n    //    if (!string.IsNullOrEmpty(content))\n    //    {\n    //        // format html content, remove scripts, and filter duplicate elements\n    //        var elements = (\">\" + content.Replace(\"\\n\", \"\") + \"<\").Split(\"><\");\n    //        foreach (var element in elements)\n    //        {\n    //            if (!string.IsNullOrEmpty(element) && !element.ToLower().StartsWith(\"script\"))\n    //            {\n    //                if (!siteState.Properties.HeadContent.Contains(\"<\" + element + \">\"))\n    //                {\n    //                    siteState.Properties.HeadContent += \"<\" + element + \">\" + \"\\n\";\n    //                }\n    //            }\n    //        }\n    //    }\n    //}\n\n    //public static string AddScript(string html, string src, Alias alias)\n    //{\n    //    if (src.IsNullOrEmpty())\n    //        return html;\n    //    var script = CreateScript(new() { Url = src }, alias);\n    //    if (!html.Contains(script))\n    //        html += script + Environment.NewLine;\n    //    return html;\n    //}\n\n    public static string? GetMetaTagContent(string html, string name, bool decode = true)\n    {\n        if (html.IsNullOrEmpty() || name.IsNullOrEmpty())\n            return null;\n        var pattern = \"<meta\\\\s+name\\\\s*=\\\\s*[\\\"']\" + WebUtility.HtmlEncode(name) + \"[\\\"']\\\\s+content\\\\s*=\\\\s*[\\\"'](.*?)[\\\"']\\\\s*/?>\";\n        var match = Regex.Match(html, pattern, RegexOptions.IgnoreCase);\n        return match.Success ? (decode ? WebUtility.HtmlDecode(match.Groups[1].Value) : match.Groups[1].Value) : null;\n    }\n\n    [return: NotNullIfNotNull(nameof(html))]\n    public static string? AddOrUpdateMetaTagContent(string? html, string name, string content, bool encode = true)\n    {\n        if (name.IsNullOrEmpty())\n            return html;\n        html ??= string.Empty;\n\n        // Define a regex pattern to match the meta tag\n        var pattern = $@\"(<meta\\s+name\\s*=\\s*[\"\"']{WebUtility.HtmlEncode(name)}[\"\"']\\s+content\\s*=\\s*[\"\"'])(.*?)([\"\"']\\s*/?>)\";\n\n        // If the meta tag exists, replace its content\n        if (Regex.IsMatch(html, pattern, RegexOptions.IgnoreCase))\n            return Regex.Replace(html, pattern, $\"$1{(encode ? WebUtility.HtmlEncode(content) : content)}$3\", RegexOptions.IgnoreCase);\n\n        // If the meta tag doesn't exist, add it\n        return html + $\"<meta name=\\\"{WebUtility.HtmlEncode(name)}\\\" content='{(encode ? WebUtility.HtmlEncode(content) : content)}'>{Environment.NewLine}\";\n    }\n\n    [return: NotNullIfNotNull(nameof(html))]\n    public static string? AddHeadChanges(string? html, IEnumerable<OqtHeadChange> headChanges)\n    {\n        if (headChanges == null! /* paranoid, should never happen */)\n            return html;\n        html ??= string.Empty;\n\n        var str = string.Empty;\n        foreach (var headChange in headChanges)\n        {\n            if (!string.IsNullOrEmpty(headChange.Tag))\n                str += headChange.Tag + Environment.NewLine;\n        }\n        return html + str;\n    }\n\n    [return: NotNullIfNotNull(nameof(html))]\n    public static string? ManageStyleSheets(string? html, OqtViewResultsDto viewResults, Alias alias, string themeName, string pageHtml = \"\")\n    {\n        if (viewResults == null! /* paranoid */)\n            return html;\n        html ??= string.Empty;\n\n        var list = (viewResults.TemplateResources ?? [])\n            .Where(r => r is { IsExternal: true, ResourceType: ResourceType.Stylesheet })\n            .Select(r => r.Url)\n            .ToList();\n        var count = 0;\n        foreach (var url in (viewResults.SxcStyles ?? []).Union(list))\n        {\n            var src = url ?? \"\";\n            if (src.StartsWith('~'))\n                src = src.Replace(\"~\", \"/Themes/\" + themeName + \"/\").Replace(\"//\", \"/\");\n            if (!src.Contains(\"://\") && !string.IsNullOrEmpty(alias.BaseUrl) && !src.StartsWith(alias.BaseUrl))\n                src = alias.BaseUrl + src;\n            if (!html.Contains(src, StringComparison.OrdinalIgnoreCase) && !pageHtml.Contains(src, StringComparison.OrdinalIgnoreCase))\n            {\n                ++count;\n                var assetHtml= \"<link\"\n                    + \" id=\\\"app-stylesheet-\" + nameof(ResourceLevel.Page).ToLower() + \"-\" + Timestamp + \"-\" + count.ToString(\"00\") + \"\\\"\"\n                    + \" rel=\\\"stylesheet\\\" href=\\\"\" + src + \"\\\" type=\\\"text/css\\\"/>\";\n                html = AddAssetWhenMissing(html, assetHtml);\n            }\n        }\n        return html;\n    }\n\n    [return: NotNullIfNotNull(nameof(html))]\n    public static string? ManageScripts(string? html, OqtViewResultsDto? viewResults, Alias alias, string pageHtml = \"\")\n    {\n        // If no view result, exit early\n        if (viewResults == null)\n            return html;\n\n        // Ensure html is a safe non-null string\n        html ??= string.Empty;\n\n        // Extract external JS resources\n        var externalScripts = (viewResults.TemplateResources ?? [])\n            .Where(r => r is { IsExternal: true, ResourceType: ResourceType.Script })\n            .ToList();\n\n        foreach (var sxcResource in externalScripts)\n            html = AddScript(html, sxcResource, alias, pageHtml);\n\n        var count = 0;\n        foreach (var url in viewResults.SxcScripts ?? []) \n            html = url.IsNullOrEmpty()\n                ? html\n                : AddScript(html, new() { Url = url, Reload = false }, alias, pageHtml, ++count);\n\n        return html;\n    }\n\n    [return: NotNullIfNotNull(nameof(html))]\n    public static string? ManageInlineScripts(string? html, OqtViewResultsDto? viewResults, Alias alias, string pageHtml = \"\")\n    {\n        if (viewResults == null)\n            return html;\n        html ??= string.Empty;\n\n        if (viewResults.TemplateResources != null)\n            foreach (var sxcResource in viewResults.TemplateResources.Where(r => !r.IsExternal))\n                html = AddScript(html, sxcResource, alias, pageHtml);\n\n        return html;\n    }\n\n    [return: NotNullIfNotNull(nameof(html))]\n    private static string? AddScript(string? html, Resource? resource, Alias alias, string pageHtml = \"\", int count = 0)\n    {\n        // If no resource, exit early\n        if (resource == null)\n            return html;\n\n        // Newer oqtane defaults empty resources to being \"/\" which we don't want to process\n        var resourceHasNoUrl = resource.Url.IsNullOrEmpty() || resource.Url == \"/\";\n        if (resourceHasNoUrl && resource.Content.IsNullOrEmpty())\n            return html;\n\n        html ??= string.Empty;\n\n        var script = CreateScript(resource, alias, count);\n        if (!pageHtml.Contains(script, StringComparison.OrdinalIgnoreCase))\n            html = AddAssetWhenMissing(html, script);\n\n        return html;\n    }\n\n    [return: NotNullIfNotNull(nameof(html))]\n    private static string? AddAssetWhenMissing(string? html, string? assetHtml)\n    {\n        if (assetHtml.IsNullOrEmpty())\n            return html;\n        html ??= string.Empty;\n\n        if (!html.Contains(assetHtml!, StringComparison.OrdinalIgnoreCase))\n            html += assetHtml + Environment.NewLine;\n\n        return html;\n    }\n\n    private static string CreateScript(Resource resource, Alias alias, int count)\n    {\n        if (!resource.Content.IsNullOrEmpty())\n            return \"<script\" +\n                (resource.Type == \"module\" ? \" type=\\\"module\\\"\" : \"\") +\n                \">\" + resource.Content + \"</script>\";\n\n        // use custom element which can execute script on every page transition\n        if (resource.Reload)\n            return \"<page-script src=\\\"\" + resource.Url + \"\\\"></page-script>\";\n\n        var str = resource.Url.Contains(\"://\")\n            ? resource.Url\n            : alias.BaseUrl + (alias.BaseUrl.EndsWith('/')\n                ? resource.Url.TrimStart('/')\n                : resource.Url); // avoid \"path//file.js\" in URL\n\n        return \"<script\" + \n            //\" id=\\\"app-script-\" + ResourceLevel.Page.ToString().ToLower() + \"-\" + DateTime.UtcNow.ToString(\"yyyyMMddHHmmssfff\") + \"-\" + count.ToString(\"00\") + \"\\\"\" +\n            (!string.IsNullOrEmpty(resource.Integrity) ? \" integrity=\\\"\" + resource.Integrity + \"\\\"\" : \"\") +\n            (!string.IsNullOrEmpty(resource.CrossOrigin) ? \" crossorigin=\\\"\" + resource.CrossOrigin + \"\\\"\" : \"\") +\n            (resource.Type == \"module\" ? \" type=\\\"module\\\"\" : \"\") +\n            \" src=\\\"\" + str + \"\\\"></script>\";\n    }\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Interfaces/IOqtDebugStateService.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Interfaces;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOqtDebugStateService\n{\n    bool IsDebugEnabled { get; }\n    Task<bool> GetDebugAsync();\n    void SetDebug(bool value);\n    string Platform { get; }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Interfaces/IOqtHybridLog.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Interfaces;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOqtHybridLog\n{\n    /// <summary>\n    /// console.log\n    /// </summary>\n    /// <param name=\"message\"></param>\n    /// <returns></returns>\n    void Log(params object[] message);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Interfaces/IOqtPageChangesOnServerService.cs",
    "content": "﻿using ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Shared.Interfaces;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOqtPageChangesOnServerService\n{\n    int ApplyHttpHeaders(OqtViewResultsDto result, IOqtHybridLog page);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Interfaces/IOqtPrerenderService.cs",
    "content": "﻿using Oqtane.Shared;\nusing ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Shared.Interfaces;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOqtPrerenderService\n{\n    string GetPrerenderHtml(bool isPrerendered, OqtViewResultsDto viewResults, SiteState siteState, string themeType);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Interfaces/IOqtSxcRenderService.cs",
    "content": "using ToSic.Sxc.Oqt.Shared.Models;\n\nnamespace ToSic.Sxc.Oqt.Shared.Interfaces;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOqtSxcRenderService\n{\n    Task<OqtViewResultsDto> RenderAsync(RenderParameters @params);\n\n    OqtViewResultsDto Render(RenderParameters @params);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Interfaces/IOqtTurnOnService.cs",
    "content": "﻿using ToSic.Oqt.Coding;\n\nnamespace ToSic.Sxc.Oqt.Shared.Interfaces;\n\n/// <summary>\n/// turnOn Service helps initialize / boot JavaScripts when all requirements (usually dependencies) are ready.\n/// </summary>\n[PrivateApi(\"Don't publish yet - the functionality is surfaced on the PageService!\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOqtTurnOnService \n{\n    string Run(object runOrSpecs,\n        NoParamOrderOqtane noParamOrder = default,\n        object? require = null,\n        object? data = null,\n        IEnumerable<object>? args = default,\n        string? addContext = default\n    );\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Interfaces/IRenderInfoService.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Interfaces;\n\n/// <summary>\n/// Service for providing rendering information based on the current HTTP context and module render mode.\n/// </summary>\npublic interface IRenderInfoService\n{\n\n    /// <summary>\n    /// Checks if the module render mode is static SSR (Server-Side Rendering).\n    /// </summary>\n    /// <param name=\"renderMode\">The module render mode.</param>\n    /// <returns>True if the render mode is static SSR, otherwise false.</returns>\n    bool IsStaticSsr(string renderMode);\n\n    /// <summary>\n    /// Checks if Blazor Enhanced Navigation is enabled for static SSR.\n    /// </summary>\n    /// <param name=\"renderMode\">The module render mode.</param>\n    /// <returns>True if Blazor Enhanced Navigation is enabled, otherwise false.</returns>\n    /// <remarks>\n    /// Blazor Enhanced Navigation is a feature in .NET 8 that allows for progressively-enhanced navigation in multi-page apps.\n    /// This is enabled when the app loads `blazor.web.js` and does not use an interactive Router. It works by intercepting \n    /// navigation within the base href URI space, loading content via `fetch` requests, and syncing the DOM.\n    /// </remarks>\n    bool IsBlazorEnhancedNav(string renderMode);\n\n    /// <summary>\n    /// Checks if the SSR Framing response header exists, indicating a fetch page request in Blazor Enhanced Navigation.\n    /// </summary>\n    /// <param name=\"renderMode\">The module render mode.</param>\n    /// <returns>\n    /// True if the SSR Framing response header exists (indicating a fetch page request during Blazor Enhanced Navigation).\n    /// False if it is a standard full page load in the browser.\n    /// </returns>\n    /// <remarks>\n    /// This helps distinguish between a full page load (initial load) and a fetch page request (subsequent navigation within the app).\n    /// This behavior occurs when Blazor Enhanced Navigation is in use for static SSR.\n    /// </remarks>\n    bool IsSsrFraming(string renderMode);\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Models/EavSystemInfo.cs",
    "content": "using System.Reflection;\n\nnamespace ToSic.Sxc.Oqt.Shared.Models;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EavSystemInfo\n{\n    public static Version Version => Assembly.GetExecutingAssembly().GetName().Version!;\n\n    public static readonly string VersionString = VersionToNiceFormat(Version);\n\n    // Todo: probably move to plumbing or extension method?\n    public static string VersionToNiceFormat(Version version)\n        => $\"{version.Major:00}.{version.Minor:00}.{version.Build:00}\";\n\n\n    // Version is used also as cache-break for js assets.\n    // In past build revision was good cache-break value, but since assemblies are deterministic \n    // we use application start unix time as slow changing revision value for cache-break purpose. \n    public static readonly string VersionWithStartUpBuild = VersionWithFakeBuildNumber(Version).ToString();\n\n    /// <summary>\n    /// application start unix time as slow changing revision value\n    /// </summary>\n    /// <param name=\"version\"></param>\n    /// <returns></returns>\n    private static Version VersionWithFakeBuildNumber(Version version) =>\n        new(version.Major, version.Minor, version.Build,\n            (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds);\n\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Models/HttpHeader.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Models;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HttpHeader\n{\n    public HttpHeader(string name, string value)\n    {\n        Name = name;\n        Value = value;\n    }\n\n    public string Name { get; set; }\n    public string Value { get; set; }\n\n    /// <summary>\n    /// If set, would flush existing headers\n    /// </summary>\n    public bool Reset { get; set; }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Models/OqtHeadChange.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Models;\n\n// Equivalent to ToSic.Sxc.Web.PageService.HeadChange\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtHeadChange\n{\n    public required OqtPagePropertyOperation PropertyOperation { get; init; }\n\n    public required string Tag { get; init; }\n\n    /// <summary>\n    /// This is part of the original property, which would be replaced.\n    /// </summary>\n    public required string ReplacementIdentifier { get; init; }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Models/OqtPagePropertyChanges.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Models;\n\n/// <summary>\n/// Used to transfer what / how page properties should change based on the Razor file\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic struct OqtPagePropertyChanges\n{\n    public OqtPagePropertyOperation Change { get; set; }\n    public OqtPageProperties Property { get; set; }\n    public string? Value { get; set; }\n    public string Placeholder { get; set; }\n\n\n\n    /// <summary>\n    /// If new value has placeholder token [original], token will be replaced\n    /// with old value, effectively injecting old value in new value\n    /// </summary>\n    /// <param name=\"original\">old value</param>\n    public OqtPagePropertyChanges InjectOriginalInValue(string? original)\n    {\n        if (string.IsNullOrEmpty(Value) || !Value.Contains(OriginalToken, StringComparison.OrdinalIgnoreCase))\n            return this;\n\n        Value = Value?.Replace(OriginalToken, original ?? string.Empty, StringComparison.OrdinalIgnoreCase);\n        Change = OqtPagePropertyOperation.Replace;\n\n        return this;\n    }\n\n    public const string OriginalToken = \"[original]\"; // new value can have [original] placeholder to inject old value in that position\n}\n\npublic enum OqtPageProperties\n{\n    Title,\n    Keywords,\n    Description,\n    Base\n}\n\n// equivalent to ToSic.Sxc.Web.PageChangeModes\n// GetOp convert from PageChangeModes to OqtPagePropertyOperation\n[PrivateApi(\"not final yet, probably will not be implemented like this\")]\n\npublic enum OqtPagePropertyOperation\n{\n    /// <summary>\n    /// Replace the original implementation.\n    /// </summary>\n    Replace,\n\n    /// <summary>\n    /// Attempt to replace, otherwise don't apply the change.\n    /// </summary>\n    ReplaceOrSkip,\n\n    /// <summary>\n    /// Suffix the change.\n    /// </summary>\n    Suffix,\n\n    /// <summary>\n    /// Prefix the change. \n    /// </summary>\n    Prefix\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Models/OqtViewResultsDto.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Models;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OqtViewResultsDto\n{\n    public OqtViewResultsDto() {}\n    /// <summary>\n    /// The final HTML to show in the browser\n    /// </summary>\n    public string FinalHtml => $\"{Html}{PrerenderHtml}\";\n\n    /// <summary>\n    /// The content HTML\n    /// </summary>\n    public string? Html { get; set; }\n\n    /// <summary>\n    /// For special error messages, in case the backend has trouble with refs etc.\n    /// </summary>\n    public string? ErrorMessage { get; set; }\n\n    /// <summary>\n    /// The resources which the template will need\n    /// </summary>\n    public List<SxcResource>? TemplateResources { get; set; }\n\n    /// <summary>\n    /// The Context meta name tag - null if not needed\n    /// </summary>\n    public string? SxcContextMetaName { get; set; }\n        \n    /// <summary>\n    /// Will return the meta-header which the $2sxc client needs for context, page id, request verification token etc.\n    /// </summary>\n    /// <returns></returns>\n    public string? SxcContextMetaContents { get; set; }\n\n    /// <summary>\n    /// The JavaScripts needed by 2sxc (not by the template)\n    /// </summary>\n    /// <returns></returns>\n    public List<string>? SxcScripts { get; set; }\n\n    /// <summary>\n    /// The styles to add for 2sxc inpage to work (not from the template)\n    /// </summary>\n    /// <returns></returns>\n    public List<string>? SxcStyles { get; set; }\n        \n    /// <summary>\n    /// List of page property changes as specified\n    /// </summary>\n    public IEnumerable<OqtPagePropertyChanges>? PageProperties { get; set; }\n\n    /// <summary>\n    /// Changes to the Page Header like Meta-Tags etc.\n    /// </summary>\n    public IEnumerable<OqtHeadChange>? HeadChanges { get; set; }\n\n    ///// <summary>\n    ///// Features which are defined in the SystemSettings and wer requested by the code and should be enabled.\n    ///// </summary>\n    //IList<IPageFeature> FeaturesFromSettings { get; }\n\n    /// <summary>\n    /// Prerender HTML fragment\n    /// </summary>\n    public string? PrerenderHtml { get; set; }\n\n    /// <summary>\n    /// List of HttpHeaders to add to the response in format \"key:value\"\n    /// </summary>\n    //IList<string> HttpHeaders { get; }\n    public IList<HttpHeader>? HttpHeaders { get; set; }\n\n    public bool CspEnabled { get; set; }\n    public bool CspEnforced { get; set; }\n    public IList<string>? CspParameters { get; set; }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Models/RenderParameters.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared.Models;\n\npublic record RenderParameters\n{\n    public required int AliasId { get; init; }\n    public required int PageId { get; init; }\n    public required int ModuleId { get; init; }\n    public required string Culture { get; init; }\n    public required bool PreRender { get; init; }\n    public required string OriginalParameters { get; init; }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Models/SxcResource.cs",
    "content": "﻿using Oqtane.Models;\n\nnamespace ToSic.Sxc.Oqt.Shared.Models;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcResource: Resource\n{\n    public string? UniqueId { get; set; }\n\n    ///// <summary>\n    ///// For the contents of a script tag\n    ///// </summary>\n    //public string Content { get; set; }\n\n    public bool IsExternal { get; set; } = true;\n\n    /// <summary>\n    /// Used to store all other html attributes from html tag.\n    /// </summary>\n    /// <remarks>\n    /// Setting HtmlAttributes will also try to set Integrity and CrossOrigin properties\n    /// that are explicitly supported by Oqtane.Models.Resource.\n    /// </remarks>\n    public IDictionary<string, string>? HtmlAttributes\n    {\n        get;\n        set\n        {\n            // copy dictionary or null;\n            field = value == null\n                ? null\n                : new Dictionary<string, string>(value, StringComparer.InvariantCultureIgnoreCase);\n\n            // set additional html attribute properties that are explicitly supported by Oqtane.Models.Resource\n            HtmlAttributesGetValueAndRemoveKey(\"integrity\", value => Integrity = value);\n            HtmlAttributesGetValueAndRemoveKey(\"crossorigin\", value => CrossOrigin = value);\n        }\n    }\n\n    /// <summary>\n    /// Helper method used to set key value on static key-property,\n    /// and remove key from HtmlAttributes dictionary\n    /// </summary>\n    /// <param name=\"key\"></param>\n    /// <param name=\"setter\">property setter</param>\n    private void HtmlAttributesGetValueAndRemoveKey(string key, Action<string> setter)\n    {\n        if (HtmlAttributes == null)\n            return;\n        if (!HtmlAttributes.ContainsKey(key))\n            return;\n        if (string.IsNullOrEmpty(HtmlAttributes[key]))\n            return;\n\n        // set new value only when we have it\n        setter(HtmlAttributes[key]);\n        HtmlAttributes.Remove(key);\n    }\n\n    public new string? Url\n    {\n        get => base.Url;\n        set\n        {\n            // fix issue in Oqtane 3.2\n            // can't set Resource.Url to null\n            if (value != null)\n                base.Url = value;\n        }\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/ModuleInfoConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared\n{\n    public class ModuleInfoConstants\n    {\n        /// <summary>\n        /// Cleans up specific 2sxc/eav old assemblies in v20.00.00,\n        /// which are no longer needed and may cause conflicts.\n        /// Also to execute migration SQL script for 20.00.00\n        /// </summary>\n        public const string V20_00_00 = \"20-00-00\";\n\n        /// <summary>\n        /// Performs 2sxc folder reorganization for multi tenants support in v21.00.00\n        /// and cleans up 1 net9 assembly in net10 runtime, which is no longer needed and may cause conflicts.\n        /// Also to execute migration SQL script for 21.00.00\n        /// </summary>\n        public const string V21_00_00 = \"21-00-00\";\n    }\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/OqtConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Oqt.Shared;\n\n/// <summary>\n/// This should only contain constants which should really be final, no WIP or similar\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class OqtConstants\n{\n    // used as PackageID in nupkg, oqtane module PackageName, wwwroot/Modules/PackageName, namespace in module.js, etc...\n    public const string PackageName = \"ToSic.Sxc.Oqtane\";\n\n    public const string AppRoot = \"2sxc\";\n\n    public const string TenantsFolderName = \"Tenants\";\n\n    public const string SitesFolderName = \"Sites\";\n\n    public const string AppRootPublicBase = $\"{AppRoot}\\\\{{0}}\";\n\n    public const string AppRootTenantSiteBase = AppRoot + \"\\\\\" + TenantsFolderName + \"\\\\{0}\\\\\" + SitesFolderName + \"\\\\{1}\";\n\n    public const string SharedAppFolder =  \"Shared\";\n\n    public const string ContentSubfolder = \"Content\";\n\n    public const string ContentRootPublicBase = $\"{ContentSubfolder}\\\\{TenantsFolderName}\\\\{{0}}\\\\{SitesFolderName}\\\\{{1}}\";\n\n    public const string ApiAppLinkPart = \"api/sxc/app\";\n\n    public const string DownloadLinkTemplate = \"/{0}/api/file/download/{1}\";\n\n    public const string UserTokenPrefix = \"oqt:userid=\";\n\n    // #uncertain: maybe should incorporate the virtual path of the application?\n    public const string UiRoot = $\"/Modules/{OqtConstants.PackageName}\";\n    // #uncertain: maybe should be more dynamic\n    public const string SiteRoot = \"/\";\n\n    // Logging constants\n    public const string OqtLogPrefix = \"Oqt\";\n        \n    // Special Oqtane constants missing in Oqtane\n    public const string EntityIdParam = \"entityid\";\n\n    public const int Unknown = -1;\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/Sys/NoParamOrderOqtane.cs",
    "content": "﻿namespace ToSic.Oqt.Coding;\n\n/// <summary>\n/// Special placeholder to indicate that all parameters following this should be named. See [Convention: Named Parameters](https://go.2sxc.org/named-params).\n/// </summary>\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic struct NoParamOrderOqtane\n{\n    public const string HelpLink = \"https://go.2sxc.org/named-params\";\n}\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/ToSic.Sxc.Oqt.Shared.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-NetCore.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <PropertyGroup>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>ToSic.Sxc.Oqt.Shared</RootNamespace>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Oqtane.Shared</AssemblyName>\n  </PropertyGroup>\n\n\n  <ItemGroup>\n    <PackageReference Include=\"System.ComponentModel.Annotations\" Version=\"5.0.0\" /><!-- from Oqtane.Shared.csproj -->\n    <PackageReference Include=\"Microsoft.AspNetCore.Components\" Version=\"9.0.5\" />\n    <PackageReference Include=\"Oqtane.Shared\" Version=\"6.1.3\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/UrlHelpers.cs",
    "content": "﻿using System.Collections.Specialized;\n\nnamespace ToSic.Sxc.Oqt.Shared;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class UrlHelpers\n{\n    /// <summary>\n    /// Safer replacement to the HttpUtility.ParseQueryString because that changes umlauts etc. to %u0043 characters which is not very common\n    /// </summary>\n    /// <param name=\"query\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// See https://stackoverflow.com/questions/68624/how-to-parse-a-query-string-into-a-namevaluecollection-in-net\n    /// </remarks>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static NameValueCollection ParseQueryString(string query)\n    {\n        // Note that this NameValueCollection is different than the one from HttpUtility\n        // but because that one is internal, we cannot create one directly\n        var nvc = new NameValueCollection();\n        query = (query ?? \"\").Trim();\n        if (string.IsNullOrWhiteSpace(query))\n            return nvc;\n\n        // remove anything other than query string from url\n        if (query.StartsWith(\"?\"))\n            query = query.Substring(1);\n\n        foreach (var vp in query.Split('&'))\n        {\n            if (string.IsNullOrWhiteSpace(vp))\n                continue;\n\n            var singlePair = vp.Split('=');\n            nvc.Add(singlePair[0], singlePair.Length == 2 ? singlePair[1] : string.Empty);\n        }\n\n        return nvc;\n    }\n\n    /// <summary>\n    /// Converts a NameValueCollection to string.\n    /// Used in link generations and especially also the <see cref=\"Context.Query.Parameters\"/>\n    /// so be very careful if you change anything!\n    /// </summary>\n    /// <param name=\"nvc\"></param>\n    /// <returns></returns>\n    internal static string NvcToString(this NameValueCollection nvc)\n        => NvcToString(nvc, \"=\", \"&\", \"\", \"\", true, null);\n\n    private class KeyValuePairTemp\n    {\n        public required string Key;\n        public required string? Value;\n        //public string[] AllValues;\n    }\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static string NvcToString(NameValueCollection nvc, string keyValueSeparator, string pairSeparator,\n        string terminator, string empty, bool repeatKeyForEachValue, string? valueSeparator)\n    {\n        // Note 2dm: reworked this entire logic 2022-04-07, all tests passed, believe it's ok, but there is a minimal risk\n        var allPairs = nvc.AllKeys\n            .SelectMany(key =>\n            {\n                var values = nvc.GetValues(key) ?? [];\n                var noValues = values.Length == 0;\n                if (!noValues)\n                {\n                    values = values.Where(v => !string.IsNullOrEmpty(v)).ToArray();\n                    noValues = values.Length == 0;\n                }\n\n                // Key null; 2 options left, values or no values\n                if (key is null)\n                    return noValues\n                        ? []\n                        // If no key, treat the values as standalone keys\n                        : values.Select(v => new KeyValuePairTemp { Key = v, Value = null }).ToArray();\n\n                // Key not null, no values\n                if (noValues) return [new() { Key = key, Value = null }];\n\n                // Key null, values - two options - give as array or single item\n                return repeatKeyForEachValue\n                    ? values.Select(v => new KeyValuePairTemp { Key = key, Value = v.ToString() })\n                    : [new() { Key = key, Value = string.Join(valueSeparator, values) }];\n            })\n            .Select(set => set.Key + (string.IsNullOrEmpty(set.Value) ? \"\" : keyValueSeparator + set.Value))\n            //.SelectMany(set =>\n            //{\n            //    var key = set.Key;\n            //    // Important - both key and values can be null; values can be a list of things\n            //    var values = set.AllValues;// nvc.GetValues(key);\n            //    var noValues = (values == null || values.Length == 0);\n            //    if (key is null)\n            //    {\n            //        if (noValues) return Array.Empty<string>();\n            //        if (repeatKeyForEachValue)\n            //            return values.Select(v => v.ToString())\n            //                .ToArray();\n            //        return new[] { string.Join(valueSeparator, values) };\n            //    }\n\n            //    if (noValues) return new[] { key };\n\n            //    if (repeatKeyForEachValue)\n            //        return values.Select(v => key + (string.IsNullOrEmpty(v) ? \"\" : keyValueSeparator + v));\n\n            //    return new[] { key + (values.All(string.IsNullOrEmpty) ? \"\" : keyValueSeparator + string.Join(valueSeparator, values)) };\n            //})\n            .ToArray();\n        return allPairs.Any() ? string.Join(pairSeparator, allPairs) + terminator : empty;\n    }\n\n\n    /// <summary>\n    /// Import an NVC into another\n    /// </summary>\n    /// <returns></returns>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static NameValueCollection Merge(this NameValueCollection first, NameValueCollection source, bool replace = false)\n    {\n        var target = new NameValueCollection(first);\n        source.AllKeys\n            .Where(k => !string.IsNullOrEmpty(k))\n            .ToList()\n            .ForEach(k =>\n            {\n                var values = source.GetValues(k) ?? [null!]; // catch null-values\n\n                foreach (var v in values)\n                {\n                    if (replace)\n                        target.Set(k, v);\n                    else\n                        target.Add(k, v);\n                }\n            });\n        return target;\n    }\n\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static string QuickAddUrlParameter(string url, string name, string value)\n        => $\"{url}{(url.IndexOf('?') > 0 ? '&' : '?')}{name}={value}\";\n\n\n    [ShowApiWhenReleased(ShowApiMode.Never)] \n    public static string AddQueryString(string url, string newParams) => AddQueryString(url, ParseQueryString(newParams));\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static string AddQueryString(string url, NameValueCollection? newParams)\n    {\n        // check do we have any work to do\n        if (newParams == null || newParams.Count == 0)\n            return url;\n\n        // 1. Get only the query string parts\n        var parts = new UrlParts(url);\n\n        // if the url already has some params we should take that and split it into it's pieces\n        var queryParams = ParseQueryString(parts.Query);\n\n        // new params would replace existing queryString params or append new param to queryString\n        var finalParams = queryParams.Merge(newParams);\n\n        // combine new query string in url\n        return GetUrlWithUpdatedQueryString(parts, finalParams);\n    }\n\n\n    private static string GetUrlWithUpdatedQueryString(UrlParts parts, NameValueCollection queryString)\n    {\n        var newUrl = parts.ToLink(suffix: false);\n        if (queryString.Count > 0)\n            newUrl += UrlParts.QuerySeparator + queryString.NvcToString();\n\n        if (!string.IsNullOrWhiteSpace(parts.Fragment))\n            newUrl += UrlParts.FragmentSeparator + parts.Fragment;\n\n        return newUrl;\n\n    }\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static string RemoveQuery(this string url) => RemoveAfterSeparator(url, UrlParts.QuerySeparator);\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static string RemoveFragment(this string url) => RemoveAfterSeparator(url, UrlParts.FragmentSeparator);\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static string RemoveQueryAndFragment(this string url) => url.RemoveQuery().RemoveFragment();\n    private static string RemoveAfterSeparator(string @string, char separator)\n    {\n        if (string.IsNullOrEmpty(@string)) return @string;\n        var start = @string.IndexOf(separator);\n        return start < 0 ? @string : @string.Substring(0, start);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared/UrlParts.cs",
    "content": "﻿using System.Text;\n\nnamespace ToSic.Sxc.Oqt.Shared;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class UrlParts\n{\n    public const char QuerySeparator = '?';\n    public const char FragmentSeparator = '#';\n    public const char ValuePairSeparator = '&';\n    public const string ProtocolColon = \":\";\n    public const string Slash = \"/\";\n    public const string ProtocolSeparator = \"://\";\n    public const string RootWithoutProtocol = \"//\";\n\n\n    public string Url;\n    public string Query = string.Empty;\n    public string Fragment = string.Empty;\n    public string Path = string.Empty;\n    public string Protocol = string.Empty;\n    public string Domain = string.Empty;\n\n    public UrlParts(string url)\n    {\n        url = (url ?? \"\").Trim();\n        Url = url;\n        if (string.IsNullOrEmpty(url)) return;\n\n        var rest = url;\n        rest = ExtractFragment(url, rest);\n        Path = rest;\n        rest = ExtractQuery(rest);\n        Path = rest;\n        rest = ExtractProtocol(rest);\n        Path = rest;\n\n        // now check domain - only valid if the link had a \"//\" in it to start with or after the protocol\n        var domainAtStartPossible = !string.IsNullOrEmpty(Protocol);\n        rest = ExtractDomain(domainAtStartPossible, rest);\n        Path = rest;\n\n    }\n\n    public void ReplaceRoot(string url)\n    {\n        if (string.IsNullOrEmpty(url)) return;\n\n        if (!url.Contains(Slash) && !url.Contains(ProtocolColon))\n            Domain = url;\n        else\n        {\n            var newParts = new UrlParts(url);\n            if (!string.IsNullOrEmpty(newParts.Domain)) Domain = newParts.Domain;\n            if (!string.IsNullOrEmpty(newParts.Protocol)) Protocol = newParts.Protocol;\n        }\n        if (!string.IsNullOrEmpty(Domain) && string.IsNullOrEmpty(Protocol))\n            Protocol = RootWithoutProtocol;\n    }\n\n    private string ExtractDomain(bool domainAtStartPossible, string rest)\n    {\n        if (domainAtStartPossible && !string.IsNullOrEmpty(rest))\n        {\n            var postDomainSlash = rest.IndexOf('/');\n            if (postDomainSlash == -1) postDomainSlash = rest.Length;\n            Domain = rest.Substring(0, postDomainSlash);\n            rest = rest.Substring(postDomainSlash);\n        }\n\n        return rest;\n    }\n\n    private string ExtractProtocol(string rest)\n    {\n        if (rest.StartsWith(RootWithoutProtocol))\n        {\n            Protocol = RootWithoutProtocol;\n            rest = rest.Substring(RootWithoutProtocol.Length);\n            return rest;\n        }\n\n        var separator = rest.IndexOf(ProtocolSeparator, StringComparison.Ordinal);\n        // protocol would have to be at least 1 char\n        if (separator > 1)\n        {\n            Protocol = rest.Substring(0, separator + ProtocolSeparator.Length);\n            rest = rest.Substring(Protocol.Length); // drop protocol + ':'\n        }\n\n        return rest;\n    }\n\n    private string ExtractQuery(string rest)\n    {\n        var queryStart = rest.IndexOf(QuerySeparator);\n        if (queryStart < 0) return rest;\n        Query = rest.Substring(queryStart + 1);\n        return rest.Substring(0, queryStart);\n    }\n\n    private string ExtractFragment(string url, string rest)\n    {\n        var fragmentStart = rest.IndexOf(FragmentSeparator);\n        if (fragmentStart < 0) return rest;\n        Fragment = url.Substring(fragmentStart + 1);\n        return url.Substring(0, fragmentStart);\n    }\n\n    public bool IsAbsolute => !string.IsNullOrEmpty(Protocol); // Path.StartsWith(\"//\") || Path.StartsWith(\"http://\") || Path.StartsWith(\"https://\");\n    public bool IsRelative => Path.StartsWith(\".\") && !IsAbsolute && !string.IsNullOrEmpty(Domain);\n\n\n    public string ToLink(string? format = null, bool suffix = true)\n    {\n        var endPart = Path + (suffix ? Suffix() : \"\");\n        if (format == \"/\") return endPart;\n        if (format == \"//\")\n            return string.IsNullOrEmpty(Domain)\n                ? endPart\n                : RootWithoutProtocol + Domain + endPart;\n\n        return Protocol + Domain + endPart;\n    }\n\n    public string BuildUrl()\n    {\n        var urlStringBuilder = new StringBuilder(!string.IsNullOrEmpty(Path) ? Path : string.Empty);\n        AppendSuffix(urlStringBuilder);\n        return urlStringBuilder.ToString();\n    }\n\n    // would return the entire suffix starting from the `?` _including_ the `?` or `#` - if nothing is there, empty string\n    public string Suffix()\n    {\n        var urlStringBuilder = new StringBuilder();\n        AppendSuffix(urlStringBuilder);\n        return urlStringBuilder.ToString();\n    }\n\n    private void AppendSuffix(StringBuilder urlStringBuilder)\n    {\n        if (!string.IsNullOrEmpty(Query)) urlStringBuilder.Append($\"{QuerySeparator}{Query}\");\n        if (!string.IsNullOrEmpty(Fragment)) urlStringBuilder.Append($\"{FragmentSeparator}{Fragment}\");\n    }\n\n    public static string ConnectParameters(params string[] parameters)\n    {\n        if (parameters == null || parameters.Length == 0) return \"\";\n        var realParams = parameters.Where(p => !string.IsNullOrWhiteSpace(p)).ToArray();\n        return string.Join(ValuePairSeparator.ToString(), realParams);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared.Tests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using ToSic.Sxc.Oqt.Shared.Helpers;\nglobal using static Xunit.Assert;"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared.Tests/HtmlHelper/HtmlHelperScriptTests.cs",
    "content": "﻿using Oqtane.Models;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.Oqtane.Shared.HtmlHelper;\n\n\npublic class HtmlHelperScriptTests(ITestOutputHelper output)\n{\n    /// <summary>\n    ///  Add Script Test Accessor\n    /// </summary>\n    private static string AddScriptTac(string html, string src, Alias alias) =>\n        Oqt.Shared.Helpers.HtmlHelper.ManageScripts(\n            html,\n            new()\n            {\n                SxcScripts = [src],\n                TemplateResources = [],\n            },\n            alias\n        );\n\n    [Theory]\n    [InlineData(\"Add Script\", \"\"\"<!-- just a comment --><script src=\"https://example.com/script.js\"></script>\"\"\", \"<!-- just a comment -->\", \"script.js\")]\n    public void TestVariousCombinationsOfAdd(string name, string expected, string html, string src)\n    {\n        // Arrange\n        //var html = \"<!-- just a comment -->\";\n        //var src = \"script.js\";\n        var alias = new Alias { BaseUrl = \"https://example.com/\" };\n\n        // Act\n        var result = AddScriptTac(html, src, alias);\n\n        // Assert\n        output.WriteLine($\"Expected: {expected}\");\n        output.WriteLine($\"Result: {result}\");\n        //Assert.Equal(expected, result);\n        Contains(expected, result);\n\n    }\n\n    //[Fact]\n    //public void AddScript_WithValidHtmlAndSrc_AddsScript()\n    //{\n    //    // Arrange\n    //    var html = \"<!-- just a comment -->\";\n    //    var src = \"script.js\";\n    //    var alias = new Alias { BaseUrl = \"https://example.com/\" };\n\n    //    // Act\n    //    var result = AddScriptTac(html, src, alias);\n\n    //    // Assert\n    //    Assert.Contains(\"\"\"<script src=\"https://example.com/script.js\"></script>\"\"\", result);\n    //}\n\n    [Fact]\n    public void AddScript_WithExistingScript_DoesNotAddScript()\n    {\n        // Arrange\n        var html = \"<!-- just a comment --><script src=\\\"https://example.com/script.js\\\"></script><!-- just a comment -->\";\n        var src = \"script.js\";\n        var alias = new Alias { BaseUrl = \"https://example.com/\" };\n\n        // Act\n        var result = AddScriptTac(html, src, alias);\n\n        // Assert\n        var scriptCount = result.Split([\"\"\"<script src=\"https://example.com/script.js\"></script>\"\"\"], StringSplitOptions.None).Length - 1;\n        Equal(1, scriptCount);\n    }\n\n    [Fact]\n    public void AddScript_WithEmptyHtml_AddsScript()\n    {\n        // Arrange\n        var html = string.Empty;\n        var src = \"script.js\";\n        var alias = new Alias { BaseUrl = \"https://example.com/\" };\n\n        // Act\n        var result = AddScriptTac(html, src, alias);\n\n        // Assert\n        Contains(\"\"\"<script src=\"https://example.com/script.js\"></script>\"\"\", result);\n    }\n\n    [Fact]\n    public void AddScript_WithNullSrc_ReturnsOriginalHtml()\n    {\n        // Arrange\n        var html = \"<!-- just a comment -->\";\n        var alias = new Alias { BaseUrl = \"https://example.com/\" };\n\n        // Act\n#pragma warning disable CS8600\n        string src = null;\n#pragma warning disable CS8604\n        var result = AddScriptTac(html, src, alias);\n#pragma warning restore CS8604\n#pragma warning restore CS8600\n\n        // Assert\n        Equal(html, result);\n    }\n\n    [Fact]\n    public void AddScript_WithEmptySrc_ReturnsOriginalHtml()\n    {\n        // Arrange\n        var html = \"<!-- just a comment -->\";\n        var src = string.Empty;\n        var alias = new Alias { BaseUrl = \"https://example.com/\" };\n\n        // Act\n        var result = AddScriptTac(html, src, alias);\n\n        // Assert\n        Equal(html, result);\n    }\n\n    [Fact]\n    public void AddScript_WithFullUrlSrc_AddsScriptWithFullUrl()\n    {\n        // Arrange\n        var html = \"<!-- just a comment -->\";\n        var src = \"https://cdn.example.com/script.js\";\n        var alias = new Alias { BaseUrl = \"https://example.com/\" };\n\n        // Act\n        var result = AddScriptTac(html, src, alias);\n\n        // Assert\n        Contains(\"\"\"<script src=\"https://cdn.example.com/script.js\"></script>\"\"\", result);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared.Tests/HtmlHelper/HtmlHelperTests.cs",
    "content": "//using System.Xml.Linq;\n//using ToSic.Sxc.Oqt.Client.Helpers;\n\n//namespace ToSic.Sxc.Oqt.Client.Tests\n//{\n//    [TestClass]\n//    public class HtmlHelperTests\n//    {\n//        private static string SetMetaTag(string id, string name, string content) => HtmlHelper.SetMetaTag(id, name, content);\n//        private static string GetAttribute(string element, string attribute) => HtmlHelper.GetAttribute(element, attribute);\n\n//        [Fact]\n//        [DataRow(\"testId\", \"testName\", \"testContent\", \"<meta id=\\\"testId\\\" name=\\\"testName\\\" content=\\\"testContent\\\" />\\n\")]\n//        [DataRow(\"testId\", \"\", \"testContent\", \"<meta id=\\\"testId\\\" content=\\\"testContent\\\" />\\n\")]\n//        [DataRow(null, \"testName\", \"\", \"<meta name=\\\"testName\\\" />\\n\")]\n//        public void SetMetaTag_ValidInput_ReturnsExpectedResult(string id, string name, string content, string expected)\n//            => Assert.Equal(expected, SetMetaTag(id, name, content));\n\n//        [Fact]\n//        [DataRow(\"<meta id=\\\"testId\\\" name=\\\"testName\\\" content=\\\"testContent\\\" />\\n\", \"content\", \"testContent\")]\n//        [DataRow(\"<meta id=\\\"testId\\\" name=\\\"testName\\\" />\\n\", \"content\", null)]\n//        public void SetMetaTag_GetAttribute_ReturnsCorrectString(string element, string attribute, string expected)\n//            => Assert.Equal(expected, GetAttribute(element, attribute));\n\n//        //[Fact]\n//        //public void GetAttribute_ValidInputs_ReturnsCorrectValue()\n//        //{\n//        //    // Arrange\n//        //    var expected = \"test-value\";\n//        //    var element = $\"<test-element test-attribute=\\\"{expected}\\\"></test-element>\";\n\n//        //    // Act\n//        //    var actual = ToSic.Sxc.Oqt.Client.Helpers.HtmlHelper.GetAttribute(element, \"test-attribute\");\n\n//        //    // Assert\n//        //    Assert.Equal(expected, actual);\n//        //}\n//    }\n//}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared.Tests/HtmlHelper/MetaTagExtractorTests.cs",
    "content": "﻿namespace ToSic.Sxc.Oqtane.Shared.HtmlHelper;\n\npublic class MetaTagExtractorTests\n{\n    private static string GetMetaTagContent(string html, string name) =>\n        Oqt.Shared.Helpers.HtmlHelper.GetMetaTagContent(html, name);\n\n    [Fact]\n    public void Test_ValidMetaTag_ReturnsContentValue()\n    {\n        var html = \"\"\"<meta name=\"keywords\" content=\"apple, banana, cherry\">\"\"\";\n        var result = GetMetaTagContent(html, \"keywords\");\n        Equal(\"apple, banana, cherry\", result);\n    }\n\n    [Fact]\n    public void Test_NoMetaTag_ReturnsNull()\n    {\n        var html = \"\"\"<meta name=\"description\" content=\"This is a description.\">\"\"\";\n        var result = GetMetaTagContent(html, \"keywords\");\n        Null(result);\n    }\n\n    [Fact]\n    public void Test_EmptyContentAttribute_ReturnsEmptyString()\n    {\n        var html = \"\"\"<meta name=\"keywords\" content=\"\">\"\"\";\n        var result = GetMetaTagContent(html, \"keywords\");\n        Equal(string.Empty, result);\n    }\n\n    [Fact]\n    public void Test_MetaTagNameCaseInsensitive_ReturnsContentValue()\n    {\n        var html = \"\"\"<meta NAME=\"KEYWORDS\" content=\"apple, banana, cherry\">\"\"\";\n        var result = GetMetaTagContent(html, \"keywords\");\n        Equal(\"apple, banana, cherry\", result);\n    }\n\n    [Fact]\n    public void Test_ContentValueWithQuotes_ReturnsCorrectValue()\n    {\n        var html = \"\"\"<meta name=\"keywords\" content=\"apple, \"banana\", cherry\">\"\"\";\n        var result = GetMetaTagContent(html, \"keywords\");\n        Equal(\"\"\"apple, \"banana\", cherry\"\"\", result);\n    }\n\n    [Fact]\n    public void Test_NullHtml_ReturnsNull()\n    {\n        var result = GetMetaTagContent(null!, \"keywords\");\n        Null(result);\n    }\n\n    [Fact]\n    public void Test_EmptyHtml_ReturnsNull()\n    {\n        var result = GetMetaTagContent(string.Empty, \"keywords\");\n        Null(result);\n    }\n\n    [Fact]\n    public void Test_NullMetaTagName_ReturnsNull()\n    {\n        var html = \"\"\"<meta name=\"keywords\" content=\"apple, banana, cherry\">\"\"\";\n        var result = GetMetaTagContent(html, null!);\n        Null(result);\n    }\n\n    [Fact]\n    public void Test_EmptyMetaTagName_ReturnsNull()\n    {\n        var html = \"\"\"<meta name=\"keywords\" content=\"apple, banana, cherry\">\"\"\";\n        var result = GetMetaTagContent(html, string.Empty);\n        Null(result);\n    }\n\n    [Fact]\n    public void Test_MetaTagWithSpaces_ReturnsContentValue()\n    {\n        var html = \"\"\"<meta    name   =   \"keywords\"   content   =   \"apple, banana, cherry\"   >\"\"\";\n        var result = GetMetaTagContent(html, \"keywords\");\n        Equal(\"apple, banana, cherry\", result);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared.Tests/HtmlHelper/MetaTagUpdaterTests.cs",
    "content": "﻿namespace ToSic.Sxc.Oqtane.Shared.HtmlHelper;\n\npublic class MetaTagUpdaterTests\n{\n    private const string MetaFruitDoubleQuote = \"\"\"<meta name=\"keywords\" content=\"orange, grape, strawberry\">\"\"\";\n    private const string MetaFruitSingleQuote = \"\"\"<meta name=\"keywords\" content='orange, grape, strawberry'>\"\"\";\n\n    private static string AddOrUpdateMetaTagContent(string html, string name, string content) =>\n        Oqt.Shared.Helpers.HtmlHelper.AddOrUpdateMetaTagContent(html, name, content);\n\n    [Fact]\n    public void Test_UpdateExistingMetaTag()\n    {\n        var headContent = \"\"\"<meta name=\"keywords\" content=\"apple, banana, cherry\">\"\"\";\n        var result = AddOrUpdateMetaTagContent(headContent, \"keywords\", \"orange, grape, strawberry\");\n        Contains(MetaFruitDoubleQuote, result);\n    }\n\n    [Fact]\n    public void Test_AppendNewMetaTag()\n    {\n        var headContent = \"\"\"<meta name=\"description\" content=\"This is a description.\">\"\"\";\n        var result = AddOrUpdateMetaTagContent(headContent, \"keywords\", \"orange, grape, strawberry\");\n        Contains(MetaFruitSingleQuote, result);\n    }\n\n    [Fact]\n    public void Test_EmptyHeadContent_AppendNewMetaTag()\n    {\n        var headContent = @\"\";\n        var result = AddOrUpdateMetaTagContent(headContent, \"keywords\", \"orange, grape, strawberry\");\n        Contains(MetaFruitSingleQuote, result);\n    }\n\n    [Fact]\n    public void Test_NullHeadContent_ReturnsOriginal()\n    {\n        var result = AddOrUpdateMetaTagContent(null!, \"keywords\", \"orange, grape, strawberry\");\n        Contains(MetaFruitSingleQuote, result);\n    }\n\n    [Fact]\n    public void Test_NullMetaTagName_ReturnsOriginal()\n    {\n        var headContent = \"\"\"<meta name=\"keywords\" content='apple, banana, cherry'>\"\"\";\n        var result = AddOrUpdateMetaTagContent(headContent, null!, \"orange, grape, strawberry\");\n        Equal(headContent, result);\n    }\n\n    [Fact]\n    public void Test_EmptyMetaTagName_ReturnsOriginal()\n    {\n        var headContent = \"\"\"<meta name=\"keywords\" content=\"apple, banana, cherry\">\"\"\";\n        var result = AddOrUpdateMetaTagContent(headContent, \"\", \"orange, grape, strawberry\");\n        Equal(headContent, result);\n    }\n\n    [Fact]\n    public void Test_NullContentValue_UpdatesToEmpty()\n    {\n        var headContent = \"\"\"<meta name=\"keywords\" content=\"apple, banana, cherry\">\"\"\";\n        var result = AddOrUpdateMetaTagContent(headContent, \"keywords\", null!);\n        Contains(\"\"\"<meta name=\"keywords\" content=\"\">\"\"\", result);\n    }\n\n    [Fact]\n    public void Test_EmptyContentValue_UpdatesToEmpty()\n    {\n        var headContent = \"\"\"<meta name=\"keywords\" content=\"apple, banana, cherry\">\"\"\";\n        var result = AddOrUpdateMetaTagContent(headContent, \"keywords\", \"\");\n        Contains(\"\"\"<meta name=\"keywords\" content=\"\">\"\"\", result);\n    }\n}"
  },
  {
    "path": "Src/Oqtane/ToSic.Sxc.Oqt.Shared.Tests/ToSic.Sxc.Oqt.Shared.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net9.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <IsPackable>false</IsPackable>\n    <LangVersion>preview</LangVersion>\n    <RootNamespace>ToSic.Sxc.Oqtane.Shared</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"Xunit.DependencyInjection\" Version=\"9.9.0\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.0\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Oqt.Shared\\ToSic.Sxc.Oqt.Shared.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Using Include=\"Xunit\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Patches/readme.md",
    "content": "## 2sxc Patches\n\nThis folder contains small solutions which patch a specific issue. \n\nAs of now, there is this\n\n## DisablePagePublishing\n\nFolder `ToSic.Sxc.Patch.DisablePagePublishing`\n\nThis is for Dnn and should disable PagePublishing completely, so if you use Evoq and explicitly don't want page publishing, this should do it for you\n\n2022-05-17 Was removed, as it's now a built-in feature of 2sxc"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/CompilationReferencesProvider.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.Loader;\nusing Microsoft.AspNetCore.Mvc.ApplicationParts;\n\n// Used by RazorView compilation.\n// Based on https://stackoverflow.com/questions/58685966/adding-assemblies-types-to-be-made-available-to-razor-page-at-runtime to work\nnamespace ToSic.Sxc.Razor;\n\npublic class CompilationReferencesProvider(Assembly assembly) : AssemblyPart(assembly), ICompilationReferencesProvider\n{\n    public IEnumerable<string> GetReferencePaths()\n    {\n        // your `LoadPrivateBinAssemblies()` method needs to be called before the next line executes!\n        // So you should load all private bin's before the first RazorPage gets requested.\n\n        // 2022-11-09 2dm - original code, using deprecated CodeBase property\n        //return AssemblyLoadContext.GetLoadContext(_assembly).Assemblies\n        //    .Where(_ => !_.IsDynamic)\n        //    .Select(_ => new Uri(_.CodeBase).LocalPath);\n\n        // 2022-11-09 2dm new code\n        // 1. Ensure we don't run into null problems\n        var loadContext = AssemblyLoadContext.GetLoadContext(Assembly);\n        if (loadContext == null) return Enumerable.Empty<string>();\n\n        var nonDynamicAssemblies = loadContext.Assemblies\n            .Where(a => !a.IsDynamic)\n            .ToList();\n\n        // 2. use new code with location. has some duplicates and many \"\" empty strings\n        // which seem to be merged dynamic libraries - usually the CodeBase called them \"System.Private.CoreLib.dll\"\n        // But that one is already included\n        var newer = nonDynamicAssemblies.Select(a => a.Location).ToList();\n        var newerDistinct = newer.Distinct().Where(path => !string.IsNullOrEmpty(path)).ToList();\n\n        // Temporary tests to figure out why we had missmatches\n        // Leave the code in for now, in case we need to debug\n\n        //var codeBase = nonDynamicAssemblies.Select(_ => new Uri(_.CodeBase).LocalPath).ToList();\n        //var codeBaseDistinct = codeBase.Distinct().ToList();\n\n        // if all is ok, remove 2023 #removeV15\n        //var notInNewer = newerDistinct.Where(n => !codeBaseDistinct.Contains(n)).ToList();\n        //var notInCodebase = codeBaseDistinct.Where(n => !newerDistinct.Contains(n)).ToList();\n\n        //if (codeBaseDistinct.Count != newerDistinct.Count)\n        //    throw new(\"count missmatch\");\n\n        //if (notInNewer.Count > 0)\n        //    throw new(\"not-in-newer has entries\");\n\n        //if (!codeBase.All(newer.Contains))\n        //    throw new(\"test 2\");\n\n        //foreach (var cbEntry in codeBase)\n        //    if (!newer.Contains(cbEntry))\n        //        throw new Exception(\"can't find \" + cbEntry);\n\n        return newerDistinct;\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Custom.Hybrid/OqtRazorBase.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing Microsoft.AspNetCore.Mvc.Razor.Internal;\nusing Microsoft.AspNetCore.Mvc.ViewFeatures;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Razor;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing IHasLog = ToSic.Sys.Logging.IHasLog;\nusing ILog = ToSic.Sys.Logging.ILog;\nusing Logging_IHasLog = ToSic.Sys.Logging.IHasLog;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class OqtRazorBase<TModel>: Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>, IHasCodeLog, Logging_IHasLog, ISetDynamicModel, IGetCodePath\n{\n    #region Constructor / DI / SysHelp\n\n    /// <summary>\n    /// Constructor - only available for inheritance\n    /// </summary>\n    [PrivateApi]\n    protected OqtRazorBase(int compatibilityLevel, string logName)\n    {\n        CompatibilityLevel = compatibilityLevel;\n        RzrHlp = new(this);\n        //Log.Rename(logName);\n    }\n\n    [PrivateApi] public int CompatibilityLevel { get; }\n\n\n    /// <summary>\n    /// Special helper to move all Razor logic into a separate class.\n    /// For architecture of Composition over Inheritance.\n    /// </summary>\n    [PrivateApi]\n    internal OqtRazorHelper<TModel> RzrHlp { get; }\n\n    #endregion\n\n    #region GetService / Logs / DevTools\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class\n        => RzrHlp.ExCtxRoot.GetTypedApi().GetService<TService>();\n\n    /// <inheritdoc cref=\"ITypedCode16.GetService{TService}(NoParamOrder, string?)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TService GetService<TService>(NoParamOrder npo = default, string? typeName = default) where TService : class\n        => AppCodeGetNamedServiceHelper.GetService<TService>(owner: this, RzrHlp.CodeHelper.Specs, typeName);\n\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public ICodeLog Log => RzrHlp.CodeLog;\n\n    [PrivateApi] ILog IHasLog.Log => RzrHlp.Log;\n\n    [PrivateApi(\"Not yet ready\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public IDevTools DevTools => RzrHlp.ExCtxRoot.GetTypedApi().DevTools;\n\n    #endregion\n\n    #region DynCode Root\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    internal IExecutionContext ExCtx => RzrHlp.ExCtxRoot!;\n\n    [PrivateApi]\n    public void ConnectToRoot(IExecutionContext exCtx)\n        => RzrHlp.ConnectToRoot(exCtx);\n\n    [RazorInject]\n    [PrivateApi]\n    public new ViewDataDictionary<TModel> ViewData\n    {\n        get => base.ViewData;\n        set => base.ViewData = RzrHlp.HandleViewDataInject(value);\n    }\n\n    #endregion\n\n    #region Dynamic Model\n\n    void ISetDynamicModel.SetDynamicModel(RenderSpecs renderSpecs) => RzrHlp.SetDynamicModel(renderSpecs);\n\n    #endregion\n\n\n\n    #region CreateInstance\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstancePath\"/>\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    // Note: The path for CreateInstance / GetCode - unsure if this is actually used anywhere on this object\n    string IGetCodePath.CreateInstancePath\n    {\n        get => field ?? Path;\n        set;\n    }\n\n    #endregion\n\n\n\n\n\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Custom.Hybrid/Razor12.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\npublic abstract class Razor12: Razor12<object>;"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Custom.Hybrid/Razor12_T.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing Custom.Razor.Sys;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Services;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Engines.Sys;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\n[method: PrivateApi]\npublic abstract class Razor12<TModel>() : OqtRazorBase<TModel>(CompatibilityLevels.CompatibilityLevel12, \"Oqt.Rzr12\"),\n    IHasCodeLog, IRazor, IRazor12, ISetDynamicModel\n{\n    internal ICodeDynamicApiHelper CodeApi => RzrHlp.ExCtxRoot.GetDynamicApi();\n\n    #region Dynamic Model\n\n    public dynamic DynamicModel => RzrHlp.DynamicModel;\n\n    #endregion\n\n    #region CreateInstance\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstancePath\"/>\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    // Note: The path for CreateInstance / GetCode - unsure if this is actually used anywhere on this object\n    string IGetCodePath.CreateInstancePath\n    {\n        get => field ?? Path;\n        set;\n    }\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\"/>\n    public dynamic? CreateInstance(string virtualPath, NoParamOrder npo = default, string? name = null, string? relativePath = null, bool throwOnError = true)\n        => RzrHlp.CreateInstance(virtualPath, npo, name, relativePath, throwOnError);\n\n    #endregion\n\n    #region Content, Header, etc.\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic? Content => CodeApi.Content;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic? Header => CodeApi.Header;\n\n    #endregion\n\n\n    #region Link, Edit, App, Data\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public IEditService Edit => CodeApi.Edit;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi.Data;\n\n    #endregion\n\n    #region AsDynamic in many variations + AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic? AsDynamic(string json, string? fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic? AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic? AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public dynamic? AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n    #region CreateSource\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n    #endregion\n\n    #region Convert-Service - V12 only!\n\n    [PrivateApi] public IConvertService Convert => field ??= CodeApi.Convert;\n\n    #endregion\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    #endregion\n\n    #region CmsContext \n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    public dynamic Settings => CodeApi.Settings;\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Custom.Hybrid/Razor14.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing Custom.Razor.Sys;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Services;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n// ReSharper disable once UnusedMember.Global\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\npublic abstract class Razor14: Razor12<dynamic>, IRazor14<object, ServiceKit14>\n{\n    [field: AllowNull, MaybeNull]\n    public ServiceKit14 Kit => field ??= CodeApi.ServiceKit14;\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    [PrivateApi(\"added in 16.05, but not sure if it should be public\")]\n    public dynamic? GetCode(string path, NoParamOrder npo = default, string? className = default)\n        => RzrHlp.GetCode(path, npo, className);\n\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Custom.Hybrid/RazorTyped.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\n// ReSharper disable once UnusedMember.Global\n\npublic abstract class RazorTyped : RazorTyped<dynamic>;"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Custom.Hybrid/RazorTyped_TModel.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing Custom.Razor.Sys;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Razor.Internal;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.AspNetCore.Mvc.Rendering;\nusing Microsoft.AspNetCore.Mvc.ViewFeatures;\nusing ToSic.Eav.Data;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sys.Code.Help;\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Hybrid;\n\n[PrivateApi(\"This will already be documented through the Dnn DLL so shouldn't appear again in the docs\")]\n[method: PrivateApi]\n// ReSharper disable once UnusedMember.Global\npublic abstract class RazorTyped<TModel>()\n    : OqtRazorBase<TModel>(CompatibilityLevels.CompatibilityLevel16, \"Oqt.Rzr16\"), IHasCodeLog, IRazor,\n        ISetDynamicModel, ITypedCode16, IHasCodeHelp\n{\n    #region ServiceKit\n\n    [field: AllowNull, MaybeNull]\n    internal ICodeTypedApiHelper CodeApi => field ??= RzrHlp.ExCtxRoot.GetTypedApi();\n\n    /// <inheritdoc cref=\"IHasKit{TServiceKit}.Kit\"/>\n    [field: AllowNull, MaybeNull]\n    public ServiceKit16 Kit => field ??= CodeApi.ServiceKit16;\n\n    #endregion\n\n    #region MyModel\n\n    [PrivateApi(\"WIP v16.02\")]\n    public ITypedRazorModel MyModel => CodeHelper.MyModel;\n\n    #endregion\n\n    #region New App, Settings, Resources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    /// <inheritdoc />\n    public IAppTyped App => CodeApi.AppTyped;\n\n    /// <inheritdoc cref=\"ITypedApi.AllResources\" />\n    public ITypedStack AllResources => CodeHelper.AllResources;\n\n    /// <inheritdoc cref=\"ITypedApi.AllSettings\" />\n    public ITypedStack AllSettings => CodeHelper.AllSettings;\n\n    #endregion\n\n    #region My... Stuff\n\n    private TypedCode16Helper CodeHelper => RzrHlp.CodeHelper;\n\n    public ITypedItem MyItem => CodeHelper.MyItem;\n\n    public IEnumerable<ITypedItem> MyItems => CodeHelper.MyItems;\n\n    public ITypedItem MyHeader => CodeHelper.MyHeader;\n\n    public IDataSource MyData => CodeApi.Data;\n\n    #endregion\n\n    #region As Conversions\n\n    /// <inheritdoc cref=\"ITypedApi.AsItem\" />\n    public ITypedItem AsItem(object data, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsItem(data, new() { ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsItems\" />\n    public IEnumerable<ITypedItem> AsItems(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsItems(list, new() { ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsEntity\" />\n    public IEntity AsEntity(ICanBeEntity thing)\n        => CodeApi.Cdf.AsEntity(thing);\n\n    /// <inheritdoc cref=\"ITypedApi.AsTyped\" />\n    public ITyped AsTyped(object original, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsTyped(original, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsTypedList\" />\n    public IEnumerable<ITyped> AsTypedList(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi.Cdf.AsTypedList(list, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack\" />\n    public ITypedStack AsStack(params object[] items)\n        => CodeApi.Cdf.AsStack(items);\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack{T}\" />\n    public T AsStack<T>(params object[] items)\n        where T : class, IModelFromData, new()\n        => CodeApi.Cdf.AsStack<T>(items);\n\n    #endregion\n\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    public dynamic? GetCode(string path, NoParamOrder npo = default, string? className = default)\n        => RzrHlp.GetCode(path, npo, className);\n\n    #region MyContext & UniqueKey\n\n    /// <inheritdoc cref=\"ITypedApi.MyContext\" />\n    public ICmsContext MyContext => CodeApi.CmsContext;\n\n    /// <inheritdoc cref=\"ITypedApi.MyPage\" />\n    public ICmsPage MyPage => CodeApi.CmsContext.Page;\n\n    /// <inheritdoc cref=\"ITypedApi.MyUser\" />\n    public ICmsUser MyUser => CodeApi.CmsContext.User;\n\n    /// <inheritdoc cref=\"ITypedApi.MyView\" />\n    public ICmsView MyView => CodeApi.CmsContext.View;\n\n    /// <inheritdoc cref=\"ITypedApi.UniqueKey\" />\n    public string UniqueKey => Kit.Key.UniqueKey;\n\n    #endregion\n\n    #region Dev Tools & Dev Helpers\n\n    [PrivateApi(\"Not yet ready\")]\n    public new IDevTools DevTools => CodeHelper.DevTools;\n\n    [PrivateApi] List<CodeHelp> IHasCodeHelp.ErrorHelpers => HelpDbRazor.Compile16;\n\n    #endregion\n\n\n    /// <summary>\n    /// This is a tmp workaround to enable injecting the following properties in cshtml compiled with roslyn in Oqtane\n    /// </summary>\n\n    [RazorInject]\n    public IModelExpressionProvider ModelExpressionProvider { get; set; } = null!;\n\n    [RazorInject]\n    public IUrlHelper Url { get; set; } = null!;\n\n    [RazorInject]\n    public IViewComponentHelper Component { get; set; } = null!;\n\n    [RazorInject]\n    public IJsonHelper Json { get; set; } = null!;\n\n    [RazorInject]\n    public IHtmlHelper<dynamic> Html { get; set; } = null!;\n\n    public PageContext PageContext { get; set; } = null!;\n\n    #region As / AsList WIP v17\n\n    /// <inheritdoc />\n    public T As<T>(object source, NoParamOrder npo = default)\n        where T : class, IModelFromData\n        => CodeApi.Cdf.AsCustom<T>(source: source, npo: npo)!;\n\n    /// <inheritdoc />\n    public IEnumerable<T> AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData\n        => CodeApi.Cdf.AsCustomList<T>(source: source, npo: npo, nullIfNull: nullIfNull);\n\n    #endregion\n\n    #region WIP v17\n\n    /// <summary>\n    /// Typed Model of a Razor with typed model\n    /// </summary>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Introduced in v17.03 (beta)\n    /// * Stable since v18.00\n    /// </remarks>\n    [PrivateApi(\"WIP, don't publish yet\")]\n    public new TModel Model => CodeHelper.GetModel<TModel>();\n\n    /// <inheritdoc cref=\"CodeTyped.Customize\"/>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    protected ICodeCustomizer Customize => field ??= CodeApi.GetService<ICodeCustomizer>(reuse: true);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Custom.Oqtane/Razor12.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Oqtane;\n\n/// <summary>\n/// The base class for Razor files in Oqtane.\n/// \n/// As of 2sxc 12.0 it's identical to [](xref:Custom.Hybrid.Razor12), but in future it may have some more Oqtane specific features. \n/// </summary>\n[PublicApi]\npublic abstract class Razor12: Razor12<object>;"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Custom.Oqtane/Razor12_T.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace Custom.Oqtane;\n\n/// <summary>\n/// The generic base class for Razor files in Oqtane which have a custom model.\n/// \n/// As of 2sxc 12.0 it's identical to [](xref:Custom.Hybrid.Razor12), but in future it may have some more Oqtane specific features. \n/// </summary>\n/// <typeparam name=\"TModel\"></typeparam>\n[PrivateApi(\"This probably doesn't make sense to surface, as the model is always object from 2sxc by default\")]\npublic abstract class Razor12<TModel>: Hybrid.Razor12<TModel>;"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/CSharpCompiler.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// src/Mvc/Mvc.Razor.RuntimeCompilation/src/CSharpCompiler.cs\n\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Reflection;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Emit;\nusing Microsoft.CodeAnalysis.Text;\nusing Microsoft.Extensions.DependencyModel;\nusing Microsoft.Extensions.Hosting;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing DependencyContextCompilationOptions = Microsoft.Extensions.DependencyModel.CompilationOptions;\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\n#pragma warning disable CA1852 // Seal internal types\ninternal class CSharpCompiler\n#pragma warning restore CA1852 // Seal internal types\n{\n    private readonly RazorReferenceManager _referenceManager;\n    private readonly IWebHostEnvironment _hostingEnvironment;\n    private bool _optionsInitialized;\n    private CSharpParseOptions? _parseOptions;\n    private CSharpCompilationOptions? _compilationOptions;\n    private EmitOptions? _emitOptions;\n    private bool _emitPdb;\n\n    public CSharpCompiler(RazorReferenceManager manager, IWebHostEnvironment hostingEnvironment)\n    {\n        _referenceManager = manager ?? throw new ArgumentNullException(nameof(manager));\n        _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));\n    }\n\n    public virtual CSharpParseOptions ParseOptions\n    {\n        get\n        {\n            EnsureOptions();\n            return _parseOptions;\n        }\n    }\n\n    public virtual CSharpCompilationOptions CSharpCompilationOptions\n    {\n        get\n        {\n            EnsureOptions();\n            return _compilationOptions;\n        }\n    }\n\n    public virtual bool EmitPdb\n    {\n        get\n        {\n            EnsureOptions();\n            return _emitPdb;\n        }\n    }\n\n    public virtual EmitOptions EmitOptions\n    {\n        get\n        {\n            EnsureOptions();\n            return _emitOptions;\n        }\n    }\n\n    public SyntaxTree CreateSyntaxTree(SourceText sourceText)\n    {\n        return CSharpSyntaxTree.ParseText(\n            sourceText,\n            options: ParseOptions);\n    }\n\n    public CSharpCompilation CreateCompilation(string assemblyName)\n    {\n        return CSharpCompilation.Create(\n            assemblyName,\n            options: CSharpCompilationOptions,\n            references: _referenceManager.CompilationReferences);\n    }\n\n    // Internal for unit testing.\n    protected internal virtual DependencyContextCompilationOptions GetDependencyContextCompilationOptions()\n    {\n        if (!string.IsNullOrEmpty(_hostingEnvironment.ApplicationName))\n        {\n            var applicationAssembly = Assembly.Load(new AssemblyName(_hostingEnvironment.ApplicationName));\n            var dependencyContext = DependencyContext.Load(applicationAssembly);\n            if (dependencyContext?.CompilationOptions != null)\n            {\n                return dependencyContext.CompilationOptions;\n            }\n        }\n\n        return DependencyContextCompilationOptions.Default;\n    }\n\n    [MemberNotNull(nameof(_emitOptions), nameof(_parseOptions), nameof(_compilationOptions))]\n    private void EnsureOptions()\n    {\n        if (!_optionsInitialized)\n        {\n            var dependencyContextOptions = GetDependencyContextCompilationOptions();\n            _parseOptions = GetParseOptions(_hostingEnvironment, dependencyContextOptions);\n            _compilationOptions = GetCompilationOptions(_hostingEnvironment, dependencyContextOptions);\n            _emitOptions = GetEmitOptions(dependencyContextOptions);\n\n            _optionsInitialized = true;\n        }\n\n        Debug.Assert(_parseOptions is not null);\n        Debug.Assert(_compilationOptions is not null);\n        Debug.Assert(_emitOptions is not null);\n    }\n\n    private EmitOptions GetEmitOptions(DependencyContextCompilationOptions dependencyContextOptions)\n    {\n        // Assume we're always producing pdbs unless DebugType = none\n        _emitPdb = true;\n        DebugInformationFormat debugInformationFormat;\n        if (string.IsNullOrEmpty(dependencyContextOptions.DebugType))\n        {\n            debugInformationFormat = DebugInformationFormat.PortablePdb;\n        }\n        else\n        {\n            // Based on https://github.com/dotnet/roslyn/blob/1d28ff9ba248b332de3c84d23194a1d7bde07e4d/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs#L624-L640\n            switch (dependencyContextOptions.DebugType.ToLowerInvariant())\n            {\n                case \"none\":\n                    // There isn't a way to represent none in DebugInformationFormat.\n                    // We'll set EmitPdb to false and let callers handle it by setting a null pdb-stream.\n                    _emitPdb = false;\n                    return new();\n                case \"portable\":\n                    debugInformationFormat = DebugInformationFormat.PortablePdb;\n                    break;\n                case \"embedded\":\n                    // Roslyn does not expose enough public APIs to produce a binary with embedded pdbs.\n                    // We'll produce PortablePdb instead to continue providing a reasonable user experience.\n                    debugInformationFormat = DebugInformationFormat.PortablePdb;\n                    break;\n                case \"full\":\n                case \"pdbonly\":\n                    debugInformationFormat = DebugInformationFormat.PortablePdb;\n                    break;\n                default:\n                    throw new InvalidOperationException(\"Resources.FormatUnsupportedDebugInformationFormat(dependencyContextOptions.DebugType)\");\n            }\n        }\n\n        var emitOptions = new EmitOptions(debugInformationFormat: debugInformationFormat);\n        return emitOptions;\n    }\n\n    private static CSharpCompilationOptions GetCompilationOptions(\n        IWebHostEnvironment hostingEnvironment,\n        DependencyContextCompilationOptions dependencyContextOptions)\n    {\n        var csharpCompilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, usings: ImplicitUsings.ForRazor);\n\n        // Disable 1702 until roslyn turns this off by default\n        csharpCompilationOptions = csharpCompilationOptions.WithSpecificDiagnosticOptions(\n            new Dictionary<string, ReportDiagnostic>\n            {\n                    {\"CS1701\", ReportDiagnostic.Suppress}, // Binding redirects\n                    {\"CS1702\", ReportDiagnostic.Suppress},\n                    {\"CS1705\", ReportDiagnostic.Suppress}\n            });\n\n        if (dependencyContextOptions.AllowUnsafe.HasValue)\n        {\n            csharpCompilationOptions = csharpCompilationOptions.WithAllowUnsafe(\n                dependencyContextOptions.AllowUnsafe.Value);\n        }\n\n        OptimizationLevel optimizationLevel;\n        if (dependencyContextOptions.Optimize.HasValue)\n        {\n            optimizationLevel = dependencyContextOptions.Optimize.Value ?\n                OptimizationLevel.Release :\n                OptimizationLevel.Debug;\n        }\n        else\n        {\n            optimizationLevel = hostingEnvironment.IsDevelopment() ?\n                OptimizationLevel.Debug :\n                OptimizationLevel.Release;\n        }\n        csharpCompilationOptions = csharpCompilationOptions.WithOptimizationLevel(optimizationLevel);\n\n        if (dependencyContextOptions.WarningsAsErrors.HasValue)\n        {\n            var reportDiagnostic = dependencyContextOptions.WarningsAsErrors.Value ?\n                ReportDiagnostic.Error :\n                ReportDiagnostic.Default;\n            csharpCompilationOptions = csharpCompilationOptions.WithGeneralDiagnosticOption(reportDiagnostic);\n        }\n\n        return csharpCompilationOptions;\n    }\n\n    private static CSharpParseOptions GetParseOptions(\n        IWebHostEnvironment hostingEnvironment,\n        DependencyContextCompilationOptions dependencyContextOptions)\n    {\n        var configurationSymbol = hostingEnvironment.IsDevelopment() ? \"DEBUG\" : \"RELEASE\";\n        var defines = dependencyContextOptions.Defines.Concat(new[] { configurationSymbol }).Where(define => define != null);\n\n        var parseOptions = new CSharpParseOptions(preprocessorSymbols: (IEnumerable<string>)defines);\n\n        if (string.IsNullOrEmpty(dependencyContextOptions.LanguageVersion))\n        {\n            // If the user does not specify a LanguageVersion, assume CSharp 8.0. This matches the language version Razor 3.0 targets by default.\n            parseOptions = parseOptions.WithLanguageVersion(LanguageVersion);\n        }\n        else if (LanguageVersionFacts.TryParse(dependencyContextOptions.LanguageVersion, out var languageVersion))\n        {\n            parseOptions = parseOptions.WithLanguageVersion(languageVersion);\n        }\n        //else\n        //{\n        //    Debug.Fail($\"LanguageVersion {languageVersion} specified in the deps file could not be parsed.\");\n        //}\n\n        return parseOptions;\n    }\n\n    /// <summary>\n    /// Specifies the C# language version to use during Roslyn compilation.\n    /// The \"Preview\" version allows the use of the latest language features.\n    /// </summary>\n    private static readonly LanguageVersion LanguageVersion = Enum.TryParse<LanguageVersion>(RoslynConstants.LanguageVersion, out var languageVersion) ? languageVersion : LanguageVersion.Default;\n}\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/ChecksumValidator.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// src/Mvc/Mvc.Razor.RuntimeCompilation/src/ChecksumValidator.cs\n\nusing System.Globalization;\nusing System.Security.Cryptography;\nusing Microsoft.AspNetCore.Razor.Hosting;\nusing Microsoft.AspNetCore.Razor.Language;\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\ninternal static class ChecksumValidator\n{\n    public static bool IsRecompilationSupported(RazorCompiledItem item)\n    {\n        ArgumentNullException.ThrowIfNull(item);\n\n        // A Razor item only supports recompilation if its primary source file has a checksum.\n        //\n        // Other files (view imports) may or may not have existed at the time of compilation,\n        // so we may not have checksums for them.\n        var checksums = item.GetChecksumMetadata();\n        return checksums.Any(c => string.Equals(item.Identifier, c.Identifier, StringComparison.OrdinalIgnoreCase));\n    }\n\n    // Validates that we can use an existing precompiled view by comparing checksums with files on\n    // disk.\n    public static bool IsItemValid(RazorProjectFileSystem fileSystem, RazorCompiledItem item)\n    {\n        ArgumentNullException.ThrowIfNull(fileSystem);\n        ArgumentNullException.ThrowIfNull(item);\n\n        var checksums = item.GetChecksumMetadata();\n\n        // The checksum that matches 'Item.Identity' in this list is significant. That represents the main file.\n        //\n        // We don't really care about the validation unless the main file exists. This is because we expect\n        // most sites to have some _ViewImports in common location. That means that in the case you're\n        // using views from a 3rd party library, you'll always have **some** conflicts.\n        //\n        // The presence of the main file with the same content is a very strong signal that you're in a\n        // development scenario.\n        var primaryChecksum = checksums\n            .FirstOrDefault(c => string.Equals(item.Identifier, c.Identifier, StringComparison.OrdinalIgnoreCase));\n        if (primaryChecksum == null)\n        {\n            // No primary checksum, assume valid.\n            return true;\n        }\n\n        var projectItem = fileSystem.GetItem(primaryChecksum.Identifier, fileKind: null);\n        if (!projectItem.Exists)\n        {\n            // Main file doesn't exist - assume valid.\n            return true;\n        }\n\n        var sourceDocumentChecksum = ComputeChecksum(projectItem, primaryChecksum.ChecksumAlgorithm);\n        if (!string.Equals(sourceDocumentChecksum.algorithm, primaryChecksum.ChecksumAlgorithm) ||\n            !ChecksumsEqual(primaryChecksum.Checksum, sourceDocumentChecksum.checksum))\n        {\n            // Main file exists, but checksums not equal.\n            return false;\n        }\n\n        for (var i = 0; i < checksums.Count; i++)\n        {\n            var checksum = checksums[i];\n            if (string.Equals(item.Identifier, checksum.Identifier, StringComparison.OrdinalIgnoreCase))\n            {\n                // Ignore primary checksum on this pass.\n                continue;\n            }\n\n            var importItem = fileSystem.GetItem(checksum.Identifier, fileKind: null);\n            if (!importItem.Exists)\n            {\n                // Import file doesn't exist - assume invalid.\n                return false;\n            }\n\n            sourceDocumentChecksum = ComputeChecksum(importItem, checksum.ChecksumAlgorithm);\n            if (!string.Equals(sourceDocumentChecksum.algorithm, checksum.ChecksumAlgorithm) ||\n                !ChecksumsEqual(checksum.Checksum, sourceDocumentChecksum.checksum))\n            {\n                // Import file exists, but checksums not equal.\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private static (byte[] checksum, string algorithm) ComputeChecksum(RazorProjectItem projectItem, string checksumAlgorithm)\n    {\n        ArgumentNullException.ThrowIfNull(projectItem);\n\n        Func<Stream, byte[]> hashData;\n        string algorithmName;\n\n        //only SHA1 and SHA256 are supported.  Default to SHA1\n        switch (checksumAlgorithm)\n        {\n            case nameof(SHA256):\n                hashData = SHA256.HashData;\n                algorithmName = nameof(SHA256);\n                break;\n            default:\n                hashData = SHA1.HashData;\n                algorithmName = nameof(SHA1);\n                break;\n        }\n\n        using (var stream = projectItem.Read())\n        {\n            return (hashData(stream), algorithmName);\n        }\n    }\n\n    private static bool ChecksumsEqual(string checksum, byte[] bytes)\n    {\n        if (bytes.Length * 2 != checksum.Length)\n        {\n            return false;\n        }\n\n        for (var i = 0; i < bytes.Length; i++)\n        {\n            var text = bytes[i].ToString(\"x2\", CultureInfo.InvariantCulture);\n            if (checksum[i * 2] != text[0] || checksum[i * 2 + 1] != text[1])\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/CompilationFailedException.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// src/Mvc/Mvc.Razor.RuntimeCompilation/src/CompilationFailedException.cs\n\nusing Microsoft.AspNetCore.Diagnostics;\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\ninternal class CompilationFailedException : Exception, ICompilationException\n{\n    public CompilationFailedException(\n        IEnumerable<CompilationFailure> compilationFailures)\n        : base(FormatMessage(compilationFailures))\n    {\n        ArgumentNullException.ThrowIfNull(compilationFailures);\n\n        CompilationFailures = compilationFailures;\n    }\n\n    public IEnumerable<CompilationFailure> CompilationFailures { get; }\n\n    private static string FormatMessage(IEnumerable<CompilationFailure> compilationFailures)\n    {\n        return \"Resources.CompilationFailed\" + Environment.NewLine +\n               string.Join(\n                   Environment.NewLine,\n                   compilationFailures.SelectMany(f => f.Messages!).Select(message => message!.FormattedMessage));\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/CompilationFailedExceptionFactory.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// src/Mvc/Mvc.Razor.RuntimeCompilation/src/CompilationFailedExceptionFactory.cs\n\nusing System.Globalization;\nusing Microsoft.AspNetCore.Diagnostics;\nusing Microsoft.AspNetCore.Razor.Language;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\ninternal static class CompilationFailedExceptionFactory\n{\n    // error CS0234: The type or namespace name 'C' does not exist in the namespace 'N' (are you missing\n    // an assembly reference?)\n    private const string CS0234 = nameof(CS0234);\n    // error CS0246: The type or namespace name 'T' could not be found (are you missing a using directive\n    // or an assembly reference?)\n    private const string CS0246 = nameof(CS0246);\n\n    public static CompilationFailedException Create(\n        RazorCodeDocument codeDocument,\n        IEnumerable<RazorDiagnostic> diagnostics)\n    {\n        // If a SourceLocation does not specify a file path, assume it is produced from parsing the current file.\n        var messageGroups = diagnostics.GroupBy(\n            razorError => razorError.Span.FilePath ?? codeDocument.Source.FilePath,\n            StringComparer.Ordinal);\n\n        var failures = messageGroups.Select(group =>\n            {\n                var filePath = group.Key;\n                var fileContent = ReadContent(codeDocument, filePath);\n                return new CompilationFailure(\n                    filePath,\n                    fileContent,\n                    compiledContent: string.Empty,\n                    messages: group.Select(parserError => CreateDiagnosticMessage(parserError, filePath)));\n\n            })\n            .ToList();\n\n        return new(failures);\n    }\n\n    public static CompilationFailedException Create(\n        RazorCodeDocument codeDocument,\n        string compilationContent,\n        string assemblyName,\n        IEnumerable<Diagnostic> diagnostics)\n    {\n        var diagnosticGroups = diagnostics\n            .Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error)\n            .GroupBy(diagnostic => GetFilePath(codeDocument, diagnostic), StringComparer.Ordinal);\n\n        var failures = diagnosticGroups.Select(group =>\n            {\n                var sourceFilePath = group.Key;\n                string sourceFileContent;\n                if (string.Equals(assemblyName, sourceFilePath, StringComparison.Ordinal))\n                {\n                    // The error is in the generated code and does not have a mapping line pragma\n                    sourceFileContent = compilationContent;\n                    sourceFilePath = \"Resources.GeneratedCodeFileName\";\n                }\n                else\n                {\n                    sourceFileContent = ReadContent(codeDocument, sourceFilePath);\n                }\n\n                string? additionalMessage = null;\n                if (group.Any(g =>\n                        string.Equals(CS0234, g.Id, StringComparison.OrdinalIgnoreCase) ||\n                        string.Equals(CS0246, g.Id, StringComparison.OrdinalIgnoreCase)))\n                {\n                    additionalMessage = \"CopyRefAssembliesToPublishDirectory\";\n                }\n\n                return new CompilationFailure(\n                    sourceFilePath,\n                    sourceFileContent,\n                    compilationContent,\n                    group.Select(GetDiagnosticMessage),\n                    additionalMessage);\n\n            })\n            .ToList();\n\n        return new(failures);\n    }\n\n    private static string ReadContent(RazorCodeDocument codeDocument, string filePath)\n    {\n        RazorSourceDocument? sourceDocument;\n        if (string.IsNullOrEmpty(filePath) || string.Equals(codeDocument.Source.FilePath, filePath, StringComparison.Ordinal))\n        {\n            sourceDocument = codeDocument.Source;\n        }\n        else\n        {\n            sourceDocument = codeDocument.Imports.FirstOrDefault(f => string.Equals(f.FilePath, filePath, StringComparison.Ordinal));\n        }\n\n        if (sourceDocument != null)\n        {\n            var contentChars = new char[sourceDocument.Length];\n            sourceDocument.CopyTo(0, contentChars, 0, sourceDocument.Length);\n            return new(contentChars);\n        }\n\n        return string.Empty;\n    }\n\n    private static DiagnosticMessage GetDiagnosticMessage(Diagnostic diagnostic)\n    {\n        var mappedLineSpan = diagnostic.Location.GetMappedLineSpan();\n        return new(\n            diagnostic.GetMessage(CultureInfo.CurrentCulture),\n            CSharpDiagnosticFormatter.Instance.Format(diagnostic, CultureInfo.CurrentCulture),\n            mappedLineSpan.Path,\n            mappedLineSpan.StartLinePosition.Line + 1,\n            mappedLineSpan.StartLinePosition.Character + 1,\n            mappedLineSpan.EndLinePosition.Line + 1,\n            mappedLineSpan.EndLinePosition.Character + 1);\n    }\n\n    private static DiagnosticMessage CreateDiagnosticMessage(\n        RazorDiagnostic razorDiagnostic,\n        string filePath)\n    {\n        var sourceSpan = razorDiagnostic.Span;\n        var message = razorDiagnostic.GetMessage(CultureInfo.CurrentCulture);\n        return new(\n            message: message,\n            formattedMessage: razorDiagnostic.ToString(),\n            filePath: filePath,\n            startLine: sourceSpan.LineIndex + 1,\n            startColumn: sourceSpan.CharacterIndex,\n            endLine: sourceSpan.LineIndex + 1,\n            endColumn: sourceSpan.CharacterIndex + sourceSpan.Length);\n    }\n\n    private static string GetFilePath(RazorCodeDocument codeDocument, Diagnostic diagnostic)\n    {\n        if (diagnostic.Location == Location.None)\n        {\n            return codeDocument.Source.FilePath;\n        }\n\n        return diagnostic.Location.GetMappedLineSpan().Path;\n    }\n}\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/RazorReferenceManager.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// src/Mvc/Mvc.Razor.RuntimeCompilation/src/RazorReferenceManager.cs\n\nusing System.Reflection.PortableExecutable;\nusing Microsoft.AspNetCore.Mvc.ApplicationParts;\nusing Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.Extensions.Options;\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\n#pragma warning disable CA1852 // Seal internal types\ninternal class RazorReferenceManager\n#pragma warning restore CA1852 // Seal internal types\n{\n    private readonly ApplicationPartManager _partManager;\n    private readonly MvcRazorRuntimeCompilationOptions _options;\n    private object _compilationReferencesLock = new();\n    private bool _compilationReferencesInitialized;\n    private IReadOnlyList<MetadataReference>? _compilationReferences;\n\n    public RazorReferenceManager(\n        ApplicationPartManager partManager,\n        IOptions<MvcRazorRuntimeCompilationOptions> options)\n    {\n        _partManager = partManager;\n        _options = options.Value;\n    }\n\n    public virtual IReadOnlyList<MetadataReference> CompilationReferences\n    {\n        get\n        {\n            return LazyInitializer.EnsureInitialized(\n                ref _compilationReferences,\n                ref _compilationReferencesInitialized,\n                ref _compilationReferencesLock,\n                GetCompilationReferences)!;\n        }\n    }\n\n    private IReadOnlyList<MetadataReference> GetCompilationReferences()\n    {\n        var referencePaths = GetReferencePaths();\n\n        return referencePaths\n            .Select(CreateMetadataReference)\n            .ToList();\n    }\n\n    // For unit testing\n    internal IEnumerable<string> GetReferencePaths()\n    {\n        var referencePaths = new List<string>(_options.AdditionalReferencePaths.Count);\n\n        foreach (var part in _partManager.ApplicationParts)\n        {\n            if (part is ICompilationReferencesProvider compilationReferenceProvider)\n            {\n                referencePaths.AddRange(compilationReferenceProvider.GetReferencePaths());\n            }\n            else if (part is AssemblyPart assemblyPart)\n            {\n                referencePaths.AddRange(assemblyPart.GetReferencePaths());\n            }\n        }\n\n        referencePaths.AddRange(_options.AdditionalReferencePaths);\n\n        return referencePaths;\n    }\n\n    protected static MetadataReference CreateMetadataReference(string path)\n    {\n        using (var stream = File.OpenRead(path))\n        {\n            var moduleMetadata = ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata);\n            var assemblyMetadata = AssemblyMetadata.Create(moduleMetadata);\n\n            return assemblyMetadata.GetReference(filePath: path);\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/RazorReferenceManagerOld.cs",
    "content": "﻿//using System.Collections.Generic;\n//using System.IO;\n//using System.Linq;\n//using System.Reflection.PortableExecutable;\n//using System.Threading;\n//using Microsoft.AspNetCore.Mvc.ApplicationParts;\n//using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;\n//using Microsoft.CodeAnalysis;\n//using Microsoft.Extensions.Options;\n\n//namespace ToSic.Sxc.Razor.DotNetOverrides\n//{\n//    /// <summary>\n//    /// This is a copy of the .net core 3.1 internal RazorReferenceManager\n//    /// It's not used in runtime, but we need during development to to verify what's happening\n//    /// when dependencies are missing\n//    /// </summary>\n//    [ShowApiWhenReleased(ShowApiMode.Never)]\n//    internal class RazorReferenceManager\n//    {\n//        private readonly ApplicationPartManager _partManager;\n//        private readonly MvcRazorRuntimeCompilationOptions _options;\n//        private object _compilationReferencesLock = new();\n//        private bool _compilationReferencesInitialized;\n//        private IReadOnlyList<MetadataReference> _compilationReferences;\n\n//        public RazorReferenceManager(\n//            ApplicationPartManager partManager,\n//            IOptions<MvcRazorRuntimeCompilationOptions> options)\n//        {\n//            _partManager = partManager;\n//            _options = options.Value;\n//        }\n\n//        public virtual IReadOnlyList<MetadataReference> CompilationReferences =>\n//            LazyInitializer.EnsureInitialized(\n//                ref _compilationReferences,\n//                ref _compilationReferencesInitialized,\n//                ref _compilationReferencesLock,\n//                GetCompilationReferences);\n\n//        private IReadOnlyList<MetadataReference> GetCompilationReferences()\n//        {\n//            var referencePaths = GetReferencePaths();\n\n//            return referencePaths\n//                .Select(CreateMetadataReference)\n//                .ToList();\n//        }\n\n//        // For unit testing\n//        internal IEnumerable<string> GetReferencePaths()\n//        {\n//            var referencePaths = new List<string>(_options.AdditionalReferencePaths.Count);\n\n//            foreach (var part in _partManager.ApplicationParts)\n//                if (part is ICompilationReferencesProvider compilationReferenceProvider)\n//                {\n//                    referencePaths.AddRange(compilationReferenceProvider.GetReferencePaths());\n//                }\n//                else if (part is AssemblyPart assemblyPart)\n//                {\n//                    referencePaths.AddRange(assemblyPart.GetReferencePaths());\n//                }\n\n//            referencePaths.AddRange(_options.AdditionalReferencePaths);\n\n//            return referencePaths;\n//        }\n\n//        private static MetadataReference CreateMetadataReference(string path)\n//        {\n//            using var stream = File.OpenRead(path);\n//            var moduleMetadata = ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata);\n//            var assemblyMetadata = AssemblyMetadata.Create(moduleMetadata);\n\n//            return assemblyMetadata.GetReference(filePath: path);\n//        }\n//    }\n//}\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/RuntimeCompilationFileProvider.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// src/Mvc/Mvc.Razor.RuntimeCompilation/src/RuntimeCompilationFileProvider.cs\n\nusing Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;\nusing Microsoft.Extensions.FileProviders;\nusing Microsoft.Extensions.Options;\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\ninternal sealed class RuntimeCompilationFileProvider\n{\n    private readonly MvcRazorRuntimeCompilationOptions _options;\n    private IFileProvider? _compositeFileProvider;\n\n    public RuntimeCompilationFileProvider(IOptions<MvcRazorRuntimeCompilationOptions> options)\n    {\n        ArgumentNullException.ThrowIfNull(options);\n\n        _options = options.Value;\n    }\n\n    public IFileProvider FileProvider\n    {\n        get\n        {\n            if (_compositeFileProvider == null)\n            {\n                _compositeFileProvider = GetCompositeFileProvider(_options);\n            }\n\n            return _compositeFileProvider;\n        }\n    }\n\n    private static IFileProvider GetCompositeFileProvider(MvcRazorRuntimeCompilationOptions options)\n    {\n        var fileProviders = options.FileProviders;\n        if (fileProviders.Count == 0)\n        {\n            var message = \"Resources.FormatFileProvidersAreRequired(typeof(MvcRazorRuntimeCompilationOptions).FullName,nameof(MvcRazorRuntimeCompilationOptions.FileProviders),typeof(IFileProvider).FullName)\";\n            throw new InvalidOperationException(message);\n        }\n        else if (fileProviders.Count == 1)\n        {\n            return fileProviders[0];\n        }\n\n        return new CompositeFileProvider(fileProviders);\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/RuntimeViewCompiler.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// src/Mvc/Mvc.Razor.RuntimeCompilation/src/RuntimeViewCompiler.cs\n\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc.Razor.Compilation;\nusing Microsoft.AspNetCore.Razor.Hosting;\nusing Microsoft.AspNetCore.Razor.Language;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Emit;\nusing Microsoft.CodeAnalysis.Text;\nusing Microsoft.Extensions.Caching.Memory;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.FileProviders;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Primitives;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.Text;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Sxc.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\n#pragma warning disable CA1852 // Seal internal types\ninternal partial class RuntimeViewCompiler : ServiceBase, IViewCompiler, ILogShouldNeverConnect\n#pragma warning restore CA1852 // Seal internal types\n{\n    private readonly object _cacheLock = new();\n    private readonly Dictionary<string, CompiledViewDescriptor> _precompiledViews;\n    private readonly ConcurrentDictionary<string, string> _normalizedPathCache;\n    private readonly IFileProvider _fileProvider;\n    private readonly RazorProjectEngine _projectEngine;\n    private readonly IMemoryCache _cache;\n    private readonly ILogger _logger;\n    private readonly AssemblyResolver _assemblyResolver;\n    private readonly IHttpContextAccessor _httpContextAccessor;\n    private readonly SourceAnalyzer _sourceAnalyzer;\n    private readonly IWebHostEnvironment _env;\n    private readonly CSharpCompiler _csharpCompiler;\n\n#if DEBUG\n    private const bool Dbg = true;\n#else\n    private const bool Dbg = false;\n#endif\n\n    public RuntimeViewCompiler(\n        IFileProvider fileProvider,\n        RazorProjectEngine projectEngine,\n        CSharpCompiler csharpCompiler,\n        IList<CompiledViewDescriptor> precompiledViews,\n        ILogger logger,\n        AssemblyResolver assemblyResolver,\n        IHttpContextAccessor httpContextAccessor,\n        SourceAnalyzer sourceAnalyzer,\n        IWebHostEnvironment env,\n        ILogStore logStore) \n        : base($\"{SxcLogging.SxcLogName}.RzrViewCmp\", connect: [assemblyResolver, sourceAnalyzer])\n    {\n        var l = Dbg ? base.Log.Fn($\"{nameof(precompiledViews)}:{precompiledViews?.Count}\") : null;\n\n        if (Dbg)\n            logStore.Add(SxcLogging.SxcLogAppCodeLoader, base.Log);\n\n        ArgumentNullException.ThrowIfNull(fileProvider);\n        ArgumentNullException.ThrowIfNull(projectEngine);\n        ArgumentNullException.ThrowIfNull(csharpCompiler);\n        ArgumentNullException.ThrowIfNull(precompiledViews);\n        ArgumentNullException.ThrowIfNull(logger);\n\n        _fileProvider = fileProvider;\n        _projectEngine = projectEngine;\n        _csharpCompiler = csharpCompiler;\n        _logger = logger;\n        _assemblyResolver = assemblyResolver;\n        _httpContextAccessor = httpContextAccessor;\n        _sourceAnalyzer = sourceAnalyzer;\n        _env = env;\n\n        _normalizedPathCache = new(StringComparer.Ordinal);\n\n        // This is our L0 cache, and is a durable store. Views migrate into the cache as they are requested\n        // from either the set of known precompiled views, or by being compiled.\n        _cache = new MemoryCache(new MemoryCacheOptions());\n\n        // We need to validate that the all of the precompiled views are unique by path (case-insensitive).\n        // We do this because there's no good way to canonicalize paths on windows, and it will create\n        // problems when deploying to linux. Rather than deal with these issues, we just don't support\n        // views that differ only by case.\n        _precompiledViews = new(\n            precompiledViews.Count,\n            StringComparer.OrdinalIgnoreCase);\n\n        foreach (var precompiledView in precompiledViews)\n        {\n            Log.ViewCompilerLocatedCompiledView(_logger, precompiledView.RelativePath);\n            l.A($\"{precompiledView.RelativePath}:'{precompiledView.RelativePath}'\");\n\n            if (!_precompiledViews.ContainsKey(precompiledView.RelativePath))\n            {\n                // View ordering has precedence semantics, a view with a higher precedence was\n                // already added to the list.\n                _precompiledViews.Add(precompiledView.RelativePath, precompiledView);\n                l.A($\"add precompiledView:'{precompiledView.RelativePath}'\");\n            }\n        }\n\n        if (_precompiledViews.Count == 0)\n        {\n            Log.ViewCompilerNoCompiledViewsFound(_logger);\n            l.A($\"no compiled views found\");\n        }\n\n        l.Done();\n    }\n\n    public Task<CompiledViewDescriptor> CompileAsync(string relativePath)\n    {\n        var l = Dbg ? base.Log.Fn<Task<CompiledViewDescriptor>>($\"{nameof(relativePath)}:'{relativePath}'\") : null;\n        \n        ArgumentNullException.ThrowIfNull(relativePath);\n\n        // Attempt to lookup the cache entry using the passed in path. This will succeed if the path is already\n        // normalized and a cache entry exists.\n        if (_cache.TryGetValue<Task<CompiledViewDescriptor>>(relativePath, out var cachedResult) && cachedResult is not null)\n        {\n            return l.Return(cachedResult, $\"OK, got cache result for {nameof(relativePath)}:'{relativePath}'\");\n        }\n        l.A($\"NO cache result for {nameof(relativePath)}:'{relativePath}'\");\n\n        var normalizedPath = GetNormalizedPath(relativePath);\n        l.A($\"{nameof(normalizedPath)}:'{normalizedPath}'\");\n        if (_cache.TryGetValue(normalizedPath, out cachedResult) && cachedResult is not null)\n        {\n            return l.Return(cachedResult, $\"OK, got cache result for {nameof(normalizedPath)}:'{normalizedPath}'\");\n        }\n        l.A($\"NO cache result for {nameof(normalizedPath)}:'{normalizedPath}'\");\n\n        // Entry does not exist. Attempt to create one.\n        l.A($\"Entry does not exist. Attempt to create one for {nameof(normalizedPath)}:'{normalizedPath}'\");\n        cachedResult = OnCacheMiss(normalizedPath);\n        return l.ReturnAsOk(cachedResult);\n    }\n\n    private Task<CompiledViewDescriptor> OnCacheMiss(string normalizedPath)\n    {\n        ViewCompilerWorkItem item;\n        TaskCompletionSource<CompiledViewDescriptor> taskSource;\n        MemoryCacheEntryOptions cacheEntryOptions;\n\n        // Safe races cannot be allowed when compiling Razor pages. To ensure only one compilation request succeeds\n        // per file, we'll lock the creation of a cache entry. Creating the cache entry should be very quick. The\n        // actual work for compiling files happens outside the critical section.\n        lock (_cacheLock)\n        {\n            // Double-checked locking to handle a possible race.\n            if (_cache.TryGetValue<Task<CompiledViewDescriptor>>(normalizedPath, out var result) && result is not null)\n            {\n                return result;\n            }\n\n            if (_precompiledViews.TryGetValue(normalizedPath, out var precompiledView))\n            {\n                Log.ViewCompilerLocatedCompiledViewForPath(_logger, normalizedPath);\n                item = CreatePrecompiledWorkItem(normalizedPath, precompiledView);\n            }\n            else\n            {\n                item = CreateRuntimeCompilationWorkItem(normalizedPath);\n            }\n\n            // At this point, we've decided what to do - but we should create the cache entry and\n            // release the lock first.\n            cacheEntryOptions = new();\n\n            Debug.Assert(item.ExpirationTokens != null);\n            for (var i = 0; i < item.ExpirationTokens.Count; i++)\n            {\n                cacheEntryOptions.ExpirationTokens.Add(item.ExpirationTokens[i]);\n            }\n\n            taskSource = new(creationOptions: TaskCreationOptions.RunContinuationsAsynchronously);\n            if (item.SupportsCompilation)\n            {\n                // We'll compile in just a sec, be patient.\n            }\n            else\n            {\n                // If we can't compile, we should have already created the descriptor\n                Debug.Assert(item.Descriptor != null);\n                taskSource.SetResult(item.Descriptor);\n            }\n\n            _cache.Set(normalizedPath, taskSource.Task, cacheEntryOptions);\n        }\n\n        // Now the lock has been released so we can do more expensive processing.\n        if (item.SupportsCompilation)\n        {\n            Debug.Assert(taskSource != null);\n\n            if (item.Descriptor?.Item != null &&\n                ChecksumValidator.IsItemValid(_projectEngine.FileSystem, item.Descriptor.Item))\n            {\n                // If the item has checksums to validate, we should also have a precompiled view.\n                Debug.Assert(item.Descriptor != null);\n\n                taskSource.SetResult(item.Descriptor);\n                return taskSource.Task;\n            }\n\n            Log.ViewCompilerInvalidatingCompiledFile(_logger, item.NormalizedPath);\n            try\n            {\n                var descriptor = CompileAndEmit(normalizedPath);\n                descriptor.ExpirationTokens = cacheEntryOptions.ExpirationTokens;\n                taskSource.SetResult(descriptor);\n            }\n            catch (Exception ex)\n            {\n                taskSource.SetException(ex);\n            }\n        }\n\n        return taskSource.Task;\n    }\n\n    private ViewCompilerWorkItem CreatePrecompiledWorkItem(string normalizedPath, CompiledViewDescriptor precompiledView)\n    {\n        // We have a precompiled view - but we're not sure that we can use it yet.\n        //\n        // We need to determine first if we have enough information to 'recompile' this view. If that's the case\n        // we'll create change tokens for all of the files.\n        //\n        // Then we'll attempt to validate if any of those files have different content than the original sources\n        // based on checksums.\n        if (precompiledView.Item == null || !ChecksumValidator.IsRecompilationSupported(precompiledView.Item))\n        {\n            return new()\n            {\n                // If we don't have a checksum for the primary source file we can't recompile.\n                SupportsCompilation = false,\n\n                ExpirationTokens = Array.Empty<IChangeToken>(), // Never expire because we can't recompile.\n                Descriptor = precompiledView, // This will be used as-is.\n            };\n        }\n\n        var item = new ViewCompilerWorkItem()\n        {\n            SupportsCompilation = true,\n\n            Descriptor = precompiledView, // This might be used, if the checksums match.\n\n            // Used to validate and recompile\n            NormalizedPath = normalizedPath,\n\n            ExpirationTokens = GetExpirationTokens(precompiledView),\n        };\n\n        // We also need to create a new descriptor, because the original one doesn't have expiration tokens on\n        // it. These will be used by the view location cache, which is like an L1 cache for views (this class is\n        // the L2 cache).\n        item.Descriptor = new()\n        {\n            ExpirationTokens = item.ExpirationTokens,\n            Item = precompiledView.Item,\n            RelativePath = precompiledView.RelativePath,\n        };\n\n        return item;\n    }\n\n    private ViewCompilerWorkItem CreateRuntimeCompilationWorkItem(string normalizedPath)\n    {\n        IList<IChangeToken> expirationTokens = new List<IChangeToken>\n            {\n                _fileProvider.Watch(normalizedPath),\n            };\n\n        var projectItem = _projectEngine.FileSystem.GetItem(normalizedPath, fileKind: null);\n        if (!projectItem.Exists)\n        {\n            Log.ViewCompilerCouldNotFindFileAtPath(_logger, normalizedPath);\n\n            // If the file doesn't exist, we can't do compilation right now - we still want to cache\n            // the fact that we tried. This will allow us to re-trigger compilation if the view file\n            // is added.\n            return new()\n            {\n                // We don't have enough information to compile\n                SupportsCompilation = false,\n\n                Descriptor = new()\n                {\n                    RelativePath = normalizedPath,\n                    ExpirationTokens = expirationTokens,\n                },\n\n                // We can try again if the file gets created.\n                ExpirationTokens = expirationTokens,\n            };\n        }\n\n        Log.ViewCompilerFoundFileToCompile(_logger, normalizedPath);\n\n        GetChangeTokensFromImports(expirationTokens, projectItem);\n\n        GetChangeTokenFromAppCode(expirationTokens, normalizedPath);\n\n        return new()\n        {\n            SupportsCompilation = true,\n\n            NormalizedPath = normalizedPath,\n            ExpirationTokens = expirationTokens,\n        };\n    }\n\n    private IList<IChangeToken> GetExpirationTokens(CompiledViewDescriptor precompiledView)\n    {\n        var checksums = precompiledView.Item.GetChecksumMetadata();\n        var expirationTokens = new List<IChangeToken>(checksums.Count);\n\n        for (var i = 0; i < checksums.Count; i++)\n        {\n            // We rely on Razor to provide the right set of checksums. Trust the compiler, it has to do a good job,\n            // so it probably will.\n            expirationTokens.Add(_fileProvider.Watch(checksums[i].Identifier));\n        }\n\n        return expirationTokens;\n    }\n\n    private void GetChangeTokensFromImports(IList<IChangeToken> expirationTokens, RazorProjectItem projectItem)\n    {\n        // OK this means we can do compilation. For now let's just identify the other files we need to watch\n        // so we can create the cache entry. Compilation will happen after we release the lock.\n        var importFeature = _projectEngine.ProjectFeatures.OfType<IImportProjectFeature>().ToArray();\n        foreach (var feature in importFeature)\n        {\n            foreach (var file in feature.GetImports(projectItem))\n            {\n                if (file.FilePath != null)\n                {\n                    expirationTokens.Add(_fileProvider.Watch(file.FilePath));\n                }\n            }\n        }\n    }\n\n    private void GetChangeTokenFromAppCode(IList<IChangeToken> expirationTokens, string relativePath)\n    {\n        // find do we require dependency on AppCode in razor view?\n        if (!_sourceAnalyzer.TypeOfVirtualPath(relativePath).IsHotBuildSupported()) return;\n\n        // if AppCode folder exists, related to relativePath, watch it\n        var appCodeRelativePath = AppCodeRelativePathIfExists(relativePath.Backslash());\n        if (appCodeRelativePath != null)\n            expirationTokens.Add(_fileProvider.Watch($\"{appCodeRelativePath.ForwardSlash().PrefixSlash().SuffixSlash()}**/*.cs\"));\n    }\n\n    private string AppCodeRelativePathIfExists(string normalizedPath)\n    {\n        var l = Dbg ? base.Log.Fn<string>($\"{nameof(normalizedPath)}:'{normalizedPath}'\") : null;\n\n        var (appRelativePath, edition) = GetSxcAppRelativePathWithEdition(normalizedPath);\n        l.A($\"{nameof(appRelativePath)}:'{appRelativePath}'; {nameof(edition)}:'{edition}'\");\n\n        if (!appRelativePath.HasValue())\n            return l.Return(\"\", $\"{nameof(appRelativePath)} is empty\");\n\n        if (edition.HasValue() && Directory.Exists(Path.Combine(_env.ContentRootPath, appRelativePath.Backslash(), edition, FolderConstants.AppCodeFolder)))\n            return l.ReturnAndLog(Path.Combine(appRelativePath.Backslash(), edition, FolderConstants.AppCodeFolder));\n\n        return l.ReturnAndLog((Directory.Exists(Path.Combine(_env.ContentRootPath, appRelativePath.Backslash(), FolderConstants.AppCodeFolder))\n            ? Path.Combine(appRelativePath.Backslash(), FolderConstants.AppCodeFolder)\n            : \"\"));\n    }\n\n    protected virtual CompiledViewDescriptor CompileAndEmit(string relativePath)\n    {\n        var projectItem = _projectEngine.FileSystem.GetItem(relativePath, fileKind: null);\n        var codeDocument = _projectEngine.Process(projectItem);\n        var cSharpDocument = codeDocument.GetCSharpDocument();\n\n        if (cSharpDocument.Diagnostics.Count > 0)\n        {\n            throw CompilationFailedExceptionFactory.Create(\n                codeDocument,\n                cSharpDocument.Diagnostics);\n        }\n\n        var assembly = CompileAndEmit(codeDocument, cSharpDocument.GeneratedCode, GetMetadataReferences(relativePath));\n\n        // Anything we compile from source will use Razor 2.1 and so should have the new metadata.\n        var loader = new RazorCompiledItemLoader();\n        var item = loader.LoadItems(assembly).Single();\n        return new(item);\n    }\n\n    /// <summary>\n    /// get MetadataReferences for relativePath\n    /// </summary>\n    /// <param name=\"relativePath\"></param>\n    /// <returns></returns>\n    private IEnumerable<MetadataReference> GetMetadataReferences(string relativePath)\n    {\n        IEnumerable<MetadataReference> references = new List<MetadataReference>();\n        var appCodePath = GetAppCodeDllPath(relativePath);\n        if (appCodePath != null)\n            references = references.Append(MetadataReference.CreateFromFile(appCodePath));\n        return references;\n    }\n\n    private string? GetAppCodeDllPath(string relativePath)\n    {\n        var (appRelativePath, edition) = GetSxcAppRelativePathWithEdition(relativePath);\n        if (appRelativePath == null)\n            return null;\n        if (edition.HasValue()) appRelativePath = Path.Combine(appRelativePath, edition);\n        appRelativePath = appRelativePath.Backslash();\n        var appCodeDllPath = _assemblyResolver.GetAssemblyLocation(appRelativePath);\n        return appCodeDllPath;\n    }\n\n    private (string? appRelativePath, string? edition) GetSxcAppRelativePathWithEdition(string relativePath)\n    {\n        if (_httpContextAccessor?.HttpContext == null)\n            return GetSxcAppRelativePathWithEditionFallback(relativePath);\n        \n        var sp = _httpContextAccessor.HttpContext.RequestServices;\n        var ctxResolver = sp.GetService<ISxcCurrentContextService>();\n\n        var block = ctxResolver?.BlockOrNull();\n        if (block == null)\n            return GetSxcAppRelativePathWithEditionFallback(relativePath);\n\n        // appRelativePath from block (this is not working for inner-content)\n        var appRelativePath = block.App.RelativePath;\n\n        // Inner-content app case\n        if (!IsTemplateLocatedInAppFolder(appRelativePath, relativePath))\n            return GetSxcAppRelativePathWithEditionFallback(relativePath);\n\n        // Standard case (appRelativePath and edition from block)\n        var edition = sp.GetService<PolymorphConfigReader>()!.UseViewEditionOrGet(block);\n        return (appRelativePath, edition);\n    }\n\n    /// <summary>\n    /// Validate that relative path of template is not located in relative app path,\n    /// indicates that razor template is not in app, so it likely in inner app.\n    /// </summary>\n    /// <param name=\"appRelativePath\">app relative path</param>\n    /// <param name=\"relativePath\">template relative path</param>\n    /// <returns></returns>\n    private static bool IsTemplateLocatedInAppFolder(string appRelativePath, string relativePath) \n        => relativePath.ForwardSlash().TrimPrefixSlash().StartsWith(appRelativePath.ForwardSlash());\n\n    /// <summary>\n    /// extract appRelativePathWithEdition from relativePath\n    /// fallback, when block is null\n    /// </summary>\n    /// <param name=\"relativePath\">string \"/2sxc/n/aaa-folder-name/edition/etc...\"</param>\n    /// <returns>string \"2sxc\\\\n\\\\aaa-folder-name\\\\edition\" or null</returns>\n    private (string? appRelativePath, string? edition) GetSxcAppRelativePathWithEditionFallback(string? relativePath)\n    {\n        var l = Dbg ? base.Log.Fn<(string? appRelativePath, string? edition)>($\"{nameof(relativePath)}:'{relativePath}'\") : null;\n\n        relativePath = relativePath?.ForwardSlash();\n\n        if (string.IsNullOrEmpty(relativePath)\n            || relativePath.Length < 8\n            || relativePath[0] != '/'\n            || relativePath[5] != '/')\n            //throw new($\"relativePath:'{relativePath}' is not in format '/2sxc/n/app-folder-name/etc...'\");\n            return l.ReturnAsError((appRelativePath: null, edition: null));\n\n        // find position of 4th slash in relativePath \n        var posApp = 6; // skipping first 2 slashes\n        for (var i = 0; i < 2; i++)\n        {\n            posApp = relativePath.IndexOf('/', posApp + 1);\n            if (posApp < 0)\n                //throw new($\"relativePath:'{relativePath}' is not in format '/2sxc/n/app-folder-name/etc...'\");\n                return l.ReturnAsError((appRelativePath: null, edition: null));\n        }\n        var appRelativePath = relativePath.Substring(1, posApp - 1);\n\n        if (relativePath.Length <= posApp)\n            return l.ReturnAsOk((appRelativePath, edition: \"\"));\n\n        // find optional \"edition\" subfolder\n        var edition = \"\";\n\n        // next subfolder is probably optional \"edition\" subfolder\n        var posEdition = relativePath.IndexOf('/', posApp + 1);\n\n        // can't find \"edition\" subfolder, so return app folder without edition\n        if (posEdition >= 0)\n            edition = relativePath.Substring(posApp + 1, posEdition - posApp -1);\n\n        return l.ReturnAsOk((appRelativePath, edition));\n    }\n\n    internal Assembly CompileAndEmit(RazorCodeDocument codeDocument, string generatedCode, IEnumerable<MetadataReference> references)\n    {\n        Log.GeneratedCodeToAssemblyCompilationStart(_logger, codeDocument.Source.FilePath);\n\n        var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;\n\n        var assemblyName = Path.GetRandomFileName();\n        var compilation = CreateCompilation(generatedCode, assemblyName, references);\n\n        var emitOptions = _csharpCompiler.EmitOptions;\n        var emitPdbFile = _csharpCompiler.EmitPdb && emitOptions.DebugInformationFormat != DebugInformationFormat.Embedded;\n\n        using (var assemblyStream = new MemoryStream())\n        using (var pdbStream = emitPdbFile ? new MemoryStream() : null)\n        {\n            var result = compilation.Emit(\n                assemblyStream,\n                pdbStream,\n                options: emitOptions);\n\n            if (!result.Success)\n            {\n                throw CompilationFailedExceptionFactory.Create(\n                    codeDocument,\n                    generatedCode,\n                    assemblyName,\n                    result.Diagnostics);\n            }\n\n            assemblyStream.Seek(0, SeekOrigin.Begin);\n            pdbStream?.Seek(0, SeekOrigin.Begin);\n\n            var assembly = Assembly.Load(assemblyStream.ToArray(), pdbStream?.ToArray());\n            Log.GeneratedCodeToAssemblyCompilationEnd(_logger, codeDocument.Source.FilePath, startTimestamp);\n\n            return assembly;\n        }\n    }\n\n    private CSharpCompilation CreateCompilation(string compilationContent, string assemblyName, IEnumerable<MetadataReference> references)\n    {\n        var sourceText = SourceText.From(compilationContent, Encoding.UTF8);\n        var syntaxTree = _csharpCompiler.CreateSyntaxTree(sourceText).WithFilePath(assemblyName);\n        return _csharpCompiler\n            .CreateCompilation(assemblyName)\n            .AddSyntaxTrees(syntaxTree)\n            .AddReferences(references);\n    }\n\n    private string GetNormalizedPath(string relativePath)\n    {\n        Debug.Assert(relativePath != null);\n        if (relativePath.Length == 0)\n        {\n            return relativePath;\n        }\n\n        if (!_normalizedPathCache.TryGetValue(relativePath, out var normalizedPath))\n        {\n            normalizedPath = ViewPath.NormalizePath(relativePath);\n            _normalizedPathCache[relativePath] = normalizedPath;\n        }\n\n        return normalizedPath;\n    }\n\n    private class ViewCompilerWorkItem\n    {\n        public bool SupportsCompilation { get; init; } = default!;\n\n        public string NormalizedPath { get; init; } = default!;\n\n        public IList<IChangeToken> ExpirationTokens { get; init; } = default!;\n\n        public CompiledViewDescriptor Descriptor { get; set; } = default!;\n    }\n\n#pragma warning disable CS0108, CS0114\n    private static partial class Log\n#pragma warning restore CS0108, CS0114\n    {\n        [LoggerMessage(1, LogLevel.Debug, \"Compilation of the generated code for the Razor file at '{FilePath}' started.\")]\n        public static partial void GeneratedCodeToAssemblyCompilationStart(ILogger logger, string filePath);\n\n        [LoggerMessage(2, LogLevel.Debug, \"Compilation of the generated code for the Razor file at '{FilePath}' completed in {ElapsedMilliseconds}ms.\")]\n        private static partial void GeneratedCodeToAssemblyCompilationEnd(ILogger logger, string filePath, double elapsedMilliseconds);\n\n        public static void GeneratedCodeToAssemblyCompilationEnd(ILogger logger, string filePath, long startTimestamp)\n        {\n            // Don't log if logging wasn't enabled at start of request as time will be wildly wrong.\n            if (startTimestamp != 0)\n            {\n                var currentTimestamp = Stopwatch.GetTimestamp();\n                var elapsed = Stopwatch.GetElapsedTime(startTimestamp, currentTimestamp);\n                GeneratedCodeToAssemblyCompilationEnd(logger, filePath, elapsed.TotalMilliseconds);\n            }\n        }\n\n        [LoggerMessage(3, LogLevel.Debug, \"Initializing Razor view compiler with compiled view: '{ViewName}'.\")]\n        public static partial void ViewCompilerLocatedCompiledView(ILogger logger, string viewName);\n\n        [LoggerMessage(4, LogLevel.Debug, \"Initializing Razor view compiler with no compiled views.\")]\n        public static partial void ViewCompilerNoCompiledViewsFound(ILogger logger);\n\n        [LoggerMessage(5, LogLevel.Trace, \"Located compiled view for view at path '{Path}'.\")]\n        public static partial void ViewCompilerLocatedCompiledViewForPath(ILogger logger, string path);\n\n        [LoggerMessage(6, LogLevel.Trace, \"Invalidating compiled view for view at path '{Path}'.\")]\n        public static partial void ViewCompilerRecompilingCompiledView(ILogger logger, string path);\n\n        [LoggerMessage(7, LogLevel.Trace, \"Could not find a file for view at path '{Path}'.\")]\n        public static partial void ViewCompilerCouldNotFindFileAtPath(ILogger logger, string path);\n\n        [LoggerMessage(8, LogLevel.Trace, \"Found file at path '{Path}'.\")]\n        public static partial void ViewCompilerFoundFileToCompile(ILogger logger, string path);\n\n        [LoggerMessage(9, LogLevel.Trace, \"Invalidating compiled view at path '{Path}' with a file since the checksum did not match.\")]\n        public static partial void ViewCompilerInvalidatingCompiledFile(ILogger logger, string path);\n    }\n}\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/RuntimeViewCompilerProvider.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// src/Mvc/Mvc.Razor.RuntimeCompilation/src/RuntimeViewCompilerProvider.cs\n\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc.ApplicationParts;\nusing Microsoft.AspNetCore.Mvc.Razor.Compilation;\nusing Microsoft.AspNetCore.Razor.Language;\nusing Microsoft.Extensions.Logging;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Sys;\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\ninternal sealed class RuntimeViewCompilerProvider : ServiceBase, IViewCompilerProvider, ILogShouldNeverConnect\n{\n    private readonly RazorProjectEngine _razorProjectEngine;\n    private readonly ApplicationPartManager _applicationPartManager;\n    private readonly CSharpCompiler _csharpCompiler;\n    private readonly AssemblyResolver _assemblyResolver;\n    private readonly IHttpContextAccessor _httpContextAccessor;\n    private readonly SourceAnalyzer _sourceAnalyzer;\n    private readonly IWebHostEnvironment _env;\n    private readonly ILogStore _logStore;\n    private readonly RuntimeCompilationFileProvider _fileProvider;\n    private readonly ILogger<RuntimeViewCompiler> _logger;\n    private readonly Func<IViewCompiler> _createCompiler;\n\n    private object _initializeLock = new();\n    private bool _initialized;\n    private IViewCompiler? _compiler;\n\n#if DEBUG\n    private const bool Dbg = true;\n#else\n    private const bool Dbg = false;\n#endif\n\n    public RuntimeViewCompilerProvider(\n        ApplicationPartManager applicationPartManager,\n        RazorProjectEngine razorProjectEngine,\n        RuntimeCompilationFileProvider fileProvider,\n        CSharpCompiler csharpCompiler,\n        ILoggerFactory loggerFactory,\n        AssemblyResolver assemblyResolver,\n        IHttpContextAccessor httpContextAccessor,\n        SourceAnalyzer sourceAnalyzer,\n        IWebHostEnvironment env,\n        ILogStore logStore) : base($\"{SxcLogging.SxcLogName}.RzrViewCmpProv\",\n            connect: [assemblyResolver, sourceAnalyzer])\n    {\n        var l = Dbg ? Log.Fn() : null;\n\n        _applicationPartManager = applicationPartManager;\n        _razorProjectEngine = razorProjectEngine;\n        _csharpCompiler = csharpCompiler;\n        _assemblyResolver = assemblyResolver;\n        _httpContextAccessor = httpContextAccessor;\n        _assemblyResolver = assemblyResolver;\n        _sourceAnalyzer = sourceAnalyzer;\n        _env = env;\n        _logStore = logStore;\n        _fileProvider = fileProvider;\n\n        _logger = loggerFactory.CreateLogger<RuntimeViewCompiler>();\n\n        _createCompiler = CreateCompiler;\n\n        if (Dbg)\n            logStore.Add(SxcLogging.SxcLogAppCodeLoader, Log);\n\n        l.Done();\n    }\n\n    public IViewCompiler GetCompiler()\n    {\n        var l = Dbg ? Log.Fn<IViewCompiler>() : null;\n\n        return l.ReturnAsOk(LazyInitializer.EnsureInitialized(\n            ref _compiler,\n            ref _initialized,\n            ref _initializeLock,\n            _createCompiler)!);\n    }\n\n    private IViewCompiler CreateCompiler()\n    {\n        var l = Dbg ? Log.Fn<IViewCompiler>() : null;\n\n        var feature = new ViewsFeature();\n        _applicationPartManager.PopulateFeature(feature);\n\n        return l.ReturnAsOk(new RuntimeViewCompiler(\n            _fileProvider.FileProvider,\n            _razorProjectEngine,\n            _csharpCompiler,\n            feature.ViewDescriptors,\n            _logger,\n            _assemblyResolver,\n            _httpContextAccessor,\n            _sourceAnalyzer,\n            _env,\n            _logStore));\n    }\n}\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/DotNetOverrides/ViewPath.cs",
    "content": "﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n// based on: https://github.dev/dotnet/aspnetcore/tree/v8.0.5\n// dotnet/aspnetcore/src/Mvc/Mvc.Razor/src/ViewPath.cs\n\nnamespace ToSic.Sxc.Razor.DotNetOverrides;\n\ninternal static class ViewPath\n{\n    public static string NormalizePath(string path)\n    {\n        var addLeadingSlash = path[0] != '\\\\' && path[0] != '/';\n        var transformSlashes = path.Contains('\\\\');\n\n        if (!addLeadingSlash && !transformSlashes)\n        {\n            return path;\n        }\n\n        var length = path.Length;\n        if (addLeadingSlash)\n        {\n            length++;\n        }\n\n        return string.Create(length, (path, addLeadingSlash), (span, tuple) =>\n        {\n            var (pathValue, addLeadingSlashValue) = tuple;\n            var spanIndex = 0;\n\n            if (addLeadingSlashValue)\n            {\n                span[spanIndex++] = '/';\n            }\n\n            foreach (var ch in pathValue)\n            {\n                span[spanIndex++] = ch == '\\\\' ? '/' : ch;\n            }\n        });\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/HotBuildReferenceManager.cs",
    "content": "﻿using Microsoft.CodeAnalysis;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Razor.DotNetOverrides;\nusing ToSic.Sxc.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Razor;\n\ninternal class HotBuildReferenceManager(\n    RazorReferenceManager referenceManager,\n    LazySvc<DependenciesLoader> dependenciesLoader,\n    AssemblyResolver assemblyResolver,\n    LazySvc<ExtensionCompileReferenceService> extensionReference)\n    : ServiceBase($\"{SxcLogging.SxcLogName}.HbRefMgr\",\n        connect: [referenceManager, dependenciesLoader, assemblyResolver, extensionReference])\n{\n    private readonly RazorReferenceManagerEnhanced _referenceManager = (RazorReferenceManagerEnhanced)referenceManager;\n\n    internal IEnumerable<MetadataReference> GetMetadataReferences(string? appCodeFullPath, HotBuildSpec spec, string? sourcePath)\n    {\n        var additionalReferencePaths = new List<string>();\n        try\n        {\n            if (spec != null! /* paranoid */ )\n            {\n                // TODO: need to invalidate this cache (_referencedAssembliesCache, _assemblyResolver, ...) if there is change in Dependencies folder\n                var (dependencies, _) = dependenciesLoader.Value.TryGetOrFallback(spec);\n\n                if (dependencies != null)\n                {\n                    assemblyResolver.AddAssemblies(dependencies);\n                    additionalReferencePaths.AddRange(dependencies.Select(dependency => dependency.Location));\n                }\n            }\n\n            if (!string.IsNullOrEmpty(appCodeFullPath) && File.Exists(appCodeFullPath))\n                additionalReferencePaths.Add(appCodeFullPath);\n\n            if (sourcePath.HasValue())\n            {\n                var referenceReader = extensionReference.Value;\n                foreach (var reference in referenceReader.GetReferences(sourcePath, netFramework: false))\n                {\n                    var resolved = ExtensionCompileReferenceService.IsAssemblyName(reference.Value)\n                        ? referenceReader.TryResolveAssemblyLocation(reference.Value)\n                        : referenceReader.ResolveReferencePath(reference);\n\n                    if (resolved.IsEmpty())\n                    {\n                        Log.W($\"Extension reference '{reference.Value}' in '{reference.ExtensionFolder}' could not be resolved.\");\n                        continue;\n                    }\n\n                    if (!File.Exists(resolved))\n                    {\n                        Log.W($\"Resolved reference '{resolved}' for '{reference.Value}' not found.\");\n                        continue;\n                    }\n\n                    additionalReferencePaths.Add(resolved);\n                }\n            }\n        }\n        catch\n        {\n            // ReSharper disable once EmptyStatement\n        };\n\n        return _referenceManager.GetAdditionalCompilationReferences(additionalReferencePaths);\n    }\n}\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/IRazorCompiler.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Razor;\nusing Microsoft.AspNetCore.Mvc.ViewEngines;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys.HotBuild;\n\nnamespace ToSic.Sxc.Razor;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IRazorCompiler\n{\n    Task<(IView view, ActionContext context)> CompileView(string partialName, Action<RazorView> configure, IApp app, HotBuildSpec spec);\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/IRazorRenderer.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc.Razor;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Engines.Sys;\n\nnamespace ToSic.Sxc.Razor;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IRazorRenderer\n{\n    Task<string> RenderToStringAsync<TModel>(EngineSpecs engineSpecs, /*string templatePath,*/ TModel model, Action<RazorView> configure/*, IApp app, HotBuildSpec hotBuildSpec*/);\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/OqtRazorHelper.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing Custom.Hybrid;\nusing Microsoft.AspNetCore.Mvc.ViewFeatures;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Razor;\n\ninternal class OqtRazorHelper<TModel>(OqtRazorBase<TModel> owner) : RazorHelperBase(\"Oqt.RzrHlp\"), ISetDynamicModel\n{\n    #region DynamicCode Attachment / Handling through ViewData\n\n    public override void ConnectToRoot(IExecutionContext exCtx)\n    {\n        base.ConnectToRoot(exCtx);\n        _exCtx = exCtx;\n        owner.LinkLog(exCtx.Log);\n        Log.A(\"OqtRazorHelper connect Log\");\n    }\n\n    private const string DynCode = \"_dynCode\";\n\n    public IExecutionContext ExCtxRoot\n    {\n        get\n        {\n            // 2026-05-23 2dm - original code, looks buggy because it would often return null, which should never happen IMHO\n            //// Child razor page will have _dynCode == null, so it is provided via ViewData from parent razor page.\n            //if (_dynCode != null || owner.ViewData?[DynCode] is not IExecutionContext cdRt)\n            //    return _dynCode;\n\n            if (_exCtx != null)\n                return _exCtx;\n            \n            // Child razor page will have _dynCode == null, so it is provided via ViewData from parent razor page.\n            // changed 2025-06-23 2dm to throw if null, because I don't think it's correct\n            // If I'm wrong, pls discuss.\n            if (owner.ViewData?[DynCode] is not IExecutionContext cdRt)\n                throw new InvalidOperationException(\n                    \"OqtRazorHelper: ExCtxRoot is null, and ViewData does not contain _dynCode. \" +\n                    \"This means the parent razor page did not set the _dynCode in ViewData, which is required for child razor pages.\");\n\n            // Connect to root, which also sets the _exCtx field\n            ConnectToRoot(cdRt);\n            Log.A( \"DynCode attached from ViewData\");\n\n            return _exCtx!;\n        }\n    }\n    private IExecutionContext? _exCtx { get; set; }\n\n    [return: NotNullIfNotNull(nameof(value))]\n    public ViewDataDictionary<TModel>? HandleViewDataInject(ViewDataDictionary<TModel>? value)\n    {\n        // Store _dynCode in ViewData, for child razor page.\n        if (_exCtx != null && value != null && value[DynCode] == null)\n            value[DynCode] = _exCtx;\n        return value;\n    }\n\n    internal new IExecutionContext ExCtx => ExCtxOrNull ?? ExCtxRoot!;\n\n    #endregion\n\n    #region Dynamic Model / MyModel\n\n    [field: AllowNull, MaybeNull]\n    public dynamic DynamicModel => field ??= owner.GetService<ICodeDataPoCoWrapperService>()\n        .DynamicFromObject(_overridePageData ?? owner.Model!, WrapperSettings.Dyn(false, false));\n\n    private RenderSpecs? _renderSpecs;\n    private object? _overridePageData;\n\n    // TODO: DON'T think this is called in Oqtane - maybe document how it works, or remove it?\n    public void SetDynamicModel(RenderSpecs renderSpecs)\n    {\n        var l = Log.Fn();\n        _renderSpecs = renderSpecs;\n        _overridePageData = renderSpecs.Data;\n        l.Done();\n    }\n\n    [field: AllowNull, MaybeNull]\n    public TypedCode16Helper CodeHelper\n        => field ??= CreateCodeHelper();\n\n    private TypedCode16Helper CreateCodeHelper()\n        => new(\n            helperSpecs: new(ExCtx, true, owner.Path),\n            getRazorModel: () => _overridePageData ?? owner.Model,\n            getModelDic: () => (_renderSpecs?.DataDic ?? owner.Model?.ToDicInvariantInsensitive())!\n        );\n\n    #endregion\n\n    #region GetCode / Create Instance\n\n    protected override string GetCodeNormalizePath(string virtualPath)\n    {\n        var directory = Path.GetDirectoryName(owner.Path)\n                        ?? throw new(\"Current directory seems to be null\");\n        return Path.Combine(directory, virtualPath);\n    }\n\n    /// <summary>\n    /// Cshtml CreateInstance - just throw error, as not supported in Oqtane\n    /// </summary>\n    /// <exception cref=\"NotSupportedException\"></exception>\n    protected override object GetCodeCshtml(string path) =>\n        throw new NotSupportedException(\n            \"CreateInstance with .cshtml files is not supported in Oqtane. Use a .cs file instead.\");\n\n\n    protected override string GetCodeFullPathForExistsCheck(string path)\n    {\n        var l = Log.Fn<string>(path);\n        var pathFinder = ExCtx.GetService<IServerPaths>();\n        var fullPath = pathFinder.FullAppPath(path);\n        return l.ReturnAndLog(fullPath);\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Oqtane.Server\")]\n"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/RazorCompiler.cs",
    "content": "﻿using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.ApplicationParts;\nusing Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.AspNetCore.Mvc.Razor;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Sys;\nusing ToSic.Sys.Utils;\nusing IView = Microsoft.AspNetCore.Mvc.ViewEngines.IView;\n\nnamespace ToSic.Sxc.Razor;\n\ninternal class RazorCompiler(\n    ApplicationPartManager applicationPartManager,\n    IRazorViewEngine viewEngine,\n    IServiceProvider serviceProvider,\n    IHttpContextAccessor httpContextAccessor,\n    IActionContextAccessor actionContextAccessor,\n    LazySvc<AppCodeLoader> appCodeLoader,\n    AssemblyResolver assemblyResolver,\n    SourceAnalyzer sourceAnalyzer)\n    : ServiceBase($\"{SxcLogging.SxcLogName}.RzrCmp\",\n        connect:\n        [\n            applicationPartManager, viewEngine, /* never! serviceProvider,*/ httpContextAccessor, actionContextAccessor, appCodeLoader, assemblyResolver, sourceAnalyzer\n        ]), IRazorCompiler\n{\n    public async Task<(IView view, ActionContext context)> CompileView(string partialName, Action<RazorView> configure, IApp app, HotBuildSpec spec)\n    {\n        var l = Log.Fn<(IView view, ActionContext context)>($\"partialName:{partialName},appCodePath:{app}\");\n        var actionContext = actionContextAccessor.ActionContext ?? NewActionContext();\n        var partial = await FindViewAsync(actionContext, partialName, app, spec);\n        // do callback to configure the object we received\n        if (partial is RazorView rzv) configure?.Invoke(rzv);\n        return l.ReturnAsOk((partial, actionContext));\n    }\n\n    private static bool _executedAlready;\n    private async Task<IView> FindViewAsync(ActionContext actionContext, string partialName, IApp app, HotBuildSpec spec)\n    {\n        var l = Log.Fn<IView>($\"partialName:{partialName}\");\n        var searchedLocations = new List<string>();\n        var exceptions = new List<Exception>();\n        try\n        {\n            List<ApplicationPart>? removeThis = null;\n            if (!_executedAlready)\n            {\n                l.A($\"one time execute, remove problematic ApplicationPart assemblies\");\n                // fix special case that happens with oqtane custom module server project assembly (like Name.Server.Oqtane.dll)\n                // that has empty reference paths (for unknown reason) and IRazorViewEngine.GetView breaks when there are empty\n                // reference paths in the ApplicationParts/AssemblyPart\n                removeThis = applicationPartManager.ApplicationParts.Where(part =>\n                    part is not ICompilationReferencesProvider\n                    && part is AssemblyPart assemblyPart\n                    && assemblyPart.GetReferencePaths().Any(string.IsNullOrEmpty)).ToList();\n                foreach (var part in removeThis)\n                    applicationPartManager.ApplicationParts.Remove(part);\n                l.A($\"removed:{removeThis.Count}\");\n                _executedAlready = true;\n            }\n\n            // TODO: SHOULD OPTIMIZE so the file doesn't need to read multiple times\n            // 1. probably change so the CodeFileInfo contains the source code\n            var razorType = sourceAnalyzer.TypeOfVirtualPath(partialName);\n            if (razorType.IsHotBuildSupported())\n                AddAppCodeAssembly(partialName, app, spec);\n\n            var firstAttempt = viewEngine.GetView(null, partialName, false);\n            l.A($\"firstAttempt: {firstAttempt}\");\n\n            if (removeThis != null)\n            {\n                foreach (var part in removeThis)\n                    applicationPartManager.ApplicationParts.Add(part);\n                l.A($\"restore removed ApplicationParts:{removeThis.Count}\");\n            }\n\n            if (firstAttempt.Success)\n                return l.ReturnAsOk(firstAttempt.View);\n\n            searchedLocations.AddRange(firstAttempt.SearchedLocations);\n            l.A($\"searchedLocations({searchedLocations.Count}): {string.Join(\";\", searchedLocations)}\");\n        }\n        catch (Exception e)\n        {\n            l.Ex(e);\n            exceptions.Add(e);\n        }\n\n        try\n        {\n            var secondAttempt = viewEngine.FindView(actionContext, partialName, false);\n            l.A($\"secondAttempt: {secondAttempt}\");\n\n            if (secondAttempt.Success)\n                return l.ReturnAsOk(secondAttempt.View);\n\n            searchedLocations.AddRange(secondAttempt.SearchedLocations);\n            l.A($\"searchedLocations({searchedLocations.Count}): {string.Join(\";\", searchedLocations)}\");\n        }\n        catch (Exception e)\n        {\n            l.Ex(e);\n            exceptions.Add(e);\n        }\n\n        foreach (var exception in exceptions)\n            throw exception;\n\n        var errorMessage = string.Join(\n            Environment.NewLine,\n            new[] { $\"Unable to find partial '{partialName}'. The following locations were searched:\" }.Concat(searchedLocations));\n        l.A($\"error:{errorMessage}\");\n        throw new InvalidOperationException(errorMessage);\n    }\n\n    private ActionContext NewActionContext()\n    {\n        var l = Log.Fn<ActionContext>();\n        var httpContext = httpContextAccessor.HttpContext ?? new DefaultHttpContext { RequestServices = serviceProvider };\n        return l.ReturnAsOk(new(httpContext, new(), new()));\n    }\n\n    private void AddAppCodeAssembly(string partialName, IApp app, HotBuildSpec spec)\n    {\n        var log = Log.Fn($\"{nameof(partialName)}:{partialName}; {nameof(app.RelativePath)}:{app.RelativePath}; {spec}\", timer: true);\n\n        // Get assembly - try to get from cache, otherwise compile\n        var (assemblyResult, _) = appCodeLoader.Value.GetAppCode(spec);\n        log.A($\"has AppCode assembly: {assemblyResult?.HasAssembly}\");\n\n        if (assemblyResult?.Assembly != null)\n        {\n            var appRelativePathWithEdition = spec.Edition.HasValue() ? Path.Combine(app.RelativePath, spec.Edition) : app.RelativePath;\n            log.A($\"{nameof(appRelativePathWithEdition)}: '{appRelativePathWithEdition}'\");\n\n            // Add assembly to resolver, so it will be provided to the compiler when used in cshtml\n            assemblyResolver.AddAssembly(assemblyResult.Assembly, appRelativePathWithEdition);\n        };\n\n        log.Done();\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/RazorEngine.cs",
    "content": "﻿using Custom.Razor.Sys;\nusing Microsoft.AspNetCore.Mvc.Razor;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Razor;\n\n/// <summary>\n/// The razor engine, which compiles / runs engine templates\n/// </summary>\n[PrivateApi(\"used to be marked as internal, but it doesn't make sense to show in docs\")]\n[EngineDefinition(Name = \"Razor\")]\ninternal class RazorEngine(\n    EngineSpecsService engineSpecsService,\n    IBlockResourceExtractor blockResourceExtractor,\n    EngineAppRequirements engineAppRequirements,\n    LazySvc<IRazorRenderer> razorRenderer,\n    LazySvc<IExecutionContextFactory> exCtxFactory,\n    LazySvc<CodeErrorHelpService> errorHelp,\n    LazySvc<IRenderingHelper> renderingHelper)\n    : ServiceBase(\"Sxc.RzrEng\", connect: [engineSpecsService, blockResourceExtractor, engineAppRequirements, exCtxFactory, errorHelp, renderingHelper, razorRenderer]),\n        IRazorEngine\n{\n    /// <inheritdoc />\n    public RenderEngineResult Render(IBlock block, RenderSpecs specs)\n    {\n        var l = Log.Fn<RenderEngineResult>(timer: true);\n\n        // Prepare #1: Specs\n        var engineSpecs = engineSpecsService.GetSpecs(block);\n\n        // Preflight: check if rendering is possible, or throw exceptions...\n        var preFlightResult = engineAppRequirements.CheckExpectedNoRenderConditions(engineSpecs);\n        if (preFlightResult != null)\n            return l.ReturnAsError(preFlightResult);\n\n        // Render and process / return\n        var renderedTemplate = RenderEntryRazor(engineSpecs, specs);\n        var result = blockResourceExtractor.Process(renderedTemplate);\n        return l.ReturnAsOk(result);\n    }\n\n    /// <inheritdoc/>\n    private RenderEngineResultRaw RenderEntryRazor(EngineSpecs engineSpecs, RenderSpecs specs)\n    {\n        var l = Log.Fn<RenderEngineResultRaw>();\n        var task = RenderTask(engineSpecs, specs);\n        try\n        {\n            task.Wait();\n            var result = task.Result;\n\n            if (result.Exception == null)\n                return l.ReturnAsOk(new ()\n                {\n                    Html = result.TextWriter?.ToString() ?? \"\",\n                    ExceptionsOrNull  = null\n                });\n\n            var errorMessage = renderingHelper.Value.Init(engineSpecs.Block).DesignErrorMessage([result.Exception], true);\n            return l.Return(new ()\n            {\n                Html = errorMessage ?? \"\",\n                ExceptionsOrNull = [result.Exception]\n            });\n        }\n        catch (Exception ex)\n        {\n            var myEx = task.Exception?.InnerException ?? ex;\n            return l.Return(new ()\n            {\n                Html = myEx.ToString(),\n                ExceptionsOrNull = [myEx]\n            });\n        }\n    }\n\n    [PrivateApi]\n    private async Task<(TextWriter? TextWriter, Exception? Exception)> RenderTask(EngineSpecs engineSpecs, RenderSpecs specs)\n    {\n        Log.A(\"will render into TextWriter\");\n        RazorView? page = null;\n        try\n        {\n            if (string.IsNullOrEmpty(engineSpecs.TemplatePath))\n                return (null, null);\n\n            var result = await razorRenderer.Value.RenderToStringAsync(\n                engineSpecs,\n                specs.Data,\n                rzv =>\n                {\n                    page = rzv; // keep for better errors\n                    if (rzv.RazorPage is not IRazor asSxc)\n                        return;\n\n                    var exCtx = exCtxFactory.Value.New(new()\n                    {\n                        OwnerOrNull = asSxc,\n                        BlockOrNull = engineSpecs.Block,\n                        ParentLog = Log,\n                        CompatibilityFallback = CompatibilityLevels.CompatibilityLevel12,\n                    });\n\n                    asSxc.ConnectToRoot(exCtx);\n                    // Note: Don't set the purpose here anymore, it's a deprecated feature in 12+\n                }\n            );\n            var writer = new StringWriter();\n            await writer.WriteAsync(result);\n            return (writer, null);\n        }\n        catch (Exception maybeIEntityCast)\n        {\n            return (null, errorHelp.Value.AddHelpIfKnownError(maybeIEntityCast, page));\n        }\n\n        // WIP https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Razor.RuntimeCompilation/src/RuntimeViewCompiler.cs#L397-L404\n        // maybe also https://stackoverflow.com/questions/48206993/how-to-load-asp-net-core-razor-view-dynamically-at-runtime\n        // later also check loading more DLLs on https://stackoverflow.com/questions/58685966/adding-assemblies-types-to-be-made-available-to-razor-page-at-runtime\n\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/RazorReferenceManagerEnhanced.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing Microsoft.AspNetCore.Mvc.ApplicationParts;\nusing Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.Extensions.Options;\nusing ToSic.Sxc.Razor.DotNetOverrides;\n\nnamespace ToSic.Sxc.Razor;\n\ninternal class RazorReferenceManagerEnhanced(ApplicationPartManager partManager, IOptions<MvcRazorRuntimeCompilationOptions> options) : RazorReferenceManager(partManager, options)\n{\n    // cache references for reuse;\n    [field: AllowNull, MaybeNull]\n    public override IReadOnlyList<MetadataReference> CompilationReferences => field ??= base.CompilationReferences;\n\n    public IReadOnlyList<MetadataReference> GetAdditionalCompilationReferences(IEnumerable<string> additionalReferencePaths)\n    {\n        if (additionalReferencePaths == null! /* paranoid */)\n            return CompilationReferences;\n\n        var additionalMetadataReferences = additionalReferencePaths\n            .Select(CreateMetadataReference)\n            .ToList();\n        return CompilationReferences.Concat(additionalMetadataReferences).ToList().AsReadOnly(); ;\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/RazorRenderer.cs",
    "content": "﻿using Custom.Hybrid;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\nusing Microsoft.AspNetCore.Mvc.Razor;\nusing Microsoft.AspNetCore.Mvc.Rendering;\nusing Microsoft.AspNetCore.Mvc.ViewEngines;\nusing Microsoft.AspNetCore.Mvc.ViewFeatures;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Sys;\n\nnamespace ToSic.Sxc.Razor;\n\ninternal class RazorRenderer(\n    ITempDataProvider tempDataProvider,\n    IRazorCompiler appCodeRazorCompiler)\n    : ServiceBase($\"{SxcLogging.SxcLogName}.RzrRdr\",\n        connect: [tempDataProvider, appCodeRazorCompiler]), IRazorRenderer\n{\n\n    public async Task<string> RenderToStringAsync<TModel>(EngineSpecs engineSpecs, /*string templatePath,*/ TModel model, Action<RazorView> configure /*IApp app, HotBuildSpec hotBuildSpec*/)\n    {\n        var templatePath = engineSpecs.TemplatePath;\n        var app = engineSpecs.App;\n        var hotBuildSpec = engineSpecs.ToHotBuildSpec();\n        var l = Log.Fn<string>($\"{nameof(templatePath)}: '{templatePath}'; {nameof(app.PhysicalPath)}: '{app.PhysicalPath}'; {hotBuildSpec}\");\n\n        var (view, actionContext) = await appCodeRazorCompiler.CompileView(templatePath, configure, app, hotBuildSpec);\n\n        var viewDataDictionary = CreateViewDataDictionaryForRazorViewWithGenericBaseTypeOrNull(view, model) \n            ?? new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new()) { Model = model };\n\n        // Prepare to render\n        await using var output = new StringWriter();\n\n        var viewContext = new ViewContext(\n            actionContext,\n            view,\n            viewDataDictionary,\n            new TempDataDictionary(\n                actionContext.HttpContext,\n                tempDataProvider),\n            output,\n            new()\n        );\n        await view.RenderAsync(viewContext);\n        return l.ReturnAsOk(output.ToString());\n    }\n\n    /// <summary>\n    /// Creates a ViewDataDictionary object based on the provided IView for RazorView with generic base type\n    /// taking care of setting ViewDataDictionary type is of the same type as the base type and\n    /// the Model property if the model is not null is of the same type as the base type.\n    /// </summary>\n    /// <param name=\"view\">The IView object.</param>\n    /// <param name=\"model\"></param>\n    /// <returns>ViewDataDictionary or null</returns>\n    /// <remarks>\n    /// This code is executed for main razor view only.\n    /// Main razor page view normally do not have instance of Model data (except in special case when model data is \n    /// eventually provided in uncommon rendering that could happen from our custom razor render code call)\n    /// </remarks>\n    private ViewDataDictionary? CreateViewDataDictionaryForRazorViewWithGenericBaseTypeOrNull(IView view, object? model)\n    {\n        var l = Log.Fn<ViewDataDictionary?>($\"{nameof(view.Path)}: '{view.Path}'\");\n\n        if (view is not RazorView rsv)\n            return l.ReturnNull(\"Not a RazorView\");\n\n        var baseType = rsv.RazorPage.GetType().BaseType;\n        if (baseType is not { IsGenericType: true } || baseType.GetGenericTypeDefinition() != typeof(RazorTyped<>))\n            return l.ReturnNull(\"Base type is not generic\");\n\n        var baseTypeGenericTypeArgument = baseType.GenericTypeArguments[0];\n        l.A($\"Base type is generic: {baseTypeGenericTypeArgument}\");\n\n        // Create an instance of ViewDataDictionary<TModel> \n        var viewDataDictionary = (ViewDataDictionary?)Activator.CreateInstance(\n            typeof(ViewDataDictionary<>).MakeGenericType(baseTypeGenericTypeArgument),\n            [new EmptyModelMetadataProvider(), new ModelStateDictionary()]\n        );\n        l.A($\"Created ViewDataDictionary<{baseTypeGenericTypeArgument}>\");\n\n        // Set the Model property\n        if (model != null && model.GetType() == baseTypeGenericTypeArgument)\n        {\n            viewDataDictionary!.Model = model; /* ((dynamic)rsv.RazorPage).Model*/;\n            l.A($\"Set Model to {viewDataDictionary.Model}\");\n        }\n\n\n        l.Done(\"ok\");\n        return l.Return(viewDataDictionary);\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/StartupRazor.cs",
    "content": "﻿using Microsoft.AspNetCore.Mvc.Razor.Compilation;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Razor;\nusing ToSic.Sxc.Razor.DotNetOverrides;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n// ReSharper disable once InconsistentNaming\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupRazor\n{\n    public static IServiceCollection AddSxcRazor(this IServiceCollection services)\n    {\n        // 2sxc Razor Parts\n        services.TryAddTransient<IRazorCompiler, RazorCompiler>();\n        services.TryAddTransient<IRazorRenderer, RazorRenderer>();\n        services.TryAddTransient<IRazorEngine, RazorEngine>();\n\n        // debugging\n        services.Replace(ServiceDescriptor.Singleton<IViewCompilerProvider, RuntimeViewCompilerProvider>());\n        services.TryAddSingleton<CSharpCompiler>();\n        services.TryAddSingleton<RazorReferenceManager, RazorReferenceManagerEnhanced>();\n        services.TryAddSingleton<RuntimeCompilationFileProvider>();\n        services.TryAddTransient<HotBuildReferenceManager>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Razor/ToSic.Sxc.Razor/ToSic.Sxc.Razor.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-NetCore.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <PropertyGroup>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace>ToSic.Sxc.Razor</RootNamespace>\n  </PropertyGroup>\n\n  <!-- Note: not sure what this is for... -->\n  <PropertyGroup>\n    <RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation\" Version=\"9.0.5\" /><!-- from ToSic.Sxc.Oqt.Server.csproj  (affects Oqtane only) -->\n    <!-- Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation transitive dependecy, but force updated to latest version  (affects Oqtane only) -->\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Razor.Extensions\" Version=\"6.0.36\" />\n    <!-- Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation transitive dependecy, but force updated to latest version  (affects Oqtane only) -->\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Razor\" Version=\"6.0.36\" />\n    <!-- Microsoft.CodeAnalysis.Razor transitive dependecy, but force updated to latest version (affects Oqtane only) -->\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp\" Version=\"4.14.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.DataSources\\ToSic.Eav.DataSources.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Engines\\ToSic.Sxc.Engines.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/AllImportsForRealCode-NetCore.props",
    "content": "<Project>\n  <!-- Set Target Framework and C# version -->\n  <Import Project=\"./TargetFrameworkAndCSharp-NetCore.props\" />\n\n  <!-- Set Default Namespace to ToSic.Sxc-->\n  <Import Project=\"./DefaultNamespace ToSic.Sxc.props\" />\n\n  <!-- Lots of rules to disable generating Assembly Info (since we provide it through an object) -->\n  <Import Project=\"./GenerateAssemblyDisable.props\" />\n\n  <!-- Disable some common warnings we don't care about-->\n  <Import Project=\"./ConfigurationsAndWarnings.props\" />\n\n  <!-- Include C# files which contain the Assembly Info and some classes so that C# latest is supported (such as init-properties) -->\n  <Import Project=\"./IncludeCode/Compiler Features and API Hiding.props\" />\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/AllImportsForRealCode-NetFramework.props",
    "content": "<Project>\n  <!-- Set Target Framework and C# version -->\n  <Import Project=\"./TargetFrameworkAndCSharp-NetFramework.props\" />\n\n  <!-- Set Default Namespace to ToSic.Sxc-->\n  <Import Project=\"./DefaultNamespace ToSic.Sxc.props\" />\n\n  <!-- Lots of rules to disable generating Assembly Info (since we provide it through an object) -->\n  <Import Project=\"./GenerateAssemblyDisable.props\" />\n\n  <!-- Disable some common warnings we don't care about-->\n  <Import Project=\"./ConfigurationsAndWarnings.props\" />\n\n  <!-- Include C# files which contain the Assembly Info and some classes so that C# latest is supported (such as init-properties) -->\n  <Import Project=\"./IncludeCode/Compiler Features and API Hiding.props\" />\n\n\n  <!-- This section was in all DNN Projects, not sure if useful, but better centralize -->\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Debug' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Release' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <!-- ignore warning that it's using a dangerous version of Dnn (v9.6.1 / v9.11.2) @2dm -->\n    <NoWarn>$(NoWarn);NU1902</NoWarn>\n  </PropertyGroup>\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props",
    "content": "<Project>\n  <!-- Set Target Framework and C# version -->\n  <Import Project=\"./TargetFrameworkAndCSharp.props\" />\n\n  <!-- Set Default Namespace to ToSic.Sxc-->\n  <Import Project=\"./DefaultNamespace ToSic.Sxc.props\" />\n\n  <!-- Lots of rules to disable generating Assembly Info (since we provide it through an object) -->\n  <Import Project=\"./GenerateAssemblyDisable.props\" />\n\n  <!-- Disable some common warnings we don't care about-->\n  <Import Project=\"./ConfigurationsAndWarnings.props\" />\n\n  <!-- Include C# files which contain the Assembly Info and some classes so that C# latest is supported (such as init-properties) -->\n  <Import Project=\"./IncludeCode/Compiler Features and API Hiding.props\" />\n\n  <!-- Nullable -->\n  <Import Project=\"./Nullable.props\" />\n\n  <PropertyGroup>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/AllImportsForTestCode-NetFramework.props",
    "content": "<Project>\n\n  <!--\n    *** This is critical for the Tests to run ***\n    Otherwise the unit tests don't know that they should use dependency injection - not sure why though.\n    -->\n  <PropertyGroup>\n    <GenerateAssemblyInfo>true</GenerateAssemblyInfo>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <IsTestProject>true</IsTestProject>\n    <IsPackable>false</IsPackable>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Using Include=\"Xunit\" />\n  </ItemGroup>\n\n  <Import Project=\"./TargetFrameworkAndCSharp-NetFramework.props\" />\n\n  <!-- Set Default Namespace to ToSic.Sxc-->\n  <Import Project=\"./DefaultNamespace ToSic.Sxc.props\" />\n\n  <!-- Lots of rules to disable generating Assembly Info (since we provide it through an object) -->\n  <Import Project=\"./GenerateAssemblyDisable.props\" />\n\n  <!-- Disable some common warnings we don't care about-->\n  <Import Project=\"./ConfigurationsAndWarnings.props\" />\n\n  <!-- Include C# files which contain the Assembly Info and some classes so that C# latest is supported (such as init-properties) -->\n  <Import Project=\"./IncludeCode/Compiler Features and API Hiding.props\" />\n\n  <!-- Include most xUnit packages and more -->\n  <Import Project=\"./Tests/xUnit Test Framework.props\" />\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/AllImportsForTestCode.props",
    "content": "<Project>\n\n  <!--\n    *** This is critical for the Tests to run ***\n    Otherwise the unit tests don't know that they should use dependency injection - not sure why though.\n    -->\n  <PropertyGroup>\n    <GenerateAssemblyInfo>true</GenerateAssemblyInfo>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <IsTestProject>true</IsTestProject>\n    <IsPackable>false</IsPackable>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Using Include=\"Xunit\" />\n  </ItemGroup>\n\n  <Import Project=\"./TargetFrameworkAndCSharp.props\" />\n\n  <!-- Set Default Namespace to ToSic.Sxc-->\n  <Import Project=\"./DefaultNamespace ToSic.Sxc.props\" />\n\n  <!-- Lots of rules to disable generating Assembly Info (since we provide it through an object) -->\n  <Import Project=\"./GenerateAssemblyDisable.props\" />\n\n  <!-- Disable some common warnings we don't care about-->\n  <Import Project=\"./ConfigurationsAndWarnings.props\" />\n\n  <!-- Include C# files which contain the Assembly Info and some classes so that C# latest is supported (such as init-properties) -->\n  <Import Project=\"./IncludeCode/Compiler Features and API Hiding.props\" />\n\n  <!-- Include most xUnit packages and more -->\n  <Import Project=\"./Tests/xUnit Test Framework.props\" />\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/ConfigurationsAndWarnings.props",
    "content": "<Project>\n  <PropertyGroup>\n    <!-- Not sure what this is?  -->\n    <NoWarn>$(NoWarn);7035</NoWarn>\n\n    <!-- Disable warnings on production build about public APIs not having XDocs -->\n    <NoWarn>$(NoWarn);CS1591</NoWarn>\n\n    <!-- This is a warning that duplicate imports exist - which is because we're importing the DLL specs in each project\n    so projects further down think it's already there-->\n    <NoWarn>$(NoWarn);CS0436</NoWarn>\n\n    <Configurations>Debug;Release;Testing;</Configurations>\n\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/CreateXDocsOnRelease.props",
    "content": "<Project>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\">\n    <!-- generate xml docs -->\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <NoWarn>1701;1702;CS1570;CS1572;CS1573;CS1574;CS1587;CS1591;CS1710;CS1711</NoWarn>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/DefaultNamespace ToSic.Sxc.props",
    "content": "<Project>\n  <PropertyGroup>\n    <!-- By Default, als 2sxc DLLs will have the same root namespace -->\n    <RootNamespace>ToSic.Sxc</RootNamespace>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/GenerateAssemblyDisable.props",
    "content": "<Project>\n  <!-- Don't generate assembly properties from this XML which should come from the core file, like version - these lines must be in sync in all ToSic.Eav.*.csproj files -->\n  <PropertyGroup>\n    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>\n    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>\n    <GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>\n    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>\n    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>\n    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/IncludeCode/Compiler Features and API Hiding.props",
    "content": "<Project>\n\n  <!-- Import common files which change how the project compiles; AssemblyInfo from 2sxc; rest form Lib.Imports -->\n  <ItemGroup>\n    <Compile Include=\"..\\..\\SharedImports\\Properties\\SxcSharedAssemblyInfo.cs\" Link=\"Properties\\SxcSharedAssemblyInfo.cs\" />\n    <Compile Include=\"..\\..\\..\\..\\eav-server\\SharedImports\\Code\\System.Runtime.CompilerServices.cs\" Link=\"Properties\\System.Runtime.CompilerServices.cs\" />\n    <Compile Include=\"..\\..\\..\\..\\eav-server\\SharedImports\\Code\\HideInternalApisOnReleaseOnly.cs\" Link=\"Properties\\HideInternalApisOnReleaseOnly.cs\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/Nullable.props",
    "content": "<Project>\n\n  <!-- All Sys projects are nullable -->\n  <PropertyGroup  Condition=\"$(TargetFramework) == 'net9.0'\">\n    <!--<Nullable>enable</Nullable>-->\n  </PropertyGroup>\n\n  <!-- Support Nullable in .net Framework -->\n  <ItemGroup Condition=\"$(TargetFramework) == 'net472'\">\n    <PackageReference Include=\"Nullable\" Version=\"1.3.1\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/Reference/RazorBlade.props",
    "content": "<Project>\n\n  <ItemGroup>\n    <Reference Include=\"ToSic.Razor\">\n      <HintPath Condition=\"'$(TargetFramework)' == 'net472'\">..\\..\\..\\Dependencies\\RazorBlade\\Release\\net472\\ToSic.Razor.dll</HintPath>\n      <HintPath Condition=\"'$(TargetFramework)' == 'net9.0'\">..\\..\\..\\Dependencies\\RazorBlade\\Release\\net6.0\\ToSic.Razor.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n  <!-- This is needed for the IHtmlString or whatever in .net Framework -->\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net472'\">\n    <Reference Include=\"System.Web\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/TargetFrameworkAndCSharp-NetCore.props",
    "content": "<Project>\n  <PropertyGroup>\n    <!-- Dual Compile for DNN and Oqtane -->\n    <!--<TargetFrameworks>net472;net9.0;</TargetFrameworks>-->\n    <TargetFramework>net9.0</TargetFramework>\n\n    <!-- C# Latest -->\n    <LangVersion>preview</LangVersion>\n\n    <!-- Don't try to generate web.config redirects -->\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n\n    <!-- Build in a way so the DLLs remain identical on every build without code changes (so no build number) -->\n    <Deterministic>true</Deterministic>\n\n    <!-- Enable Implicit usings (which ones depend on the exact project type) -->\n    <ImplicitUsings>enable</ImplicitUsings>\n    \n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/TargetFrameworkAndCSharp-NetFramework.props",
    "content": "<Project>\n  <PropertyGroup>\n    <!-- Dual Compile for DNN and Oqtane -->\n    <!--<TargetFrameworks>net472;net9.0;</TargetFrameworks>-->\n    <!--<TargetFramework>net9.0</TargetFramework>-->\n    <TargetFramework>net472</TargetFramework>\n\n    <!-- C# Latest -->\n    <LangVersion>preview</LangVersion>\n\n    <!-- Don't try to generate web.config redirects -->\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n\n    <!-- Build in a way so the DLLs remain identical on every build without code changes (so no build number) -->\n    <Deterministic>true</Deterministic>\n\n    <!-- Enable Implicit usings (which ones depend on the exact project type) -->\n    <ImplicitUsings>enable</ImplicitUsings>\n    \n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/TargetFrameworkAndCSharp.props",
    "content": "<Project>\n  <PropertyGroup>\n    <!-- Dual Compile for DNN and Oqtane -->\n    <TargetFrameworks>net472;net9.0;</TargetFrameworks>\n\n    <!-- C# Latest -->\n    <LangVersion>preview</LangVersion>\n\n    <!-- Don't try to generate web.config redirects -->\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n\n    <!-- Build in a way so the DLLs remain identical on every build without code changes (so no build number) -->\n    <Deterministic>true</Deterministic>\n\n    <!-- Enable Implicit usings (which ones depend on the exact project type) -->\n    <ImplicitUsings>enable</ImplicitUsings>\n    \n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/Tests/xUnit Test Framework - Copy.props",
    "content": "<Project>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net472'\">\n    <PackageReference Include=\"MSTest.TestAdapter\" Version=\"3.4.3\" />\n    <PackageReference Include=\"MSTest.TestFramework\" Version=\"3.4.3\" />\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n    <PackageReference Include=\"MSTest.TestAdapter\" Version=\"3.4.3\" />\n    <PackageReference Include=\"MSTest.TestFramework\" Version=\"3.4.3\" />\n    <FrameworkReference Include=\"Microsoft.NETCore.App\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/Tests/xUnit Test Framework.props",
    "content": "<Project>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"Xunit.DependencyInjection\" Version=\"9.9.0\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.0\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/CsProj.Props/xxx AllImportsForRealCode.props",
    "content": "<Project>\n  <!-- Set Target Framework and C# version -->\n  <Import Project=\"./TargetFrameworkAndCSharp.props\" />\n\n  <!-- Set Default Namespace to ToSic.Sxc-->\n  <Import Project=\"./DefaultNamespace ToSic.Sxc.props\" />\n\n  <!-- Lots of rules to disable generating Assembly Info (since we provide it through an object) -->\n  <Import Project=\"./GenerateAssemblyDisable.props\" />\n\n  <!-- Disable some common warnings we don't care about-->\n  <Import Project=\"./ConfigurationsAndWarnings.props\" />\n\n  <!-- Include C# files which contain the Assembly Info and some classes so that C# latest is supported (such as init-properties) -->\n  <Import Project=\"./IncludeCode/Compiler Features and API Hiding.props\" />\n\n</Project>"
  },
  {
    "path": "Src/SharedImports/Properties/SxcSharedAssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing static ToSic.Sxc.Sys.SxcSharedAssemblyInfo;\n\n// Use the globally defined assembly version information in all projects\n// This file lies in the ToSic.Eav.Core project and is used as linked in other EAV projects\n// See: https://denhamcoder.net/2018/09/11/visual-studio-synchronize-a-version-number-across-multiple-assemblies/\n\n// For this to work, the .csproj file must also have some <generate...> set to false\n\n[assembly: AssemblyVersion(AssemblyVersion)]\n[assembly: AssemblyFileVersion(AssemblyVersion)]\n[assembly: AssemblyInformationalVersion(AssemblyVersion)]\n[assembly: AssemblyProduct(SxcProduct)]\n[assembly: AssemblyCompany(Company)]\n[assembly: AssemblyCopyright(SxcCopyright)]\n\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Sys;\n\n\n/// <summary>\n/// Contains information for all assemblies to use\n/// </summary>\n//[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static class SxcSharedAssemblyInfo\n{\n    public const string AssemblyVersion = \"21.07.00\";\n    public const string Company = \"2sic internet solutions GmbH, Switzerland\";\n    public const string SxcProduct = \"2sxc CMS- and Meta-Module for Dnn and Oqtane\";\n    public const string SxcCopyright = \"Copyright MIT © 2sic 2025\";\n}"
  },
  {
    "path": "Src/SharedImports/Shared Imports (never build this).csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net9.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/SharedImports/readme.md",
    "content": "# Shared Imports\n\nThis project is not meant to compile.\n\nIt's just here to store all files which should be imported into the `csproj` of all other projects."
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Obsolete/AdamFile.cs",
    "content": "﻿#if NETFRAMEWORK\nusing ToSic.Sxc.Adam;\n\n// Obsolete class / namespace\n// Used in some previous apps like BlueImp\n// Leave for compatibility\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.SexyContent.Adam;\n\n// ReSharper disable once InconsistentNaming\n[Obsolete(\"use ToSic.Sxc.Adam.IFile instead\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface AdamFile: IFile\n{\n    [Obsolete(\"use FullName instead\")]\n    string FileName { get; }\n\n    [Obsolete(\"use Created instead\")]\n    DateTime CreatedOnDate { get; }\n\n    [Obsolete(\"use Id instead\")]\n    int FileId { get; }\n\n}\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys/AdamAssetId.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys;\n\n/// <summary>\n/// Dummy interface to mark a object which is used as a file identifier.\n/// This is to avoid specifying the underlying type of the real ID.\n/// </summary>\npublic record AdamAssetIdentifier\n{\n    public static AdamAssetId<T> Create<T>(T sysId) => new() { SysId = sysId };\n}\n\n\npublic record AdamAssetId<TFileId> : AdamAssetIdentifier\n{\n    public TFileId SysId { get; init; } = default!;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys/AdamExportListHelper.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets.Sys;\nusing ToSic.Sxc.Adam.Sys.FileSystem;\nusing ToSic.Sxc.Adam.Sys.Manager;\n\nnamespace ToSic.Sxc.Adam.Sys;\n\n/// <summary>\n/// Export helper\n/// provides a list of all files / folders in ADAM for export\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamExportListHelper<TFolderId, TFileId>(AdamManager adm)\n{\n    private readonly IFolder _root = adm.RootFolder ?? throw new ArgumentNullException(nameof(adm.RootFolder), @\"needs a root folder to export from ADAM\");\n    // todo #adamid - should use TFile/TFolder\n    private readonly List<TFileId> _fileIds = [];\n    private readonly List<TFolderId> _folderIds = [];\n\n    private readonly IAdamFileSystem _envFs = adm.AdamFs;\n\n    public List<TFileId> AppFiles\n    {\n        get\n        {\n            if (_fileIds.Count == 0)\n                AddFolder(_root);\n            return _fileIds;\n        }\n    }\n\n    public List<TFolderId> AppFolders\n    {\n        get\n        {\n            if (_folderIds.Count == 0)\n                AddFolder(_root);\n            return _folderIds;\n        }\n            \n    } \n    private void AddFolder(IFolder folder)\n    {\n        _folderIds.Add(((IAssetSysId<TFolderId>)folder).SysId);  // track of the folder\n        AddFilesInFolder(folder);   // keep track of the files\n\n        foreach (var f in _envFs.GetFolders(folder))   // then add subfolders\n            AddFolder(f);\n    }\n\n    private void AddFilesInFolder(IFolder folder) \n        => _envFs.GetFiles(folder).ForEach(f => _fileIds.Add(((IAssetSysId<TFileId>)f).SysId));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys/File.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Cms.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Field;\nusing ToSic.Sxc.Images.Sys;\n\nnamespace ToSic.Sxc.Adam.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class File<TFolderId, TFileId>(AdamManager adamManager)\n    : Eav.Apps.Assets.Sys.File<TFolderId, TFileId>,\n        IFile,\n        IHasLink\n{\n    protected AdamManager AdamManager { get; } = adamManager;\n\n    #region Metadata\n\n    /// <inheritdoc />\n    [JsonIgnore]\n    [field: AllowNull, MaybeNull]\n    public ITypedMetadata Metadata => field\n        ??= AdamManager.CreateMetadataTyped($\"{CmsMetadata.FilePrefix}{SysId}\", FullName, AttachMdRecommendations);\n\n    /// <summary>\n    /// Attach metadata recommendations\n    /// </summary>\n    /// <param name=\"mdOf\"></param>\n    protected void AttachMdRecommendations(IMetadata mdOf)\n    {\n        if (mdOf?.Target == null || Type != AssetTypes.Image)\n            return;\n        mdOf.Target.Recommendations = AdamManager.Cdf\n            .GetService<IImageMetadataRecommendationsService>()\n            .GetImageRecommendations();\n    }\n\n    IMetadata IHasMetadata.Metadata => (Metadata as IHasMetadata).Metadata;\n\n    /// <inheritdoc />\n    [JsonIgnore]\n    public bool HasMetadata => (Metadata as IHasMetadata)?.Metadata.Any() ?? false;\n\n\n    #endregion\n\n    public string? Url { get; set; }\n\n    public string Type => AssetTypeNames.GetTypeName(Extension);\n\n\n    [PrivateApi]\n    public IField? Field { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys/FileDynamic.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Cms.Sys;\n\nnamespace ToSic.Sxc.Adam.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class FileDynamic<TFolderId, TFileId>(AdamManager adamManager): File<TFolderId, TFileId>(adamManager)\n#if NETFRAMEWORK\n#pragma warning disable 618\n    , ToSic.SexyContent.Adam.AdamFile\n#pragma warning restore 618\n#endif\n\n{\n    public string FileName => FullName;\n\n    public DateTime CreatedOnDate => Created;\n\n    public int FileId => SysId as int? ?? 0;\n\n    [JsonIgnore]\n    [field: AllowNull, MaybeNull]\n    public new dynamic Metadata => field\n        ??= AdamManager.CreateMetadataDynamic($\"{CmsMetadata.FilePrefix}{SysId}\", FullName, AttachMdRecommendations);\n\n    public static FileDynamic<TFolderId, TFileId> Create(AdamManager adamManager, File<TFolderId, TFileId> typed)\n        => new(adamManager)\n        {\n            FullName = typed.FullName,\n            Extension = typed.Extension,\n            Size = typed.Size,\n            SysId = typed.SysId,\n            Folder = typed.Folder,\n            ParentSysId = typed.ParentSysId,\n\n            Path = typed.Path,\n\n            Created = typed.Created,\n            Modified = typed.Modified,\n            Name = typed.Name,\n            Url = typed.Url,\n            PhysicalPath = typed.PhysicalPath,\n        };\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys/Folder.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam.Sys.FileSystem;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Cms.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sys.Performance;\n\nnamespace ToSic.Sxc.Adam.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class Folder<TFolderId, TFileId>(AdamManager adamManager)\n    : Eav.Apps.Assets.Sys.Folder<TFolderId, TFileId>, IFolder\n{\n    protected AdamManager AdamManager { get; } = adamManager;\n    protected IAdamFileSystem AdamFs { get; } = adamManager.AdamFs;\n\n    /// <inheritdoc />\n    [JsonIgnore]\n    [field: AllowNull, MaybeNull]\n    public ITypedMetadata Metadata => field\n        ??= AdamManager.CreateMetadataTyped($\"{CmsMetadata.FolderPrefix}{SysId}\", Name);\n\n    IMetadata IHasMetadata.Metadata => (Metadata as IHasMetadata).Metadata;\n\n    /// <inheritdoc />\n    [JsonIgnore]\n    public bool HasMetadata => (Metadata as IHasMetadata).Metadata.Any();\n\n\n\n    /// <inheritdoc />\n    public string? Url { get; set; }\n\n    /// <inheritdoc />\n    public string Type => AssetTypes.Folder;\n\n\n    /// <inheritdoc />\n    public override bool HasChildren\n        => _hasChildren ??= AdamFs.GetFiles(this).Any()\n                            || AdamFs.GetFolders(this).Any();\n    private bool? _hasChildren;\n\n\n\n    /// <inheritdoc />\n    public IEnumerable<IFolder> Folders => _folders.Get(() =>\n    {\n        var folders = AdamFs.GetFolders(this);\n        foreach (var f in folders)\n            ((Folder<TFolderId, TFileId>)f).Field = Field;\n        return folders;\n    })!;\n    private readonly GetOnce<IEnumerable<IFolder>> _folders = new();\n\n\n    /// <inheritdoc/>\n    public IEnumerable<IFile> Files => _files.Get(() =>\n    {\n        var files = AdamFs\n            .GetFiles(this)\n            .ToListOpt();\n        foreach (var f in files)\n            ((File<TFolderId, TFileId>)f).Field = Field;\n        return files;\n    })!;\n    private readonly GetOnce<IEnumerable<IFile>> _files = new();\n\n    [PrivateApi]\n    public IField? Field { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys/FolderDynamic.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Cms.Sys;\n\nnamespace ToSic.Sxc.Adam.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class FolderDynamic<TFolderId, TFileId>(AdamManager adamManager): Folder<TFolderId, TFileId>(adamManager)\n{\n\n    [JsonIgnore]\n    [field: AllowNull, MaybeNull]\n    public new dynamic Metadata => field ??= AdamManager.CreateMetadataDynamic($\"{CmsMetadata.FolderPrefix}{SysId}\", Name);\n\n    /// <summary>\n    /// Create a dynamic folder from a typed folder.\n    /// </summary>\n    public static FolderDynamic<TFolderId, TFileId> Create(AdamManager adamManager, Folder<TFolderId, TFileId> typed)\n        => new(adamManager)\n        {\n            Path = typed.Path,\n            SysId = typed.SysId,\n\n            ParentSysId = typed.ParentSysId,\n\n            Name = typed.Name,\n            Created = typed.Created,\n            Modified = typed.Modified,\n            Url = typed.Url,\n            PhysicalPath = typed.PhysicalPath,\n        };\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys/FolderOfField.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Adam.Sys.Storage;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Adam.Sys;\n\n/// <summary>\n/// The ADAM Navigator creates a folder object for an entity/field combination\n/// This is the root folder where all files for this field are stored\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class FolderOfField<TFolderId, TFileId> : Folder<TFolderId, TFileId>\n{\n    private FolderOfField(AdamManager adamManager, IField? field) : base(adamManager)\n    {\n        Field = field;\n    }\n\n    public static FolderOfField<TFolderId, TFileId> Create(AdamManager adamManager, AdamStorageOfField adamStorageOfField, IField? field)\n    {\n        // WIP - maybe still provide some basic info?\n        //Url = adamStorageOfField.Manager.AdamFs.GetUrl(adamStorageOfField.Root);\n        var quickInit = !adamManager.AdamFs.FolderExists(adamStorageOfField.Root);\n        var f = quickInit\n            ? null\n            : adamManager.Folder(adamStorageOfField.Root);\n        if (f == null)\n            quickInit = true;\n\n        if (quickInit)\n            return new(adamManager, field)\n            {\n                ParentSysId = default!,\n                SysId = default!,\n                Created = default,\n                Modified = default,\n                Path = null!,\n                Name = null!,\n                PhysicalPath = null!,\n            };\n\n        return new(adamManager, field)\n        {\n            ParentSysId = default!,\n            SysId = ((IAssetSysId<TFolderId>)f!).SysId,\n            Created = f.Created,\n            Modified = f.Modified,\n            Path = f.Path,\n            Name = f.Name,\n            PhysicalPath = f.PhysicalPath,\n            Url = f.Url,\n        };\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.FileSystem/AdamFileSystemBase.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Adam.Sys.Paths;\n\nnamespace ToSic.Sxc.Adam.Sys.FileSystem;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class AdamFileSystemBase : ServiceBase, IAdamFileSystem\n{\n    #region Setup\n\n    protected AdamFileSystemBase(IAdamPaths adamPaths, string logPrefix, object[]? connect = default)\n        : base($\"{logPrefix}.FilSys\", connect: [adamPaths, ..connect ?? []])\n    {\n        AdamPaths = adamPaths;\n        ConnectLogs([\n            FsHelpers = new(adamPaths)\n        ]);\n    }\n\n    protected readonly AdamFileSystemHelpers FsHelpers;\n    protected readonly IAdamPaths AdamPaths;\n\n    public void Init(AdamManager adamManager)\n    {\n        var l = Log.Fn();\n        AdamManager = adamManager;\n        AdamPaths.Init(adamManager);\n        l.Done();\n    }\n\n    protected AdamManager AdamManager = null!;\n\n    #endregion\n\n\n\n    /// <inheritdoc />\n    public virtual void Rename(IFile file, string newName)\n        => Log.Do(() => FsHelpers.TryToRenameFile(AdamPaths.PhysicalPath(file.Path), newName));\n\n    /// <inheritdoc />\n    public virtual void Delete(IFile file) => Log.Do(() => File.Delete(AdamPaths.PhysicalPath(file.Path)));\n\n\n    public int MaxUploadKb() => AdamConstants.MaxUploadKbDefault;\n    //public abstract File<TFolder, TFile> GetFile(TFile fileId);\n\n    public abstract IFile GetFile(AdamAssetIdentifier fileId);\n\n    public abstract List<IFile> GetFiles(IFolder folder);\n\n    public abstract IFile Add(IFolder parent, Stream body, string fileName, bool ensureUniqueName);\n    public abstract void AddFolder(string path);\n    public abstract bool FolderExists(string path);\n    //public abstract Folder<TFolder, TFile> GetFolder(TFolder folderId);\n    public abstract IFolder GetFolder(AdamAssetIdentifier folderId);\n\n    public abstract List<IFolder> GetFolders(IFolder folder);\n    public abstract void Rename(IFolder folder, string newName);\n    public abstract void Delete(IFolder folder);\n    public abstract IFolder Get(string path);\n    public string GetUrl(string folderPath) => AdamPaths.Url(folderPath.ForwardSlash());\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.FileSystem/AdamFileSystemHelpers.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Adam.Sys.Paths;\n\nnamespace ToSic.Sxc.Adam.Sys.FileSystem;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamFileSystemHelpers(IAdamPaths adamPaths) : ServiceBase(\"Sxc.AdmFil\")\n{\n    public string EnsurePhysicalPath(string path)\n    {\n        path = path.Backslash();\n        return path.StartsWith(\"adam\", StringComparison.CurrentCultureIgnoreCase)\n            ? adamPaths.PhysicalPath(path)\n            : path;\n    }\n\n    /// <summary>\n    /// When uploading a new file, we must verify that the name isn't used. \n    /// If it is used, walk through numbers to make a new name which isn't used. \n    /// </summary>\n    /// <param name=\"serverPath\"></param>\n    /// <param name=\"fileName\"></param>\n    /// <returns></returns>\n    public string FindUniqueFileName(string serverPath, string fileName)\n    {\n        var l = Log.Fn<string>($\"{serverPath}, {fileName}\");\n\n        var name = Path.GetFileNameWithoutExtension(fileName);\n        var ext = Path.GetExtension(fileName);\n        for (var i = 1; i < AdamConstants.MaxSameFileRetries \n                        && File.Exists(Path.Combine(serverPath, Path.GetFileName(fileName))); i++)\n            fileName = $\"{name}-{i}{ext}\";\n\n        return l.ReturnAndLog(fileName);\n    }\n\n\n\n    public bool TryToRenameFile(string originalWithPath, string newName)\n    {\n        var l = Log.Fn<bool>($\"{newName}\");\n\n        if (!File.Exists(originalWithPath))\n            return l.ReturnFalse($\"Can't rename because source file does not exist {originalWithPath}\");\n\n        AdamPathsBase.ThrowIfPathContainsDotDot(newName);\n        var path = FindParentPath(originalWithPath);\n        var newFilePath = Path.Combine(path, newName);\n        if (File.Exists(newFilePath))\n            return l.ReturnFalse($\"Can't rename because file with new name exists {newFilePath}\");\n\n        File.Move(originalWithPath, newFilePath);\n        return l.ReturnTrue($\"File renamed\");\n    }\n\n\n    private static string FindParentPath(string path)\n    {\n        var cleanedPath = path.Backslash().TrimEnd('\\\\');\n        var lastSlash = cleanedPath.LastIndexOf('\\\\');\n        return lastSlash == -1 ? \"\" : cleanedPath.Substring(0, lastSlash);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.FileSystem/AdamFileSystemString.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Paths;\n\nnamespace ToSic.Sxc.Adam.Sys.FileSystem;\n\n/// <summary>\n/// Basic implementation of the ADAM file system.\n/// This is string-based, not with environment IDs.\n/// It's primarily meant for standalone implementations or as a template for other integrations. \n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class AdamFileSystemString(IAdamPaths adamPaths)\n    : AdamFileSystemBase(adamPaths, LogScopes.Base, []), IAdamFileSystem;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.FileSystem/AdamFileSystemString_Files.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys.FileSystem;\n\npublic partial class AdamFileSystemString\n{\n    public override IFile GetFile(AdamAssetIdentifier fileId)\n    {\n        var id = ((AdamAssetId<string>)fileId).SysId;\n        var dir = FsHelpers.EnsurePhysicalPath(id);\n        return ToAdamFile(dir);\n    }\n\n    /// <inheritdoc />\n    public override List<IFile> GetFiles(IFolder folder)\n    {\n        var dir = Directory.GetFiles(FsHelpers.EnsurePhysicalPath(folder.Path));\n        return dir.Select(ToAdamFile).ToList();\n    }\n\n\n    /// <inheritdoc />\n    public override IFile Add(IFolder parent, Stream body, string fileName, bool ensureUniqueName)\n    {\n        var l = Log.Fn<IFile>($\"..., ..., {fileName}, {ensureUniqueName}\");\n        if (ensureUniqueName)\n            fileName = FsHelpers.FindUniqueFileName(AdamPaths.PhysicalPath(parent.Path), fileName);\n        var fullContentPath = AdamPaths.PhysicalPath(parent.Path);\n        Directory.CreateDirectory(fullContentPath);\n        var filePath = Path.Combine(fullContentPath, fileName);\n        using var stream = new FileStream(filePath, FileMode.Create);\n        body.CopyTo(stream);\n        var fileInfo = GetFile(AdamAssetIdentifier.Create(filePath));\n\n        return l.ReturnAsOk(fileInfo);\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.FileSystem/AdamFileSystemString_Folders.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys.FileSystem;\n\npublic partial class AdamFileSystemString\n{\n    /// <inheritdoc />\n    public override void AddFolder(string path)\n    {\n        path = AdamPaths.PhysicalPath(path);\n        Directory.CreateDirectory(path);\n    }\n\n    /// <inheritdoc />\n    public override bool FolderExists(string path)\n    {\n        var serverPath = AdamPaths.PhysicalPath(path);\n        return Directory.Exists(serverPath);\n    }\n\n    /// <inheritdoc />\n    public override IFolder GetFolder(AdamAssetIdentifier folderId)\n        => ToAdamFolder(FsHelpers.EnsurePhysicalPath(((AdamAssetId<string>)folderId).SysId));\n\n    /// <inheritdoc />\n    public override List<IFolder> GetFolders(IFolder folder)\n    {\n        var dir = Directory.GetDirectories(FsHelpers.EnsurePhysicalPath(folder.Path));\n        return dir.Select(ToAdamFolder).ToList();\n    }\n\n\n    /// <inheritdoc />\n    public override void Rename(IFolder folder, string newName) => throw new NotSupportedException();\n\n    /// <inheritdoc />\n    public override void Delete(IFolder folder) => throw new NotSupportedException();\n\n    /// <inheritdoc />\n    public override IFolder Get(string path) => ToAdamFolder(path);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.FileSystem/AdamFileSystemString_ToAdam.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys.FileSystem;\n\npublic partial class AdamFileSystemString\n{\n\n    private IFile ToAdamFile(string path)\n    {\n        var physicalPath = AdamPaths.PhysicalPath(path);\n        var f = new FileInfo(physicalPath);\n        var directoryName = f.Directory!.Name;\n\n        // todo: unclear if we need both, but we need the url for the compare-if-same-path\n        var relativePath = AdamPaths.RelativeFromAdam(path);\n        var relativeUrl = relativePath.ForwardSlash();\n        return new File<string, string>(AdamManager)\n        {\n            FullName = f.Name,\n            Extension = f.Extension.TrimStart('.'),\n            Size = Convert.ToInt32(f.Length),\n            SysId = relativeUrl,\n            Folder = directoryName,\n            ParentSysId = relativeUrl.Replace(f.Name, \"\"),\n            Path = relativePath,\n\n            Created = f.CreationTime,\n            Modified = f.LastWriteTime,\n            Name = Path.GetFileNameWithoutExtension(f.Name),\n            Url = AdamPaths.Url(relativeUrl),\n            PhysicalPath = physicalPath,\n        };\n    }\n\n    private IFolder ToAdamFolder(string path)\n    {\n        var physicalPath = AdamPaths.PhysicalPath(path);\n        var f = new DirectoryInfo(physicalPath);\n\n        var relativePath = AdamPaths.RelativeFromAdam(path);\n        return new Folder<string, string>(AdamManager)\n        {\n            Path = relativePath,\n            SysId = relativePath,\n            ParentSysId = FindParentUrl(path),\n            Name = f.Name,\n            Created = f.CreationTime,\n            Modified = f.LastWriteTime,\n\n            Url = AdamPaths.Url(relativePath),\n            PhysicalPath = physicalPath,\n        };\n    }\n\n    private static string FindParentUrl(string path)\n    {\n        var cleanedPath = path.ForwardSlash().TrimEnd('/');\n        var lastSlash = cleanedPath.LastIndexOf('/');\n        return lastSlash == -1 ? \"\" : cleanedPath.Substring(0, lastSlash);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.FileSystem/IAdamFileSystem.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Manager;\n\nnamespace ToSic.Sxc.Adam.Sys.FileSystem;\n\n/// <summary>\n/// WIP \n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IAdamFileSystem: IHasLog\n{\n    void Init(AdamManager adamManager);\n\n    #region FileSystem Settings\n\n    int MaxUploadKb();\n\n    #endregion\n\n    #region Files\n\n    /// <summary>\n    /// NEW WIP\n    /// </summary>\n    /// <param name=\"fileId\"></param>\n    /// <returns></returns>\n    IFile GetFile(AdamAssetIdentifier fileId);\n\n    List<IFile> GetFiles(IFolder folder);\n\n    void Rename(IFile file, string newName);\n\n    void Delete(IFile file);\n\n    IFile Add(IFolder parent, Stream body, string fileName, bool ensureUniqueName);\n\n\n    #endregion\n\n    #region Folders\n\n    /// <summary>\n    /// Create a path (folder)\n    /// </summary>\n    /// <param name=\"path\"></param>\n    void AddFolder(string path);\n\n    /// <summary>\n    /// Verify that a path exists\n    /// </summary>\n    /// <param name=\"path\"></param>\n    /// <returns></returns>\n    bool FolderExists(string path);\n\n    IFolder GetFolder(AdamAssetIdentifier folderId);\n\n    List<IFolder> GetFolders(IFolder folder);\n\n\n    void Rename(IFolder folder, string newName);\n\n    void Delete(IFolder folder);\n\n    #endregion\n\n    IFolder Get(string path);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Manager/AdamContext.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Adam.Sys.Security;\nusing ToSic.Sxc.Adam.Sys.Storage;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sys.Capabilities.Features;\nusing static ToSic.Sys.Capabilities.Features.BuiltInFeatures;\n\nnamespace ToSic.Sxc.Adam.Sys.Manager;\n\n/// <summary>\n/// The security context of ADAM operations - containing site, app, field, entity-guid etc.\n/// Will check if operations are allowed at setup, and throw errors otherwise.\n/// </summary>\n/// <remarks>\n/// It's abstract, because there will be a typed implementation inheriting this\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamContext(AdamContext.Dependencies services)\n    : ServiceBase<AdamContext.Dependencies>(services, \"Adm.Ctx\")\n{\n    #region Constructor and DI\n\n    public record Dependencies(\n        Generator<MultiPermissionsTypes, MultiPermissionsTypes.Options> TypesPermissions,\n        Generator<IAdamSecurityCheckService> AdamSecurityGenerator,\n        LazySvc<ISysFeaturesService> FeaturesSvc,\n        LazySvc<AdamManager> AdamManagerLazy,\n        Generator<AdamStorageOfSite> SiteStorageGen,\n        Generator<AdamStorageOfField> FieldStorageGen)\n        : DependenciesRecord(connect: [TypesPermissions, AdamSecurityGenerator, FeaturesSvc, AdamManagerLazy, SiteStorageGen, FieldStorageGen]);\n\n    public IAdamSecurityCheckService Security { get; private set; } = null!;\n    public MultiPermissionsTypes Permissions { get; private set; } = null!;\n\n    public AdamManager AdamManager => Services.AdamManagerLazy.Value;\n\n    public AdamStorage AdamRoot { get; private set; } = null!;\n\n    public IAppWorkCtx AppWorkCtx => AdamManager.AppWorkCtx;\n\n    #endregion\n\n    #region Init\n\n    /// <summary>\n    /// Initializes the object and performs all the initial security checks\n    /// </summary>\n    public AdamContext Init(IContextOfApp context, string contentType, string fieldName, Guid entityGuid, bool usePortalRoot)\n    {\n        var l = Log.Fn<AdamContext>($\"app: {context.AppReaderRequired.Show()}, field:{fieldName}, guid:{entityGuid}, usePortalRoot: {usePortalRoot}\");\n        AdamManager.Init(context, CompatibilityLevels.CompatibilityLevel10);\n        AdamRoot = usePortalRoot\n            ? Services.SiteStorageGen.New()\n            : Services.FieldStorageGen.New().InitItemAndField(entityGuid, fieldName);\n        AdamRoot.Init(AdamManager);\n\n        Context = context;\n\n        Permissions = Services.TypesPermissions.New(new()\n                { SiteContext = context, App = context.AppReaderRequired, ContentTypes = [contentType] })\n            ;\n        // only do checks on field/guid if it's actually accessing that, if it's on the portal root, don't.\n        UseSiteRoot = usePortalRoot;\n        if (!usePortalRoot)\n        {\n            ItemFieldName = fieldName;\n            ItemGuid = entityGuid;\n        }\n\n        Security = Services.AdamSecurityGenerator.New().Init(this, usePortalRoot);\n\n        if (Security.MustThrowIfAccessingRootButNotAllowed(usePortalRoot, out var exception))\n            throw exception;\n\n        l.A(\"check if feature enabled\");\n        var sysFeatures = Services.FeaturesSvc.Value;\n        if (Security.UserIsRestricted && !sysFeatures.IsEnabled(FeaturesForRestrictedUsers))\n        {\n            var msg = sysFeatures.MsgMissingSome(FeaturesForRestrictedUsers);\n            throw HttpException.PermissionDenied(\n                $\"low-permission users may not access this - {msg}\");\n\n        }\n\n        if (string.IsNullOrEmpty(contentType) || string.IsNullOrEmpty(fieldName))\n            return l.Return(this);\n\n        Attribute = AttributeDefinition(context.AppReaderRequired, contentType, fieldName);\n        if (Security.FieldDoesNotSupportFiles(out var exp))\n            throw exp;\n        return l.Return(this);\n    }\n\n    #endregion\n\n    /// <summary>\n    /// Determines if the files come from the root (shared files).\n    /// Is false, if they come from the item specific ADAM folder.\n    /// </summary>\n    public bool UseSiteRoot;\n\n    /// <summary>\n    /// The field this state is for. Will be null/empty if UsePortalRoot is true\n    /// </summary>\n    public string? ItemFieldName;\n\n    /// <summary>\n    /// The item guid this state is for. Will be Empty if UsePortalRoot is true.\n    /// </summary>\n    public Guid ItemGuid;\n\n    internal IContentTypeAttribute? Attribute;\n\n    public IContextOfApp Context { get; private set; } = null!;\n\n    public readonly Guid[] FeaturesForRestrictedUsers =\n    [\n        PublicUploadFiles.Guid,\n        PublicEditForm.Guid\n    ];\n\n\n    /// <summary>\n    /// try to find attribute definition - for later extra security checks\n    /// </summary>\n    private static IContentTypeAttribute? AttributeDefinition(IAppReadContentTypes appReadContentTypes, string contentType, string fieldName)\n    {\n        var type = appReadContentTypes.GetContentType(contentType);\n        return type[fieldName];\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Manager/AdamGenericHelper.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets.Sys;\nusing ToSic.Sxc.Adam.Sys.Storage;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Adam.Sys.Manager;\n\n/// <summary>\n/// Helper construct so that correctly typed objects can be generated,\n/// without the user (mostly the AdamManager) having to know the exact types.\n/// </summary>\npublic abstract class AdamGenericHelper\n{\n    public abstract IFolder FolderOfField(AdamManager adamManager, AdamStorageOfField storage, IField? field);\n\n    public abstract bool AssetIsChildOfFolder(IFolder parentFolder, ToSic.Eav.Apps.Assets.IAsset target);\n\n    public abstract bool FoldersHaveSameId(IFolder folder1, IFolder folder2);\n}\n\n/// <summary>\n/// The generic implementation, which must be registered in Startup with the correct types of the platform.\n/// </summary>\n/// <typeparam name=\"TFolderId\"></typeparam>\n/// <typeparam name=\"TFileId\"></typeparam>\npublic class AdamGenericHelper<TFolderId, TFileId> : AdamGenericHelper\n{\n    public override IFolder FolderOfField(AdamManager adamManager, AdamStorageOfField storage, IField? field)\n        => FolderOfField<TFolderId, TFileId>.Create(adamManager, storage, field);\n\n    public override bool AssetIsChildOfFolder(IFolder parentFolder, ToSic.Eav.Apps.Assets.IAsset target)\n    {\n        var folderOwnId = ((IAssetSysId<TFolderId>)parentFolder).SysId;\n        var assetParentId = ((IAssetWithParentSysId<TFolderId>)target).ParentSysId;\n        return EqualityComparer<TFolderId>.Default.Equals(assetParentId, folderOwnId);\n    }\n\n    public override bool FoldersHaveSameId(IFolder folder1, IFolder folder2)\n    {\n        var folder1Id = ((IAssetSysId<TFolderId>)folder1).SysId;\n        var folder2Id = ((IAssetSysId<TFolderId>)folder2).SysId;\n        return EqualityComparer<TFolderId>.Default.Equals(folder1Id, folder2Id);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Manager/AdamManager.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam.Sys.FileSystem;\nusing ToSic.Sxc.Adam.Sys.Paths;\nusing ToSic.Sxc.Adam.Sys.Storage;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Adam.Sys.Manager;\n\n/// <summary>\n/// The Manager of ADAM\n/// In charge of managing assets inside this app - finding them, creating them etc.\n/// </summary>\n/// <remarks>\n/// It's abstract, because there will be a typed implementation inheriting this\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamManager(AdamManager.Dependencies services)\n    : ServiceBase<AdamManager.Dependencies>(services, \"Adm.Managr\")\n{\n    #region Dependencies\n\n    public record Dependencies(\n        LazySvc<ICodeDataFactory> CdfIfNotProvided,\n        AdamConfiguration AdamConfiguration,\n        LazySvc<IAdamFileSystem> AdamFsLazy,\n        Generator<AdamStorageOfField> FieldStorageGenerator,\n        AdamGenericHelper AdamGenericHelper)\n        : DependenciesRecord(connect: [CdfIfNotProvided, AdamConfiguration, AdamFsLazy, FieldStorageGenerator]);\n\n    #endregion\n\n    #region Init\n\n    public AdamManager Init(IContextOfApp appCtx, int compatibility, ICodeDataFactory? cdf = default)\n    {\n        var l = Log.Fn<AdamManager>();\n        AppContext = appCtx;\n        Cdf = cdf\n              ?? Services.CdfIfNotProvided\n                  .SetInit(obj => obj.SetFallbacks(appCtx.Site, compatibility, this))\n                  .Value;\n        return l.Return(this, \"ready\");\n    }\n\n    public bool UseTypedAssets => Cdf.CompatibilityLevel >= CompatibilityLevels.MinLevelForTyped;\n\n    [field: AllowNull, MaybeNull]\n    public IAdamFileSystem AdamFs => field ??= Services.AdamFsLazy.SetInit(f => f.Init(this)).Value;\n\n    [field: AllowNull, MaybeNull]\n    public IAppWorkCtx AppWorkCtx => field ??= new AppWorkCtx(AppContext.AppReaderRequired);\n\n    private IContextOfApp AppContext { get; set; } = null!;\n\n    [field: AllowNull, MaybeNull]\n    public ISite Site => field ??= AppContext.Site;\n\n    internal ICodeDataFactory Cdf { get; private set; } = null!;\n\n    #endregion\n\n    /// <summary>\n    /// Path to the app assets\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public string Path => field ??= Services.AdamConfiguration.PathForApp(AppContext.AppReaderRequired.Specs);\n\n    #region Folder Stuff\n\n    /// <summary>\n    /// Root folder object of the app assets\n    /// </summary>\n    public IFolder? RootFolder => Folder(Path, true);\n\n    internal IFolder Folder(string path)\n        => AdamFs.Get(path);\n\n    internal IFolder? Folder(string path, bool autoCreate)\n    {\n        var l = Log.Fn<IFolder>($\"{path}, {autoCreate}\");\n\n        // create all folders to ensure they exist. Must do one-by-one because the environment must have it in the catalog\n        var pathParts = path.Split('/');\n        var pathToCheck = \"\";\n        foreach (var part in pathParts.Where(p => !string.IsNullOrEmpty(p)))\n        {\n            pathToCheck += part + \"/\";\n            if (AdamFs.FolderExists(pathToCheck))\n                continue;\n            if (autoCreate)\n                AdamFs.AddFolder(pathToCheck);\n            else\n            {\n                Log.A($\"subfolder {pathToCheck} not found\");\n                return l.ReturnNull(\"not found\");\n            }\n        }\n\n        return l.ReturnAsOk(Folder(path));\n    }\n\n    public IFolder FolderOfField(Guid entityGuid, string fieldName, IField? field = default)\n    {\n        var folderStorage = Services.FieldStorageGenerator.New().InitItemAndField(entityGuid, fieldName);\n        folderStorage.Init(this);\n        var folder = Services.AdamGenericHelper.FolderOfField(this, folderStorage, field);\n        return folder;\n    }\n    #endregion\n\n    #region Metadata Maker\n\n    /// <summary>\n    /// Get the first metadata entity of an item - or return a fake one instead\n    /// </summary>\n    /// <remarks>\n    /// The metadata varies a bit, depending on whether it's typed or dynamic.\n    /// </remarks>\n    internal ITypedMetadata CreateMetadataTyped(string key, string title, Action<IMetadata>? mdInit = null)\n        => Cdf.MetadataTyped(PrepareUnderlyingMetadata(key, title, mdInit));\n\n    /// <summary>\n    /// Same for dynamic metadata, but it will be treated as just an object, since the code will be in dynamic mode.\n    /// </summary>\n    internal object CreateMetadataDynamic(string key, string title, Action<IMetadata>? mdInit = null)\n        => Cdf.MetadataDynamic(PrepareUnderlyingMetadata(key, title, mdInit));\n\n    private IMetadata PrepareUnderlyingMetadata(string key, string title, Action<IMetadata>? mdInit)\n    {\n        var mdOf = AppWorkCtx.AppReader.Metadata.GetMetadataOf(TargetTypes.CmsItem, key, title: title);\n        mdInit?.Invoke(mdOf);\n        return mdOf;\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Paths/AdamConfiguration.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Sys.Entities;\n\nnamespace ToSic.Sxc.Adam.Sys.Paths;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamConfiguration(IAppReaderFactory appReaders)\n{\n    [field: AllowNull, MaybeNull]\n    public string AdamAppRootFolder => field ??= GenerateAdamAppRootFolder();\n\n    private string GenerateAdamAppRootFolder()\n    {\n        var found = appReaders.GetSystemPreset()\n            .List\n            .First(typeName: AdamConstants.TypeName)?\n            .Get<string>(AdamConstants.ConfigFieldRootFolder);\n\n        return found ?? AdamConstants.AdamFolderMask;\n    }\n\n    internal string PathForApp(IAppSpecs app)\n    {\n        var valuesDic = new Dictionary<string, string>\n        {\n            { AppConstants.AppFolderPlaceholder, app.Folder },\n            { \"[ZoneId]\", app.ZoneId.ToString() },\n            { \"[AppId]\", app.AppId.ToString() },\n            { \"[AppGuid]\", app.NameId }\n        };\n        var finalPath = FillMask(valuesDic, AdamAppRootFolder);\n        return finalPath;\n    }\n\n    private static string FillMask(Dictionary<string, string> valuesDictionary, string mask)\n        => valuesDictionary.Aggregate(mask, (current, dicItem)\n            => Regex.Replace(current, Regex.Escape(dicItem.Key), dicItem.Value, RegexOptions.CultureInvariant));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Paths/AdamPathsBase.cs",
    "content": "﻿using ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Adam.Sys.Manager;\n\nnamespace ToSic.Sxc.Adam.Sys.Paths;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamPathsBase : ServiceBase, IAdamPaths\n{\n    #region DI Constructor & Init\n\n    public AdamPathsBase(IServerPaths serverPaths) : this(serverPaths, LogScopes.Base)\n    { }\n\n    protected AdamPathsBase(IServerPaths serverPaths, string logPrefix) : base($\"{logPrefix}.AdmPth\", connect: [serverPaths])\n    {\n        _serverPaths = serverPaths;\n    }\n    private readonly IServerPaths _serverPaths;\n\n    public IAdamPaths Init(AdamManager adamManager)\n    {\n        AdamManager = adamManager;\n        return this;\n    }\n\n    protected AdamManager AdamManager { get; private set; } = null!;\n\n    #endregion\n\n\n\n    public string PhysicalPath(string path)\n    {\n        ThrowIfPathContainsDotDot(path);\n\n        // check if it's already a physical path\n        if (Path.IsPathRooted(path)) return path;\n\n        // check if it already has the root path attached, otherwise add\n        path = path.StartsWith(AdamManager.Site.ContentPath) ? path : Path.Combine(AdamManager.Site.ContentPath, path);\n        return _serverPaths.FullContentPath(path.Backslash());\n    }\n\n    public static void ThrowIfPathContainsDotDot(string path)\n    {\n        if (string.IsNullOrEmpty(path)) return;\n\n        // detect directory traversal\n        if (Path.GetFullPath(path).ForwardSlash().IndexOf(path.ForwardSlash(), StringComparison.OrdinalIgnoreCase) == -1) \n            throw new ArgumentException(\"path traversal occurred\", nameof(path));\n    }\n    private static readonly char[] InvalidChars = Path.GetInvalidPathChars();\n\n    public string RelativeFromAdam(string path)\n    {\n        var adamPosition = path.ForwardSlash().IndexOf(\"adam/\", StringComparison.InvariantCultureIgnoreCase);\n        return adamPosition <= 0\n            ? path\n            : path.Substring(adamPosition);\n    }\n\n    /// <summary>\n    /// Will receive the path as is on the file system, and return the url form how it would be called from outside.\n    /// This default implementation assumes the path of the server and url are the same.\n    /// In .net core this will be different, so it must replace the internal logic\n    /// </summary>\n    /// <param name=\"path\"></param>\n    /// <returns></returns>\n    public virtual string Url(string path) => Path.Combine(AdamManager.Site.ContentPath, path).ForwardSlash();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Paths/AdamPathsWwwroot.cs",
    "content": "﻿using ToSic.Eav.Environment.Sys.ServerPaths;\n\nnamespace ToSic.Sxc.Adam.Sys.Paths;\n\n/// <summary>\n/// Basic AdamPaths resolver, assumes that files are in wwwroot/adam for now.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamPathsWwwroot(IServerPaths serverPaths) : AdamPathsBase(serverPaths, LogScopes.Base)\n{\n    /// <summary>\n    /// This will just assume that the path - containing 'wwwroot' will not have the 'wwwroot' in the link from outside\n    /// </summary>\n    /// <param name=\"path\"></param>\n    /// <returns></returns>\n    public override string Url(string path)\n    {\n        var original = base.Url(path);\n        var url = \"/\" + original.Replace(\"wwwroot/\", \"\");\n        return url;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Paths/IAdamPaths.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Manager;\n\nnamespace ToSic.Sxc.Adam.Sys.Paths;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IAdamPaths: IHasLog\n{\n    IAdamPaths Init(AdamManager adamManager);\n\n    string PhysicalPath(string path);\n\n    string RelativeFromAdam(string path);\n\n    string Url(string path);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Security/AdamSecurity.cs",
    "content": "﻿using ToSic.Eav.Identity;\n\nnamespace ToSic.Sxc.Adam.Sys.Security;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamSecurity\n{\n    public static bool PathIsInItemAdam(Guid guid, string? field, string? path)\n    {\n        if (string.IsNullOrWhiteSpace(field) || string.IsNullOrWhiteSpace(path))\n            return false;\n\n        var shortGuid = guid.GuidCompress();\n        // will do check, case-sensitive because the compressed guid is case-sensitive\n        return path!.Replace('\\\\', '/').Contains(shortGuid + \"/\" + field);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Security/AdamSecurityChecksBase.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.Security.Files;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Adam.Sys.Security;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class AdamSecurityChecksBase(AdamSecurityChecksBase.Dependencies services, string logPrefix)\n    : ServiceBase<AdamSecurityChecksBase.Dependencies>(services, $\"{logPrefix}.TnScCk\"), IAdamSecurityCheckService\n{\n\n    #region DI / Constructor\n\n    public record Dependencies(Generator<AppPermissionCheck> AppPermissionChecks)\n        : DependenciesRecord(connect: [AppPermissionChecks]);\n\n    public IAdamSecurityCheckService Init(AdamContext adamContext, bool usePortalRoot)\n    {\n        var l = Log.Fn<IAdamSecurityCheckService>();\n        AdamContext = adamContext;\n\n        var firstChecker = AdamContext.Permissions.PermissionCheckers.First().Value;\n        var permissionInfo = firstChecker.UserMay(GrantSets.WritePublished);\n        var userMayAdminSomeFiles = permissionInfo.Allowed;\n        var userMayAdminSiteFiles = permissionInfo.Condition is Conditions.EnvironmentGlobal or Conditions.EnvironmentInstance;\n\n        UserIsRestricted = !(usePortalRoot\n            ? userMayAdminSiteFiles\n            : userMayAdminSomeFiles);\n\n        Log.A($\"adminSome:{userMayAdminSomeFiles}, restricted:{UserIsRestricted}\");\n\n        return l.Return(this);\n    }\n\n    internal AdamContext AdamContext { get; private set; } = null!;\n    public bool UserIsRestricted { get; private set; }\n\n    #endregion\n\n    #region Abstract methods to re-implement\n\n    public abstract bool SiteAllowsExtension(string fileName);\n\n    public abstract bool CanEditFolder(Eav.Apps.Assets.IAsset? item);\n\n    #endregion\n\n    //public bool ExtensionIsOk(string fileName, out HttpExceptionAbstraction preparedException)\n    //{\n    //    if (!SiteAllowsExtension(fileName))\n    //    {\n    //        preparedException = HttpException.NotAllowedFileType(fileName, \"Not in whitelisted CMS file types.\");\n    //        return false;\n    //    }\n\n    //    if (FileNames.IsKnownRiskyExtension(fileName))\n    //    {\n    //        preparedException = HttpException.NotAllowedFileType(fileName, \"This is a known risky file type.\");\n    //        return false;\n    //    }\n    //    preparedException = null;\n    //    return true;\n    //}\n    public bool ExtensionIsNotOk(string fileName, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException)\n    {\n        if (!SiteAllowsExtension(fileName))\n        {\n            preparedException = HttpException.NotAllowedFileType(fileName, \"Not in whitelisted CMS file types.\");\n            return true;\n        }\n\n        if (FileNames.IsKnownRiskyExtension(fileName))\n        {\n            preparedException = HttpException.NotAllowedFileType(fileName, \"This is a known risky file type.\");\n            return true;\n        }\n        preparedException = null;\n        return false;\n    }\n\n\n    ///// <summary>\n    ///// Returns true if user isn't restricted, or if the restricted user is accessing a draft item\n    ///// </summary>\n    //public bool UserIsNotRestrictedOrItemIsDraft(Guid guid, out HttpExceptionAbstraction exp)\n    //{\n    //    Log.A($\"check if user is restricted ({UserIsRestricted}) or if the item '{guid}' is draft\");\n    //    exp = null;\n    //    // check that if the user should only see drafts, he doesn't see items of normal data\n    //    if (!UserIsRestricted || FieldPermissionOk(GrantSets.ReadPublished)) return true;\n\n    //    // check if the data is public\n    //    var itm = AdamContext.AppWorkCtx.AppReader.List.One(guid);\n    //    if (!(itm?.IsPublished ?? false)) return true;\n\n    //    const string msg = \"User is restricted and may not see published, but item exists and is published - not allowed\";\n    //    Log.A(msg);\n    //    exp = HttpException.PermissionDenied(msg);\n    //    return false;\n    //}\n    /// <summary>\n    /// Returns true if user isn't restricted, or if the restricted user is accessing a draft item\n    /// </summary>\n    public bool UserIsRestrictedOrItemIsNotDraft(Guid guid, [NotNullWhen(true)] out HttpExceptionAbstraction? exp)\n    {\n        var l = Log.Fn<bool>($\"is restricted ({UserIsRestricted}) or if the item '{guid}' is draft\");\n        exp = null;\n        // check that if the user should only see drafts, he doesn't see items of normal data\n        if (!UserIsRestricted || FieldPermissionOk(GrantSets.ReadPublished))\n            return l.ReturnFalse(\"user not restricted / has grants\");\n\n        // check if the data is public\n        var itm = AdamContext.AppWorkCtx.AppReader.List.GetOne(guid);\n        if (!(itm?.IsPublished ?? false))\n            return l.ReturnFalse(\"not draft\");\n\n        const string msg = \"User is restricted and may not see published, but item exists and is published - not allowed\";\n        l.A(msg);\n        exp = HttpException.PermissionDenied(msg);\n        return l.ReturnTrue(\"conditions not met\");\n    }\n\n    //public bool FileTypeIsOkForThisField(out HttpExceptionAbstraction preparedException)\n    //{\n    //    var l = Log.Fn<bool>();\n    //    var fieldDef = AdamContext.Attribute;\n    //    bool result;\n    //    // check if this field exists and is actually a file-field or a string (wysiwyg) field\n    //    if (fieldDef == null || !(fieldDef.Type != ValueTypes.Hyperlink ||\n    //                              fieldDef.Type != ValueTypes.String))\n    //    {\n    //        preparedException = HttpException.BadRequest(\"Requested field '\" + AdamContext.ItemField + \"' type doesn't allow upload\");\n    //        Log.A($\"field type:{fieldDef?.Type} - does not allow upload\");\n    //        result = false;\n    //    }\n    //    else\n    //    {\n    //        Log.A($\"field type:{fieldDef.Type}\");\n    //        preparedException = null;\n    //        result = true;\n    //    }\n    //    return l.ReturnAndLog(result);\n    //}\n    public bool FieldDoesNotSupportFiles([NotNullWhen(true)] out HttpExceptionAbstraction? preparedException)\n    {\n        var l = Log.Fn<bool>();\n        var fieldDef = AdamContext.Attribute;\n        // check if this field exists and is actually a file-field or a string (wysiwyg) field\n        if (fieldDef == null || !(fieldDef.Type != ValueTypes.Hyperlink ||\n                                  fieldDef.Type != ValueTypes.String))\n        {\n            preparedException = HttpException.BadRequest(\"Requested field '\" + AdamContext.ItemFieldName + \"' type doesn't allow upload\");\n            return l.ReturnTrue($\"field type:{fieldDef?.Type} - does not allow files\");\n        }\n\n        preparedException = null;\n        return l.ReturnFalse($\"field type:{fieldDef.Type}\");\n    }\n\n\n    //public bool UserIsPermittedOnField(List<Grants> requiredPermissions, out HttpExceptionAbstraction preparedException)\n    //{\n    //    // check field permissions, but only for non-publish-data\n    //    if (UserIsRestricted && !FieldPermissionOk(requiredPermissions))\n    //    {\n    //        preparedException = HttpException.PermissionDenied(\"this field is not configured to allow uploads by the current user\");\n    //        return false;\n    //    }\n    //    preparedException = null;\n    //    return true;\n    //}\n    public bool UserNotPermittedOnField(List<Grants> requiredPermissions, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException)\n    {\n        // check field permissions, but only for non-publish-data\n        if (UserIsRestricted && !FieldPermissionOk(requiredPermissions))\n        {\n            preparedException = HttpException.PermissionDenied(\"this field is not configured to allow uploads by the current user\");\n            return true;\n        }\n        preparedException = null;\n        return false;\n    }\n\n\n    /// <summary>\n    /// This will check if the field-definition grants additional rights\n    /// Should only be called if the user doesn't have full edit-rights\n    /// </summary>\n    public bool FieldPermissionOk(List<Grants> requiredGrant)\n    {\n        var fieldPermissions = Services.AppPermissionChecks.New()\n            .For(\"Attribute\", AdamContext.Permissions.MyOptions.SiteContext, AdamContext.Context.AppReaderRequired, AdamContext.Attribute?.Permissions);\n\n        return fieldPermissions.UserMay(requiredGrant).Allowed;\n    }\n\n    //public bool SuperUserOrAccessingItemFolder(string path, out HttpExceptionAbstraction? preparedException)\n    //{\n    //    preparedException = null;\n    //    return !UserIsRestricted || DestinationIsInItem(AdamContext.ItemGuid, AdamContext.ItemField, path, out preparedException);\n    //}\n    public bool UserIsRestrictedAndAccessingItemOutsideOfFolder(string? path, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException)\n    {\n        if (UserIsRestricted)\n            return DestinationIsNotInItem(AdamContext.ItemGuid, AdamContext.ItemFieldName, path, out preparedException);\n\n        preparedException = null;\n        return false; // not restricted, so no problem\n    }\n\n    //private static bool DestinationIsInItem(Guid guid, string field, string path, out HttpExceptionAbstraction preparedException)\n    //{\n    //    var inAdam = AdamSecurity.PathIsInItemAdam(guid, field, path);\n    //    preparedException = inAdam\n    //        ? null\n    //        : HttpException.PermissionDenied(\"Can't access a resource which is not part of this item.\");\n    //    return inAdam;\n    //}\n\n    private static bool DestinationIsNotInItem(Guid guid, string? field, string? path, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException)\n    {\n        if (AdamSecurity.PathIsInItemAdam(guid, field, path))\n        {\n            preparedException = null;\n            return false;\n        }\n        preparedException = HttpException.PermissionDenied(\"Can't access a resource which is not part of this item.\");\n        return true;\n    }\n\n\n    public bool MustThrowIfAccessingRootButNotAllowed(bool usePortalRoot, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException)\n    {\n        if (usePortalRoot && UserIsRestricted)\n        {\n            preparedException = HttpException.BadRequest(\"you may only create draft-data, so file operations outside of ADAM is not allowed\");\n            return true;\n        }\n\n        preparedException = null;\n        return false;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Security/AdamSecurityChecksBasic.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys.Security;\n\n/// <summary>\n/// This is a simple AdamSecurityChecks which doesn't know much about the environment but works to get started.\n/// \n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class AdamSecurityChecksBasic(AdamSecurityChecksBase.Dependencies services)\n    : AdamSecurityChecksBase(services, LogScopes.Base)\n{\n    /// <summary>\n    /// Our version here just gives an ok - so that the site doesn't block this extension.\n    /// Note that internally we'll still check against dangerous extensions, so this would just be an extra layer of protection,\n    /// which isn't used in the basic implementation. \n    /// </summary>\n    /// <param name=\"fileName\"></param>\n    /// <returns></returns>\n    public override bool SiteAllowsExtension(string fileName) => true;\n\n    public override bool CanEditFolder(Eav.Apps.Assets.IAsset? item)\n    {\n        var permissions = AdamContext.Context.Permissions;\n        return permissions.IsSiteAdmin\n               || permissions.IsContentAdmin\n               || permissions.IsContentEditor;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Security/IAdamSecurityCheckService.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Adam.Sys.Security;\n\npublic interface IAdamSecurityCheckService\n{\n    bool SiteAllowsExtension(string fileName);\n    bool CanEditFolder(Eav.Apps.Assets.IAsset? item);\n\n    /// <summary>\n    /// This will check if the field-definition grants additional rights\n    /// Should only be called if the user doesn't have full edit-rights\n    /// </summary>\n    bool FieldPermissionOk(List<Grants> requiredGrant);\n\n    internal IAdamSecurityCheckService Init(AdamContext adamContext, bool usePortalRoot);\n    //bool ExtensionIsOk(string fileName, out HttpExceptionAbstraction preparedException);\n    bool ExtensionIsNotOk(string fileName, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException);\n\n    ///// <summary>\n    ///// Returns true if user isn't restricted, or if the restricted user is accessing a draft item\n    ///// </summary>\n    //bool UserIsNotRestrictedOrItemIsDraft(Guid guid, [NotNullWhen(true)] out HttpExceptionAbstraction? exp);\n    /// <summary>\n    /// Returns true if user is restricted, or if the accessed item is missing or published (not draft).\n    /// </summary>\n    bool UserIsRestrictedOrItemIsNotDraft(Guid guid, [NotNullWhen(true)] out HttpExceptionAbstraction? exp);\n\n    //bool FileTypeIsOkForThisField(out HttpExceptionAbstraction preparedException);\n    bool FieldDoesNotSupportFiles([NotNullWhen(true)] out HttpExceptionAbstraction? preparedException);\n\n    //bool UserIsPermittedOnField(List<Grants> requiredPermissions, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException);\n\n    bool UserNotPermittedOnField(List<Grants> requiredPermissions, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException);\n\n    bool MustThrowIfAccessingRootButNotAllowed(bool usePortalRoot, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException);\n    bool UserIsRestricted { get; }\n    //bool SuperUserOrAccessingItemFolder(string path, out HttpExceptionAbstraction? preparedException);\n    bool UserIsRestrictedAndAccessingItemOutsideOfFolder([NotNullWhen(false)]  string? path, [NotNullWhen(true)] out HttpExceptionAbstraction? preparedException);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Storage/AdamStorage.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Manager;\n\nnamespace ToSic.Sxc.Adam.Sys.Storage;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class AdamStorage(string? logName = default) : ServiceBase(logName ?? \"Adm.Base\")\n{\n    public void Init(AdamManager manager) => Manager = manager;\n\n    protected AdamManager Manager { get; private set; } = null!;\n\n    /// <summary>\n    /// Root of this container\n    /// </summary>\n    public string Root => GeneratePath(\"\");\n\n\n    /// <summary>\n    /// Figure out the path to a subfolder within this container\n    /// </summary>\n    /// <param name=\"subFolder\"></param>\n    /// <returns></returns>\n    protected abstract string GeneratePath(string subFolder);\n\n    /// <summary>\n    /// Get the folder specified in App.Settings (BasePath) combined with the module's ID\n    /// </summary>\n    /// <remarks>\n    /// Will create the folder if it does not exist\n    /// </remarks>\n    public IFolder? Folder(string subFolder, bool autoCreate)\n    {\n        var l = Log.Fn<IFolder?>($\"{nameof(Folder)}(\\\"{subFolder}\\\", {autoCreate})\");\n        var fld = Manager.Folder(GeneratePath(subFolder), autoCreate);\n        return l.ReturnAsOk(fld);\n    }\n\n\n    /// <summary>\n    /// Get a (root) folder object for this container\n    /// </summary>\n    /// <returns></returns>\n    public IFolder? RootFolder(bool autoCreate = false)\n        => _folder.Get(() => Folder(\"\", autoCreate));\n    private readonly GetOnce<IFolder?> _folder = new();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Storage/AdamStorageOfField.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Identity;\n\nnamespace ToSic.Sxc.Adam.Sys.Storage;\n\n/// <summary>\n/// Container of the assets of a field\n/// each entity+field combination has its own container for assets\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamStorageOfField(): AdamStorage(\"Adm.OfFld\")\n{\n    private Guid _entityGuid;\n    private string _fieldName = null!;\n\n    public AdamStorageOfField InitItemAndField(Guid entityGuid, string fieldName)\n    {\n        _entityGuid = entityGuid;\n        _fieldName = fieldName;\n        return this;\n    }\n\n\n    protected override string GeneratePath(string subFolder)\n    {\n        var l = Log.Fn<string>(subFolder);\n        var result = AdamConstants.ItemFolderMask\n            .Replace(\"[AdamRoot]\", Manager.Path)\n            .Replace(\"[Guid22]\", _entityGuid.GuidCompress())\n            .Replace(\"[FieldName]\", _fieldName)\n            .Replace(\"[SubFolder]\", subFolder) // often blank, so it will just be removed\n            .Replace(\"//\", \"/\");\n        return l.ReturnAndLog(result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Storage/AdamStorageOfSite.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys.Storage;\n\n/// <summary>\n/// A container for the tenant (top level)\n/// For browsing the tenants content files\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamStorageOfSite(): AdamStorage(\"Adm.OfSite\")\n{\n\n    protected override string GeneratePath(string subFolder) => (subFolder ?? \"\").Replace(\"//\", \"/\");\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamFolderFileSet.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys.Work;\n\n/// <summary>\n/// Bundle of files/folders describing a folder and things inside it.\n/// </summary>\n/// <param name=\"Root\">the root folder, which must usually be treated in a special way when converting to DTO</param>\n/// <param name=\"Folders\">All folders inside the root.</param>\n/// <param name=\"Files\">All files inside the root.</param>\npublic record AdamFolderFileSet(\n    IFolder Root,\n    IList<IFolder> Folders,\n    IList<IFile> Files\n);\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamItemDtoMakerOptions.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Manager;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\npublic record AdamItemDtoMakerOptions\n{\n    public AdamContext? AdamContext { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamWorkBase.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class AdamWorkBase(AdamWorkBase.Dependencies services, string logName)\n    : ServiceBase<AdamWorkBase.Dependencies>(services, logName), IAdamWork\n{\n    #region MyServices / Init\n\n    public record Dependencies(\n        LazySvc<AdamContext> AdamContext,\n        ISxcAppCurrentContextService CtxService,\n        AdamGenericHelper AdamGenericHelper)\n        : DependenciesRecord(connect: [AdamContext, CtxService, AdamGenericHelper]);\n\n    public void Setup(AdamWorkOptions options)\n    {\n        var o = options;\n        var context = options.AppId > 0\n            ? Services.CtxService.GetExistingAppOrSet(options.AppId)\n            : Services.CtxService.AppNameRouteBlock(null);\n        var l = Log.Fn($\"app: {context.AppReaderRequired.Show()}, type: {o.ContentType}, itemGuid: {o.ItemGuid}, field: {o.Field}, portalRoot: {o.UsePortalRoot}\");\n        AdamContext.Init(context, o.ContentType, o.Field, o.ItemGuid, o.UsePortalRoot);\n        l.Done();\n    }\n\n    [field: AllowNull, MaybeNull]\n    public AdamContext AdamContext => field ??= Services.AdamContext.Value;\n\n    #endregion\n\n    /// <summary>\n    /// Validate that user has write permissions for folder.\n    /// In case the primary file system is used (usePortalRoot) then also check higher permissions\n    /// </summary>\n    /// <param name=\"parentFolder\"></param>\n    /// <param name=\"target\"></param>\n    /// <param name=\"errPrefix\"></param>\n    //[AssertionMethod]\n    protected void VerifySecurityAndStructure(IFolder? parentFolder, ToSic.Eav.Apps.Assets.IAsset target, string errPrefix)\n    {\n        // In case the primary file system is used (usePortalRoot) then also check higher permissions\n        if (AdamContext.UseSiteRoot && !AdamContext.Security.CanEditFolder(target)) \n            throw HttpException.PermissionDenied(errPrefix + \" - permission denied\");\n\n        if (AdamContext.Security.UserIsRestrictedAndAccessingItemOutsideOfFolder(target.Path, out var exp))\n            throw exp;\n\n        //if (!EqualityComparer<TFolderId>.Default.Equals(((IAssetWithParentSysId<TFolderId>)target).ParentSysId,\n        //        ((IAssetSysId<TFolderId>)parentFolder).SysId))\n        if (parentFolder == null || !Services.AdamGenericHelper.AssetIsChildOfFolder(parentFolder, target))\n            throw HttpException.BadRequest(errPrefix + \" - not found in folder\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamWorkDelete.cs",
    "content": "﻿using ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamWorkDelete(AdamWorkBase.Dependencies services)\n    : AdamWorkBase(services, \"Adm.TrnDel\")\n{\n    public bool Delete(string parentSubfolder, bool isFolder, AdamAssetIdentifier folderId, AdamAssetIdentifier fileId)\n    {\n        var l = Log.Fn<bool>();\n        if (AdamContext.Security.UserNotPermittedOnField(GrantSets.DeleteSomething, out var exp))\n            throw l.Ex(exp);\n\n        // check that if the user should only see drafts, he doesn't see items of published data\n        if (AdamContext.Security.UserIsRestrictedOrItemIsNotDraft(AdamContext.ItemGuid, out var permissionException))\n            throw l.Ex(permissionException);\n\n        // try to see if we can get into the subfolder - will throw error if missing\n        var parent = AdamContext.AdamRoot.Folder(parentSubfolder, false);\n\n        var fs = AdamContext.AdamManager.AdamFs;\n        if (isFolder)\n        {\n            var target = fs.GetFolder(folderId);\n            VerifySecurityAndStructure(parent, target, \"can't delete folder\");\n            fs.Delete(target);\n        }\n        else\n        {\n            var target = fs.GetFile(fileId);\n            VerifySecurityAndStructure(parent, target, \"can't delete file\");\n            fs.Delete(target);\n        }\n\n        return l.ReturnTrue(\"delete complete\");\n\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamWorkFolderCreate.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamWorkFolderCreate(AdamWorkBase.Dependencies services)\n    : AdamWorkBase(services, \"Adm.TrnFld\")\n{\n    public bool Create(string parentSubfolder, string newFolder)\n    {\n        var l = Log.Fn<bool>($\"get folders for subfolder:{parentSubfolder}, new:{newFolder}\");\n        if (AdamContext.Security.UserIsRestricted && !AdamContext.Security.FieldPermissionOk(GrantSets.ReadSomething))\n            return l.ReturnFalse();\n\n        // get root and at the same time auto-create the core folder in case it's missing (important)\n        var folder = AdamContext.AdamRoot.RootFolder();\n\n        // try to see if we can get into the subfolder - will throw error if missing\n        if (!string.IsNullOrEmpty(parentSubfolder))\n            folder = AdamContext.AdamRoot.Folder(parentSubfolder, false);\n\n        // validate that dnn user have write permissions for folder in case dnn file system is used (usePortalRoot)\n        if (AdamContext.UseSiteRoot && !AdamContext.Security.CanEditFolder(folder))\n            throw HttpException.PermissionDenied(\"can't create new folder - permission denied\");\n\n        var newFolderPath = string.IsNullOrEmpty(parentSubfolder)\n            ? newFolder\n            : Path.Combine(parentSubfolder, newFolder).Replace(\"\\\\\", \"/\");\n\n        // now access the subfolder, creating it if missing (which is what we want\n        AdamContext.AdamRoot.Folder(newFolderPath, true);\n\n        return l.ReturnTrue();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamWorkGet.cs",
    "content": "﻿using ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamWorkGet(AdamWorkBase.Dependencies services)\n    : AdamWorkBase(services, \"Adm.TrnFld\")\n{\n    public AdamFolderFileSet? ItemsInField(string subFolderName, bool autoCreate = false)\n    {\n        var l = Log.Fn<AdamFolderFileSet>($\"Subfolder: {subFolderName}; AutoCreate: {autoCreate}\");\n\n        l.A(\"starting permissions checks\");\n        if (AdamContext.Security.UserIsRestricted && !AdamContext.Security.FieldPermissionOk(GrantSets.ReadSomething))\n            return l.ReturnNull(\"user is restricted, and doesn't have permissions on field - return null\");\n\n        // check that if the user should only see drafts, he doesn't see items of published data\n        if (AdamContext.Security.UserIsRestrictedOrItemIsNotDraft(AdamContext.ItemGuid, out _))\n            return l.ReturnNull(\"user is restricted (no read-published rights) and item is published - return null\");\n\n        l.A(\"first permission checks passed\");\n\n        // get root and at the same time auto-create the core folder in case it's missing (important)\n        var root = AdamContext.AdamRoot.RootFolder(autoCreate);\n\n        // if no root exists then quit now\n        if (!autoCreate && root == null! /* paranoid */)\n            return l.Return(new(null!, [], []), \"silent error, no folder\");\n\n        // try to see if we can get into the subfolder - will throw error if missing\n        var currentFolder = AdamContext.AdamRoot.Folder(subFolderName, false);\n\n        // ensure that it's superuser, or the folder is really part of this item\n        if (AdamContext.Security.UserIsRestrictedAndAccessingItemOutsideOfFolder(currentFolder?.Path, out var ex))\n        {\n            l.A(\"user is not super-user and folder doesn't seem to be an ADAM folder of this item - will throw\");\n            throw l.Ex(ex);\n        }\n\n        var adamFolders = currentFolder!.Folders\n            //.Cast<Sxc.Adam.Internal.Folder<TFolderId, TFileId>>()\n            //.Where(s => !EqualityComparer<TFolderId>.Default.Equals(s.SysId, ((IAssetSysId<TFolderId>)currentFolder).SysId))\n            //.Cast<IFolder>()\n            .Where(s => !Services.AdamGenericHelper.FoldersHaveSameId(s, currentFolder))\n            .ToList();\n\n        // Get/Cast Files\n        var adamFiles = currentFolder.Files\n            .ToList();\n\n        return l.Return(new(currentFolder, adamFolders, adamFiles), $\"ok - fld⋮{adamFolders.Count}, files⋮{adamFiles.Count}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamWorkOptions.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys.Work;\n\npublic record AdamWorkOptions\n{\n    public /*required*/ bool UsePortalRoot { get; init; }// = UsePortalRoot;\n    public /*required*/ string Field { get; init; } = \"\";// = Field;\n    public /*required*/ Guid ItemGuid { get; init; }// = ItemGuid;\n    public /*required*/ string ContentType { get; init; } = \"\";// = ContentType;\n    public /*required*/ int AppId { get; init; }// = AppId;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamWorkRename.cs",
    "content": "﻿using ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamWorkRename(AdamWorkBase.Dependencies services)\n    : AdamWorkBase(services, \"Adm.TrnRen\")\n{\n    public bool Rename(string parentSubfolder, bool isFolder, AdamAssetIdentifier folderId, AdamAssetIdentifier fileId, string newName)\n    {\n        var l = Log.Fn<bool>();\n\n        if (AdamContext.Security.UserNotPermittedOnField(GrantSets.WriteSomething, out var exp))\n            throw l.Ex(exp);\n\n        // check that if the user should only see drafts, he doesn't see items of published data\n        if (AdamContext.Security.UserIsRestrictedOrItemIsNotDraft(AdamContext.ItemGuid, out var permissionException))\n            throw l.Ex(permissionException);\n\n        // try to see if we can get into the subfolder - will throw error if missing\n        var parent = AdamContext.AdamRoot.Folder(parentSubfolder, false);\n\n        var fs = AdamContext.AdamManager.AdamFs;\n        if (isFolder)\n        {\n            var target = fs.GetFolder(folderId);\n            VerifySecurityAndStructure(parent, target, \"Can't rename folder\");\n            fs.Rename(target, newName);\n        }\n        else\n        {\n            var target = fs.GetFile(fileId);\n            VerifySecurityAndStructure(parent, target, \"Can't rename file\");\n\n            // never allow to change the extension\n            if (target.Extension != newName.Split('.').Last())\n                newName += \".\" + target.Extension;\n            fs.Rename(target, newName);\n        }\n\n        return l.ReturnTrue(\"rename complete\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamWorkUpload.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Helpers.Http;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class AdamWorkUpload(AdamWorkBase.Dependencies services)\n    : AdamWorkBase(services, \"Adm.TrnUpl\")\n{\n\n    public IFile UploadOneNew(Stream stream, string subFolder, string fileName)\n    {\n        var file = UploadOne(stream, fileName, subFolder, false);\n        return file;\n    }\n\n    public IFile UploadOne(Stream stream, string originalFileName, string subFolder, bool skipFieldAndContentTypePermissionCheck)\n    {\n        Log.A($\"upload one subfold:{subFolder}, file: {originalFileName}\");\n\n        // make sure the file name we'll use doesn't contain injected path-traversal\n        originalFileName = Path.GetFileName(originalFileName);\n\n        if (!skipFieldAndContentTypePermissionCheck)\n        {\n            if (AdamContext.Security.UserNotPermittedOnField(GrantSets.WriteSomething, out var exp))\n                throw exp;\n\n            // check that if the user should only see drafts, he doesn't see items of published data\n            if (AdamContext.Security.UserIsRestrictedOrItemIsNotDraft(AdamContext.ItemGuid, out var permissionException))\n                throw permissionException;\n        }\n\n        // Access parent to be sure it's created\n        var folder = AdamContext.AdamRoot.RootFolder(autoCreate: true);\n\n        if (!string.IsNullOrEmpty(subFolder))\n            folder = AdamContext.AdamRoot.Folder(subFolder, true);\n\n        // start with a security check...\n        var fs = AdamContext.AdamManager.AdamFs;\n        var parentFolder = folder; // 2025-05-20 2dm: this was before, seems to just get itself: fs.GetFolder(folder.SysId);\n\n        // validate that dnn user have write permissions for folder in case dnn file system is used (usePortalRoot)\n        if (AdamContext.UseSiteRoot && !AdamContext.Security.CanEditFolder(parentFolder))\n            throw HttpException.PermissionDenied(\"can't upload - permission denied\");\n\n        // we only upload into valid adam if that's the scenario\n        if (AdamContext.Security.UserIsRestrictedAndAccessingItemOutsideOfFolder(parentFolder?.Path, out var expNotAllowed))\n            throw expNotAllowed;\n\n        #region check content-type extensions...\n\n        // Check file size and extension\n        var fileName = originalFileName;\n        if (AdamContext.Security.ExtensionIsNotOk(fileName, out var exceptionAbstraction))\n            throw exceptionAbstraction;\n\n        // check metadata of the FieldDef to see if still allowed extension\n        // note 2018-04-20 2dm: can't do this for wysiwyg, as it doesn't have a setting for allowed file-uploads\n        var additionalFilter = AdamContext.Attribute!.Metadata.Get<string>(\"FileFilter\");\n        if (!string.IsNullOrWhiteSpace(additionalFilter) && !CustomFileFilterOk(additionalFilter!, fileName))\n            throw HttpException.NotAllowedFileType(fileName, \"field has custom file-filter, which doesn't match\");\n\n        #endregion\n\n        var maxSize = (long)fs.MaxUploadKb() * 1024; // convert to bytes (without overflow that happens with int)\n        var fileSize = stream.Length;\n        Log.A($\"file size: {fileSize} (max size is {maxSize})\");\n        if (fileSize > maxSize)\n            throw new($\"file too large, {fileSize} is more than {maxSize}\");\n\n        // remove forbidden / troubling file name characters\n        fileName = fileName\n            .Replace(\"+\", \"plus\")\n            .Replace(\"%\", \"per\")\n            .Replace(\"#\", \"hash\");\n            \n        if (fileName != originalFileName)\n            Log.A($\"cleaned file name from'{originalFileName}' to '{fileName}'\");\n\n        var eavFile = fs.Add(parentFolder, stream, fileName, true);\n\n        return eavFile;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/AdamWorkUpload_FieldFilters.cs",
    "content": "﻿using System.Text.RegularExpressions;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\n\npartial class AdamWorkUpload\n{\n    #region More Checks\n\n    internal bool CustomFileFilterOk(string additionalFilter, string fileName)\n    {\n        var l = Log.Fn<bool>();\n        var extension = Path.GetExtension(fileName)?.TrimStart('.') ?? \"\";\n        var hasNonAzChars = new Regex(\"[^a-z]\", RegexOptions.IgnoreCase);\n\n        l.A($\"found additional file filter: {additionalFilter}\");\n        var filters = additionalFilter.CsvToArrayWithoutEmpty();\n        l.A($\"found {filters.Length} filters in {additionalFilter}, will test on {fileName} with ext {extension}\");\n\n        foreach (var f in filters)\n        {\n            // just a-z characters\n            if (!hasNonAzChars.IsMatch(f))\n                if (string.Equals(extension, f, StringComparison.InvariantCultureIgnoreCase))\n                    return l.ReturnTrue($\"filter {f} matched filename {fileName}\");\n                else\n                    continue;\n\n            // could be regex or simple *.ext\n            if (f.StartsWith(\"*.\"))\n                if (string.Equals(extension, f.Substring(2), StringComparison.InvariantCultureIgnoreCase))\n                    return l.ReturnTrue($\"filter {f} matched filename {fileName}\");\n                else\n                    continue;\n\n            // it's a regex\n            try\n            {\n                if (new Regex(f, RegexOptions.IgnoreCase).IsMatch(fileName))\n                    return l.Return(true, $\"filter {f} matched filename {fileName}\");\n            }\n            catch\n            {\n                l.A($\"filter {f} was detected as reg-ex but threw error\");\n            }\n\n        }\n\n        return l.ReturnFalse();\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Adam/Sys.Work/IAdamWork.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Manager;\n\nnamespace ToSic.Sxc.Adam.Sys.Work;\n\n/// <summary>\n/// Just an empty interface to mark all the AdamWork classes to support setup\n/// </summary>\npublic interface IAdamWork: IServiceWithSetup<AdamWorkOptions>\n{\n    AdamContext AdamContext { get; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using static ToSic.Sxc.Sys.SxcLogging;\nglobal using ToSic.Sys.Utils;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Properties/SxcAdamAssemblyVisibleTo.cs",
    "content": "﻿\n\n//[assembly: InternalsVisibleTo(\"ToSic.Sxc.Images\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Services/AdamService.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services.Sys;\n\nnamespace ToSic.Sxc.Services;\n\n[PrivateApi(\"hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class AdamService(): ServiceWithContext(\"Svc.AdamSv\"), IAdamService\n{\n    // Note: before 2025-06-19 it was doing a lot of nullable checks and use the ExcCtxOrNull\n    // but since I believe the AdamService is only for Razor etc. it should really never be used this way\n    // so 2dm is changing to force non-null since it's the only plausible setup for now...\n    [field: AllowNull, MaybeNull]\n    private AdamManager AdamManagerWithContext => field\n        ??= ExCtx.GetServiceForData<AdamManager>();\n\n    /// <inheritdoc />\n    public IFile? File(int id)\n        => AdamManagerWithContext.AdamFs.GetFile(AdamAssetIdentifier.Create(id));\n\n    /// <inheritdoc />\n    public IFile? File(string id)\n    {\n        var fileId = LinkParts.CheckIdStringForId(id);\n        return fileId == null\n            ? null\n            : File(fileId.Value);\n    }\n\n\n    /// <inheritdoc />\n    public IFile? File(IField field)\n    {\n        if (field?.Raw is not string id)\n            return null;\n        // Get file - can be null if invalid id, empty string or not found\n        var file = File(id);\n        if (file == null)\n            return null;\n        file.Field = field;\n        return file;\n    }\n\n    /// <inheritdoc />\n    public IFolder Folder(int id)\n        => AdamManagerWithContext.AdamFs.GetFolder(AdamAssetIdentifier.Create(id));\n\n    /// <inheritdoc />\n    public IFolder Folder(IField field)\n        => AdamManagerWithContext.FolderOfField(field.Parent.Entity.EntityGuid, field.Name);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Services/IAdamService.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Internal: Adam Service for ADAM operations such as retrieving a single file.\n/// </summary>\n/// <remarks>\n/// Avoid using this, as most objects will already have their ADAM properties such as `File` or `Folder`.\n///\n/// History: Introduced as WIP in v14.04.\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"WIP 14.04\")]\npublic interface IAdamService\n{\n    /// <summary>\n    /// Retrieve a file by int-id (usually the ID managed by the platform)\n    /// </summary>\n    /// <param name=\"id\">File ID</param>\n    /// <returns>The file object or null if not found or something else went wrong.</returns>\n    IFile? File(int id);\n\n    /// <summary>\n    /// Retrieve a file using the string-key such as \"file:72\"\n    /// </summary>\n    /// <param name=\"id\">File ID String</param>\n    /// <returns>The file object or null if not found or something else went wrong.</returns>\n    IFile? File(string id);\n\n    /// <summary>\n    /// Retrieve a file referenced in the field\n    /// </summary>\n    /// <param name=\"field\"></param>\n    /// <returns>The file object or null if not found or something else went wrong.</returns>\n    IFile? File(IField field);\n\n\n    /// <summary>\n    /// Provides an Adam Folder for the ID\n    /// </summary>\n    /// <param name=\"id\">Folder ID</param>\n    /// <returns>An Adam object for navigating the assets</returns>\n    IFolder? Folder(int id);\n\n    /// <summary>\n    /// Provides an Adam Folder for this item and field\n    /// </summary>\n    /// <param name=\"field\">The Field information object for which to get the folder</param>\n    /// <returns>An Adam object for navigating the assets</returns>\n    IFolder? Folder(IField field);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/StartupSxcAdam.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Adam.Sys.FileSystem;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Adam.Sys.Paths;\nusing ToSic.Sxc.Adam.Sys.Security;\nusing ToSic.Sxc.Adam.Sys.Storage;\nusing ToSic.Sxc.Adam.Sys.Work;\nusing ToSic.Sxc.Services;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcAdam\n{\n\n    public static IServiceCollection AddSxcAdam(this IServiceCollection services)\n    {\n        // Adam stuff\n        services.TryAddTransient<IAdamSecurityCheckService, AdamSecurityChecksBasic>();\n        services.TryAddTransient<AdamSecurityChecksBase.Dependencies>();\n        services.TryAddTransient<IAdamPaths, AdamPathsBase>();\n        services.TryAddTransient<AdamConfiguration>();\n\n        services.TryAddTransient<AdamManager>();\n        services.TryAddTransient<AdamContext>();\n        services.TryAddTransient<AdamContext.Dependencies>();\n\n        services.AddTransient<AdamManager.Dependencies>();\n\n        // WIP v14\n        services.TryAddTransient<IAdamService, AdamService>();\n\n        //services.AddSxcAdamWork();\n\n        //// Add possibly missing fallback services\n        //// This must always be at the end here so it doesn't accidentally replace something we actually need\n        services.AddSxcAdamFallbacks();\n\n        return services;\n    }\n\n    public static IServiceCollection AddSxcAdamWork<TFolder, TFile>(this IServiceCollection services)\n    {\n        // Helper Services\n        services.TryAddTransient<AdamWorkBase.Dependencies>();\n\n        // Generic Services, untyped; used when other services request helpers\n        services.TryAddTransient<AdamWorkGet>();\n        services.TryAddTransient<AdamWorkFolderCreate>();\n        services.TryAddTransient<AdamWorkDelete>();\n        services.TryAddTransient<AdamWorkUpload>();\n        services.TryAddTransient<AdamWorkRename>();\n\n        // Storage\n        services.TryAddTransient<AdamStorageOfSite>();\n        services.TryAddTransient<AdamStorageOfField>();\n\n        // Typed implementations, as specified by the caller; usually `int`\n        services.TryAddTransient<AdamGenericHelper, AdamGenericHelper<TFolder, TFile>>();\n\n        return services;\n    }\n\n\n    /// <summary>\n    /// This will add Do-Nothing services which will take over if they are not provided by the main system\n    /// In general this will result in some features missing, which many platforms don't need or care about\n    /// </summary>\n    /// <param name=\"services\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// All calls in here MUST use TryAddTransient, and never without the Try\n    /// </remarks>\n    public static IServiceCollection AddSxcAdamFallbacks(this IServiceCollection services)\n    {\n        // ADAM basics\n        // TODO: this doesn't warn yet, there should be an AdamFileSystemUnknown(WarnUseOfUnknown<AdamFileSystemUnknown> warn)\n        services.TryAddTransient<IAdamFileSystem, AdamFileSystemString>();\n\n        return services;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Sys.ExecutionContext/ICurrentContextService.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Sys.Users.Permissions;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ICurrentContextService: IHasLog, ICurrentContextUserPermissionsService\n{\n    /// <summary>\n    /// This is the most basic kind of context. ATM you could also inject it directly,\n    /// but we want to introduce the capability of giving a static site or something\n    /// without having to write code implementing IContextOfSite\n    /// </summary>\n    /// <returns></returns>\n    IContextOfSite Site();\n\n    IContextOfApp SetApp(IAppIdentity appIdentity);\n\n    IContextOfApp AppRequired();\n\n    IContextOfApp? AppOrNull();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/Sys.ExecutionContext/ISxcAppCurrentContextService.cs",
    "content": "﻿using ToSic.Eav.Context;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// This provides other systems with a context\n/// Note that it's important to always make this **Scoped**, not transient, as there is some re-use after initialization.\n///\n/// This is the reduced version, which can only provide context for the App!\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ISxcAppCurrentContextService: ICurrentContextService\n{\n    /// <summary>\n    /// Return the block if known, or an app context if not\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    IContextOfApp GetExistingAppOrSet(int appId);\n\n    IContextOfApp SetAppOrGetBlock(string nameOrPath);\n\n    IContextOfApp? SetAppOrNull(string? nameOrPath);\n\n    IContextOfApp AppNameRouteBlock(string? nameOrPath);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Adam/ToSic.Sxc.Adam.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Adam</AssemblyName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/App/App.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Apps.Sys.Assets;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing CodeInfoService = ToSic.Sys.Code.InfoSystem.CodeInfoService;\n\nnamespace ToSic.Sxc.Apps;\n\n/// <summary>\n/// A <em>single-use</em> app-object providing quick simple api to access\n/// name, folder, data, metadata etc.\n/// </summary>\n[PrivateApi(\"hide implementation - IMPORTANT: was PublicApi_Stable_ForUseInYourCode up to 16.03!\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[method: PrivateApi]\npublic partial class App(\n    SxcAppBase.Dependencies services,\n    LazySvc<GlobalPaths> globalPaths,\n    LazySvc<ICodeDataFactory> cdfLazy,\n    LazySvc<CodeInfoService> codeChanges,\n    IAppPathsMicroSvc pathFactoryTemp)\n    // Note: If this is ever changed to not inherit from the EavApp, make sure you correct/update the LightSpeed code as well as it checks for this base class\n    : SxcAppBase(services, \"App.SxcApp\", connect: [globalPaths, cdfLazy, codeChanges, pathFactoryTemp]),\n        IAppWithInternal\n{\n    #region Special objects\n\n    IAppReader IAppWithInternal.AppReader => AppReaderInt;\n\n    private ICodeDataFactory Cdf => _cdf.Get(() => cdfLazy.SetInit(obj => obj.SetFallbacks(MySite)).Value)!;\n    private readonly GetOnce<ICodeDataFactory> _cdf = new();\n\n\n    private IAppPaths AppPaths => _appPaths.Get(() => pathFactoryTemp.Get(AppReaderInt, MySite))!;\n    private readonly GetOnce<IAppPaths> _appPaths = new();\n\n    #endregion\n\n\n    #region IApp Paths\n\n\n    /// <inheritdoc cref=\"IApp.Path\" />\n    public string Path => _path.Get(() => AppPaths.Path)!;\n    private readonly GetOnce<string> _path = new();\n\n    /// <inheritdoc cref=\"IApp.Thumbnail\" />\n    public string? Thumbnail => _thumbnail.Get(() => new AppAssetThumbnail(AppReaderInt, AppPaths, globalPaths).Url);\n    private readonly GetOnce<string?> _thumbnail = new();\n\n    /// <inheritdoc cref=\"IApp.PathShared\" />\n    public string PathShared => _pathShared.Get(() => AppPaths.PathShared)!;\n    private readonly GetOnce<string> _pathShared = new();\n\n    /// <inheritdoc cref=\"IApp.PhysicalPathShared\" />\n    public string PhysicalPathShared => _physicalPathGlobal.Get(() => AppPaths.PhysicalPathShared)!;\n    private readonly GetOnce<string> _physicalPathGlobal = new();\n\n    [PrivateApi(\"not public, not sure if we should surface this\")]\n    public string RelativePath => _relativePath.Get(() => AppPaths.RelativePath)!;\n    private readonly GetOnce<string> _relativePath = new();\n\n\n    [PrivateApi(\"not public, not sure if we should surface this\")]\n    public string RelativePathShared => _relativePathShared.Get(() => AppPaths.RelativePathShared)!;\n    private readonly GetOnce<string> _relativePathShared = new();\n\n\n    #endregion\n\n    #region Special internal properties for the IAppTyped wrapper. It will need these properties, but they are protected\n\n    internal IAppPaths AppPathsForTyped => AppPaths;\n    internal IAppReader AppReaderForTyped => AppReaderInt;\n\n    internal TResult BuildDataForTyped<TDataSource, TResult>() where TDataSource : TResult where TResult : class, IDataSource\n        => BuildData<TDataSource, TResult>();\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/App/App_Obsolete17.cs",
    "content": "﻿\n\n// #TryToDropOldIApp: 2025-05-14 2dm v20 try to remove this for now\n\n//#if NETFRAMEWORK\n//namespace ToSic.Sxc.Apps\n//{\n//    public partial class App\n//    {\n//        [PrivateApi(\"obsolete, use the typed accessor instead, only included for old-compatibility\")]\n//        [Obsolete(\"use the new, typed accessor instead\")]\n//        dynamic SexyContent.Interfaces.IApp.Configuration\n//        {\n//            get\n//            {\n//                codeChanges.Value.Warn(OldIApp.Replace(nameof(Configuration)));\n//                var c = Configuration;\n//                return c?.Entity != null ? MakeDynProperty(c.Entity, propsRequired: false) : null;\n//            }\n//        }\n//        private static readonly ICodeInfo OldIApp = CodeInfoObsolete.V05To17(\"SexyContent.Interfaces.IApp.{0}\",\n//            message: \"Accessing the App.{0} through the ancient SexyContent.Interfaces.IApp interface is very deprecated.\");\n\n//        dynamic SexyContent.Interfaces.IApp.Resources => codeChanges.Value.GetAndWarn(OldIApp.Replace(nameof(Resources)), Resources);\n\n//        dynamic SexyContent.Interfaces.IApp.Settings => codeChanges.Value.GetAndWarn(OldIApp.Replace(nameof(Settings)), Settings);\n\n//        string SexyContent.Interfaces.IApp.Path => codeChanges.Value.GetAndWarn(OldIApp.Replace(nameof(Path)), Path);\n\n//        string SexyContent.Interfaces.IApp.PhysicalPath => codeChanges.Value.GetAndWarn(OldIApp.Replace(nameof(PhysicalPath)), PhysicalPath);\n\n//        string SexyContent.Interfaces.IApp.Thumbnail => codeChanges.Value.GetAndWarn(OldIApp.Replace(nameof(Thumbnail)), Thumbnail);\n//    }\n//}\n\n//#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/App/App_Query.cs",
    "content": "﻿using ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.DataSource.Sys;\n\nnamespace ToSic.Sxc.Apps;\n\npartial class App\n{\n    /// <summary>\n    /// Accessor to queries. Use like:\n    /// - App.Query.Count\n    /// - App.Query.ContainsKey(...)\n    /// - App.Query[\"One Event\"].List\n    /// </summary>\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public IDictionary<string, IQuery> Query\n    {\n        get\n        {\n            if (field != null)\n                return field;\n\n            if (AppDataConfig.LookUpEngine == null)\n                throw new(\"Can't use app-queries, because the necessary configuration provider hasn't been initialized. Call InitData first.\");\n            return field = Services.QueryManager.Value.AllQueries(this, AppDataConfig.LookUpEngine);\n        }\n    }\n\n    /// <inheritdoc />\n    public IQuery GetQuery(string name)\n    {\n        // Try to find the local query, abort if not found\n        // Not final implementation, but goal is to properly cascade from AppState to parent\n        if (Query.TryGetValue(name, out var query) && query != null)\n            return query;\n\n        // Try to find query definition - while also checking parent apps\n        var qEntity = Services.QueryManager.Value.TryGetQuery(AppReaderInt, name, AppDataConfig.LookUpEngine, recurseParents: 3);\n\n        return qEntity ?? throw new((DataSourceConstantsInternal.IsGlobalQuery(name) ? \"Global \" : \"\") + \"Query not Found!\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/App/App_SettingsResources.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Apps;\n\npublic partial class App\n{\n    #region Dynamic Properties: Configuration, Settings, Resources\n\n    // Create config object. Note that AppConfiguration could be null, then it would use default values\n    /// <inheritdoc />\n    public IAppConfiguration Configuration => AppReaderInt.Specs.Configuration;\n\n    private dynamic MakeDynProperty(IEntity contents, bool propsRequired)\n    {\n        var wrapped = CmsEditDecorator.Wrap(contents, false);\n        return Cdf.AsDynamic(wrapped, new() { ItemIsStrict = propsRequired });\n    }\n\n    internal void SetupCodeDataFactory(ICodeDataFactory cdf) => cdfLazy.Inject(cdf);\n\n    /// <inheritdoc cref=\"Eav.ImportExport.Sys.Settings\" />\n    public dynamic? Settings => AppSettings == null ? null : _settings.Get(() => MakeDynProperty(AppSettings, propsRequired: false));\n    private readonly GetOnce<dynamic> _settings = new();\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic? Resources => AppResources == null ? null : _res.Get(() => MakeDynProperty(AppResources, propsRequired: false));\n    private readonly GetOnce<dynamic> _res = new();\n\n    #endregion\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/App/readme.md",
    "content": "# App object in ToSic.Sxc.Apps\n\nThis is actually an internal object, but because it used to be in the docs as Public,\nwe have to keep it public."
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/IApp.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\n\n\n// ReSharper disable UnusedMemberInSuper.Global\n\nnamespace ToSic.Sxc.Apps;\n\n/// <summary>\n/// An app-object as is available in a razor template or WebApi when in classic/dynamic mode.\n/// </summary>\n[PublicApi]\npublic interface IApp: \n    IAppPaths,\n    IAppIdentity,\n    IHasMetadata\n// #TryToDropOldIApp: 2025-05-14 2dm v20 try to remove this for now\n//#if NETFRAMEWORK\n//        , SexyContent.Interfaces.IApp // inherits from old namespace for compatibility\n//#endif\n{\n\n    #region Experimental / new\n\n    // #DropAppConfigurationProvider\n    // [ShowApiWhenReleased(ShowApiMode.Never)]\n    // [Obsolete(\"Don't use any more?? note: 2025-06 2dm not sure if this is really deprecated, used to say: use NameId instead, will be removed ca. v14\")]\n    //ILookUpEngine ConfigurationProvider { get; }\n\n    #endregion\n\n\n    /// <summary>\n    /// App Name\n    /// </summary>\n    /// <returns>The name as configured in the app configuration.</returns>\n    string Name { get; }\n\n    /// <summary>\n    /// App Folder\n    /// </summary>\n    /// <returns>The folder as configured in the app configuration.</returns>\n    string Folder { get; }\n\n    /// <summary>\n    /// NameId of the App - usually a string-GUID\n    /// </summary>\n    string NameId { get; }\n\n    [PrivateApi]\n    [Obsolete(\"Don't use any more, use NameId instead, will be removed ca. v14\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    string AppGuid { get; }\n\n    /// <summary>\n    /// Data of the app\n    /// </summary>\n    IAppData Data { get; }\n\n    /// <summary>\n    /// Configuration object with information about the App.\n    /// This contains things like app version, path etc.\n    /// </summary>\n    IAppConfiguration Configuration { get; }\n\n    /// <summary>\n    /// All the app settings which are custom for each app. \n    /// </summary>\n    /// <returns>An <see cref=\"IDynamicEntity\"/> object</returns>\n    dynamic? Settings { get;  }\n\n    /// <summary>\n    /// All the app resources (usually used for multi-language labels etc.)\n    /// </summary>\n    /// <returns>An <see cref=\"IDynamicEntity\"/> object</returns>\n    dynamic? Resources { get;  }\n\n    #region Query\n\n    /// <summary>\n    /// All queries of the app, to access like App.Query[\"name\"]\n    /// </summary>\n    /// <returns>A dictionary with all queries. Internally the dictionary will not be built unless accessed.</returns>\n    IDictionary<string, IQuery> Query { get; }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IQuery GetQuery(string name);\n\n    #endregion\n\n    /// <summary>\n    /// The path to the current app, for linking JS/CSS files and\n    /// images in the app folder. \n    /// </summary>\n    /// <returns>Path usually starting with /portals/...</returns>\n    new string Path { get; }\n\n    /// <summary>\n    /// The path on the server hard disk for the current app. \n    /// </summary>\n    /// <returns>Path usually starting with c:\\...</returns>\n    new string PhysicalPath { get; }\n\n    /// <summary>\n    /// The path to the current apps shared/global folder, for linking JS/CSS files and\n    /// images in the app folder. \n    /// </summary>\n    /// <returns>Path usually starting with /portals/_default/...</returns>\n    /// <remarks>Added v13.01</remarks>\n// Important: Repeat definition of base interface for docs and because of Razor-Interface-Inheritance-Problems\n    new string PathShared { get; }\n\n    /// <summary>\n    /// The path on the server hard disk for the current apps shared/global folder. \n    /// </summary>\n    /// <returns>Path usually starting with c:\\...</returns>\n    /// <remarks>Added v13.01</remarks>\n    // Important: Repeat definition of base interface for docs and because of Razor-Interface-Inheritance-Problems\n    new string PhysicalPathShared { get; }\n\n    ///// <summary>\n    ///// Path relative to the website root.\n    ///// In DNN this is usually the same as the url-path.\n    ///// In Oqtane it's very different. \n    ///// </summary>\n    ///// <remarks>\n    ///// * Made public v15.06 but existed previously\n    ///// </remarks>\n    //[PrivateApi(\"not public, not sure if we should surface this\")]\n    //new string RelativePath { get; }\n\n    ///// <summary>\n    ///// Path of the shared App relative to the website root.\n    ///// In DNN this is usually the same as the url-path.\n    ///// In Oqtane it's very different. \n    ///// </summary>\n    ///// <remarks>\n    ///// * Made public v15.06 but existed previously\n    ///// </remarks>\n    //[PrivateApi(\"not public, not sure if we should surface this\")]\n    //new string RelativePathShared { get; }\n\n    /// <summary>\n    /// The thumbnail path for the current app. \n    /// </summary>\n    /// <returns>path + app-icon.png if there is an icon there. </returns>\n    string? Thumbnail { get; }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/IAppData.cs",
    "content": "﻿using ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Apps;\n\n/// <summary>\n/// An App-DataSource which also provides direct commands to edit/update/delete data.\n/// </summary>\n[PublicApi]\npublic interface IAppData: IDataSource, IMetadataSource\n{\n    /// <summary>\n    /// Create a new entity in the storage.\n    /// </summary>\n    /// <param name=\"contentTypeName\">The type name</param>\n    /// <param name=\"values\">a dictionary of values to be stored</param>\n    /// <param name=\"userName\">the current username - will be logged as the author</param>\n    /// <param name=\"target\">information if this new item is to be metadata for something</param>\n    /// <remarks>\n    /// Changed in 2sxc 10.30 - now returns the id of the created items\n    /// </remarks>\n    IEntity Create(string contentTypeName, Dictionary<string, object?> values, string? userName = null, ITarget? target = null);\n\n    /// <summary>\n    /// Create a bunch of new entities in one single call (much faster, because cache doesn't need to repopulate in the meantime).\n    /// </summary>\n    /// <param name=\"contentTypeName\">The type name</param>\n    /// <param name=\"multiValues\">many dictionaries, each will become an own item when stored</param>\n    /// <param name=\"userName\">the current username - will be logged as the author</param>\n    /// <remarks>\n    /// You can't create items which are metadata with this, for that, please use the Create-one overload <br/>\n    /// Changed in 2sxc 10.30 - now returns the id of the created items\n    /// </remarks>\n    IEnumerable<IEntity> Create(string contentTypeName, IEnumerable<Dictionary<string, object?>> multiValues, string? userName = null);\n\n    /// <summary>\n    /// Update an existing item.\n    /// </summary>\n    /// <param name=\"entityId\">The item ID</param>\n    /// <param name=\"values\">a dictionary of values to be updated</param>\n    /// <param name=\"userName\">the current username - will be logged as the author of the change</param>\n    void Update(int entityId, Dictionary<string, object?> values, string? userName = null);\n\n    /// <summary>\n    /// Delete an existing item\n    /// </summary>\n    /// <param name=\"entityId\">The item ID</param>\n    /// <param name=\"userName\">the current username - will be logged as the author of the change</param>\n    void Delete(int entityId, string? userName = null);\n\n    /// <summary>\n    /// Get metadata of TargetType.Custom - which is the most common way your code will need Metadata.\n    /// </summary>\n    /// <typeparam name=\"TKey\">Key data type</typeparam>\n    /// <param name=\"key\">The target identifier - a number, string or Guid</param>\n    /// <param name=\"contentTypeName\">Optional name of Content-Type, if you only want items of a specific type</param>\n    /// <returns></returns>\n    IEnumerable<IEntity> GetCustomMetadata<TKey>(TKey key, string? contentTypeName = null);\n\n\n    /// <summary>\n    /// All content types of the app.\n    /// </summary>\n    /// <remarks>\n    /// * Added v20\n    /// * Implemented as a method, so later we can apply filters etc. as additional parameters\n    /// </remarks>\n    IEnumerable<IContentType> GetContentTypes();\n\n    /// <summary>\n    /// Get a single content type by name (display name or NameId).\n    /// </summary>\n    /// <param name=\"name\">the name, either the normal name or the NameId which looks like a GUID</param>\n    /// <remarks>\n    /// Added v20\n    /// </remarks>\n    IContentType? GetContentType(string name);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/IAppDataTyped.cs",
    "content": "﻿using ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Apps;\n\n/// <summary>\n/// Data object of an App in **Typed** mode\n/// </summary>\n/// <remarks>Added v17</remarks>\n[PublicApi]\npublic interface IAppDataTyped: IDataSource\n{\n    #region CRUD\n\n    /// <inheritdoc cref=\"IAppData.Create(string, Dictionary{string, object}, string, ITarget)\"/>\n    IEntity Create(string contentTypeName, Dictionary<string, object?> values, string? userName = null, ITarget? target = null);\n\n    /// <inheritdoc cref=\"IAppData.Create(string, IEnumerable{Dictionary{string, object}}, string)\"/>\n    IEnumerable<IEntity> Create(string contentTypeName, IEnumerable<Dictionary<string, object?>> multiValues, string? userName = null);\n\n    /// <inheritdoc cref=\"IAppData.Update\"/>\n    void Update(int entityId, Dictionary<string, object?> values, string? userName = null);\n\n    /// <inheritdoc cref=\"IAppData.Delete\"/>\n    void Delete(int entityId, string? userName = null);\n\n    #endregion\n\n    #region ContentTypes\n\n    /// <summary>\n    /// All content types of the app.\n    /// </summary>\n    /// <remarks>\n    /// * Added v17\n    /// * Implemented as a method, so later we can apply filters etc. as additional parameters\n    /// </remarks>\n    IEnumerable<IContentType> GetContentTypes();\n\n    /// <summary>\n    /// Get a single content type by name (display name or NameId).\n    /// </summary>\n    /// <param name=\"name\">the name, either the normal name or the NameId which looks like a GUID</param>\n    /// <remarks>Added v17</remarks>\n    IContentType? GetContentType(string name);\n\n    #endregion\n\n    #region GetAll, GetOne, GetMany WIP v17.02+\n\n    /// <summary>\n    /// Get all data from the app of the specified type.\n    /// It will detect the expected Content-Type based on the name of the class used.\n    /// \n    /// So in most cases you will not add any parameters except for the type parameter `T`.\n    /// This is usually a type of your `AppCode.Data` namespace.\n    /// </summary>\n    /// <typeparam name=\"T\">The type to get and convert to - usually inheriting `Custom.Data.CustomItem`</typeparam>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"typeName\">_optional_ type name which is used as the **stream** name when retrieving the data, as each stream contains entities of one type.</param>\n    /// <param name=\"nullIfNotFound\">if set, will return null if the type doesn't exist - default is empty list.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Released in v17.03.\n    /// </remarks>\n    IEnumerable<T>? GetAll<T>(NoParamOrder npo = default, string? typeName = default,\n        bool nullIfNotFound = default)\n        where T : class, IModelFromData;\n\n    /// <summary>\n    /// Get a single item from the app with the specified ID.\n    /// </summary>\n    /// <typeparam name=\"T\">The type to convert to - usually inheriting `Custom.Data.CustomItem` or `CustomModel`</typeparam>\n    /// <param name=\"id\">the ID as an int</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"skipTypeCheck\">allow get even if the Content-Type of the item with the ID doesn't match the type specified in the parameter T</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Released in v17.03.\n    /// </remarks>\n    T? GetOne<T>(int id, NoParamOrder npo = default, bool skipTypeCheck = false)\n        where T : class, IModelFromData;\n\n\n    /// <summary>\n    /// Get a single item from the app with the specified GUID.\n    /// </summary>\n    /// <typeparam name=\"T\">The type to convert to - usually inheriting `Custom.Data.CustomItem` or `CustomModel`</typeparam>\n    /// <param name=\"id\">the ID as GUID</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"skipTypeCheck\">allow get even if the Content-Type of the item with the ID doesn't match the type specified in the parameter T</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Released in v17.03.\n    /// </remarks>\n    T? GetOne<T>(Guid id, NoParamOrder npo = default, bool skipTypeCheck = false)\n        where T : class, IModelFromData;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/IAppTyped.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Data;\n\n// ReSharper disable UnusedMemberInSuper.Global\n\nnamespace ToSic.Sxc.Apps;\n\n/// <summary>\n/// An app-object as is available in a razor template or WebApi when in **Typed** mode.\n/// </summary>\n[PublicApi]\npublic interface IAppTyped: IAppIdentity\n{\n    #region Properties basically from Eav.Apps.IApp\n\n    /// <inheritdoc cref=\"IApp.Name\"/>\n    string Name { get; }\n\n    /// <inheritdoc cref=\"IApp.Data\"/>\n    IAppDataTyped Data { get; }\n\n    #endregion\n\n    /// <summary>\n    /// Get a query in this App, optionally with more parameters and sources.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"attach\"></param>\n    /// <param name=\"parameters\"></param>\n    /// <returns></returns>\n    ITypedQuery? GetQuery(\n        string? name = default,\n        NoParamOrder npo = default,\n        IDataSourceLinkable? attach = default,\n        object? parameters = default\n    );\n\n\n    /// <inheritdoc cref=\"IApp.Configuration\"/>\n    IAppConfiguration Configuration { get; }\n\n    /// <summary>\n    /// All the app settings which are custom for each app. \n    /// </summary>\n    ITypedItem Settings { get;  }\n\n    /// <summary>\n    /// All the app resources (usually used for multi-language labels etc.)\n    /// </summary>\n    ITypedItem Resources { get;  }\n\n    #region Paths / Urls\n\n    IFolder Folder { get; }\n\n    /// <summary>\n    /// Get the folder of the current app, usually for creating links to assets etc.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"location\">name of the app location - either `auto` (default), `site` or `shared`</param>\n    /// <returns>an IFolder object which can then use `.Url`, `.PhysicalPath` etc.</returns>\n    /// <remarks>\n    /// * Despite being of type `IFolder`, the object is currently not able to traverse children folders/files.\n    ///   We may add this some day in the future.\n    /// * Previously the `Folder` property returned containing the name. This is now on `.Folder().Name`.\n    /// </remarks>\n    IFolder FolderAdvanced(NoParamOrder npo = default, string? location = default);\n\n    IFile Thumbnail { get; }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/IAppTyped_TSettings_TResources.cs",
    "content": "﻿namespace ToSic.Sxc.Apps;\n\n/// <summary>\n/// A strongly typed app, which has settings and resources as strongly typed objects.\n/// </summary>\n/// <typeparam name=\"TSettings\">Custom class for Settings</typeparam>\n/// <typeparam name=\"TResources\">Custom class for Resources</typeparam>\n/// <remarks>\n/// New v17.03\n/// </remarks>\n[PublicApi]\npublic interface IAppTyped<out TSettings, out TResources> :\n    IAppIdentity,\n    IAppTyped   // should be convertible to IAppTyped\n    where TSettings : class, IModelFromData, new()\n    where TResources : class, IModelFromData, new()\n{\n    /// <summary>\n    /// All the app settings which are custom for each app.\n    /// These are typed - typically to AppCode.Data.AppSettings\n    /// </summary>\n    new TSettings Settings { get; }\n\n    /// <summary>\n    /// All the app resources (usually used for multi-language labels etc.).\n    /// /// These are typed - typically to AppCode.Data.AppResources\n    /// </summary>\n    new TResources Resources { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/Api01/SimpleDataEditService.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Build.Sys;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.Data.Sys.EntityPair;\nusing ToSic.Eav.Data.Sys.Save;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Eav.Metadata;\nusing static System.StringComparer;\n\n\n// This is the simple API used to quickly create/edit/delete entities\n\n// todo: there is quite a lot of duplicate code here\n// like code to build attributes, or convert id-relationships to guids\n// this should be in the AttributeBuilder or similar\n\nnamespace ToSic.Sxc.Apps.Sys.Api01;\n\n/// <summary>\n/// This is a simple controller with some Create, Update and Delete commands.\n///\n/// Used to be called SimpleDataController before v17\n/// </summary>\n/// <remarks>\n/// Used for DI - must always call Init to use\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class SimpleDataEditService(\n    DataAssembler dataAssembler,\n    IZoneMapper zoneMapper,\n    IContextOfSite ctx,\n    GenWorkDb<WorkEntitySave> entSave,\n    GenWorkDb<WorkEntityUpdate> entUpdate,\n    GenWorkDb<WorkEntityDelete> entDelete,\n    LazySvc<IValueConverter> valueConverter,\n    Generator<AppPermissionCheck> appPermissionCheckGenerator) : ServiceBase(\"Dta.Simple\", connect: [entSave, entUpdate, entDelete, zoneMapper, dataAssembler, ctx, appPermissionCheckGenerator, valueConverter])\n{\n\n    #region Constructor / DI\n\n\n    private string _defaultLanguageCode = null!;\n\n    private int _appId;\n    private bool _checkWritePermissions = true; // default behavior is to check write publish/draft permissions (that should happen for REST, but not for c# API)\n    private IAppWorkCtxWithDb _ctxWithDb = null!;\n\n    /// <param name=\"zoneId\">Zone ID</param>\n    /// <param name=\"appId\">App ID</param>\n    /// <param name=\"checkWritePermissions\"></param>\n    public SimpleDataEditService Init(int zoneId, int appId, bool checkWritePermissions = true)\n    {\n        var l = Log.Fn<SimpleDataEditService>($\"{zoneId}, {appId}\");\n        _appId = appId;\n\n        // when zoneId is not that same as in current context, we need to set right site for provided zoneId\n        if (ctx.Site.ZoneId != zoneId)\n            ctx.Site = zoneMapper.SiteOfZone(zoneId);\n\n        _defaultLanguageCode = GetDefaultLanguage(zoneId);\n        var appIdentity = new AppIdentity(zoneId, appId);\n        _ctxWithDb = entSave.CtxSvc.CtxWithDb(appIdentity);\n        _checkWritePermissions = checkWritePermissions;\n        l.A($\"Default language:{_defaultLanguageCode}\");\n        return l.Return(this);\n    }\n\n    private string GetDefaultLanguage(int zoneId)\n    {\n        var l = Log.Fn<string>($\"{zoneId}\");\n        var site = zoneMapper.SiteOfZone(zoneId);\n        if (site == null! /* paranoid */)\n            return l.Return(\"\", \"site is null\");\n\n        var usesLanguages = zoneMapper.CulturesEnabledWithState(site).Any();\n        return l.Return(usesLanguages ? site.DefaultCultureCode : \"\", $\"ok, usesLanguages:{usesLanguages}\");\n    }\n        \n    #endregion\n\n    /// <summary>\n    /// Create a new entity of the content-type specified.\n    /// </summary>\n    /// <param name=\"contentTypeName\">Content-type</param>\n    /// <param name=\"multiValues\">\n    ///     Values to be set collected in a dictionary. Each dictionary item is a pair of attribute \n    ///     name and value. To set references to other entities, set the attribute value to a list of \n    ///     entity ids. \n    /// </param>\n    /// <param name=\"target\"></param>\n    /// <exception cref=\"ArgumentException\">Content-type does not exist, or an attribute in attributes</exception>\n    public IEnumerable<int> Create(string contentTypeName, IEnumerable<Dictionary<string, object?>>? multiValues, ITarget? target = null) \n    {\n        var list = multiValues?.ToListOpt();\n        var l = Log.Fn<IEnumerable<int>>($\"{contentTypeName}, items: {list?.Count()}, target: {target != null}\");\n        if (list == null)\n            return l.Return([],\"attributes were null\");\n\n        // ensure the type really exists - will throw if not\n        var type = _ctxWithDb.AppReader.GetContentType(contentTypeName);\n\n        l.A($\"Type {contentTypeName} found. Will build entities to save...\");\n\n        var entSaver = entSave.New(_ctxWithDb.AppReader);\n        var saveOptions = entSaver.SaveOptions();\n\n        var importEntity = list\n            .Select(values =>\n            {\n                var (entity, publishing) = BuildNewEntity(type, values, target, null);\n                var mySaveOptions = saveOptions with { DraftShouldBranch = publishing.ShouldBranchDrafts };\n                var pair = new EntityPair<SaveOptions>(entity, mySaveOptions);\n                return pair;\n            })\n            .ToList();\n\n        var ids = entSaver\n            .Save(importEntity);\n\n        var intIds = ids\n            .Select(i => i.Id)\n            .ToListOpt();\n\n        return l.Return(intIds, \"ok\");\n    }\n\n    private (IEntity Entity, EntitySavePublishing Publishing) BuildNewEntity(\n        IContentType type,\n        Dictionary<string, object?> values,\n        ITarget? targetOrNull,\n        bool? existingIsPublished) \n    {\n        var l = Log.Fn<(IEntity Entity, EntitySavePublishing Publishing)>\n            ($\"{type.Name}, {values.Count}, target: {targetOrNull != null}; {existingIsPublished}\");\n        // We're going to make changes to the dictionary, so we MUST copy it first, so we don't affect upstream code\n        // also ensure its case-insensitive...\n        values = values.ToInvIgnoreCaseCopy();\n\n        Guid eGuid;\n        if (values.TryGetValue(AttributeNames.EntityFieldGuid, out var entityGuidString))\n        {\n            // Note: we want an error if this guid is wrong, because we can't just take a new one if we got one\n            // since upstream may later want to access the same entity\n            eGuid = Guid.Parse(entityGuidString?.ToString() ?? \"\");\n        }\n        else\n        {\n            l.A(\"Add new generated guid, as none was provided.\");\n            eGuid = Guid.NewGuid();\n            values.Add(AttributeNames.EntityFieldGuid, eGuid);\n        }\n\n\n        // Get owner form value dictionary (and remove it from attributes) because we need to provided it in entity constructor.\n        string? owner = null;\n        if (values.TryGetValue(AttributeNames.EntityFieldOwner, out var ownerObj))\n        {\n            l.A(\"Get owner, when is provided.\");\n            owner = ownerObj?.ToString();\n            values.Remove(AttributeNames.EntityFieldOwner);\n        }\n\n        // Figure out publishing before converting to IAttribute\n        var publishing = DetectPublishingOrError(type, values, existingIsPublished);\n\n        // Prepare attributes to add\n        var preparedValues = ConvertRelationsToNullArray(type, values);\n        var preparedIAttributes = dataAssembler.AttributeList.Finalize(preparedValues);\n        var attributes = BuildNewEntityValues(type, preparedIAttributes, _defaultLanguageCode);\n\n        var newEntity = dataAssembler.Entity.Create(\n            appId: _appId,\n            guid: eGuid,\n            contentType: type,\n            attributes: dataAssembler.AttributeList.Finalize(attributes),\n            owner: owner,\n            metadataFor: targetOrNull,\n            isPublished: publishing.ShouldPublish);\n        if (targetOrNull != null)\n            l.A(\"FYI: Set metadata target which was provided.\");\n\n        return l.Return((newEntity, publishing));\n    }\n\n\n    /// <summary>\n    /// Update an entity specified by ID.\n    /// </summary>\n    /// <param name=\"entityId\">Entity ID</param>\n    /// <param name=\"values\">\n    ///     Values to be set collected in a dictionary. Each dictionary item is a pair of attribute \n    ///     name and value. To set references to other entities, set the attribute value to a list of \n    ///     entity ids. \n    /// </param>\n    /// <exception cref=\"ArgumentException\">Attribute in attributes does not exit</exception>\n    /// <exception cref=\"ArgumentNullException\">Entity does not exist</exception>\n    public void Update(int entityId, Dictionary<string, object?> values)\n    {\n        var l = Log.Fn($\"update i:{entityId}\");\n        var original = _ctxWithDb.AppReader.List.FindRepoId(entityId)\n            ?? throw new NullReferenceException($\"Can't Update, original not found with ID {entityId}\");\n        var (entity, publishing) = BuildNewEntity(original.Type, values, null, original.IsPublished);\n        entUpdate.New(_ctxWithDb.AppReader)\n            .UpdateParts(id: entityId, partialEntity: entity, publishing: publishing);\n        l.Done();\n    }\n\n\n    /// <summary>\n    /// Delete the entity specified by ID.\n    /// </summary>\n    /// <param name=\"entityId\">Entity ID</param>\n    /// <exception cref=\"InvalidOperationException\">Entity cannot be deleted for example when it is referenced by another object</exception>\n    public void Delete(int entityId) => entDelete.New(_ctxWithDb.AppReader).Delete(entityId);\n\n\n    /// <summary>\n    /// Delete the entity specified by GUID.\n    /// </summary>\n    /// <param name=\"entityGuid\">Entity GUID</param>\n    public void Delete(Guid entityGuid) => entDelete.New(_ctxWithDb.AppReader).Delete(entityGuid);\n\n\n    private IDictionary<string, object?> ConvertRelationsToNullArray(IContentType contentType, IDictionary<string, object?> values)\n    {\n        var l = Log.Fn<IDictionary<string, object?>>();\n        // Find all attributes which are relationships\n        var relationships = contentType.Attributes\n            .Where(a => a.IsEntity() /*.Type == ValueTypes.Entity*/)\n            .ToListOpt();\n\n        var newValues = values\n            .ToDictionary(\n                pair => pair.Key,\n                pair =>\n                {\n                    var value = pair.Value;\n                    // Not relationship, don't convert\n                    if (!relationships.Any(a => a.Name.EqualsInsensitive(pair.Key)))\n                        return value;\n\n                    switch (value)\n                    {\n                        case null: return null;\n                        case int intVal:\n                            return new List<int?> { intVal };\n                        case Guid guidVal:\n                            return new List<Guid?> { guidVal };\n                        case IEnumerable<int> idInt:\n                            return idInt.Cast<int?>().ToList();\n                        case IEnumerable<int?> idIntNull:\n                            return idIntNull.ToList();\n                        case IEnumerable<Guid> idGuid:\n                            return idGuid.Cast<Guid?>().ToList();\n                        case IEnumerable<Guid?> idGuidNull:\n                            return idGuidNull.ToList();\n                        case string strValEmpty when !strValEmpty.HasValue():\n                            return null;\n                        case string strVal:\n                            var parts = strVal.CsvToArrayWithoutEmpty();\n                            if (parts.Length == 0)\n                                return value;\n\n                            // could be int/guid - must convert - must all be the same\n                            if (int.TryParse(parts[0], out var intValue))\n                                return parts\n                                    .Select(item => int.TryParse(item, out intValue) ? (int?)intValue : null)\n                                    .ToList();\n\n                            if (Guid.TryParse(parts[0], out var guidValue))\n                                return parts\n                                    .Select(item => Guid.TryParse(item, out guidValue) ? (Guid?)guidValue : null)\n                                    .ToList();\n\n                            // fallback\n                            return value;\n                        default:\n                            return value;\n                    }\n                });\n        return l.Return(newValues);\n    }\n\n\n    private IDictionary<string, IAttribute> BuildNewEntityValues(IContentType contentType, IReadOnlyDictionary<string, IAttribute> attributes, string valuesLanguage)\n    {\n        var l = Log.Fn<Dictionary<string, IAttribute>>($\"..., ..., attributes: {attributes.Count}, {valuesLanguage}\");\n        if (attributes.SafeNone())\n            return l.Return(new(), \"null/empty\");\n\n        var updated = attributes\n            .Select(keyValuePair =>\n            {\n                // Handle content-type attributes\n                var ctAttr = contentType[keyValuePair.Key];\n                if (ctAttr == null || keyValuePair.Value == null)\n                    return null;\n\n                attributes.TryGetValue(ctAttr.Name, out var attribute);\n                var firstValue = keyValuePair.Value.Values?.FirstOrDefault();\n                var firstValContents = firstValue?.ObjectContents;\n                if (firstValContents == null)\n                    return null;\n                var preConverted = valueConverter.Value.PreConvertReferences(firstValContents, ctAttr.Type, true);\n                var newAttribute = dataAssembler.Attribute.CreateOrUpdate(\n                    originalOrNull: attribute,\n                    name: ctAttr.Name,\n                    value: preConverted,\n                    type: ctAttr.Type,\n                    valueToReplace: firstValue,\n                    language: valuesLanguage);\n                l.A($\"Attribute '{keyValuePair.Key}' will become '{keyValuePair.Value}' ({ctAttr.Type})\");\n                return new\n                {\n                    keyValuePair.Key,\n                    Attribute = newAttribute\n                };\n\n            })\n            .Where(x => x != null)\n            .ToDictionary(\n                pair => pair!.Key,\n                pair => pair!.Attribute,\n                InvariantCultureIgnoreCase\n            );\n        return l.Return(updated, \"done\");\n    }\n    \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/Api01/SimpleDataEditService_IsDraft.cs",
    "content": "﻿using static ToSic.Eav.Apps.Sys.Api01.SaveApiAttributes;\n\nnamespace ToSic.Sxc.Apps.Sys.Api01;\n\npartial class SimpleDataEditService\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"defaultPublished\">Either the existing published state, or a definition if allowed</param>\n    /// <param name=\"writePublishAllowed\"></param>\n    /// <param name=\"log\"></param>\n    /// <returns></returns>\n    public static EntitySavePublishing GetPublishSpecs(object? publishedState, bool? defaultPublished, bool writePublishAllowed, ILog log)\n    {\n        var l = log.Fn<EntitySavePublishing>($\"{nameof(publishedState)}: {publishedState}; {nameof(defaultPublished)}: {defaultPublished}; {nameof(writePublishAllowed)}: {writePublishAllowed}\");\n        // If it already has a published original\n        // Then we want to keep it that way, unless it's not allowed,\n        // in which case we must branch (if we will create a draft, to be determined later on)\n        var shouldBranchDrafts = defaultPublished == true && !writePublishAllowed;\n        l.A($\"shouldBranchDrafts: {shouldBranchDrafts}\");\n\n        switch (publishedState)\n        {\n            // Case No change, not specified\n            case null:\n            case string emptyString when string.IsNullOrEmpty(emptyString):\n            case string nullWritten when nullWritten.EqualsInsensitive(PublishModeNull):\n                var published = defaultPublished != false && writePublishAllowed;\n                return l.ReturnAndLog(new() { ShouldPublish = published, ShouldBranchDrafts = shouldBranchDrafts}, \"null/empty\");\n\n            // Case \"draft\"\n            case string draftString when draftString.EqualsInsensitive(PublishModeDraft):\n                return l.ReturnAndLog(new() { ShouldPublish = false, ShouldBranchDrafts = defaultPublished ?? false }, \"draft\");\n\n            // case boolean or truthy string\n            default:\n                var isPublished = publishedState.ConvertOrDefault<bool>(numeric: false, truthy: true);\n                return l.ReturnAndLog(new() { ShouldPublish = isPublished && writePublishAllowed, ShouldBranchDrafts = shouldBranchDrafts}, \"default\");\n        }\n    }\n    \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/Api01/SimpleDataEditService_PermissionsAndPublishing.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Api01;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Apps.Sys.Api01;\n\npartial class SimpleDataEditService\n{\n\n    private EntitySavePublishing DetectPublishingOrError(IContentType contentType, IDictionary<string, object?> values, bool? existingIsPublished)\n    {\n        var l = Log.Fn<EntitySavePublishing?>($\"..., ..., attributes: {values.Count}\");\n\n        // First, ensure WritePublished or WriteDraft user permissions. \n        var allowed = GetWriteAndPublishAllowed(contentType);\n        if (!allowed.WriteAllowed)\n            throw l.Ex(new Exception(\"User is not allowed to do anything. Both published and draft are not allowed.\"));\n\n        // On update, by default preserve IsPublished state\n        var shouldPublish = existingIsPublished ?? true;\n\n        // IsPublished becomes false when write published is not allowed.\n        if (shouldPublish && !allowed.PublishAllowed)\n            shouldPublish = false;\n\n        // If we don't have any values, there is nothing else to detect, so exit early\n        if (values.SafeNone())\n            return l.Return(new() { ShouldPublish = shouldPublish }, \"no attributes to process\");\n\n        // Find publishing instructions\n        // Handle special \"PublishState\" attribute\n        var publishKvp = values.FirstOrDefault(pair => pair.Key.EqualsInsensitive(SaveApiAttributes.SavePublishingState));\n\n        // did it exist? must check _key_, because key-value-pairs don't have a null-default\n        if (publishKvp.Key == default)\n            return l.Return(new() { ShouldPublish = shouldPublish }, $\"done, param {SaveApiAttributes.SavePublishingState} not provided\");\n\n        var publishAndBranch = GetPublishSpecs(publishedState: publishKvp.Value, defaultPublished: shouldPublish, allowed.PublishAllowed, Log);\n\n        return l.Return(publishAndBranch, \"done\");\n    }\n\n\n    #region Permission Checks\n\n    private (bool PublishAllowed, bool WriteAllowed) GetWriteAndPublishAllowed(IContentType targetType)\n    {\n        var l = Log.Fn<(bool PublishAllowed, bool WriteAllowed)>();\n        // skip write publish/draft permission checks when used in C# API\n        // because in that case, the developer should have already checked permissions\n        if (!_checkWritePermissions)\n            return l.ReturnAndLog((true, true), \"skip write perm check - all ok\");\n\n        // The remaining write publish/draft permission checks should happen only for REST API\n\n        // 1. Find if user may write PUBLISHED:\n        var appStateReader = _ctxWithDb.AppReader;\n\n        // 1.1. app permissions \n        if (appPermissionCheckGenerator.New().ForAppInInstance(ctx, appStateReader)\n            .UserMay(GrantSets.WritePublished).Allowed)\n            return l.ReturnAndLog((true, true), \"App check - all ok\");\n\n        // 1.2. type permissions\n        if (appPermissionCheckGenerator.New().ForType(ctx, appStateReader, targetType)\n            .UserMay(GrantSets.WritePublished).Allowed)\n            return l.ReturnAndLog((true, true), \"Type check, all ok\");\n\n\n        // 2. Find if user may write DRAFT:\n\n        // 2.1. app permissions \n        if (appPermissionCheckGenerator.New().ForAppInInstance(ctx, appStateReader)\n            .UserMay(GrantSets.WriteDraft).Allowed)\n            return l.ReturnAndLog((false, true), \"App check draft - f/t\");\n\n        // 2.2. type permissions\n        if (appPermissionCheckGenerator.New().ForType(ctx, appStateReader, targetType)\n            .UserMay(GrantSets.WriteDraft).Allowed)\n            return l.ReturnAndLog((false, true), \"Type check draft - f/t\");\n\n\n        // 3. User is not allowed to update published or draft entity.\n        return l.ReturnAndLog((false, false), \"default: all not allowed\");\n    }\n\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppBase/IAppWithInternal.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys;\n\npublic interface IAppWithInternal : IApp\n{\n    IAppReader AppReader { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppBase/SxcAppBase.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.Metadata;\nusing ToSic.Eav.Services;\nusing ToSic.Eav.Sys;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\n/// <summary>\n/// A <em>single-use</em> app-object providing quick simple api to access\n/// name, folder, data, metadata etc.\n/// </summary>\n/// <remarks>\n/// * was `ToSic.Eav.Apps.App` till ca. 2023-01-11 ca. v16.09\n/// * then was `ToSic.Eav.Apps.Internal.EavApp` v20\n/// </remarks>\n/// <param name=\"services\">All the dependencies of this app, managed by this app</param>\n/// <param name=\"logName\">must be null by default, because of DI</param>\n[PrivateApi(\"Hide implementation - was PublicApi_Stable_ForUseInYourCode till 16.09\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract partial class SxcAppBase(SxcAppBase.Dependencies services, string? logName = default, object[]? connect = default)\n    : AppBase<SxcAppBase.Dependencies>(services, logName ?? \"Eav.App\", connect: connect)\n{\n    // ReSharper disable once InconsistentNaming\n    private readonly Dependencies services = services;\n\n    #region Constructor / DI\n\n    /// <summary>\n    /// Helper class, so inheriting stuff doesn't need to update the constructor all the time\n    /// </summary>\n    [PrivateApi]\n    public record Dependencies(\n        IZoneMapper ZoneMapper,\n        ISite Site,\n        IAppReaderFactory AppReaders,\n        IDataSourcesService DataSourceFactory,\n        LazySvc<QueryManager> QueryManager,\n        IAppDataConfigProvider DataConfigProvider)\n        : DependenciesRecord(connect: [ZoneMapper, Site, AppReaders, DataSourceFactory, QueryManager, DataConfigProvider]);\n\n    #endregion\n\n    #region AppReader and all derived properties of the AppReader\n\n    protected internal IAppReader AppReaderInt\n    {\n        get => field ?? throw new(\"AppReaderInt not set, did you call Init()?\");\n        private set;\n    } = null!;\n\n\n    [field: AllowNull, MaybeNull]\n    private IAppSpecs AppSpecs => field ??= AppReaderInt.Specs;\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public string Name => field ??= AppReaderInt.Specs.Name; // ?? KnownAppsConstants.ErrorAppName;\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public string Folder => field ??= AppReaderInt.Specs.Folder; // ?? KnownAppsConstants.ErrorAppName;\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public string NameId => field ??= AppReaderInt.Specs.NameId;\n\n    /// <inheritdoc />\n    [Obsolete]\n    [PrivateApi]\n    public string AppGuid => NameId;\n\n    #region Metadata and Permission Accessors\n\n    /// <inheritdoc />\n    public IMetadata Metadata => AppSpecs.Metadata;\n\n    /// <summary>\n    /// Permissions of this app\n    /// </summary>\n    public IEnumerable<IPermission> Permissions => Metadata.Permissions;\n\n    #endregion\n\n    #region Settings, Config, Metadata\n\n    public IEntity? AppSettings => AppSpecs.Settings.MetadataItem;\n    public IEntity? AppResources => AppSpecs.Resources.MetadataItem;\n\n    #endregion\n\n    #endregion\n\n\n    public SxcAppBase Init(ISite? replaceSite, IAppIdentityPure appIdentity, AppDataConfigSpecs? dataSpecs)\n    {\n        var l = Log.Fn<SxcAppBase>();\n\n        // If we have a replacement site (like App being used from another site), set it here\n        if (replaceSite != null)\n        {\n            MySite = replaceSite;\n        }\n\n        // Env / Tenant must be re-checked here\n        if (MySite == null)\n            throw new(\"no site/portal received\");\n\n        // Update my AppIdentity and show for debug\n        InitAppBaseIds(appIdentity);\n        l.A($\"prep App #{appIdentity.Show()}, has{nameof(dataSpecs)}:{dataSpecs != null}\");\n\n        // in case the DI gave a bad tenant, try to look up\n        if (MySite.Id == EavConstants.NullId\n            && appIdentity.AppId != EavConstants.NullId\n            && appIdentity.AppId != AppConstants.AppIdNotFound)\n            MySite = Services.ZoneMapper.SiteOfApp(appIdentity.AppId);\n\n        // Look up name in cache\n        AppReaderInt = services.AppReaders.Get(this);\n\n        // for deferred initialization as needed\n        _dataConfigSpecs = dataSpecs ?? new AppDataConfigSpecs();\n\n        return l.Return(this);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppBase/SxcAppBase_Data.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\npartial class SxcAppBase\n{\n    // #DropAppConfigurationProvider\n    //[PrivateApi]\n    //public ILookUpEngine ConfigurationProvider => AppDataConfig.LookUpEngine;\n\n    protected internal IAppDataConfiguration AppDataConfig => _appDataConfigOnce.Get(() =>\n    {\n        // New v17\n        var config = Services.DataConfigProvider.GetDataConfiguration(this, _dataConfigSpecs);\n\n        // needed to initialize data - must always happen a bit later because the show-draft info isn't available when creating the first App-object.\n        // todo: later this should be moved to initialization of this object\n        Log.A($\"init data drafts:{config.ShowDrafts}, hasConf:{config.LookUpEngine}\");\n        return config;\n\n    })!;\n    private readonly GetOnce<IAppDataConfiguration> _appDataConfigOnce = new();\n    private AppDataConfigSpecs _dataConfigSpecs = null!;\n\n    #region Data\n\n\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public IAppData Data => field ??= BuildData<AppDataWithCrud, IAppData>();\n\n    [PrivateApi]\n    protected TResult BuildData<TDataSource, TResult>()\n        where TDataSource : TResult\n        where TResult : class, IDataSource\n    {\n        var l = Log.Fn<TResult>();\n        var dataConfig = AppDataConfig;\n        if (dataConfig.LookUpEngine == null) // note: as of 2025-09, I believe this can never be null.\n            throw new(\"Cannot provide Data for the object App as crucial information is missing. \" +\n                      \"Please call InitData first to provide this data.\");\n\n        // Note: ModulePermissionController does not work when indexing, return false for search\n        var options = new DataSourceOptions\n        {\n            AppIdentityOrReader = this.PureIdentity(),\n            LookUp = dataConfig.LookUpEngine,\n            ShowDrafts = dataConfig.ShowDrafts,\n        };\n        var initialSource = Services.DataSourceFactory.CreateDefault(options);\n        var appDataWithCreate = Services.DataSourceFactory.Create<TDataSource>( /*attach: initialSource*/\n            options with { Attach = initialSource, }) as TResult;\n\n        return l.Return(appDataWithCreate);\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppBase/SxcAppBase_Environment.cs",
    "content": "﻿using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Context;\nusing ToSic.Sys.Caching.PiggyBack;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\npartial class SxcAppBase\n{\n    protected ISite MySite { get; set; } = services.Site;\n\n    #region Paths\n\n    [PrivateApi]\n    public string PhysicalPath\n        => AppReaderInt.GetCache().GetPiggyBack(nameof(PhysicalPath), () => Path.Combine(MySite.AppsRootPhysicalFull, Folder));\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppBase/SxcAppBase_MetadataAndPermissions.cs",
    "content": "﻿//using ToSic.Eav.Apps.Sys;\n//using ToSic.Eav.Metadata;\n//using ToSic.Sys.Security.Permissions;\n//\n\n//namespace ToSic.Sxc.Apps.Sys;\n\n//partial class SxcAppBase: IHasPermissions, IAppWithInternal\n//{\n\n//    /// <summary>\n//    /// Assign all kinds of metadata / resources / settings (App-Mode only)\n//    /// </summary>\n//    protected void InitializeResourcesSettingsAndMetadata()\n//    {\n//        var l = Log.Fn();\n//        //Metadata = appSpecs.Metadata;\n\n//        // Get the content-items describing various aspects of this app\n//        //AppResources = appSpecs.Resources.MetadataItem;\n//        //AppSettings = AppSpecs.Settings.MetadataItem;\n//        // in some cases these things may be null, if the app was created not allowing side-effects\n//        // This can usually happen when new apps are being created\n//        l.A($\"HasResources: {AppResources != null}, HasSettings: {AppSettings != null}, HasConfiguration: {AppReaderInt.Specs.Configuration?.Entity != null}\");\n\n//        // resolve some values for easier access\n//        //Name = AppReaderInt.Specs.Name; // ?? KnownAppsConstants.ErrorAppName;\n//        //Folder = AppReaderInt.Specs.Folder; // ?? KnownAppsConstants.ErrorAppName;\n\n//        l.Done($\"Name: {Name}, Folder: {Folder}\");\n//    }\n    \n\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppData/AppDataWithCrud.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\nusing ToSic.Eav.DataSource.Sys.Caching;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Apps.Sys.Api01;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\n/// <summary>\n/// The Data object on an App. It's also a data-source of type <see cref=\"Eav.DataSources.App\"/>,\n/// so it has many streams, one for each content-type so you can use it in combination with other DataSources. <br/>\n/// The special feature is that it also has methods for data-manipulation,\n/// including Create, Update and Delete\n/// </summary>\n[PrivateApi(\"May have been visible before v17, but probably not really, name was also different. Published through the IAppData interface.\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class AppDataWithCrud : Eav.DataSources.App, IAppData\n{\n    private readonly LazySvc<IDataSourceCacheService> _dsCacheSvc;\n\n    #region Constructor stuff\n\n    public AppDataWithCrud(Dependencies services, LazySvc<SimpleDataEditService> dataController, LazySvc<IDataSourceCacheService> dsCacheSvc) : base(services)\n    {\n        ConnectLogs([\n            DataController = dataController.SetInit(dc => dc.Init(ZoneId, AppId, false)),\n            _dsCacheSvc = dsCacheSvc\n        ]);\n    }\n\n    #endregion\n\n    #region Get Content Type (added in v20 to better fix Mobius compatbility)\n\n    IContentType? IAppData.GetContentType(string name)\n        => AppReader.TryGetContentType(name);\n\n    IEnumerable<IContentType> IAppData.GetContentTypes()\n        => AppReader.ContentTypes;\n\n    #endregion\n\n    #region CRUD Data Operations\n\n    /// <summary>\n    /// Get a correctly instantiated instance of the simple data controller once needed.\n    /// </summary>\n    /// <returns>A data controller to create, update and delete entities</returns>\n    private LazySvc<SimpleDataEditService> DataController { get; }\n\n    /// <inheritdoc />\n    public IEntity Create(string contentTypeName, Dictionary<string, object?> values, string? userName = default, ITarget? target = default)\n    {\n        var l = Log.Fn<IEntity>(contentTypeName);\n        // Ensure case insensitive\n        values = values.ToInvariant();\n\n        if (!string.IsNullOrEmpty(userName))\n            ProvideOwnerInValues(values, userName!); // userName should be in 2sxc user IdentityToken format (like 'dnn:user=N')\n        var ids = DataController.Value.Create(contentTypeName, new List<Dictionary<string, object?>> { values! }, target);\n        var id = ids.FirstOrDefault();\n        FlushDataSnapshot();\n        // try to find it again (AppState.List contains also draft items)\n        var created = AppReader.List.GetOne(id)\n            ?? throw new ArgumentException($\"Can't find the freshly created entity with ID {id}, something is wrong.\");\n        return l.Return(created, $\"{created.EntityId}/{created.EntityGuid}\");\n    }\n\n    private static void ProvideOwnerInValues(IDictionary<string, object?> values, string userIdentityToken)\n    {\n        // userIdentityToken is not simple 'userName' string, but 2sxc user IdentityToken structure (like 'dnn:user=N')\n        if (values.ContainsKey(AttributeNames.EntityFieldOwner))\n            return;\n        values.Add(AttributeNames.EntityFieldOwner, userIdentityToken);\n    }\n\n    /// <inheritdoc />\n    public IEnumerable<IEntity> Create(string contentTypeName, IEnumerable<Dictionary<string, object?>> multiValues, string? userName = default)\n    {\n        var valueList = multiValues.ToListOpt();\n        var l = Log.Fn<IEnumerable<IEntity>>($\"app create many ({valueList.Count}) new entities of type:{contentTypeName}\");\n        // ensure case insensitive\n        multiValues = valueList\n            .Select(mv => mv.ToInvariant())\n            .ToList();\n\n        if (!string.IsNullOrEmpty(userName))\n            foreach (var values in multiValues)\n                ProvideOwnerInValues(values, userName!); // userName should be in 2sxc user IdentityToken format (like 'dnn:user=N')\n\n        var ids = DataController.Value.Create(contentTypeName, multiValues);\n        FlushDataSnapshot();\n        var created = List\n            .Where(e => ids.Contains(e.EntityId))\n            .ToList();\n        return l.Return(created, $\"{created.Count}\");\n    }\n\n    /// <inheritdoc />\n    public void Update(int entityId, Dictionary<string, object?> values, string? userName = default)\n    {\n        var l = Log.Fn($\"app update i:{entityId}\");\n        // FYI: userName is not used (to change owner of updated entity).\n        DataController.Value.Update(entityId, values);\n        FlushDataSnapshot();\n        l.Done();\n    }\n\n\n    /// <inheritdoc />\n    public void Delete(int entityId, string? userName = default)\n    {\n        var l = Log.Fn($\"app delete i:{entityId}\");\n        // FYI: userName is not used (to change owner of deleted entity).\n        DataController.Value.Delete(entityId);\n        FlushDataSnapshot();\n        l.Done();\n    }\n\n    /// <summary>\n    /// All 2sxc data is always snapshot, so read will only run a query once and keep it till the objects are killed.\n    /// If we do updates or perform other changes, we must clear the current snapshot so subsequent access will result\n    /// in the new data. \n    /// </summary>\n    private void FlushDataSnapshot()\n    {\n        // Purge the list and parent lists - must happen first, as otherwise the list-access will be interrupted\n        _dsCacheSvc.Value.Flush(this, true);\n        Reset();\n    }\n\n    #endregion\n\n    #region Get Metadata\n\n    /// <inheritdoc />\n    public IEnumerable<IEntity> GetMetadata<TKey>(int targetType, TKey key, string? contentTypeName = null)\n        => AppReader.Metadata.GetMetadata(targetType, key, contentTypeName);\n\n    /// <inheritdoc />\n    public IEnumerable<IEntity> GetMetadata<TKey>(TargetTypes targetType, TKey key, string? contentTypeName = null)\n        => AppReader.Metadata.GetMetadata(targetType, key, contentTypeName);\n\n    /// <inheritdoc />\n    public IEnumerable<IEntity> GetCustomMetadata<TKey>(TKey key, string? contentTypeName = null)\n        => AppReader.Metadata.GetMetadata(TargetTypes.Custom, key, contentTypeName);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppData/Configuration/AppDataConfigProviderUnknown.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sys.Engines;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Apps.Sys;\n\ninternal class AppDataConfigProviderUnknown(WarnUseOfUnknown<AppDataConfigProviderUnknown> _) : IAppDataConfigProvider\n{\n    public IAppDataConfiguration GetDataConfiguration(SxcAppBase app, AppDataConfigSpecs specs)\n        => new AppDataConfiguration(new LookUpEngine(app.Log));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppData/Configuration/AppDataConfigSpecs.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys;\n\npublic class AppDataConfigSpecs\n{\n    public bool? ShowDrafts { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppData/Configuration/AppDataConfiguration.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sys.Engines;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record AppDataConfiguration(\n    ILookUpEngine LookUpEngine,\n    bool? ShowDrafts = null\n) : IAppDataConfiguration;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppData/Configuration/IAppDataConfigProvider.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys;\n\n/// <summary>\n/// System which provides AppDataConfiguration, so that the client can know if it should show drafts etc.\n/// </summary>\npublic interface IAppDataConfigProvider\n{\n    public IAppDataConfiguration GetDataConfiguration(SxcAppBase app, AppDataConfigSpecs specs);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppData/Configuration/IAppDataConfiguration.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sys.Engines;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\n/// <summary>\n/// The configuration of an app-data - usually relevant so the source will auto-filter out unpublished data for normal viewers.\n/// </summary>\n[PrivateApi(\"before v17 was InternalApi_DoNotUse_MayChangeWithoutNotice - this is just fyi\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IAppDataConfiguration\n{\n    /// <summary>\n    /// If this instance is allowed to show draft items\n    /// This is usually dependent on the current users permissions\n    /// </summary>\n    bool? ShowDrafts { get; }\n\n\n    /// <summary>\n    /// Configuration used to query data - will deliver url-parameters and other important configuration values.\n    /// </summary>\n    ILookUpEngine LookUpEngine { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppExtensionsInternal.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sys.Engines;\n\nnamespace ToSic.Sxc.Apps.Sys;\npublic static class AppExtensionsInternal\n{\n    public static ILookUpEngine? TryGetAppLookUpEngineOrNull(this IApp? app)\n        => (app as SxcAppBase)?.AppDataConfig.LookUpEngine;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppFolderInitializer.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Eav.Sys;\nusing ToSic.Sys.Configuration;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppFolderInitializer(IServerPaths serverPaths, IGlobalConfiguration globalConfiguration, ISite site)\n    : ServiceBase(\"Viw.Help\", connect: [serverPaths, globalConfiguration, site])\n{\n\n    /// <summary>\n    /// Creates a directory and copies the needed web.config for razor files\n    /// if the directory does not exist.\n    /// </summary>\n    public void EnsureTemplateFolderExists(string appFolder, bool isShared)\n    {\n        var l = Log.Fn($\"{isShared}\");\n        var portalPath = isShared\n            ? serverPaths.FullAppPath(globalConfiguration.SharedAppsFolder())\n            : site.AppsRootPhysicalFull ?? \"\";\n\n        var sxcFolder = new DirectoryInfo(portalPath);\n\n        // Create 2sxc folder if it does not exists\n        sxcFolder.Create();\n\n        // Create a Content folder (or App Folder)\n        if (string.IsNullOrEmpty(appFolder))\n        {\n            l.Done(\"Folder name not given, won't create\");\n            return;\n        }\n\n        var contentFolder = new DirectoryInfo(Path.Combine(sxcFolder.FullName, appFolder));\n        contentFolder.Create();\n\n        var appDataProtectedFolder =\n            new DirectoryInfo(Path.Combine(contentFolder.FullName, FolderConstants.DataFolderProtected));\n        appDataProtectedFolder.Create();\n\n        var appJsonTemplateFilePath =\n            Path.Combine(globalConfiguration.AppDataTemplateFolder(), FolderConstants.AppJsonFile);\n        if (File.Exists(appJsonTemplateFilePath) && !appDataProtectedFolder.GetFiles(FolderConstants.AppJsonFile).Any())\n            File.Copy(appJsonTemplateFilePath,\n                Path.Combine(appDataProtectedFolder.FullName, FolderConstants.AppJsonFile));\n        l.Done(\"ok\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppIconHelpers.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing static System.StringComparison;\nusing static ToSic.Eav.Apps.Sys.AppConstants;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppIconHelpers(LazySvc<IValueConverter> iconConverterLazy)\n    : ServiceBase(\"Viw.Help\", connect: [iconConverterLazy])\n{\n\n    public string? IconPathOrNull(IAppPaths appPaths, IView view, PathTypes type)\n    {\n        var l = Log.Fn<string?>();\n        // 1. Check if the file actually exists or is a file:... reference\n        var iconFile = IconPath(appPaths, view, PathTypes.PhysFull);\n        var assumeExists = ValueConverterBase.CouldBeReference(iconFile) || File.Exists(iconFile);\n\n        // 2. Return as needed\n        var result = assumeExists\n            ? IconPath(appPaths, view, type)\n            : null;\n        return l.Return(result, result ?? \"not found\");\n    }\n\n    private string IconPath(IAppPaths appPaths, IView view, PathTypes type)\n    {\n        // See if we have an icon - but only if we need the link\n        if (view.Icon.HasValue())\n        {\n            // If we have the App:Path in front, replace as expected, but never on global\n            if (HasAppPathToken(view.Icon))\n                return AppPathTokenReplace(view.Icon, appPaths.PathSwitch(false, type), appPaths.PathSwitch(true, type));\n\n            // If not, we must assume it's file:## placeholder\n            // URLs (Links) we can provide...\n            if (type == PathTypes.Link)\n                return iconConverterLazy.Value.ToValue(view.Icon, view.Guid);\n\n            // ...but file:## can't convert to PhysFull; return it so the caller can check if it's a reference\n            return view.Icon;\n        }\n\n        // Don't use the saved value, but return the expected path which would be the default by convention\n        var viewPath1 = appPaths.ViewPath(view, type);\n        return viewPath1.Substring(0, viewPath1.LastIndexOf(\".\", Ordinal)) + \".png\";\n    }\n\n    public static bool HasAppPathToken(string? value)\n    {\n        value ??= \"\";\n        return value.StartsWith(AppPathPlaceholder, InvariantCultureIgnoreCase)\n               || value.StartsWith(AppPathSharedPlaceholder, InvariantCultureIgnoreCase);\n    }\n\n    public static string AppPathTokenReplace(string? value, string appPath, string appPathShared)\n    {\n        value ??= \"\";\n        if (value.StartsWith(AppPathPlaceholder, InvariantCultureIgnoreCase))\n            return appPath + value.After(AppPathPlaceholder);\n        if (value.StartsWith(AppPathSharedPlaceholder, InvariantCultureIgnoreCase))\n            return appPathShared + value.After(AppPathSharedPlaceholder);\n        return value;\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/AppPathExtensions.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\nnamespace ToSic.Sxc.Apps.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class AppPathExtensions\n{\n    public static string PhysicalPathSwitch(this IAppPaths app, bool isShared) =>\n        isShared\n            ? app.PhysicalPathShared\n            : app.PhysicalPath;\n\n    public static string PathSwitch(this IAppPaths app, bool isShared, PathTypes type) =>\n        type switch\n        {\n            PathTypes.PhysFull => isShared ? app.PhysicalPathShared : app.PhysicalPath,\n            PathTypes.PhysRelative => isShared ? app.RelativePathShared : app.RelativePath,\n            PathTypes.Link => isShared ? app.PathShared : app.Path,\n            _ => throw new ArgumentOutOfRangeException(nameof(type), type, null)\n        };\n\n    // TODO: THIS SHOULD BE inlined in the 2 places it's used, so this function isn't necessary any more\n    // Then these helpers should be moved to ToSxc.Eav.Apps.Paths\n\n    public static string ViewPath(this IAppPaths app, IView view, PathTypes type) => Path.Combine(app.PathSwitch(view.IsShared, type), view.Path);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/Paths/GlobalPaths.cs",
    "content": "﻿using ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sys.Configuration;\nusing static System.IO.Path;\n\nnamespace ToSic.Sxc.Apps.Sys.Paths;\n\npublic class GlobalPaths(LazySvc<IServerPaths> serverPaths, LazySvc<IGlobalConfiguration> config)\n    : ServiceBase(\"Viw.Help\", connect: [serverPaths, config])\n{\n\n    /// <summary>\n    /// Returns the location where module global folder web assets are stored\n    /// </summary>\n    public string GlobalPathTo(string path, PathTypes pathType)\n    {\n        var l = Log.Fn<string>($\"path:{path},pathType:{pathType}\");\n        var assetPath = Combine(config.Value.AssetsVirtualUrl().Backslash(), path);\n        var assetLocation = pathType switch\n        {\n            PathTypes.Link => assetPath.ToAbsolutePathForwardSlash(),\n            PathTypes.PhysRelative => assetPath.TrimStart('~').Backslash(),\n            PathTypes.PhysFull => serverPaths.Value.FullAppPath(assetPath).Backslash(),\n            _ => throw new ArgumentOutOfRangeException(nameof(pathType), pathType, null)\n        };\n        return l.ReturnAsOk(assetLocation);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/Paths/PathTypes.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.Paths;\n\n[PrivateApi]\npublic enum PathTypes\n{\n    PhysFull,\n    PhysRelative,\n    Link\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/Ui/AppUiInfo.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.Ui;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic struct AppUiInfo\n{\n    public string Name;\n    public int AppId;\n    public bool SupportsAjaxReload;\n    public string? Thumbnail;\n    public string Version;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/Ui/ContentTypeUiInfo.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.Ui;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic struct ContentTypeUiInfo\n{\n    public string Name;\n    public string StaticName;\n    public bool IsHidden;\n    public IDictionary<string, object?>? Properties;\n    public string? Thumbnail;\n    public bool IsDefault; // new, v13\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys/Ui/TemplateUiInfo.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.Ui;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic struct TemplateUiInfo\n{\n    public int TemplateId;\n    public string Name;\n    public string ContentTypeStaticName;\n    public bool IsHidden;\n    public string? Thumbnail;\n    public bool IsDefault; // new, v13\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.AppTyped/AppDataTyped.cs",
    "content": "﻿using ToSic.Eav.DataSource.Sys.Caching;\nusing ToSic.Sxc.Apps.Sys.Api01;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Apps.Sys.AppTyped;\n\ninternal class AppDataTyped(\n    Eav.DataSources.App.Dependencies services,\n    LazySvc<SimpleDataEditService> dataController,\n    LazySvc<IDataSourceCacheService> dsCacheSvc)\n    : AppDataWithCrud(services, dataController, dsCacheSvc), IAppDataTyped\n{\n    #region Get Content Types - explicit implementation to ensure it's only available in Typed APIs\n\n    IEnumerable<IContentType> IAppDataTyped.GetContentTypes()\n        => AppReader.ContentTypes;\n\n    IContentType? IAppDataTyped.GetContentType(string name)\n        => AppReader.TryGetContentType(name);\n\n    #endregion\n\n    #region Cdf Attachments and setup ToTypedHelper\n\n    internal AppDataTyped Setup(ICodeDataFactory cdfConnected)\n    {\n        ToTypedHelper = new(cdfConnected, this, Log);\n        return this;\n    }\n\n    [field: AllowNull, MaybeNull]\n    private DataSourceToTypedHelper ToTypedHelper { get => field ?? throw new($\"{nameof(ToTypedHelper)} not set\"); set; }\n\n    #endregion\n\n    /// <inheritdoc />\n    IEnumerable<T>? IAppDataTyped.GetAll<T>(NoParamOrder npo, string? typeName, bool nullIfNotFound)\n        => ToTypedHelper.GetAllShared<T>(typeName, nullIfNotFound, false);\n\n    /// <inheritdoc />\n    T? IAppDataTyped.GetOne<T>(int id, NoParamOrder npo, bool skipTypeCheck)\n        where T : class\n        => ToTypedHelper.GetOne<T>(id, npo, skipTypeCheck);\n\n    /// <inheritdoc />\n    T? IAppDataTyped.GetOne<T>(Guid id, NoParamOrder npo, bool skipTypeCheck)\n        where T : class\n        => ToTypedHelper.GetOne<T>(id, npo, skipTypeCheck);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.AppTyped/AppTyped.cs",
    "content": "﻿using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps.Sys.Assets;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Services.Sys.DataService;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Apps.Sys.AppTyped;\n\n// Wip, NOT PRODUCTION READY #IAppTyped\n// Goal is to use this instead of the App, to be a clean wrapper hiding the old App\n// and to ensure only this API works with the new typed data\n\n// It's not complete, because ATM it assumes it's already receiving an AppTyped - which is what this should be for.\n// So to complete\n// - provide an instance of this on the CodeApiService\n// - use that instead\n\ninternal class AppTyped(LazySvc<GlobalPaths> globalPaths, LazySvc<QueryManager<TypedQuery>> queryManager)\n    : ServiceWithContext(SxcLogName + \".AppTyp\", connect: [globalPaths, queryManager]),\n        IAppTyped\n{\n    [field: AllowNull, MaybeNull]\n    protected App App => field\n        ??= ExCtx.GetApp() as App\n            ?? throw new($\"Can't access {nameof(App)} - either null or can't convert\");\n\n\n    /// <inheritdoc />\n    int IZoneIdentity.ZoneId => App.ZoneId;\n\n    /// <inheritdoc />\n    int IAppIdentityLight.AppId => App.AppId;\n\n    /// <inheritdoc />\n    public string Name => App.Name;\n\n    /// <summary>\n    /// The CDF either comes from the ExecutionContext, or self-generated.\n    /// This is important for scenarios where the App is used on a theme, where there is no execution context.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    protected ICodeDataFactory Cdf => field ??= ExCtx.GetCdf();\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public IAppDataTyped Data => field ??= App\n        .BuildDataForTyped<AppDataTyped, AppDataTyped>()\n        .Setup(Cdf);\n\n    /// <inheritdoc />\n    public ITypedQuery? GetQuery(string? name = default, NoParamOrder npo = default, IDataSourceLinkable? attach = default, object? parameters = default)\n    {\n        var opts = new DataSourceOptionsMs(this, () => App.AppDataConfig.LookUpEngine);\n        var queryMicroService = new GetQueryMs<TypedQuery>(queryManager, opts, Log);\n        var query = queryMicroService.GetQuery(name, npo, attach, parameters);\n        query?.Setup(Cdf);\n        return query;\n    }\n\n    /// <inheritdoc />\n    public IAppConfiguration Configuration => App.Configuration;\n\n    /// <inheritdoc />\n    ITypedItem IAppTyped.Settings => _settings.Get(() => App.AppSettings.NullOrGetWith(appS => MakeTyped(appS, propsRequired: true))!)!;\n    private readonly GetOnce<ITypedItem> _settings = new();\n\n    /// <inheritdoc />\n    ITypedItem IAppTyped.Resources => _resources.Get(() => App.AppResources.NullOrGetWith(appR => MakeTyped(appR, propsRequired: true))!)!;\n    private readonly GetOnce<ITypedItem> _resources = new();\n\n    private ITypedItem MakeTyped(ICanBeEntity contents, bool propsRequired)\n    {\n        var wrapped = CmsEditDecorator.Wrap(contents.Entity, false);\n        return Cdf.AsItem(wrapped, new() { ItemIsStrict = propsRequired })!;\n    }\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public IFolder Folder => field ??= (this as IAppTyped).FolderAdvanced();\n\n    /// <inheritdoc />\n    public IFolder FolderAdvanced(NoParamOrder npo = default, string? location = default)\n        => new AppAssetFolderMain(App.AppPathsForTyped, App.Folder, AppAssetsHelpers.DetermineShared(location) ?? App.AppReaderForTyped.IsShared());\n\n    /// <inheritdoc />\n    public IFile Thumbnail => _thumbnailFile.Get(() => new AppAssetThumbnail(App.AppReaderForTyped, App.AppPathsForTyped, globalPaths))!;\n    private readonly GetOnce<IFile> _thumbnailFile = new();\n\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.AppTyped/AppTyped_TSettings_TResources.cs",
    "content": "﻿using ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Apps.Sys.AppTyped;\n\ninternal class AppTyped<TSettings, TResources>(LazySvc<GlobalPaths> globalPaths, LazySvc<QueryManager<TypedQuery>> queryManager)\n    : AppTyped(globalPaths, queryManager), IAppTyped<TSettings, TResources>\n    where TSettings : class, IModelFromData, new()\n    where TResources : class, IModelFromData, new()\n{\n    [field: AllowNull, MaybeNull]\n    TSettings IAppTyped<TSettings, TResources>.Settings\n        => field ??= Cdf.AsCustom<TSettings>(((IAppTyped)this).Settings)!;\n\n    [field: AllowNull, MaybeNull]\n    TResources IAppTyped<TSettings, TResources>.Resources\n        => field ??= Cdf.AsCustom<TResources>(((IAppTyped)this).Resources)!;\n    \n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Assets/AppAssetFile.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets;\nusing ToSic.Eav.Apps.Assets.Sys;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\nusing IAsset = ToSic.Sxc.Adam.IAsset;\nusing IFile = ToSic.Sxc.Adam.IFile;\n\nnamespace ToSic.Sxc.Apps.Sys.Assets;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class AppAssetFile: IFile\n{\n    protected const string NotImplemented = \"not implemented\";\n    public virtual string? Url => NotImplemented;\n    public virtual string Type => NotImplemented;\n\n    public virtual string Name => NotImplemented;\n    public virtual string Path => NotImplemented;\n    public virtual string PhysicalPath => NotImplemented;\n    public virtual string Extension => NotImplemented;\n    public virtual string Folder => NotImplemented;\n    public virtual string FullName => NotImplemented;\n\n    #region Metadata - won't do anything useful\n\n    bool IAsset.HasMetadata => false;\n\n    IMetadata IHasMetadata.Metadata => null!;\n\n    ITypedMetadata IAsset.Metadata => null!;\n\n    #endregion\n\n    #region Properties which are simply not implemented ATM\n\n    public int Size => 0;\n    public ISizeInfo SizeInfo => new SizeInfo(0);\n    public int FolderId => -1;\n\n    public IField? Field { get; set; }\n    public DateTime Created => DateTime.Now;\n    public int Id => -1;\n    public int ParentId => -1;\n    public DateTime Modified => DateTime.MinValue;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Assets/AppAssetFolder.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Apps.Sys.Assets;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class AppAssetFolder: IFolder\n{\n    protected const string NotImplemented = \"not implemented\";\n\n    public virtual string Name => NotImplemented;\n\n    public virtual string Path => NotImplemented;\n\n    public virtual string PhysicalPath => NotImplemented;\n\n    public virtual string Url => NotImplemented;\n\n    public bool HasChildren => false;\n\n\n    #region Metadata - won't do anything useful\n\n    bool IAsset.HasMetadata => false;\n\n    IMetadata IHasMetadata.Metadata => null!;\n\n    ITypedMetadata IAsset.Metadata => null!;\n\n    #endregion\n\n    #region Properties which are simply not implemented and won't do anything useful\n\n    public int Id => -1;\n    public int ParentId => -1;\n    public DateTime Created => DateTime.MinValue;\n    public DateTime Modified => DateTime.MinValue;\n\n    public string Type => AssetTypes.Folder;\n\n    public IField? Field { get; set; }\n\n    private const string FileFoldersNotSupported = \"As of now you can't use the App folder to navigate files/folders\";\n\n    public IEnumerable<IFile> Files => throw new NotSupportedException(FileFoldersNotSupported);\n\n    public IEnumerable<IFolder> Folders => throw new NotSupportedException(FileFoldersNotSupported);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Assets/AppAssetFolderMain.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.Assets;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class AppAssetFolderMain(IAppPaths appPaths, string folder, bool shared) : AppAssetFolder\n{\n    //internal const string LocationSite = \"site\";\n    //internal const string LocationShared = \"shared\";\n    //internal const string LocationAuto = \"auto\";\n\n    ///// <summary>\n    ///// Return true/false or null to allow upstream to do auto-detect\n    ///// </summary>\n    ///// <param name=\"location\"></param>\n    ///// <returns></returns>\n    ///// <exception cref=\"ArgumentException\"></exception>\n    //internal static bool? DetermineShared(string location)\n    //    => (location?.ToLowerInvariant() ?? LocationAuto) switch\n    //    {\n    //        LocationAuto => null,\n    //        LocationShared => true,\n    //        LocationSite => false,\n    //        _ => throw new ArgumentException($@\"should be null, {LocationAuto}, {LocationSite} or {LocationShared}\", nameof(location))\n    //    };\n\n\n    internal readonly IAppPaths AppPaths = appPaths;\n\n    public override string Name { get; } = folder;\n\n    public override string Path => shared ? AppPaths.RelativePathShared : AppPaths.RelativePath;\n\n    public override string PhysicalPath => (shared ? AppPaths.PhysicalPathShared : AppPaths.PhysicalPath);\n\n    public override string Url => shared ? AppPaths.PathShared : AppPaths.Path;\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Assets/AppAssetThumbnail.cs",
    "content": "﻿using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sys.Caching.PiggyBack;\nusing static ToSic.Eav.Apps.Sys.AppConstants;\n\nnamespace ToSic.Sxc.Apps.Sys.Assets;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class AppAssetThumbnail(IAppReader appReader, IAppPaths appPaths, LazySvc<GlobalPaths> globalPaths)\n    : AppAssetFile\n{\n    public override string? Url => _url.Get(() => GetUrl(appReader, appPaths, globalPaths));\n    private readonly GetOnce<string?> _url = new();\n\n    public static string? GetUrl(IAppReader appReader, IAppPaths appPaths, LazySvc<GlobalPaths> globalPaths)\n    {\n        // Primary app - we only PiggyBack cache the icon in this case\n        // Because otherwise the icon could get moved, and people would have a hard time seeing the effect\n        if (appReader.Specs.IsSiteSettingsApp())\n            return appReader.GetCache().GetPiggyBack(\"app-thumbnail-primary\",\n                () => globalPaths.Value.GlobalPathTo(AppPrimaryIconFile, PathTypes.Link));\n\n        // standard app (not global) try to find app-icon in its (portal) app folder\n        if (!appReader.IsShared() && File.Exists($\"{appPaths.PhysicalPath}/{AppIconFile}\"))\n            return $\"{appPaths.Path}/{AppIconFile}\";\n\n        // global app (and standard app without app-icon in its portal folder) looks for app-icon in global shared location \n        if (File.Exists($\"{appPaths.PhysicalPathShared}/{AppIconFile}\"))\n            return $\"{appPaths.PathShared}/{AppIconFile}\";\n\n        return null;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Assets/AppAssetsHelpers.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.Assets;\n\n/// <summary>\n/// Constants for App Assets\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class AppAssetsHelpers\n{\n    /// <summary>\n    /// App file is located in the site itself.\n    /// This is the Key used up until 2sxc 12.01 and will still exist in old data for a long time. \n    /// </summary>\n    /// <remarks>\n    /// It's not used in our code, but leave here for reference\n    /// </remarks>\n#pragma warning disable 414\n    private const string PortalFileSystem = \"Portal File System\";\n#pragma warning restore 414\n\n    /// <summary>\n    /// App file is located in the shared location. \n    /// This is the Key used up until 2sxc 12.01 and will still exist in old data for a long time. \n    /// </summary>\n    private const string HostFileSystem = \"Host File System\";\n\n    // New terms used in 12.02+\n    public static string AppInSite = \"Site\";\n    public static string AppInGlobal = \"Global\";\n\n    public static bool IsShared(string key)\n    {\n        return HostFileSystem.Equals(key, StringComparison.OrdinalIgnoreCase)\n               || AppInGlobal.Equals(key, StringComparison.OrdinalIgnoreCase);\n    }\n\n\n    internal const string LocationSite = \"site\";\n    internal const string LocationShared = \"shared\";\n    internal const string LocationAuto = \"auto\";\n\n    /// <summary>\n    /// Return true/false or null to allow upstream to do auto-detect\n    /// </summary>\n    /// <param name=\"location\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"ArgumentException\"></exception>\n    internal static bool? DetermineShared(string? location)\n        => (location?.ToLowerInvariant() ?? LocationAuto) switch\n        {\n            LocationAuto => null,\n            LocationShared => true,\n            LocationSite => false,\n            _ => throw new ArgumentException($@\"should be null, {LocationAuto}, {LocationSite} or {LocationShared}\", nameof(location))\n        };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Work/WorkApps.cs",
    "content": "﻿using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Apps.Sys.Assets;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Apps.Sys.Ui;\n\nnamespace ToSic.Sxc.Apps.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WorkApps(IAppStateCacheService appStates, IAppReaderFactory appReaders, Generator<IAppPathsMicroSvc> appPathsGen, LazySvc<GlobalPaths> globalPaths, IAppsCatalog appsCatalog)\n    : ServiceBase(\"Cms.AppsRt\", connect: [appStates, appReaders, appPathsGen, globalPaths, appsCatalog])\n{\n\n    public IList<AppUiInfo> GetSelectableApps(ISite site, string? filter)\n    {\n        var l = Log.Fn<List<AppUiInfo>>($\"filter:{filter}\");\n        var list =\n            GetApps(site)\n                .Where(reader =>\n                {\n                    var name = reader.Specs.Name;\n                    return name != KnownAppsConstants.ContentAppName\n                           && name != KnownAppsConstants.ErrorAppName // \"Error\" it is a name of empty Content app (before content templates are installed)\n                           && name != KnownAppsConstants.PrimaryAppName\n                           && name != KnownAppsConstants.PrimaryAppGuid;\n                }) // #SiteApp v13\n                .Where(reader => !reader.Specs.Configuration.IsHidden)\n                .Select(reader =>\n                {\n                    var paths = appPathsGen.New().Get(reader, site);\n                    var thumbnail = AppAssetThumbnail.GetUrl(reader, paths, globalPaths);\n                    var specs = reader.Specs;\n                    return new AppUiInfo\n                    {\n                        Name = specs.Name,\n                        AppId = specs.AppId,\n                        SupportsAjaxReload = specs.Configuration.EnableAjax,\n                        Thumbnail = thumbnail,\n                        Version = specs.Configuration.Version.ToString() ?? \"\"\n                    };\n                })\n                .ToList();\n\n        if (string.IsNullOrWhiteSpace(filter)) return l.Return(list, \"unfiltered\");\n\n        // New feature in 10.27 - if app-list is provided, only return these\n        var appNames = filter.CsvToArrayWithoutEmpty();\n        list = list.Where(ap => appNames\n                .Any(name => string.Equals(name, ap.Name, StringComparison.InvariantCultureIgnoreCase)))\n            .ToList();\n        return l.Return(list, \"ok\");\n    }\n\n    /// <summary>\n    /// Returns all Apps for the current zone\n    /// </summary>\n    /// <returns></returns>\n    public List<IAppReader> GetApps(ISite site)\n    {\n        // todo: unclear if this is the right way to do this - probably the ZoneId should come from the site?\n        var zId = site.ZoneId;\n        var appIds = appsCatalog.Apps(zId);\n\n        return appIds\n            .Select(a => appReaders.Get(new AppIdentityPure(zId, a.Key)))\n            .OrderBy(a => a.Specs.Name)\n            .ToList();\n    }\n\n    /// <summary>\n    /// Returns all Apps for the current zone\n    /// </summary>\n    /// <returns></returns>\n    public ICollection<IAppReader> GetInheritableApps(ISite site)\n    {\n        // Get existing apps, as we should not list inheritable apps which are already inherited\n        var siteApps = appsCatalog.Apps(site.ZoneId)\n            // TODO: #AppStates we could only get the specs here...\n            .Select(a => appReaders.Get(a.Key).Specs.Folder)\n            .ToListOpt();\n\n        var zones = appsCatalog.Zones;\n        var result = zones\n            // Skip all global apps on the current site, as they shouldn't be inheritable\n            .Where(z => z.Key != site.ZoneId)\n            .SelectMany(zSet =>\n            {\n                // todo: probably the ZoneId should come from the site?\n                var zId = zSet.Key;\n                var appIds = appsCatalog.Apps(zId);\n\n                return appIds\n                    //.Select(a => new AppIdentityPure(zId, a.Key))\n                    .Select(a =>\n                    {\n                        var appIdentity = new AppIdentityPure(zId, a.Key);\n                        return appStates.IsCached(appIdentity)\n                            ? appReaders.Get(appIdentity)\n                            : null!; // will be filtered out later\n                    })\n                    .Where(reader =>\n                    {\n                        if (reader == null)\n                            return false;\n                        return reader.IsShared() && !siteApps.Any(sa => sa.Equals(reader.Specs.Folder, StringComparison.InvariantCultureIgnoreCase));\n                    })\n                    //.Select(a => _appGenerator.New().PreInit(site).Init(a, buildConfig) as IApp)\n                    .OrderBy(reader => reader!.Specs.Name)\n                    .ToListOpt();\n            })\n            .ToListOpt();\n        return result;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Work/WorkAppsRemove.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.ImportExport.Sys.Zip;\n\nnamespace ToSic.Sxc.Apps.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WorkAppsRemove(\n    LazySvc<ZoneManager> zoneManagerLazy,\n    IAppReaderFactory appReaders,\n    IAppPathsMicroSvc appPaths,\n    IAppsCatalog appsCatalog\n) : ServiceBase(\"Cms.AppsRt\", connect: [zoneManagerLazy, appReaders, appPaths, appsCatalog])\n{\n\n    internal void RemoveAppInSiteAndEav(int zoneId, int appId, bool fullDelete)\n    {\n        // check portal assignment and that it's not the default app\n        // enable restore for DefaultApp\n        if (appId == appsCatalog.DefaultAppIdentity(zoneId).AppId && fullDelete)\n            throw new(\"The default app of a zone cannot be removed.\");\n\n        if (appId == KnownAppsConstants.MetaDataAppId)\n            throw new(\"The special old global app cannot be removed.\");\n\n        // todo: maybe verify the app is of this portal; I assume delete will fail anyhow otherwise\n\n        // Prepare to Delete folder in dnn - this must be done, before deleting the app in the DB\n        var appReader = appReaders.Get(new AppIdentity(zoneId, appId));\n        var paths = appPaths.Get(appReader);\n        var folder = appReader.Specs.Folder;\n        var physPath = paths.PhysicalPath;\n\n        // now remove from DB. This sometimes fails, so we do this before trying to clean the files\n        // as the db part should be in a transaction, and if it fails, everything should stay as is\n        zoneManagerLazy.Value.SetId(zoneId).DeleteApp(appId, fullDelete);\n\n        // now really delete the files - if the DB didn't end up throwing an error\n        // ...but only if it's a full-delete\n        if (fullDelete && !string.IsNullOrEmpty(folder) && Directory.Exists(physPath))\n            Zipping.TryToDeleteDirectory(physPath, Log);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Work/WorkViews.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.Metadata.Sys;\nusing ToSic.Sxc.Apps.Sys.Ui;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\n// note: not sure if the final namespace should be Sxc.Apps or Sxc.Views\nnamespace ToSic.Sxc.Apps.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WorkViews(\n    GenWorkPlus<WorkEntities> appEntities,\n    LazySvc<IValueConverter> valConverterLazy,\n    IZoneCultureResolver cultureResolver,\n    IConvertToEavLight dataToFormatLight,\n    Generator<QueryDefinitionFactory> qDefBuilder)\n    : WorkUnitBase<IAppWorkCtxPlus>(\"Cms.ViewRd\",\n        connect: [appEntities, valConverterLazy, cultureResolver, dataToFormatLight, qDefBuilder])\n{\n    /// <summary>\n    /// Helper class to get information about views, especially for selecting them based on the url identifier\n    /// </summary>\n    /// <param name=\"View\"></param>\n    /// <param name=\"Name\"></param>\n    /// <param name=\"UrlIdentifier\"></param>\n    /// <param name=\"IsRegex\"></param>\n    /// <param name=\"MainKey\"></param>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public record ViewInfoForPathSelect(IView View, string Name, string UrlIdentifier, bool IsRegex, string MainKey);\n\n    private List<IEntity> ViewEntities => _viewDs.Get(() => AppWorkCtx.AppReader.GetPiggyBackPropExpiring(\n            () => appEntities.New(AppWorkCtx)\n                .Get(AppConstants.TemplateContentType)\n                .ToList()\n        ).Value\n    )!;\n    private readonly GetOnce<List<IEntity>> _viewDs = new();\n\n    /// <summary>\n    /// Get all the views.\n    /// </summary>\n    /// <returns></returns>\n    /// <remarks>\n    /// Never cache this result in PiggyBack, as it has a service which would expire later on.\n    /// </remarks>\n    public List<IView> GetAll() =>\n        _all ??= [.. ViewEntities\n            .Select(e => ViewOfEntity(e, e.EntityId))\n            .OrderBy(e => e.Name)];\n\n    private List<IView>? _all;\n\n    public IEnumerable<IView> GetRazor() => GetAll().Where(t => t.IsRazor);\n    public IEnumerable<IView> GetToken() => GetAll().Where(t => !t.IsRazor);\n\n    /// <summary>\n    /// Get all views which have a url identifier, to be used for view-switching\n    /// </summary>\n    /// <returns></returns>\n    public List<ViewInfoForPathSelect> GetForViewSwitch()\n    {\n        var l = Log.Fn<List<ViewInfoForPathSelect>>();\n\n        // get from cache if available or generate\n        var views = AppWorkCtx.AppReader.GetPiggyBackPropExpiring(() => GetAll()\n            .Where(t => !string.IsNullOrEmpty(t.UrlIdentifier))\n            .Select(v =>\n            {\n                var urlIdentifier = v.UrlIdentifier.ToLowerInvariant();\n                var isRegex = urlIdentifier.EndsWith(\"/.*\");\n                var mainParam = isRegex\n                    ? urlIdentifier.Substring(0, urlIdentifier.Length - 3)\n                    : urlIdentifier;\n\n                // Only save the necessary information in the PiggyBack\n                // Never save the View or the ViewInfoForPathSelect, as that would also preserve an old Service used in the View\n                return new\n                {\n                    v.Entity,\n                    v.Name,\n                    urlIdentifier,\n                    isRegex,\n                    MainParam = mainParam.ToLowerInvariant()\n                };\n            })\n            .ToList()\n        );\n\n        var final = views.Value\n            .Select(v => new ViewInfoForPathSelect(\n                ViewOfEntity(v.Entity, v.Entity.EntityId, withServices: true, isReplacement: true),\n                v.Name, v.urlIdentifier, v.isRegex, v.MainParam)\n            )\n            .ToList();\n\n        return l.Return(final, $\"all: {GetAll().Count}; switchable: {final.Count}; wasCached: {views.IsCached}\");\n    }\n\n\n    public IView Get(int templateId)\n        => ViewOfEntity(ViewEntities.GetOne(templateId), templateId, withServices: true);\n\n    public IView Get(Guid guid)\n        => ViewOfEntity(ViewEntities.GetOne(guid), guid, withServices: true);\n\n    public IView Recreate(IView originalWithoutServices) => \n           ViewOfEntity(originalWithoutServices.Entity, originalWithoutServices.Id, withServices: true);\n\n    private IView ViewOfEntity(IEntity? templateEntity, object templateId, bool withServices = true, bool isReplacement = false)\n        => templateEntity == null\n            ? throw new(\"The template with id '\" + templateId + \"' does not exist.\")\n            : new View(templateEntity, [cultureResolver.CurrentCultureCode], withServices ? qDefBuilder : null, isReplaced: isReplacement);\n\n\n    // todo: check if this call could be replaced with the normal ContentTypeController.Get to prevent redundant code\n    public IList<ContentTypeUiInfo> GetContentTypesWithStatus(string appPath, string appPathShared)\n    {\n        var templates = GetAll().ToList();\n        var visible = templates.Where(t => !t.IsHidden).ToList();\n\n        var valConverter = valConverterLazy.Value;\n\n        var result = AppWorkCtx.AppReader.ContentTypes\n            .OfScope(ScopeConstants.Default) \n            .Where(ct => templates.Any(t => t.ContentType == ct.NameId)) // must exist in at least 1 template\n            .OrderBy(ct => ct.Name)\n            .Select(ct =>\n            {\n                var details = ct.DetailsOrNull();\n                var thumbnail = valConverter.ToValue(details?.Icon);\n                if (AppIconHelpers.HasAppPathToken(thumbnail))\n                    thumbnail = AppIconHelpers.AppPathTokenReplace(thumbnail, appPath, appPathShared);\n                return new ContentTypeUiInfo {\n                    StaticName = ct.NameId,\n                    Name = ct.Name,\n                    IsHidden = visible.All(t => t.ContentType != ct.NameId),   // must check if *any* template is visible, otherwise tell the UI that it's hidden\n                    Thumbnail = thumbnail,\n                    Properties = ((details as ICanBeEntity)?.Entity).NullOrGetWith(dataToFormatLight.Convert),\n                    IsDefault = ct.Metadata.HasType(KnownDecorators.IsDefaultDecorator),\n                };\n            })\n            .ToList();\n        return result;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Apps/Sys.Work/WorkViewsMod.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.Work;\n\n// Note: Unclear if this worker makes any sense, or should just be dropped.\n// ATM it only has delete-entity without real view-specific logic\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WorkViewsMod(GenWorkPlus<WorkViews> appViews, GenWorkDb<WorkEntityDelete> entityDelete)\n    : WorkUnitBase<IAppWorkCtx>(\"AWk.EntCre\", connect: [appViews, entityDelete])\n{\n\n    public bool DeleteView(int viewId)\n    {\n        // really get template first, to be sure it is a template\n        var template = appViews.New(AppWorkCtx).Get(viewId);\n        return entityDelete.New(AppWorkCtx).Delete(template.Id);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Blocks/Sys.Views/IView.cs",
    "content": "﻿using ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Blocks.Sys.Views;\n\n/// <summary>\n/// Defines a view configuration which is loaded from an entity.\n/// </summary>\n[PrivateApi(\"Was Public API till v17, but I can't see any reason why people would have used it since it would go through ICmsView\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IView: IModelFromEntityBasic, IHasMetadata\n{\n    /// <summary>\n    /// The name, localized in the current UI language.\n    /// </summary>\n    string Name { get; }\n\n    /// <summary>\n    /// An optional unique identifier for this View configuration. \n    /// </summary>\n    /// <remarks>New in 12.02</remarks>\n    string Identifier { get; }\n        \n    /// <summary>\n    /// An optional Icon for this View configuration. Would be used instead of the file name in the App-folder. WIP\n    /// </summary>\n    /// <remarks>New in 12.02</remarks>\n    string Icon { get; }\n\n    /// <summary>\n    /// Path to the template\n    /// </summary>\n    string Path { get; }\n\n\n    [PrivateApi] string ContentType { get; }\n    [PrivateApi] IEntity? ContentItem { get; }\n    [PrivateApi] string PresentationType { get; }\n    [PrivateApi] IEntity? PresentationItem { get; }\n    [PrivateApi] string HeaderType { get; }\n    [PrivateApi] IEntity? HeaderItem { get; }\n    [PrivateApi] string HeaderPresentationType { get; }\n    [PrivateApi] IEntity? HeaderPresentationItem { get; }\n\n    /// <summary>\n    /// The underlying type name of the template, ATM they are unfortunately hard-coded as \"C# Razor\" and \"Token\"\n    /// </summary>\n    string Type { get; }\n\n    /// <summary>\n    /// Determine if we should hide this view/template from the pick-UI.\n    /// </summary>\n    bool IsHidden { get; }\n\n    /// <summary>\n    /// Translates the location to tell us if it's a shared view (the template is in a shared location)\n    /// </summary>\n    // TODO: SHOULD PROBABLY rename to something else like IsGlobal ? \n    bool IsShared { get; }\n\n    /// <summary>\n    /// Determines if the view should behave as a list or not. Views that are lists also\n    /// have Header configuration and treat content in a special way. \n    /// </summary>\n    [PrivateApi] bool UseForList { get; }\n\n    // Publishing was removed a long time ago, commented out v21\n    //[PrivateApi] bool PublishData { get; }\n    //[PrivateApi] string StreamsToPublish { get; }\n\n    /// <summary>\n    /// The query which provides data to this view. \n    /// </summary>\n    [PrivateApi]\n    IEntity? QueryRaw { get; }\n\n    /// <summary>\n    /// The query attached to this view (if one was specified)\n    /// </summary>\n    /// <returns>A query object or null</returns>\n    QueryDefinition? Query { get; }\n\n    /// <summary>\n    /// An identifier which could occur in the url, causing the view to automatically switch to this one. \n    /// </summary>\n    [PrivateApi] string UrlIdentifier { get; }\n\n    /// <summary>\n    /// Returns true if the current template uses Razor\n    /// </summary>\n    [PrivateApi]\n    bool IsRazor { get; }\n\n    /// <summary>\n    /// Contains the polymorph edition name for this view, which changes\n    /// what path is loaded.\n    /// </summary>\n    [PrivateApi] string? Edition { get; set; }\n\n    [PrivateApi] string? EditionPath { get; set; }\n\n\n    [PrivateApi(\"WIP 12.02\")]\n    IEntity? Resources { get; }\n\n    [PrivateApi(\"WIP 12.02\")]\n    IEntity? Settings { get; }\n\n    /// <summary>\n    /// Determines if search indexing should be disabled - so this view will not provide search data.\n    /// </summary>\n    bool SearchIndexingDisabled { get; }\n        \n    /// <summary>\n    /// The external class which should be compiled / used to customize search.\n    /// \n    /// In future this could do more, which is why it's called ViewController and not SearchController or something. \n    /// </summary>\n    string ViewController { get; }\n\n    /// <summary>\n    /// Streams which should be included in the search index.\n    /// If empty will use all streams.\n    /// CSV\n    /// </summary>\n    string SearchIndexingStreams { get; }\n\n    /// <summary>\n    /// Inform the system that this view was replaced, e.g. because of the url-parameter\n    /// </summary>\n    [PrivateApi]\n    bool IsReplaced { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Blocks/Sys.Views/View.cs",
    "content": "﻿using ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.Metadata;\nusing static ToSic.Sxc.Blocks.Sys.Views.ViewConstants;\n\n\nnamespace ToSic.Sxc.Blocks.Sys.Views;\n\n[PrivateApi(\"Internal implementation - don't publish\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record View : ViewConfiguration, IView\n{\n    public View(IEntity templateEntity,\n        string?[] languageCodes,\n        Generator<QueryDefinitionFactory>? qDefBuilder,\n        bool isReplaced = false) : base(templateEntity, languageCodes)\n    {\n        //LookupLanguages = languageCodes;\n        _qDefBuilder = qDefBuilder;\n        IsReplaced = isReplaced;\n    }\n\n    private IEntity? Child(string key)\n        => Entity.Children(key).FirstOrDefault();\n\n\n    //public string Name => GetThis(\"unknown name\");\n\n    //public string Identifier => GetThis(\"\");\n        \n    //public string Icon => GetThis(\"\");\n\n    //public string Path => GetThis(\"\");\n\n    //public string ContentType => Get(FieldContentType, \"\");\n\n    //public IEntity? ContentItem => Child(FieldContentDemo);\n\n    //public string PresentationType => Get(FieldPresentationType, \"\");\n\n    //public IEntity? PresentationItem => Child(FieldPresentationItem);\n\n    //public string HeaderType => Get(FieldHeaderType, \"\");\n\n    //public IEntity? HeaderItem => Child(FieldHeaderItem);\n\n    //public string HeaderPresentationType => Get(FieldHeaderPresentationType, \"\");\n\n    //public IEntity? HeaderPresentationItem => Child(FieldHeaderPresentationItem);\n\n    //public string Type => GetThis(\"\");\n\n    //public bool IsHidden => GetThis(false);\n\n    //public bool IsShared => _isShared ??= AppAssetsHelpers.IsShared(Get(FieldLocation, AppAssetsHelpers.AppInSite));\n    //private bool? _isShared;\n\n    //public bool UseForList => GetThis(false);\n\n    public IEntity? QueryRaw => QueryInfo.QueryEntity;\n\n    public QueryDefinition? Query => QueryInfo.Definition;\n\n    private (IEntity? QueryEntity, QueryDefinition? Definition) QueryInfo => _queryInfo.Get(() =>\n    {\n        var queryRaw = Child(FieldPipeline);\n        var query = queryRaw != null\n            ? (_qDefBuilder ?? throw new ArgumentException(\n                @\"Query Definition builder is null. View is probably from PiggyBack cache. To use it, you must first Recreate it with the WorkViews\",\n                nameof(_qDefBuilder))\n            ).New().Create(Entity.AppId, queryRaw)\n            : null;\n        return (queryRaw, query);\n    });\n\n    private readonly GetOnce<(IEntity? QueryEntity, QueryDefinition? Definition)> _queryInfo = new();\n    private readonly Generator<QueryDefinitionFactory>? _qDefBuilder;\n\n\n    //public string UrlIdentifier => Get(FieldNameInUrl, \"\");\n\n    /// <summary>\n    /// Returns true if the current template uses Razor\n    /// </summary>\n    public bool IsRazor => Type == TypeRazorValue;\n\n    public string? Edition { get; set; }\n\n    public string? EditionPath { get; set; }\n\n    //public IEntity? Resources => Child(FieldResources);\n\n    //public IEntity? Settings => Child(FieldSettings);\n\n    /// <inheritdoc />\n    //public bool SearchIndexingDisabled => Get(FieldSearchDisabled, false);\n\n    ///// <inheritdoc />\n    //public string ViewController => Get(FieldViewController, \"\");\n\n    ///// <inheritdoc />\n    //public string SearchIndexingStreams => Get(FieldSearchStreams, \"\");\n\n    public bool IsReplaced { get; }\n\n    public IMetadata Metadata => Entity.Metadata;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Blocks/Sys.Views/ViewConfiguration.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Apps.Sys.Assets;\nusing static ToSic.Sxc.Blocks.Sys.Views.ViewConstants;\n\n\nnamespace ToSic.Sxc.Blocks.Sys.Views;\n\n[PrivateApi(\"Internal implementation - don't publish\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record ViewConfiguration : ModelFromEntityBasic // , IView\n{\n    public const string ContentTypeNameId = AppConstants.TemplateContentType;\n    public const string ContentTypeName = AppConstants.TemplateContentType;\n\n    // Temp, empty constructor...\n    public ViewConfiguration() {}\n\n    public ViewConfiguration(IEntity templateEntity, string?[] languageCodes) : base(templateEntity)\n    {\n        LookupLanguages = languageCodes;\n    }\n\n    private IEntity? Child(string key)\n        => Entity.Children(key).FirstOrDefault();\n\n\n    public string Name => GetThis(\"unknown name\");\n\n    public string Identifier => GetThis(\"\");\n        \n    public string Icon => GetThis(\"\");\n\n    public string Path => GetThis(\"\");\n\n    public string ContentType => Get(FieldContentType, \"\");\n\n    public IEntity? ContentItem => Child(FieldContentDemo);\n\n    public string PresentationType => Get(FieldPresentationType, \"\");\n\n    public IEntity? PresentationItem => Child(FieldPresentationItem);\n\n    public string HeaderType => Get(FieldHeaderType, \"\");\n\n    public IEntity? HeaderItem => Child(FieldHeaderItem);\n\n    public string HeaderPresentationType => Get(FieldHeaderPresentationType, \"\");\n\n    public IEntity? HeaderPresentationItem => Child(FieldHeaderPresentationItem);\n\n    public string Type => GetThis(\"\");\n\n    public bool IsHidden => GetThis(false);\n\n    public bool IsShared => _isShared ??= AppAssetsHelpers.IsShared(Get(FieldLocation, AppAssetsHelpers.AppInSite));\n    private bool? _isShared;\n\n    public bool UseForList => GetThis(false);\n\n    // Publishing was removed a long time ago, commented out v21\n    //public bool PublishData => GetThis(false);\n    //public string StreamsToPublish => GetThis(\"\");\n\n\n    public string UrlIdentifier => Get(FieldNameInUrl, \"\");\n\n    ///// <summary>\n    ///// Returns true if the current template uses Razor\n    ///// </summary>\n    //public bool IsRazor => Type == TypeRazorValue;\n\n    //public string? Edition { get; set; }\n\n    //public string? EditionPath { get; set; }\n\n    public IEntity? Resources => Child(FieldResources);\n\n    public IEntity? Settings => Child(FieldSettings);\n\n    /// <inheritdoc />\n    public bool SearchIndexingDisabled => Get(FieldSearchDisabled, false);\n\n    /// <inheritdoc />\n    public string ViewController => Get(FieldViewController, \"\");\n\n    /// <inheritdoc />\n    public string SearchIndexingStreams => Get(FieldSearchStreams, \"\");\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Blocks/Sys.Views/ViewConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys.Views;\n\ninternal class ViewConstants\n{\n    internal const string FieldContentType = \"ContentTypeStaticName\";\n    internal const string FieldContentDemo = \"ContentDemoEntity\";\n    internal const string FieldPresentationType = \"PresentationTypeStaticName\";\n    internal const string FieldPresentationItem = \"PresentationDemoEntity\";\n    internal const string FieldHeaderType = \"ListContentTypeStaticName\";\n    internal const string FieldHeaderItem = \"ListContentDemoEntity\";\n    internal const string FieldHeaderPresentationType = \"ListPresentationTypeStaticName\";\n    internal const string FieldHeaderPresentationItem = \"ListPresentationDemoEntity\";\n\n    internal const string FieldLocation = \"Location\";\n    internal const string FieldUseList = \"UseForList\";\n\n    internal const string FieldPipeline = \"Pipeline\";\n    internal const string FieldNameInUrl = \"ViewNameInUrl\";\n    internal const string TypeRazorValue = \"C# Razor\";\n        \n    // new / WIP 12.02\n    internal const string FieldSettings = \"Settings\";\n    internal const string FieldResources = \"Resources\";\n    internal const string FieldViewController = \"ViewController\";\n    internal const string FieldSearchDisabled = \"SearchIndexingDisabled\";\n    internal const string FieldSearchStreams = \"SearchIndexingStreams\";\n\n    // kind of almost unused, deprecated stuff\n    internal const string FieldPublishEnable = \"PublishData\";\n    internal const string FieldPublishStreams = \"StreamsToPublish\";\n\n\n    /// <summary>\n    /// Old fake field name for adding a toolbar\n    /// </summary>\n    internal const string FieldToolbar = \"Toolbar\";\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Blocks/Sys.Views/ViewExtensions.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys.Views;\n\ninternal static class ViewExtensions\n{\n    [PrivateApi]\n    internal static string GetTypeStaticName(this IView view, string groupPart)\n        => groupPart.ToLowerInvariant() switch\n        {\n            ViewParts.ContentLower => view.ContentType,\n            ViewParts.PresentationLower => view.PresentationType,\n            ViewParts.ListContentLower => view.HeaderType,\n            ViewParts.ListPresentationLower => view.HeaderPresentationType,\n            _ => throw new NotSupportedException(\"Unknown group part: \" + groupPart)\n        };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Blocks/Sys.Views/ViewParts.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys.Views;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ViewParts\n{\n    public const string ViewFieldInContentBlock = \"Template\";\n    public const string TemplateContentType = \"Template\";\n\n    public const string Content = \"Content\";\n    public const string ContentLower = \"content\";\n\n    public const string Presentation = \"Presentation\";\n    public const string PresentationLower = \"presentation\";\n\n\n\n    private const string ListContent = \"ListContent\";\n    public const string ListContentLower = \"listcontent\";\n    public static readonly string FieldHeader = ListContent;\n\n    // todo: not implemented in tokens just yet\n    public const string Header = \"Header\";\n    public const string HeaderLower = \"header\";\n\n    public const string ListPresentation = \"ListPresentation\";\n    public const string ListPresentationLower = \"listpresentation\";\n    public static readonly string FieldHeaderPresentation = \"ListPresentation\";\n\n    // Stream Names\n    public static string StreamHeader = Header;\n    public static string StreamHeaderOld = ListContent;\n        \n\n    #region Field Pairs for saving / loading\n\n    public static string[] ContentPair = [Content, Presentation];\n    public static string[] HeaderPair = [FieldHeader, FieldHeaderPresentation];\n\n    public static string[] PickFieldPair(string primaryField)\n    {\n        var lowered = primaryField.ToLowerInvariant();\n        switch (lowered)\n        {\n            case ContentLower:\n            case PresentationLower:\n                return ContentPair;\n            case ListContentLower:\n            case ListPresentationLower:\n            case HeaderLower:   // new in 11.13, trying to move away from ListContent naming\n                return HeaderPair;\n            default:\n                throw new($\"tried to find field pair, but input was '{primaryField}' - can't figure it out.\");\n        }\n    }\n\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Compatibility (disabled)/ToSic.SexyContent.Interfaces.IApp.cs",
    "content": "﻿// 2025-05-14 2dm\n// This was introduced to ensure compatibility with the old namespace\n// but AFAIK all old code was never typed, so it would probably never have been using this interface anyhow!\n//\n// #TryToDropOldIApp: 2025-05-14 2dm v20 try to remove this for now\n\n\n//#if NETFRAMEWORK\n//// ReSharper disable once CheckNamespace\n//namespace ToSic.SexyContent.Interfaces\n//{\n//    /// <summary>\n//    /// This is the old interface with the \"wrong\" namespace\n//    /// We'll probably need to keep it alive so old code doesn't break\n//    /// But this interface shouldn't be enhanced or documented publicly\n//    /// </summary>\n\n//    [ShowApiWhenReleased(ShowApiMode.Never)]\n//    public interface IApp: Eav.Apps.IApp\n//    {\n//        dynamic Configuration { get;  }\n\n//        dynamic Settings { get;  }\n\n//        dynamic Resources { get;  }\n\n//        string Path { get; }\n\n//        string PhysicalPath { get; }\n\n//        string Thumbnail { get; }\n//    }\n//}\n//#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Compatibility (disabled)/ToSic.SexyContent.Interfaces.IAppData.cs",
    "content": "﻿// 2025-05-14 2dm\n// This was introduced to ensure compatibility with the old namespace\n// but AFAIK all old code was never typed, so it would probably never have been using this interface anyhow!\n//\n// #TryToDropOldIAppData: 2025-05-14 2dm v20 try to remove this for now\n\n//#if NETFRAMEWORK\n\n\n//// ReSharper disable once CheckNamespace\n//namespace ToSic.SexyContent.Interfaces\n//{\n//    // Note: we can't just remove this.\n//    // Code which uses it, would work because it simulates the Eav IAppData\n//    // So even if it looks unused, it could still be used\n//    [Obsolete(\"please use the Eav.Apps.Interfaces.IAppData instead\")]\n//    [ShowApiWhenReleased(ShowApiMode.Never)]\n//    public interface IAppData : Eav.Apps.IAppData { }\n//}\n\n//#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Data/ITypedQuery.cs",
    "content": "﻿using ToSic.Sxc.Apps;\n\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// Query object from <see cref=\"IAppTyped.GetQuery\"/> an App in **Typed** mode, with quick get-and-convert-helpers such as `GetAll` or `GetOne`.\n/// </summary>\n/// <remarks>\n/// WIP v20\n/// </remarks>\n[WorkInProgressApi(\"Still WIP\")]\npublic interface ITypedQuery: IDataSource\n{\n    #region GetAll, GetOne, GetMany WIP v17.02+\n\n    /// <summary>\n    /// Get all data from the app of the specified type in a stream with the same name (or \"Default\").\n    /// It will detect the expected stream name based on the name of the class used.\n    /// \n    /// So in most cases you will not add any parameters except for the type parameter `T`.\n    /// This is usually a type of your `AppCode.Data` namespace.\n    /// </summary>\n    /// <typeparam name=\"T\">The type to convert to - usually inheriting `Custom.Data.CustomItem` or `CustomModel`</typeparam>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"typeName\">_optional_ type name which is used as the **stream** name when retrieving the data, as each stream contains entities of one type.</param>\n    /// <param name=\"nullIfNotFound\">if set, will return null if the type doesn't exist - default is empty list.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// WIP in v20.00\n    /// </remarks>\n    IEnumerable<T>? GetAll<T>(NoParamOrder npo = default, string? typeName = default, bool nullIfNotFound = default)\n        where T : class, IModelFromData;\n\n    /// <summary>\n    /// Get a single item from the query with the specified ID.\n    /// </summary>\n    /// <typeparam name=\"T\">The type to convert to - usually inheriting `Custom.Data.CustomItem` or `CustomModel`</typeparam>\n    /// <param name=\"id\">the ID as an int</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"skipTypeCheck\">allow get even if the Content-Type of the item with the ID doesn't match the type specified in the parameter T</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// WIP in v20.00\n    /// </remarks>\n    T? GetOne<T>(int id, NoParamOrder npo = default, bool skipTypeCheck = false)\n        where T : class, IModelFromData;\n\n\n    /// <summary>\n    /// Get a single item from the query with the specified GUID.\n    /// </summary>\n    /// <typeparam name=\"T\">The type to convert to - usually inheriting `Custom.Data.CustomItem` or `CustomModel`</typeparam>\n    /// <param name=\"guid\">the ID as GUID</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"skipTypeCheck\">allow get even if the Content-Type of the item with the ID doesn't match the type specified in the parameter T</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// WIP in v20.00\n    /// </remarks>\n    T? GetOne<T>(Guid guid, NoParamOrder npo = default, bool skipTypeCheck = false)\n        where T : class, IModelFromData;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Data/Sys.Typed/DataSourceToTypedHelper.cs",
    "content": "﻿using ToSic.Eav.Models.Sys;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing static ToSic.Eav.DataSource.DataSourceConstants;\n\nnamespace ToSic.Sxc.Data.Sys.Typed;\ninternal class DataSourceToTypedHelper(ICodeDataFactory cdf, IDataSource dataSource, ILog? parentLog) : HelperBase(parentLog, \"Sxc.Ds2Typ\")\n{\n\n    internal IEnumerable<T>? GetAllShared<T>(string? typeName, bool nullIfNotFound, bool useDefaultIfNameNotSetAndNotFound)\n        where T : class, IModelFromData\n    {\n        var autoUseDefault = typeName == null && useDefaultIfNameNotSetAndNotFound;\n\n        var streamNames = typeName == null\n            ? DataModelAnalyzer.GetStreamNameList<T>()\n            : autoUseDefault\n                ? [typeName, StreamDefaultName]\n                : [typeName];\n\n        // Get the list - will be null if not found\n        IDataStream? list = null;\n        foreach (var name in streamNames)\n            list ??= dataSource.GetStream(name, nullIfNotFound: true);\n\n        // New for queries - which may use a type name but still expect to use the default stream\n        if (list == null && autoUseDefault)\n            list ??= dataSource.GetStream(StreamDefaultName, nullIfNotFound: true);\n\n        // If we didn't find anything yet, then we must now try to re-access the stream\n        // but in a way which will throw an exception with the expected stream names\n        if (list == null && !nullIfNotFound)\n            list = dataSource.GetStream(string.Join(\",\", streamNames), nullIfNotFound: false);\n\n        return list == null\n            ? null\n            : cdf.AsCustomList<T>(source: list, npo: default, nullIfNull: nullIfNotFound);\n    }\n\n    /// <inheritdoc />\n    public T? GetOne<T>(int id, NoParamOrder npo, bool skipTypeCheck)\n        where T : class, IModelFromData\n        => cdf.GetOne<T>(() => dataSource.List.GetOne(id), id, skipTypeCheck);\n\n    /// <inheritdoc />\n    public T? GetOne<T>(Guid id, NoParamOrder npo, bool skipTypeCheck)\n        where T : class, IModelFromData\n        => cdf.GetOne<T>(() => dataSource.List.GetOne(id), id, skipTypeCheck);\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Data/Sys.Typed/TypedQuery.cs",
    "content": "﻿using ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Sys.Typed;\n\ninternal class TypedQuery(DataSourceBase.Dependencies services, LazySvc<QueryFactory> queryBuilder, LazySvc<QueryDefinitionFactory> queryDefBuilder)\n    : Query(services, queryBuilder, queryDefBuilder), ITypedQuery\n{\n    #region Cdf Attachments and setup ToTypedHelper\n\n    internal TypedQuery Setup(ICodeDataFactory cdfConnected)\n    {\n        ToTypedHelper = new(cdfConnected, this, Log);\n        return this;\n    }\n\n    [field: AllowNull, MaybeNull]\n    private DataSourceToTypedHelper ToTypedHelper { get => field ?? throw new($\"{nameof(ToTypedHelper)} not set\"); set; }\n\n    #endregion\n\n    /// <inheritdoc />\n    IEnumerable<T>? ITypedQuery.GetAll<T>(NoParamOrder npo, string? typeName, bool nullIfNotFound)\n        => ToTypedHelper.GetAllShared<T>(typeName, nullIfNotFound, useDefaultIfNameNotSetAndNotFound: true);\n\n    /// <inheritdoc />\n    T? ITypedQuery.GetOne<T>(int id, NoParamOrder npo, bool skipTypeCheck)\n        where T : class\n        => ToTypedHelper.GetOne<T>(id, npo, skipTypeCheck);\n\n    /// <inheritdoc />\n    T? ITypedQuery.GetOne<T>(Guid guid, NoParamOrder npo, bool skipTypeCheck)\n        where T : class\n        => ToTypedHelper.GetOne<T>(guid, npo, skipTypeCheck);\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/DataSources/AppEditions.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\n\nnamespace ToSic.Sxc.DataSources;\n\n[PrivateApi]\n[VisualQuery(\n    NiceName = \"App Editions\",\n    NameId = \"6cce259b-bf0c-4752-b451-a3eb04825350\",\n    NameIds = [\"System.AppEditions\"], // for use in the front end\n    Type = DataSourceType.System,\n    Audience = Audience.System,\n    DataConfidentiality = DataConfidentiality.System,\n    UiHint = \"App Editions\")]\npublic class AppEditions : CustomDataSource\n{\n    public AppEditions(Dependencies services, LazySvc<IAppJsonConfigurationService> appJsonService)\n        : base(services, logName: \"App.EditDS\", connect: [appJsonService])\n    {\n        ProvideOutRaw(\n            () => GetList(appJsonService.Value),\n            options: () => new()\n            {\n                AutoId = false,\n                TitleField = \"Name\",\n                TypeName = \"Edition\",\n            });\n    }\n\n    private IEnumerable<IRawEntity> GetList(IAppJsonConfigurationService appJsonService)\n    {\n        var l = Log.Fn<IEnumerable<IRawEntity>>();\n        var appJson = appJsonService.GetAppJson(AppId);\n\n        // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n        if (appJson?.Editions?.Count > 0)\n        {\n            l.A($\"has editions in app.json: {appJson.Editions.Count}\");\n            var list = appJson.Editions\n                .Select(s => new RawEntity(new()\n                {\n                    { \"Name\", s.Key },\n                    { \"Description\", s.Value.Description },\n                    { \"IsDefault\", s.Value.IsDefault },\n                }))\n                .ToList();\n            return l.Return(list, $\"{list.Count}\");\n        }\n\n        // default data\n        var rootEdition = new RawEntity(new()\n        {\n            { \"Name\", \"\" },\n            { \"Description\", \"Root edition\" },\n            { \"IsDefault\", true },\n        });\n        return l.Return([rootEdition], $\"editions are not specified, so using default edition data\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using ToSic.Eav.Apps;\nglobal using ToSic.Eav.Apps.Sys.Work;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Eav.DataSource;\nglobal using ToSic.Eav.Models;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Performance;\nglobal using ToSic.Sys.Utils;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/LookUp/LookUpInAppProperty.cs",
    "content": "﻿using ToSic.Eav.LookUp;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Sxc.Data;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.LookUp;\n\n/// <summary>\n/// Look up things in app-settings, app-resources etc.\n/// </summary>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"this is just fyi\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LookUpInAppProperty(string name, IApp app) : LookUpBase(name, \"LookUp in App Properties - mainly path\")\n{\n    #region Internal stuff to be able to supply sub-properties\n\n    private ILookUp? Settings\n    {\n        get\n        {\n            if (field != null || app.Settings == null)\n                return field;\n            var dynEnt = app.Settings as IDynamicEntity;\n            // ReSharper disable once StringLiteralTypo\n            return field = new LookUpInEntity(\"appsettings\", dynEnt?.Entity, dynEnt?.Cdf.Dimensions);\n        }\n    }\n\n    private ILookUp? Resources\n    {\n        get\n        {\n            if (field != null || app.Resources == null)\n                return field;\n            var dynEnt = app.Resources as IDynamicEntity;\n            return field = new LookUpInEntity(\"appresources\", dynEnt?.Entity, dynEnt?.Cdf.Dimensions);\n        }\n    }\n\n    #endregion\n\n    /// <inheritdoc/>\n    public override string Get(string key, string strFormat)\n    {\n        key = key.ToLowerInvariant();\n        switch (key)\n        {\n            case \"path\":\n                return app.Path;\n            case \"physicalpath\":\n                return app.PhysicalPath;\n            // Maybe someday: also retrieve metadata like Folder, Name, Version\n        }\n\n        var subToken = LookUpHelpers.CheckAndGetSubToken(key);\n\n        if (!subToken.HasSubToken)\n            return string.Empty;\n\n        var subProvider = subToken.Source switch\n        {\n            \"settings\" => Settings,\n            \"resources\" => Resources,\n            _ => null\n        };\n\n        return subProvider?.Get(subToken.Rest ?? string.Empty, strFormat) ?? string.Empty;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Properties/SxcAppsAssemblyVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Code\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Services\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.WebApi\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Services/IDataService.cs",
    "content": "﻿\n\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Services on [`Kit.Data`](xref:ToSic.Sxc.Services.ServiceKit16.Data) to create DataSources in Razor.\n/// </summary>\n/// <remarks>\n/// Can also be used in external code such as Skins using Dependency Injection.\n/// New in v16.00\n/// </remarks>\n[PublicApi]\npublic interface IDataService\n{\n    #region CreateDataSource - new in v15 - make sure it's copied in identical form to IDynamicCode, ...\n\n    /// <summary>\n    /// Spawn a new <see cref=\"IDataService\"/> with specific configuration.\n    /// Uses the [Spawn New convention](xref:NetCode.Conventions.SpawnNew).\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"appIdentity\"></param>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IDataService SpawnNew(NoParamOrder npo = default,\n        IAppIdentity? appIdentity = default,\n        int zoneId = default,\n        int appId = default);\n\n    /// <summary>\n    /// Get the App DataSource containing the App Data.\n    /// The `Default` stream of this source has the data the current user is allowed to see.\n    /// So public users won't get draft data.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"parameters\">Parameters to use - as anonymous object like `new { Count = 7, Filter = 3 }`</param>\n    /// <param name=\"options\">Options how to build/construct the DataSource. </param>\n    /// <returns></returns>\n    [PublicApi]\n    IDataSource GetAppSource(NoParamOrder npo = default, object? parameters = default, object? options = default);\n\n    /// <summary>\n    /// Create a DataSource object using it's type.\n    /// This is the new, preferred way to get DataSources in v15.06+.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of DataSource, usually from [](xref:ToSic.Eav.DataSources) or [](xref:ToSic.Sxc.DataSources)</typeparam>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"attach\">Link to one or more other DataSources / streams to attach upon creation.</param>\n    /// <param name=\"parameters\">Parameters to use - as anonymous object like `new { Count = 7, Filter = 3 }`</param>\n    /// <param name=\"options\">Options how to build/construct the DataSource. </param>\n    /// <remarks>new v16.00</remarks>\n    [PublicApi]\n    T GetSource<T>(NoParamOrder npo = default,\n        IDataSourceLinkable? attach = default,\n        object? parameters = default,\n        object? options = default\n    ) where T : IDataSource;\n\n    /// <summary>\n    /// Create a DataSource object using it's name.\n    /// This is only meant for dynamically compiled DataSources which are part of the current App - a new feature in v15.10+.\n    /// For any other DataSources, use the overload which specifies the type. \n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"name\">The name of the DataSource type, which matches the file name and class in the `/DataSources/` folder.</param>\n    /// <param name=\"attach\">Link to one or more other DataSources / streams to attach upon creation.</param>\n    /// <param name=\"parameters\">Parameters to use - as anonymous object like `new { Count = 7, Filter = 3 }`</param>\n    /// <param name=\"options\">Options how to build/construct the DataSource. </param>\n    /// <param name=\"debug\">Determines if exceptions should be shown. Default is only for Developers.</param>\n    /// <remarks>new v16.00</remarks>\n    [PublicApi]\n    IDataSource GetSource(NoParamOrder npo = default,\n        string? name = default,\n        IDataSourceLinkable? attach = default,\n        object? parameters = default,\n        object? options = default,\n        bool? debug = default\n    );\n\n    /// <summary>\n    /// Get a Query from the current App.\n    /// </summary>\n    /// <param name=\"name\">Name of the query</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"attach\">Attach in-stream to the query (not yet implemented)</param>\n    /// <param name=\"parameters\">Parameters to use - as anonymous object like `new { Count = 7, Filter = 3 }`</param>\n    /// <returns></returns>\n    /// <remarks>New 16.01</remarks>\n    [PublicApi]\n    IDataSource? GetQuery(\n        string? name = default,\n        NoParamOrder npo = default,\n        IDataSourceLinkable? attach = default,\n        object? parameters = default\n    );\n\n    #endregion\n\n    /// <summary>\n    /// Create a connection-link of a data source or stream.\n    /// Mainly used for linking to a source with another name.\n    /// </summary>\n    /// <param name=\"source\">The source (stream or data source)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"inName\">What In-Stream it should connect to. Optional, default is \"Default\"</param>\n    /// <param name=\"outName\">What Out-stream it should use from the source. Optional, default is \"Default\" (rarely changed).</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Introduced in v21.04, previous API (rarely used) has not worked for a while.\n    /// </remarks>\n    IDataSourceLink CreateLink(IDataSourceLinkable source,\n        NoParamOrder npo = default,\n        string? inName = default,\n        string? outName = default\n    );\n\n    /// <summary>\n    /// Merge many links to usually attach to a new data source.\n    /// Use this when you want to attach more than one source to a new DataSource.\n    /// </summary>\n    /// <param name=\"sources\">One or more sources. Make sure they specify different In names - usually using <see cref=\"CreateLink\"/>.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Introduced in v21.04, previous API (rarely used) has not worked for a while.\n    /// </remarks>\n    IDataSourceLink CombineLinks(params IDataSourceLinkable[] sources);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Services/Sys.DataService/DataSourceOptionsMs.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.LookUp.Sys.Engines;\n\nnamespace ToSic.Sxc.Services.Sys.DataService;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class DataSourceOptionsMs(IAppIdentity? identity, Func<ILookUpEngine?>? getLookup)\n    : ServiceBase(SxcLogName + \"DtOptH\")\n{\n    private ILookUpEngine? LookUpEngine => _lookupEngine.Get(() => getLookup?.Invoke());\n    private readonly GetOnce<ILookUpEngine?> _lookupEngine = new();\n\n    public IDataSourceOptions SafeOptions(object? dsParams, object? options, bool identityRequired = false)\n    {\n        var l = Log.Fn<IDataSourceOptions>($\"{nameof(options)}: {options}, {nameof(identityRequired)}: {identityRequired}\");\n        // Ensure we have a valid AppIdentity\n        var appIdentity = identity\n                          ?? (options as IDataSourceOptions)?.AppIdentityOrReader\n                          ?? (identityRequired\n                              ? throw new(\n                                  \"Creating a DataSource requires an AppIdentity which must either be supplied by the context, \" +\n                                  $\"(the Module / WebApi call) or provided manually by spawning a new {nameof(IDataService)} with the AppIdentity using 'New(...).\")\n                              : new AppIdentity(0, 0)\n                          );\n        var opts = new DataSourceOptionConverter().Create(new DataSourceOptions\n        {\n            // Convert to a pure identity, in case the original object was much more\n            AppIdentityOrReader = appIdentity.PureIdentity(),\n            LookUp = LookUpEngine,\n            Immutable = true,\n        }, options);\n\n        // Check if parameters were supplied, if yes, they override any values in the existing options (16.01)\n        var parameters = new DataSourceOptionConverter().TryGetParams(dsParams: dsParams, throwIfNull: false, throwIfNoMatch: true);\n        return parameters != null\n            ? l.Return(opts with { MyConfigValues = parameters }, \"with parameters\")\n            : l.Return(opts, \"without parameters\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Services/Sys.DataService/GetQueryMs.cs",
    "content": "﻿using ToSic.Eav.DataSource.Query.Sys;\n\nnamespace ToSic.Sxc.Services.Sys.DataService;\n\n/// <summary>\n/// Get-Query Micro Service\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class GetQueryMs<TQuery>: ServiceBase where TQuery : Query\n{\n    private readonly LazySvc<QueryManager<TQuery>> _queryManager;\n    private readonly DataSourceOptionsMs _optionsMs;\n\n    internal GetQueryMs(LazySvc<QueryManager<TQuery>> queryManager, DataSourceOptionsMs optionsMs, ILog parentLog): base(SxcLogName + \".DtGqMs\")\n    {\n        _queryManager = queryManager;\n        _optionsMs = optionsMs;\n        this.LinkLog(parentLog);\n    }\n\n    public TQuery? GetQuery(\n        string? name = default,\n        NoParamOrder npo = default,\n        IDataSourceLinkable? attach = default,\n        object? parameters = default)\n    {\n        var l = Log.Fn<TQuery>($\"{name}, {nameof(parameters)}: {(parameters == null ? \"null\" : \"not null\")}\");\n\n\n        // If no in-source was provided, make sure that we create one from the current app\n        var fullOptions = _optionsMs.SafeOptions(parameters, null, true /*, options: options*/);\n\n        // #WipAppIdentityOrReader must become not null\n        var query = _queryManager.Value.TryGetQuery(fullOptions.AppIdentityOrReader! /* WIP */, name, fullOptions.LookUp!, 3);\n\n        if (query == null)\n            return l.ReturnNull(\"query was null\");\n\n        if (parameters == null)\n            return l.Return(query, \"query, no parameters\");\n\n        var paramsDic = parameters.ObjectToDictionary();\n        foreach (var param in paramsDic)\n            query.Params(param.Key, param.Value);\n\n        return l.Return(query, \"with params\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/StartupSxcApps.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Apps.Sys.Api01;\nusing ToSic.Sxc.Apps.Sys.AppTyped;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Apps.Sys.Work;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcApps\n{\n\n    public static IServiceCollection AddSxcApps(this IServiceCollection services)\n    {\n        // App Dependencies\n        services.TryAddTransient<SxcAppBase.Dependencies>();\n\n        // Configuration objects\n        services.TryAddTransient<GlobalPaths>();\n\n        services.TryAddTransient<App>();\n\n        services.TryAddTransient<IAppTyped, AppTyped>();\n        services.TryAddTransient(typeof(IAppTyped<,>), typeof(AppTyped<,>));    // new v17\n\n        services.TryAddTransient<AppFolderInitializer>();\n\n        services.TryAddTransient<AppIconHelpers>();\n\n        // Runtimes - new: better architecture v16.07+\n        //services.TryAddTransient<WorkBlocks>();\n        //services.TryAddTransient<WorkBlocksMod>();\n        services.TryAddTransient<WorkViewsMod>();\n        services.TryAddTransient<WorkViews>();\n        services.TryAddTransient<WorkApps>();\n        services.TryAddTransient<WorkAppsRemove>();\n\n        // Simple DataController - registration was missing\n        services.TryAddTransient<SimpleDataEditService>();\n\n        return services;\n    }\n\n    public static IServiceCollection AddSxcAppsFallbacks(this IServiceCollection services)\n    {\n        services.TryAddTransient<IAppDataConfigProvider, AppDataConfigProviderUnknown>();\n\n        return services;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/Sys.ExecutionContext/ExecutionContextExtensions.cs",
    "content": "﻿using IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\npublic static class ExecutionContextExtensions\n{\n    /// <summary>\n    /// Special helper to ensure that AppState is always a Sxc IApp.\n    /// There is a big risk that the code uses the Eav.Apps.IApp.\n    /// </summary>\n    public static IApp GetApp(this IExecutionContext exCtx)\n        => exCtx.GetState<IApp>();\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/ToSic.Sxc.Apps.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Apps</AssemblyName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps/ToSic.Sxc.Apps.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apps_005Capp/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apps_005Csys_005Capi01/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apps_005Csys_005Cappbase/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apps_005Csys_005Cappdata/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apps_005Csys_005Cappdata_005Cconfiguration/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=apps_005Csys_005Cpaths/@EntryIndexedValue\">False</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps.Tests/Api.Api01/SimpleDataControllerTests_IsDraft.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys.Api01;\n\nnamespace ToSic.Eav.Apps.Tests.Api.Api01;\n\n\n// ReSharper disable once InconsistentNaming\npublic class SimpleDataControllerTests_IsDraft\n{\n    private static (bool ShouldPublish, bool ShouldBranchDrafts) TestGetPublishSpecs(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var r = SimpleDataEditService.GetPublishSpecs(publishedState, existingIsPublished, writePublishAllowed,\n            new Log(\"test\"));\n        return (r.ShouldPublish, r.ShouldBranchDrafts);\n    }\n\n    /// <summary>\n    /// Scenarios when creating new.\n    /// 1.\tNo published state – result should be default,\n    /// so depending on user permissions it's published or draft.\n    /// This should be the same as previous implementation. \n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    [Theory]\n    [InlineData(null)]\n    [InlineData(\"\")]\n    [InlineData(\"null\")]\n    [InlineData(\"NULL\")]\n    [InlineData(\"NUll\")]\n    public void New_NoPublishedState(object publishedState)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState, \n            existingIsPublished: null,\n            writePublishAllowed: true);\n\n        True(published); // true is default\n        False(branch); // false because is it new one, so no branch\n    }\n\n    /// <summary>\n    /// Scenarios when creating new.\n    /// 1.\tNo published state – result should be default,\n    /// so depending on user permissions it's published or draft.\n    /// This should be the same as previous implementation. \n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    [Theory]\n    [InlineData(null)]\n    public void New_NoPublishedState_WritePublishNotAllowed(object publishedState)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: null,\n            writePublishAllowed: false);\n\n        False(published); // false because publish is not allowed\n        False(branch); // false because is it new one, so no branch\n    }\n\n    /// <summary>\n    /// Scenarios when creating new.\n    /// 2.\t\"true\", 1 etc. – should be published, assuming user permissions allow this.\n    /// Basically it should not set the published for saving at all, as the default is true,\n    /// and permissions may not work if you set it.\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    [Theory]\n    [InlineData(true)]\n    [InlineData(1)]\n    [InlineData(\"true\")]\n    [InlineData(\"TRUE\")]\n    [InlineData(\"TRue\")]\n    public void New_True(object publishedState)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: null,\n            writePublishAllowed: true);\n\n        True(published); // true (and publish is allowed)\n        False(branch); // false because is it new one, so no branch\n    }\n\n    /// <summary>\n    /// Scenarios when creating new.\n    /// 2.\t\"true\", 1 etc. – should be published, assuming user permissions allow this.\n    /// Basically it should not set the published for saving at all, as the default is true,\n    /// and permissions may not work if you set it.\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    [Theory]\n    [InlineData(true)]\n    public void New_True_WritePublishNotAllowed(object publishedState)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: null,\n            writePublishAllowed: false);\n\n        False(published); // false because publish is not allowed\n        False(branch); // false because is it new one, so no branch\n    }\n\n    /// <summary>\n    /// Scenarios when creating new.\n    /// 3.\tFalse, 0, etc. – should not be published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    [Theory]\n    [InlineData(false)]\n    [InlineData(0)]\n    [InlineData(\"false\")]\n    [InlineData(\"FALSE\")]\n    [InlineData(\"FAlse\")]\n    public void New_False(object publishedState)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: null,\n            writePublishAllowed: true);\n\n        False(published); // false and publish is allowed\n        False(branch); // false because is it new one, so no branch\n    }\n\n    /// <summary>\n    /// Scenarios when creating new.\n    /// 3.\tFalse, 0, etc. – should not be published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    [Theory]\n    [InlineData(false)]\n    public void New_False_WritePublishNotAllowed(object publishedState)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: null,\n            writePublishAllowed: false);\n\n        False(published); // false because publish is not allowed\n        False(branch); // false because is it new one, so no branch\n    }\n\n    /// <summary>\n    /// Existing data which is published\n    /// 1.\tNo published state – unchanged, shouldn't set at all, because if user permisisons restrict to draft-only,\n    /// that should happen automatically. Result\n    /// a.\tIf user is allowed to publish, it's published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(null, true, true)]\n    public void ExistingPublished_NoPublishedState(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        True(published); // true because existing is published and save publish is allowed\n        False(branch); // false because is it allowed to save publish\n    }\n\n    /// <summary>\n    /// Existing data which is published\n    /// 1.\tNo published state – unchanged, shouldn't set at all, because if user permisisons restrict to draft-only,\n    /// that should happen automatically. Result\n    /// b.\tIf user is draft-only, it's should draft/fork\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(null, true, false)]\n    public void ExistingPublished_NoPublishedState_WritePublishNotAllowed(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false because save publish is not allowed\n        True(branch); // true because save publish is not allowed\n    }\n\n    /// <summary>\n    /// Existing data which is published\n    /// 2.\tTrue, 1, etc. – unchanged, shouldn't set at all, again because of user permissions. Result\n    /// a.\tIf user is allowed to publish, it's published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(true, true, true)]\n    public void ExistingPublished_True(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        True(published); // true (and save publish is allowed)\n        False(branch); // false because save publish is allowed\n    }\n\n    /// <summary>\n    /// Existing data which is published\n    /// 2.\tTrue, 1, etc. – unchanged, shouldn't set at all, again because of user permissions. Result\n    /// b.\tIf user is draft-only, it's should draft/fork\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(true, true, false)]\n    public void ExistingPublished_True_WritePublishNotAllowed(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false because save publish is not allowed\n        True(branch); // true because save publish is not allowed\n    }\n\n    /// <summary>\n    /// Existing data which is published\n    /// 3.\tFalse: depending on user permissions. Result\n    /// b.\tIf user is allowed to change published (full write permissions), then this should result in no publish, no branch\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(false, true, true)]\n    public void ExistingPublished_False(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false (also save publish is allowed)\n        False(branch); // false because save publish is allowed\n    }\n\n    /// <summary>\n    /// Existing data which is published\n    /// 3.\tFalse: depending on user permissions. Result\n    /// a.\tIf user can only create draft, then it should branch, as the user is not allowed to affect published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(false, true, false)]\n    public void ExistingPublished_False_WritePublishNotAllowed(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false because save publish is not allowed\n        True(branch); // true because save publish is not allowed\n    }\n\n    /// <summary>\n    /// Existing data which is published\n    /// 4.\t\"draft\" – result always draft and no published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(\"draft\", true, true)]\n    public void ExistingPublished_Draft(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false (even that publish is allowed)\n        True(branch); // true because result always draft\n    }\n\n    /// <summary>\n    /// Existing data which is published\n    /// 4.\t\"draft\" – result always draft and no published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(\"draft\", true, false)]\n    public void ExistingPublish_Draft_WritePublishNotAllowed(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false because save publish is not allowed\n        True(branch); // true because save publish is not allowed\n    }\n\n    /// <summary>\n    /// Existing data which is draft ONLY\n    /// 1.\tNo state: unchanged, should remain draft\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(null, false, true)]\n    [InlineData(null, false, false)]\n    public void ExistingDraft_NoPublishedState(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false, because it is draft\n        False(branch); // false (it is already draft)\n    }\n\n    /// <summary>\n    /// Existing data which is draft ONLY\n    /// 2.\tTrue, 1, etc. – should save changes and publish\n    /// b.\tIf user is allowed to save published, then publish should happen\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(true, false, true)]\n    public void ExistingDraft_True(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        True(published); // true because it is allowed to save publish\n        False(branch); // false because it is allowed to save publish\n    }\n\n    /// <summary>\n    /// Existing data which is draft ONLY\n    /// 2.\tTrue, 1, etc. – should save changes and publish\n    /// a.\tIf user is only allowed to create drafts, then publishing should not happen, draft only\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(true, false, false)]\n    public void ExistingDraft_True_WritePublishNotAllowed(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false because it is not allowed to save publish\n        False(branch); // false because it already a draft\n    }\n\n    /// <summary>\n    /// Existing data which is draft ONLY\n    /// 3.\tFalse, 0, etc. – Result always draft and no published\n    ///  </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(false, false, true)]\n    [InlineData(false, false, false)]\n    public void ExistingDraft_False(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false because no publish\n        False(branch); // false because it is already draft\n    }\n\n    /// <summary>\n    /// Existing data which is draft ONLY\n    /// 4.\t\"draft\" – result always draft and no published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(\"DRAFT\", false, true)]\n    [InlineData(\"DRaft\", false, false)]\n    public void ExistingDraft_Draft(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        False(published); // false because no publish\n        False(branch); // false because it is already draft\n    }\n\n    /// <summary>\n    /// Existing Data which is draft and published\n    /// 1.\tNo state: unchanged, the updated data should only be in the draft\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(null, false, true)]\n    [InlineData(null, false, false)]\n    public void ExistingDraftAndPublish_NoPublishedState(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        // the updated data should only be in the draft\n        False(published); // false, because it is draft\n        False(branch); // false (it is already draft)\n    }\n\n    /// <summary>\n    /// Existing Data which is draft and published\n    /// 2.\tTrue: Result \n    /// a.\tIf user may write published, then all is now published\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(true, false, true)]\n    public void ExistingDraftAndPublish_True(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        // draft become published\n        True(published); // true because it is allowed to save publish\n        False(branch); // false because it is allowed to save publish\n    }\n\n    /// <summary>\n    /// Existing Data which is draft and published\n    /// 2.\tTrue: Result \n    /// b.\tIf user may not do that, it's ignored, draft is updated only\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(true, false, false)]\n    public void ExistingDraftAndPublish_True_WritePublishNotAllowed(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n            \n        // draft is updated only\n        False(published); // false because it is not allowed to save publish\n        False(branch); // false because it is already a draft\n    }\n\n    /// <summary>\n    /// Existing Data which is draft and published\n    /// 3.\tFalse: Result based on permissions\n    /// a.\tUser may change published: all is now unpublished\n    /// b.\tUser may not change published: ignore; update the draft only\n    ///  </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(false, false, true)]\n    [InlineData(false, false, false)]\n    public void ExistingDraftAndPublish_False(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n            \n        // publish is unpublished (or draft update only)\n        False(published); // false because no publish\n        False(branch); // false because it is already draft\n    }\n\n    /// <summary>\n    /// Existing Data which is draft and published\n    /// 4.\t\"draft\" Result always draft and published, only draft was updated\n    /// </summary>\n    /// <param name=\"publishedState\"></param>\n    /// <param name=\"existingIsPublished\"></param>\n    /// <param name=\"writePublishAllowed\"></param>\n    [Theory]\n    [InlineData(\"DRAFT\", false, true)]\n    [InlineData(\"DRaft\", false, false)]\n    public void ExistingDraftAndPublish_Draft(object publishedState, bool? existingIsPublished, bool writePublishAllowed)\n    {\n        var (published, branch) = TestGetPublishSpecs(\n            publishedState: publishedState,\n            existingIsPublished: existingIsPublished,\n            writePublishAllowed: writePublishAllowed);\n\n        // only draft was updated\n        False(published); // false because no publish\n        False(branch); // false because it is already draft\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps.Tests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using ToSic.Sys.Logging;\nglobal using static Xunit.Assert;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Apps.Tests/ToSic.Sxc.Apps.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForTestCode.props\" />\n\n  <!--<Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />-->\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\" />\n    <!--<ProjectReference Include=\"..\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\" />-->\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <!--<ProjectReference Include=\"..\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Various.SystemTests\\ToSic.Sxc.Various.SystemTests.csproj\" />-->\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/BlockBuildingConstants.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\n\nnamespace ToSic.Sxc.Blocks;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockBuildingConstants\n{\n    public const string InputTypeForContentBlocksField = \"entity-content-blocks\";\n    internal const string CbPropertyApp = \"App\";\n    internal const string CbPropertyTitle = AttributeNames.TitleNiceName;\n    internal const string CbPropertyContentGroup = \"ContentGroup\";\n\n    #region Error Messages\n\n    public static string ErrorInstallationNotOk = \"InstallationNotOk\";\n\n    public static string ErrorDataIsMissing = \"DataIsMissing\";\n\n    public static string ErrorRendering = \"Rendering\";\n\n    public static string ErrorGeneral = \"General\";\n\n    public static string ErrorHtmlMarker = \"<!--2sxc:error-->\";\n\n    public static string ErrorAppIsUnhealthy = \"AppIsUnhealthy\";\n    \n    public static string AppIsUnhealthy = \"2sxc app is unhealthy. \";\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/ModuleSettingNames.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks;\n\n/// <summary>\n/// Contains special constants for setting-names stored in the Dnn/Oqtane module settings.\n/// </summary>\n/// <remarks>\n/// Note that for historical reasons, the keys where different in Dnn and Oqtane until 2025-08-19.\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ModuleSettingNames\n{\n    // Important note: always use static-readonly, NOT constant\n    // This prevents the value from being compiled into other DLLs,\n    // So if a value ever changes, it will always be retrieved from here\n\n\n    /// <summary>\n    /// This setting will store what App is to be shown on a module. \n    /// The value must contain the Guid/Name (so the word \"Default\" or the app guid)\n    /// </summary>\n    /// <remarks>\n    /// \"EavApp\" in Oqtane until 2025-08-19\n    /// </remarks>\n    public static readonly string AppName = \"TsDynDataApp\";\n\n    /// <summary>\n    /// This key is for storing the setting, which content-group (bundle/block) is to be shown in the module.\n    /// The value will be a GUID. \n    /// </summary>\n    /// <remarks>\n    /// \"EavContentGroup\" in Oqtane until 2025-08-19\n    /// </remarks>\n    public static readonly string ContentGroup = \"TsDynDataContentGroup\";\n\n    /// <summary>\n    /// This is used to store the Guid of the Preview-View in the module settings.\n    /// The preview is only used till the App has a real content-group attached,\n    /// after which the content-group will provide the correct view. \n    /// </summary>\n    /// <remarks>\n    /// \"EavPreview\" in Oqtane until 2025-08-19\n    /// </remarks>\n    public static readonly string PreviewView = \"TsDynDataPreview\";\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/BlockConfiguration.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\n// ReSharper disable ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record BlockConfiguration: ModelFromEntityBasic, IAppIdentity\n{\n    public  int ZoneId { get; }\n    public  int AppId { get; }\n\n    public IEntity? PreviewViewEntity { get; }\n\n    public IBlockIdentifier? BlockIdentifierOrNull { get; set; }\n\n    private readonly Generator<QueryDefinitionFactory> _qDefBuilder;\n\n    public BlockConfiguration(IEntity? entity, IAppIdentity appIdentity, IEntity? previewViewEntity, Generator<QueryDefinitionFactory> qDefBuilder, string languageCode, ILog parentLog):\n        base(entity!)\n    {\n        parentLog.SubLogOrNull(\"Blk.Config\").A(\"Entity is \" + (entity == null ? \"\" : \"not\") + \" null\");\n        LookupLanguages = [languageCode];\n        _qDefBuilder = qDefBuilder;\n        ZoneId = appIdentity.ZoneId;\n        AppId = appIdentity.AppId;\n        PreviewViewEntity = previewViewEntity;\n    }\n        \n    internal BlockConfiguration WarnIfMissingData() =>\n        Entity != null\n            ? this\n            : throw new(\"BlockConfiguration entity is null. \" +\n                        \"This usually happens when you are duplicating a site, and have not yet imported the other content/apps. \" +\n                        \"If that is your issue, check 2sxc.org/help?tag=export-import\");\n\n    /// <summary>\n    /// Returns true if a content group entity for this group really exists\n    /// Means for example, that the app can't be changed anymore\n    /// </summary>\n    public bool Exists => Entity != null!;\n\n    internal bool DataIsMissing = false;\n\n\n    #region View stuff\n\n    /// <summary>\n    /// The view as it is in the configuration.\n    /// This can be different from the view which is actually used,\n    /// as it could be replaced by a different view because of url-parameter.\n    /// </summary>\n    public IView? View\n    {\n        get\n        {\n            if (field != null)\n                return field;\n\n            // if we're previewing another template, look that up\n            var viewEntity = PreviewViewEntity\n                             ?? Entity\n                                 ?.Children(ViewParts.ViewFieldInContentBlock)\n                                 .FirstOrDefault();\n            return field = viewEntity == null\n                ? null\n                : new View(viewEntity, LookupLanguages, _qDefBuilder);\n        }\n    }\n\n    #endregion\n\n    #region Retrieve the lists - either as object or by the type-indexer\n\n    /// <summary>\n    /// Content is a bit special, it must always return a list with at least one null-item\n    /// </summary>\n    public IList<IEntity?> Content\n    {\n        get\n        {\n            if (Entity == null!)\n                return [null];\n            var list = Entity.Children(ViewParts.Content).ToListOpt();\n            return list.Count > 0\n                ? list\n                : [null];\n        }\n    }\n\n    [field: AllowNull, MaybeNull]\n    public IList<IEntity?> Presentation => field ??= Entity?.Children(ViewParts.Presentation).ToListOpt() ?? [];\n\n    public IList<IEntity?> Header => Entity?.Children(ViewParts.FieldHeader).ToListOpt() ?? [];\n\n    public IList<IEntity?> HeaderPresentation => Entity?.Children(ViewParts.ListPresentation).ToListOpt() ?? [];\n\n    public IList<IEntity> this[string type] =>\n        type.ToLowerInvariant() switch\n        {\n            ViewParts.ContentLower => Content,\n            ViewParts.PresentationLower => Presentation,\n            ViewParts.ListContentLower => Header,\n            ViewParts.ListPresentationLower => HeaderPresentation,\n            _ => throw new(\"Type \" + type + \" not allowed\")\n        };\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/BlockFeaturesHelpers.cs",
    "content": "﻿using ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\n\nnamespace ToSic.Sxc.Blocks.Sys;\npublic class BlockFeaturesHelpers\n{\n    public static List<IPageFeature> BlockFeatures(IBlock block, ILog log)\n        => !block.BlockFeatureKeys.Any()\n            ? []\n            : ((ContextOfBlock)block.Context).PageServiceShared.PageFeatures.GetWithDependents(block.BlockFeatureKeys, log);\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/BlockGeneratorHelpers.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Apps.Sys.Work;\nusing ToSic.Sxc.Blocks.Sys.Work;\nusing ToSic.Sxc.DataSources.Sys;\nusing ToSic.Sxc.LookUp.Sys;\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\npublic class BlockGeneratorHelpers(GenWorkPlus<WorkViews> workViews, GenWorkPlus<WorkBlocks> appBlocks, LazySvc<BlockDataSourceFactory> bdsFactoryLazy, LazySvc<App> appLazy)\n    : ServiceBase(\"Eav.BlGenH\", connect: [bdsFactoryLazy, appLazy, workViews, appBlocks])\n{\n    internal LazySvc<App> AppLazy { get; } = appLazy;\n    public GenWorkPlus<WorkViews> WorkViews { get; } = workViews;\n    public GenWorkPlus<WorkBlocks> AppBlocks { get; } = appBlocks;\n\n    public BlockSpecs CompleteInit(BlockSpecs currentSpecs, IBlock? parentOrNull, IBlockIdentifier blockIdentifier, int blockId)\n    {\n        var l = Log.Fn<BlockSpecs>();\n\n        var specs = currentSpecs with\n        {\n            ParentBlockOrNull = parentOrNull,\n            RootBlock = parentOrNull?.RootBlock!, // if parent is null, this is the root block\n\n            ContentBlockId = blockId,\n        };\n\n        l.A($\"parent#{specs.ParentId}, content-block#{specs.ContentBlockId}, z#{specs.ZoneId}, a#{specs.AppId}\");\n\n        switch (specs.AppId)\n        {\n            // If specifically no app found, end initialization here\n            // Means we have no data, and no BlockBuilder\n            case AppConstants.AppIdNotFound or EavConstants.NullId:\n                return l.Return(specs, \"stop: app & data are missing\");\n            // If no app yet, stop now with BlockBuilder created\n            case KnownAppsConstants.AppIdEmpty:\n                return l.Return(specs, $\"stop a:{specs.AppId}, container:{specs.ParentId}, content-group:{specs.ContentBlockId}\");\n        }\n\n        l.A(\"Real app specified, will load App object with Data\");\n\n        // note: requires EditAllowed, which isn't ready till App is created\n        // 2dm #???\n        var appWorkCtxPlus = WorkViews.CtxSvc.ContextPlus(specs.PureIdentity());\n        var config = AppBlocks\n            .New(appWorkCtxPlus)\n            .GetOrGeneratePreviewConfig(blockIdentifier);\n\n        specs = specs with\n        {\n            Configuration = config,\n        };\n\n        // handle cases where the content group is missing - usually because of incomplete import\n        if (config.DataIsMissing)\n            return l.Return(specs, $\"DataIsMissing a:{specs.AppId}, container:{specs.ParentId}, content-group:{config.Id}\");\n\n        // Get App for this block\n        var app = AppLazy.Value;\n        app.Init(specs.Context.Site, specs.PureIdentity(), new SxcAppDataConfigSpecs { BlockForLookupOrNull = specs });\n        specs = specs with\n        {\n            AppOrNull = app,\n        };\n        l.A(\"App created\");\n\n        // use the content-group template, which already covers stored data + module-level stored settings\n        var view = new BlockViewLoader(Log)\n            .PickView(specs, config.View, WorkViews.New(appWorkCtxPlus));\n\n        if (view == null)\n            return l.Return(specs, $\"no view; a:{specs.AppId}, container:{specs.ParentId}, content-group:{config.Id}\");\n\n        specs = specs with\n        {\n            ViewOrNull = view,\n        };\n\n        // Do this after adding view, as it requires the view to continue\n        specs = specs with\n        {\n            Data = bdsFactoryLazy.Value.GetContextDataSourceFromView(specs, specs.AppOrNull.TryGetAppLookUpEngineOrNull()),\n        };\n\n        return l.Return(specs, $\"ok a:{specs.AppId} , container: {specs.ParentId}, content-group:{config.Id}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/BlockInstanceConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys;\n\npublic class BlockInstanceConstants\n{\n    [PrivateApi] internal const string InstanceLookupName = \"module\";\n    [PrivateApi] internal const string ModuleIdKey = \"Id\";\n    [PrivateApi] internal const string FieldInstanceId = \"InstanceId\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/BlockOfEntity.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic sealed class BlockOfEntity(BlockGeneratorHelpers helpers, LazySvc<AppFinder> appFinderLazy)\n    : ServiceBase(\"CB.Ent\", connect: [appFinderLazy, helpers])\n{\n    #region Init\n\n    public IBlock GetBlockOfEntity(IBlock parentBlock, IEntity? blockEntity, int contentBlockId = -1)\n    {\n        var l = Log.Fn<BlockSpecs>($\"{nameof(contentBlockId)}:{contentBlockId}; {nameof(blockEntity)}:{blockEntity?.EntityId}\", timer: true);\n\n        // Get the content-block definition if we only have the ID\n        // The block ID. Is usually negative to mark inner-content-blocks\n        blockEntity ??= parentBlock.App.Data.List.GetOne(Math.Abs(contentBlockId))!;\n\n        var (isContentApp, blockId) = LoadBlockDefinition(appFinderLazy, parentBlock.ZoneId, blockEntity);\n        var ctx = (IContextOfBlock)parentBlock.Context.Clone(Log);\n        ctx.ResetApp(blockId);\n\n        // Must override previous AppId, as that was of the container-block\n        // but the current instance can be of another block\n        var specs = new BlockSpecs\n        {\n            Context = ctx,\n            AppId = blockId.AppId,\n            ZoneId = parentBlock.ZoneId,\n            IsContentApp = isContentApp,\n            IsInnerBlock = true,\n        };\n\n        specs = helpers.CompleteInit(specs, parentBlock, blockId, -blockEntity.EntityId);\n\n        return l.Return(specs);\n    }\n\n    #endregion\n\n\n    #region ContentBlock Definition Entity\n\n    /// <summary>\n    /// Get all the specs for this content-block from the entity\n    /// </summary>\n    /// <returns></returns>\n    private static (bool IsContentApp, IBlockIdentifier BlockIdentifier) LoadBlockDefinition(LazySvc<AppFinder> appFinderLazy, int zoneId, IEntity blockDefinition)\n    {\n        var appNameId = blockDefinition.Get(BlockBuildingConstants.CbPropertyApp, fallback: \"\");\n        var isContentApp = appNameId == KnownAppsConstants.DefaultAppGuid;\n\n        var temp = blockDefinition.Get(BlockBuildingConstants.CbPropertyContentGroup, fallback: \"\");\n#pragma warning disable CA1806\n        Guid.TryParse(temp, out var contentGroupGuid);\n\n        temp = blockDefinition.Get(ViewParts.TemplateContentType, fallback: \"\");\n        Guid.TryParse(temp, out var previewTemplateGuid);\n#pragma warning restore CA1806\n\n        var appId = appFinderLazy.Value.FindAppId(zoneId, appNameId);\n        var identifier = new BlockIdentifier(zoneId, appId, appNameId, contentGroupGuid, previewTemplateGuid);\n        return (isContentApp, identifier);\n    }\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/BlockOfModule.cs",
    "content": "﻿using ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\n/// <summary>\n/// Official constructor, must call Init afterward\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic sealed class BlockOfModule(BlockGeneratorHelpers helpers) : ServiceBase(\"CB.Mod\", connect: [helpers])\n{\n    /// <summary>\n    /// Create a module-content block\n    /// </summary>\n    /// <param name=\"ctx\"></param>\n    ///// <param name=\"overrideParams\">optional override parameters</param>\n    public IBlock GetBlockOfModule(IContextOfBlock ctx)\n    {\n        var l = Log.Fn<BlockSpecs>(timer: true);\n        var appIdentity = ctx.Module.BlockIdentifier;\n        var specs = new BlockSpecs\n        {\n            Context = ctx,\n            AppId = appIdentity.AppId,\n            ZoneId = appIdentity.ZoneId,\n\n            IsContentApp = ctx.Module.IsContent,\n            IsInnerBlock = false,\n        };\n        specs = helpers.CompleteInit(specs, null, ctx.Module.BlockIdentifier, ctx.Module.Id);\n\n        return l.ReturnAsOk(specs);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/BlockSpecs.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.DataSource;\nusing ToSic.Sxc.Blocks.Sys.Problems;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Context.Sys;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\n/// <summary>\n/// INTERNAL: A unit / block of output in a CMS. \n/// </summary>\n[PrivateApi(\"Was InternalApi_DoNotUse_... till v17\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record BlockSpecs : IBlock\n{\n    public required int AppId { get; init; }\n    public required int ZoneId { get; init; }\n\n    public required bool IsInnerBlock { get; init; }\n\n    /// <summary>\n    /// The module ID or the parent-content-block id, probably not ideal here, but not sure\n    /// </summary>\n    public int ParentId => Context.Module?.Id ?? 0;\n\n    public List<ProblemReport> Problems { get; init; } = [];\n\n    public int ContentBlockId { get; init; }\n\n    #region Values related to the current unit of content / the view\n        \n    /// <summary>\n    /// The context we're running in, with tenant, container etc.\n    /// </summary>\n    public required IContextOfBlock Context { get; init; }\n\n    /// <summary>\n    /// The view which will be used to render this block\n    /// </summary>\n    public IView View => ViewOrNull ?? throw new($\"View is not available and can't be accessed. Rode running early on accessing the view, must first check for {nameof(ViewIsReady)}\");\n    public IView? ViewOrNull { get; /*init;*/ set; }\n    public bool ViewIsReady => ViewOrNull != null;\n\n    public BlockConfiguration Configuration\n    {\n        get => _configuration ?? throw new($\"BlockConfiguration is not available and can't be accessed. Code running early on must first check for {nameof(ConfigurationIsReady)}\");\n        init => _configuration = value;\n    }\n\n    private readonly BlockConfiguration? _configuration;\n    public bool ConfigurationIsReady => _configuration != null;\n\n    /// <inheritdoc />\n    public IApp App => AppOrNull ?? throw new($\"App (and Data) are missing and can't be accessed. Code running early on must first check for {nameof(AppIsReady)} or use {nameof(AppOrNull)}\");\n    \n    /// <inheritdoc />\n    public bool AppIsReady => AppOrNull != null;\n\n    /// <inheritdoc />\n    public IApp? AppOrNull { get; init; }\n\n    /// <inheritdoc />\n    public IDataSource Data\n    {\n        get => _data ?? throw new NullReferenceException($\"Can't access {nameof(Data)}, it was never properly initialized.\");\n        set => _data = value;\n    }\n    private IDataSource? _data;\n\n    public bool DataIsReady => _data != null;\n\n    public required bool IsContentApp { get; init; }\n\n    #endregion\n\n    public bool ContentGroupExists => _configuration?.Exists ?? false; // This check may happen before Configuration is accessed, so we need the null check\n\n    /// <summary>\n    /// All the keys / features which were added in this block; in case the block should also modify its behavior.\n    /// </summary>\n    public List<string> BlockFeatureKeys { get; init; } = [];\n\n    /// <summary>\n    /// The parent block of this block, if any.\n    /// </summary>\n    [PrivateApi]\n    public IBlock? ParentBlockOrNull { get; init; }\n\n    /// <summary>\n    /// The root block of this block - can be the same as `this`.\n    /// </summary>\n    [PrivateApi]\n    public IBlock RootBlock\n    {\n        get => field ??\n               this; // never store the result, as the fallback should still return me-object in future if never set.\n        init;\n    }\n\n    public List<IDependentApp> DependentApps { get; } = [];\n\n    /// <summary>\n    /// Must override ToString, otherwise any ToString() will result in properties being accessed, which throw because they are not available yet.\n    /// </summary>\n    public override string ToString()\n        => $\"Block with App: {this.Show()}; IsInner: {IsInnerBlock}; IsContent: {IsContentApp}; View: {ViewIsReady} {ViewOrNull}; Parent: {ParentId}; Block: {ContentBlockId}\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/BlockViewLoader.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys.Work;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\n/// <summary>\n/// This contains the logic to decide which view a block will have\n/// Basically the one which is configured, or a replacement based on the url\n/// </summary>\ninternal class BlockViewLoader(ILog parentLog) : HelperBase(parentLog, \"Blk.ViewLd\")\n{\n    internal IView? PickView(BlockSpecs block, IView? configView, WorkViews views)\n    {\n        // #1 skip on ContentApp (Url-View-Switching is not a feature there) or if not relevant or not yet initialized\n        if (block.IsContentApp || !block.AppIsReady)\n            return configView;\n\n        // #2 Change Template if URL contains the part in the metadata \"ViewNameInUrl\"\n        var viewFromUrlParam = TryGetViewBasedOnUrlParams(block.Context, views);\n        return viewFromUrlParam ?? configView;\n    }\n\n\n    private IView? TryGetViewBasedOnUrlParams(IContextOfBlock context, WorkViews views)\n    {\n        var l = Log.Fn<IView>(\"template override - check\");\n\n        // Get the parameters from the page, and exit early if there are none\n        var parameters = context.Page.Parameters;\n        if (parameters == null || parameters.Count == 0)\n            return l.ReturnNull(\"no params\");\n\n        // Get all views which can switch, and exit early if there are none\n        var templatesWithUrlIdentifier = views.GetForViewSwitch();\n        if (templatesWithUrlIdentifier.Count == 0)\n            return l.ReturnNull(\"no templates with view-switch\");\n\n        // Log url parameters and convert to dictionary for use below\n        var urlParameterString = string.Join(\", \", parameters.Select(pair => $\"'{pair.Key}'='{pair.Value}'\"));\n        l.A($\"url params: {parameters.Count} - {urlParameterString}\");\n\n        var urlParameterDict = parameters\n            .ToDictionary(\n                pair => pair.Key?.ToLowerInvariant() ?? \"\",\n                pair => $\"{pair.Key}/{pair.Value}\".ToLowerInvariant()\n            );\n\n        // check all views if they apply here\n        foreach (var (finalView, name, urlIdentifier, isRegex, mainKey) in templatesWithUrlIdentifier)\n        {\n            l.A($\"checking: '{urlIdentifier}'; IsRegex: {isRegex}; MainKey: '{mainKey}'\");\n            var foundMatch = isRegex\n                ? urlParameterDict.ContainsKey(mainKey)         // match details/.*\n                : urlParameterDict.ContainsValue(mainKey);      // match view/details\n\n            if (!foundMatch) continue;\n\n            //var originalWithoutServices = set.View;\n            //var finalView = views.Recreate(originalWithoutServices);\n            return l.Return(finalView, \"template override: \" + name);\n        }\n\n        return l.ReturnNull(\"template override: none\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/IBlock.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource;\nusing ToSic.Sxc.Blocks.Sys.Problems;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Context.Sys;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\n/// <summary>\n/// INTERNAL: A unit / block of output in a CMS. \n/// </summary>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IBlock: IAppIdentity\n{\n    public bool IsInnerBlock { get; }\n\n    /// <summary>\n    /// The module ID or the parent-content-block id, probably not ideal here, but not sure\n    /// </summary>\n    [PrivateApi]\n    int ParentId { get; }\n\n    [PrivateApi]\n    List<ProblemReport> Problems { get; }\n\n    [PrivateApi]\n    int ContentBlockId { get; }\n\n    #region Values related to the current unit of content / the view\n        \n    /// <summary>\n    /// The context we're running in, with tenant, container etc.\n    /// </summary>\n    IContextOfBlock Context { get; }\n\n    /// <summary>\n    /// The view which will be used to render this block\n    /// </summary>\n    IView View { get; }\n    bool ViewIsReady { get; }\n\n    [PrivateApi(\"unsure if this should be public, or only needed to initialize it?\")]\n    BlockConfiguration Configuration { get; }\n\n    /// <summary>\n    /// The app this block is running in\n    /// </summary>\n    IApp App { get; }\n\n    /// <summary>\n    /// The DataSource which delivers data for this block (will be used by the [](xref:ToSic.Sxc.Engines.IEngine) together with the View)\n    /// </summary>\n    IDataSource Data { get; }\n\n    [PrivateApi(\"might rename this some time\")]\n    bool IsContentApp { get; }\n\n    #endregion\n\n    [PrivateApi(\"naming not final\")]\n    bool ContentGroupExists { get; }\n\n    /// <summary>\n    /// All the keys / features which were added in this block; in case the block should also modify its behavior.\n    /// </summary>\n    /// <remarks>\n    /// Must be a real List, since it will be modified.\n    /// </remarks>\n    [PrivateApi(\"WIP 13.x do get/set if toolbar/context are used\")]\n    List<string> BlockFeatureKeys { get; }\n\n    /// <summary>\n    /// The parent block of this block, if any.\n    /// </summary>\n    [PrivateApi]\n    IBlock? ParentBlockOrNull { get; }\n\n    /// <summary>\n    /// The root block of this block - can be the same as `this`.\n    /// </summary>\n    [PrivateApi]\n    public IBlock RootBlock { get; }\n\n    /// <summary>\n    /// The App is ready when it was added. Other parts (View, Data) may still be missing.\n    /// </summary>\n    bool AppIsReady { get; }\n\n    /// <summary>\n    /// Data is ready when both App and View are available - and then the Data was also initialized.\n    /// </summary>\n    bool DataIsReady { get; }\n\n    bool ConfigurationIsReady { get; }\n\n    IApp? AppOrNull { get; }\n\n    /// <summary>\n    /// This list is only populated on the root builder. Child builders don't actually use this.\n    /// </summary>\n    /// <remarks>\n    /// Must be a real List, because we will add things to it later.\n    /// In the future, should be modified to be read only list, but only once rendering has been improved to pass the data around in a better way.\n    /// </remarks>\n    List<IDependentApp> DependentApps { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/IDependentApp.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDependentApp\n{\n    int AppId { get; }\n    bool IsSitePrimaryApp { get; }\n\n    bool IsEnabled { get; }\n    ICollection<string> PathsToMonitor { get; }\n    List<string> CacheKeys { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/Problems/ProblemReport.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing static System.Text.Json.Serialization.JsonIgnoreCondition;\n\nnamespace ToSic.Sxc.Blocks.Sys.Problems;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ProblemReport\n{\n    // ReSharper disable InconsistentNaming\n    public enum ErrorSeverity\n    {\n        none = 0,\n        info = 1,\n        warning = 2,\n        error = 3,\n    }\n\n    public enum ErrorScope\n    {\n        view,\n        app\n    }\n    // ReSharper restore InconsistentNaming\n\n    [JsonPropertyName(\"severity\")]\n    public ErrorSeverity Severity { get; set; }\n\n    [JsonPropertyName(\"scope\")]\n    public ErrorScope Scope { get; set; }\n\n    [JsonPropertyName(\"code\")]\n    [JsonIgnore(Condition = WhenWritingDefault)]\n    public string? Code { get; set; }\n\n    [JsonPropertyName(\"message\")]\n    public string? Message { get; set; }\n\n    [JsonPropertyName(\"link\")]\n    public string? Link { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys/SpecsForLogHistory.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sys.Utils;\nusing static System.StringComparer;\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SpecsForLogHistory\n{\n    public IDictionary<string, string> BuildSpecsForLogHistory(IBlock block, IApp? app = default, string? entry = default, bool addView = true)\n    {\n        try\n        {\n            // use app provided or try to use from block\n            app ??= block?.AppOrNull;\n\n            // No context - neither blog nor App, exit\n            var specs = new Dictionary<string, string>(InvariantCultureIgnoreCase);\n            if (block == default && app == default)\n                return specs;\n\n            if (entry != default)\n                specs.Add(\"Entry\", entry);\n\n            string? bestTitle = null;\n\n            if (block != null)\n            {\n                specs.Add(nameof(block.ContentBlockId), block.ContentBlockId.ToString());\n\n                var view = block.ViewIsReady ? block.View : null; \n                if (addView && view != null)\n                {\n                    specs.Add(\"ViewId\", view.Id.ToString());\n                    specs.Add(\"ViewEdition\", view.Edition ?? \"\");\n                    specs.Add(\"ViewPath\", view.Path);\n                }\n\n                var ctx = block.Context;\n                if (ctx != null!)\n                {\n                    var site = ctx.Site;\n                    if (site != null!)\n                    {\n                        specs.Add(\"SiteId\", site.Id.ToString());\n                        specs.Add(\"SiteUrl\", site.Url);\n                    }\n\n                    var page = ctx.Page;\n                    if (page != null!)\n                    {\n                        var pageParams = page.Parameters.ToString();\n                        var pageUrl = page.Url + (string.IsNullOrEmpty(pageParams) ? \"\" : \"?\" + pageParams);\n                        specs.Add(\"PageId\", page.Id.ToString());\n                        specs.Add(\"PageUrl\", pageUrl);\n                        var urlToShow = Text.After(Text.After(pageUrl, \"//\"), \"/\")\n                                            .NullOrGetWith(v => \"/\" + v)\n                                        ?? pageUrl;\n                        bestTitle = urlToShow;\n                    }\n\n                    var module = ctx.Module;\n                    if (module != null!)\n                    {\n                        var mid = module.Id.ToString();\n                        specs.Add(\"ModuleId\", mid);\n                    }\n\n                    var usr = ctx.User;\n                    if (usr != null!)\n                    {\n                        var uid = usr.Id.ToString();\n                        specs.Add(\"UserId\", uid);\n                    }\n                }\n\n            }\n\n            if (app != null)\n            {\n                var appId = app.AppId.ToString();\n                specs.Add(nameof(app.AppId), appId);\n                specs.Add(\"AppPath\", app.Path);\n                specs.Add(\"AppName\", app.Name);\n            }\n\n            if (bestTitle != null)\n                specs.Add(LogStoreEntry.TitleKey, bestTitle);\n\n            return specs;\n        }\n        catch\n        {\n            /* fail silently */\n            return new Dictionary<string, string>(InvariantCultureIgnoreCase);\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockBuilder/IModuleAndBlockBuilder.cs",
    "content": "﻿using ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Blocks.Sys.BlockBuilder;\n\n[PrivateApi(\"internal use only\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IModuleAndBlockBuilder: IHasLog\n{\n    IBlock BuildBlock(int pageId, int moduleId);\n\n    IBlock BuildBlock<TPlatformModule>(TPlatformModule module, int? page) where TPlatformModule : class;\n\n    /// <summary>\n    /// Get the module specific to each platform.\n    /// </summary>\n    IModule GetModule(int pageId, int moduleId);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockBuilder/ModuleAndBlockBuilder.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Blocks.Sys.BlockBuilder;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class ModuleAndBlockBuilder(Generator<BlockOfModule> blockGenerator, string logPrefix, object[]? connect = default)\n    : ServiceBase($\"{logPrefix}.BnMBld\", connect: [..connect ?? [], blockGenerator]), IModuleAndBlockBuilder\n{\n    /// <summary>\n    /// Get the module specific to each platform.\n    /// </summary>\n    public abstract IModule GetModule(int pageId, int moduleId);\n\n    protected void ThrowIfModuleIsNull<TModule>(int pageId, int moduleId, TModule moduleInfo)\n    {\n        if (moduleInfo != null) return;\n        var msg = $\"Can't find module {moduleId} on page {pageId}. Maybe you reversed the ID-order?\";\n        Log.A(msg);\n        throw new(msg);\n    }\n\n    public IBlock BuildBlock(int pageId, int moduleId)\n    {\n        var l = Log.Fn<IBlock>($\"{pageId}, {moduleId}\");\n        var module = GetModule(pageId, moduleId);\n        var ctx = GetContextOfBlock(module, pageId);\n        \n        var block = blockGenerator.New().GetBlockOfModule(ctx);\n        return l.ReturnAsOk(block);\n    }\n\n    public IBlock BuildBlock<TPlatformModule>(TPlatformModule module, int? page) where TPlatformModule : class\n    {\n        var l = Log.Fn<IBlock>($\"{module}, {page}\");\n        var ctx = GetContextOfBlock(module, page);\n        var block = blockGenerator.New().GetBlockOfModule(ctx);\n        return l.Return(block);\n    }\n\n    protected abstract IContextOfBlock GetContextOfBlock(IModule module, int? pageId);\n\n    protected abstract IContextOfBlock GetContextOfBlock<TPlatformModule>(TPlatformModule module, int? pageId);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockBuilder/ModuleAndBlockBuilderUnknown.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Blocks.Sys.BlockBuilder;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ModuleAndBlockBuilderUnknown: ModuleAndBlockBuilder\n{\n    public ModuleAndBlockBuilderUnknown(WarnUseOfUnknown<ModuleAndBlockBuilderUnknown> _, Generator<BlockOfModule>bfmGenerator) : base(bfmGenerator, \"Unk\")\n    { }\n\n    public override IModule GetModule(int pageId, int moduleId)\n        => throw new NotSupportedException();\n\n    protected override IContextOfBlock GetContextOfBlock(IModule module, int? pageId)\n        => throw new NotSupportedException();\n\n    protected override IContextOfBlock GetContextOfBlock<TPlatformModule>(TPlatformModule module, int? pageId)\n        => throw new NotSupportedException();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockEditor/BlockEditorBase.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Blocks.Sys.Work;\n\nnamespace ToSic.Sxc.Blocks.Sys.BlockEditor;\n\n// todo: create interface\n// todo: move some parts out into a BlockManagement\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract partial class BlockEditorBase : ServiceBase<BlockEditorBase.Dependencies>\n{\n    #region DI and Construction\n\n    public record Dependencies(\n        GenWorkPlus<WorkBlocks> AppBlocks,\n        GenWorkDb<WorkBlocksMod> WorkBlocksMod,\n        GenWorkDb<WorkEntityPublish> Publisher)\n        : DependenciesRecord(connect: [WorkBlocksMod, AppBlocks, Publisher]);\n\n    internal BlockEditorBase(Dependencies services, object[] connect) : base(services, \"CG.RefMan\", connect: connect)\n    { }\n\n    internal void Init(IBlock block) => Block = block;\n\n    #endregion\n\n    protected IBlock Block = null!;\n\n    #region methods which are fairly stable / the same across content-block implementations\n\n    [field: AllowNull, MaybeNull]\n    protected BlockConfiguration BlockConfiguration => field ??= Block.Configuration;\n        \n    public Guid? SaveTemplateId(int templateId, bool forceCreateContentGroup)\n    {\n        var l = Log.Fn<Guid?>($\"save template#{templateId}, CG-exists:{BlockConfiguration.Exists} forceCreateCG:{forceCreateContentGroup}\");\n\n        // if it exists or has a force-create, then write to the Content-Group, otherwise it's just a preview\n        if (BlockConfiguration.Exists || forceCreateContentGroup)\n        {\n            var existedBeforeSettingTemplate = BlockConfiguration.Exists;\n            var contentGroupGuid = Services.WorkBlocksMod\n                .New(Block.Context.AppReaderRequired)\n                .UpdateOrCreateContentGroup(BlockConfiguration, templateId);\n\n            if (!existedBeforeSettingTemplate) EnsureLinkToContentGroup(contentGroupGuid);\n\n            return l.ReturnAndLog(contentGroupGuid);\n        }\n\n        // only set preview / content-group-reference - but must use the guid\n        var templateGuid = Block.App.Data.List.GetOne(templateId)!.EntityGuid;\n        SavePreviewTemplateId(templateGuid);\n        return l.Return(null, \"only set preview, return null\");\n    }\n\n    public bool Publish(string part, int index)\n    {\n        var l = Log.Fn<bool>($\"publish part{part}, order:{index}\");\n        var contentGroup = BlockConfiguration;\n        var contEntity = contentGroup[part][index];\n        var presKey = part.ToLowerInvariant() == ViewParts.ContentLower \n            ? ViewParts.PresentationLower \n            : ViewParts.ListPresentationLower;\n        var presEntity = contentGroup[presKey][index];\n\n\n        // make sure we really have the draft item an not the live one\n        var appReader = Block.Context.AppReaderRequired;\n        var publisher = Services.Publisher.New(appReader: appReader);\n        var contDraft = contEntity.IsPublished\n            ? appReader.GetDraft(contEntity)\n            : contEntity;\n\n        if (contDraft != null)\n            publisher.Publish(contDraft.RepositoryId);\n\n        // if has presentation entity, publish that too\n        if (presEntity != null)\n        {\n            var presDraft = presEntity.IsPublished\n                ? appReader.GetDraft(presEntity)\n                : presEntity;\n            if (presDraft != null)\n                publisher.Publish(presDraft.RepositoryId);\n        }\n\n        return l.ReturnTrue();\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockEditor/BlockEditorBase_More.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys.BlockEditor;\n\npublic partial class BlockEditorBase\n{\n    // methods which the entity-implementation must customize - so it's virtual\n\n    protected abstract void SavePreviewTemplateId(Guid templateGuid);\n\n    internal abstract void SetAppId(int? appId);\n\n    internal abstract void EnsureLinkToContentGroup(Guid cgGuid);\n\n    internal abstract void UpdateTitle(IEntity titleItem);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockEditor/BlockEditorBase_Title.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys.BlockEditor;\n\npublic partial class BlockEditorBase\n{\n    internal void UpdateTitle()\n    {\n        var l = Log.Fn(\"update title\");\n\n        // check the blockConfiguration as to what should be the module title, then try to set it\n        // technically it could have multiple different groups to save in, \n        // ...but for now we'll just update the current modules title\n        // note: it also correctly handles published/unpublished, but I'm not sure why :)\n        var contentGroup = Services.AppBlocks\n            .New(Block.Context.AppReaderRequired)\n            .GetBlockConfig(BlockConfiguration.Guid);\n\n        var titleItem = contentGroup.Header.FirstOrDefault() ?? contentGroup.Content.FirstOrDefault();\n            \n        if (titleItem != null) UpdateTitle(titleItem);\n\n        l.Done();\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockEditor/BlockEditorForEntity.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\nnamespace ToSic.Sxc.Blocks.Sys.BlockEditor;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockEditorForEntity(\n    BlockEditorBase.Dependencies services,\n    GenWorkDb<WorkEntityUpdate> entityUpdate,\n    IAppsCatalog appsCatalog)\n    : BlockEditorBase(services, connect: [entityUpdate, appsCatalog])\n{\n    #region methods which the entity-implementation must customize \n\n    protected override void SavePreviewTemplateId(Guid templateGuid)\n        => Update(new()\n        {\n            {ViewParts.TemplateContentType, templateGuid.ToString()}\n        });\n\n\n    internal override void SetAppId(int? appId)\n    {\n        // 2rm 2016-04-05 added resolver for app guid here (discuss w/ 2dm, I'm not sure why the id was saved before)\n        var appName = \"\";\n        if (appId.HasValue)\n        {\n            var zoneAppId = appsCatalog.AppIdentity(appId.Value);\n            appName = appsCatalog.AppNameId(zoneAppId);\n        }\n        UpdateValue(BlockBuildingConstants.CbPropertyApp, appName);\n    }\n\n    internal override void EnsureLinkToContentGroup(Guid cgGuid)\n        => UpdateValue(BlockBuildingConstants.CbPropertyContentGroup, cgGuid.ToString()); // must pre-convert to string, as it's not a reference to an entity in the same app\n\n\n    internal override void UpdateTitle(IEntity? titleItem)\n    {\n        var title = titleItem?.GetBestTitle();\n        if (title == null)\n            return;\n        UpdateValue(BlockBuildingConstants.CbPropertyTitle, title);\n    }\n\n    #endregion\n\n    #region private helpers\n\n    private void UpdateValue(string key, object value) \n        => Update(new() { { key, value } });\n\n    private void Update(Dictionary<string, object> newValues)\n    {\n        var parentBlock = Block.ParentBlockOrNull!; // must exist on an entity-block\n        var parentBlockAppState = ((IAppWithInternal)parentBlock.App).AppReader;\n        entityUpdate.New(parentBlockAppState)\n            .UpdateParts(Math.Abs(Block.ContentBlockId), newValues, new());\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockEditor/BlockEditorForModule.cs",
    "content": "﻿using ToSic.Sxc.Integration.Modules;\n\nnamespace ToSic.Sxc.Blocks.Sys.BlockEditor;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockEditorForModule(\n    BlockEditorBase.Dependencies services,\n    LazySvc<IPlatformModuleUpdater> platformModuleUpdater)\n    : BlockEditorBase(services, connect: [platformModuleUpdater])\n{\n    private IPlatformModuleUpdater PlatformModuleUpdater => platformModuleUpdater.Value;\n\n\n    protected override void SavePreviewTemplateId(Guid templateGuid)\n        => PlatformModuleUpdater.SetPreview(Block.Context.Module.Id, templateGuid);\n\n\n    internal override void SetAppId(int? appId)\n        => PlatformModuleUpdater.SetAppId(Block.Context.Module, appId);\n\n    internal override void EnsureLinkToContentGroup(Guid cgGuid)\n        => PlatformModuleUpdater.SetContentGroup(Block.Context.Module.Id, true, cgGuid);\n\n    internal override void UpdateTitle(IEntity titleItem)\n    {\n        Log.A(\"update title\");\n        PlatformModuleUpdater.UpdateTitle(Block, titleItem);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.BlockEditor/BlockEditorSelector.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys.BlockEditor;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockEditorSelector(LazySvc<BlockEditorForModule> blkEdtForMod, LazySvc<BlockEditorForEntity> blkEdtForEnt)\n    : ServiceBase($\"{SxcLogName}.BlEdSl\", connect: [blkEdtForMod, blkEdtForEnt])\n{\n    public BlockEditorBase GetEditor(IBlock block)\n    {\n        var l = Log.Fn<BlockEditorBase>();\n        var editor = GetEditorInternal(block);\n        editor.Init(block);\n        return l.Return(editor);\n    }\n\n    private BlockEditorBase GetEditorInternal(IBlock block)\n        => block.IsInnerBlock switch\n        {\n            false => blkEdtForMod.Value,\n            true => blkEdtForEnt.Value,\n        };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.Work/WorkBlockViewsGet.cs",
    "content": "﻿using ToSic.Eav.Metadata.Sys;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Apps.Sys.Ui;\nusing ToSic.Sxc.Apps.Sys.Work;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\n// note: not sure if the final namespace should be Sxc.Apps or Sxc.Views\nnamespace ToSic.Sxc.Blocks.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WorkBlockViewsGet(GenWorkPlus<WorkViews> workViews, LazySvc<AppIconHelpers> appIconHelpers)\n    : WorkUnitBase<IAppWorkCtxPlus>(\"Cms.ViewRd\", connect: [workViews, appIconHelpers])\n{\n    [field: AllowNull, MaybeNull]\n    public List<IView> GetAll => field\n        ??= workViews.New(AppWorkCtx)\n            .GetAll()\n            .ToList();\n\n    internal IEnumerable<TemplateUiInfo> GetCompatibleViews(IBlock block)\n    {\n        List<IView> availableTemplates;\n        var blockConfiguration = block.Configuration;\n        var items = blockConfiguration.Content;\n\n        // if any items were already initialized...\n        if (items.Any(e => e != null))\n            availableTemplates = GetFullyCompatibleViews(blockConfiguration);\n\n        // if it's only nulls, and only one (no list yet)\n        else if (items.Count <= 1)\n            availableTemplates = GetAll; \n\n        // if it's a list of nulls, only allow lists\n        else\n            availableTemplates = GetAll.Where(p => p.UseForList).ToList();\n\n        var thumbnailHelper = appIconHelpers.Value;\n\n        var result = availableTemplates\n            .Select(t => new TemplateUiInfo\n            {\n                TemplateId = t.Id,\n                Name = t.Name,\n                ContentTypeStaticName = t.ContentType,\n                IsHidden = t.IsHidden,\n                Thumbnail = block.AppOrNull == null ? null : thumbnailHelper.IconPathOrNull(block.App, t, PathTypes.Link),\n                IsDefault = t.Metadata.HasType(KnownDecorators.IsDefaultDecorator),\n            })\n            .ToList();\n        return result;\n    }\n\n\n    /// <summary>\n    /// Get templates which match the signature of possible content-items, presentation etc. of the current template\n    /// </summary>\n    /// <param name=\"blockConfig\"></param>\n    /// <returns></returns>\n    private List<IView> GetFullyCompatibleViews(BlockConfiguration blockConfig)\n    {\n        var isList = blockConfig.Content.Count > 1;\n\n        var compatibleTemplates = GetAll\n            .Where(t => t.UseForList || !isList)\n            .ToList();\n\n        // Compatibility check must verify each config on the view and compare with the current blockConfig\n        compatibleTemplates = compatibleTemplates\n            .Where(t => VerifyCompatible(blockConfig.Content, t.ContentType))\n            .Where(t => VerifyCompatible(blockConfig.Presentation, t.PresentationType))\n            .Where(t => VerifyCompatible(blockConfig.Header, t.HeaderType))\n            .Where(t => VerifyCompatible(blockConfig.HeaderPresentation, t.HeaderPresentationType))\n            .ToList();\n\n        return compatibleTemplates;\n\n        bool VerifyCompatible(IList<IEntity?> list, string expectedName)\n        {\n            var firstNonNull = list.FirstOrDefault(e => e != null);\n            if (firstNonNull == null)\n                return true; // all nulls, so compatible\n            return firstNonNull.Type.NameId == expectedName;\n        }\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.Work/WorkBlocks.cs",
    "content": "﻿using System.Collections.Immutable;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\nnamespace ToSic.Sxc.Blocks.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WorkBlocks(IZoneCultureResolver cultureResolver, Generator<QueryDefinitionFactory> qDefBuilder, GenWorkPlus<WorkEntities> workEntities)\n    : WorkUnitBase<IAppWorkCtxPlus>(\"SxS.Blocks\", connect: [cultureResolver, qDefBuilder, workEntities])\n{\n    public const string BlockTypeName = \"2SexyContent-ContentGroup\";\n\n    private IImmutableList<IEntity> GetContentGroups()\n        => workEntities.New(AppWorkCtx).Get(BlockTypeName).ToImmutableOpt();\n\n    public ICollection<BlockConfiguration> AllWithView()\n    {\n        var appIdentity = AppWorkCtx.PureIdentity();\n        return GetContentGroups()\n            .Select(b =>\n            {\n                var templateGuid = b.Children(ViewParts.ViewFieldInContentBlock)\n                    .FirstOrDefault()\n                    ?.EntityGuid;\n                return templateGuid != null\n                    ? new { Entity = b, ViewGuid = templateGuid }\n                    : null;\n            })\n            .Where(p => p != null)\n            .Select(p => new BlockConfiguration(p!.Entity, appIdentity, null, qDefBuilder, cultureResolver.CurrentCultureCode, Log))\n            .ToListOpt();\n    }\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <returns>Will always return an object, even if the group doesn't exist yet. The .Entity would be null then</returns>\n    public BlockConfiguration GetBlockConfig(Guid contentGroupGuid)\n    {\n        var l = Log.Fn<BlockConfiguration>($\"get CG#{contentGroupGuid}\");\n        var groupEntity = GetContentGroups().GetOne(contentGroupGuid);\n        var found = groupEntity != null;\n        return l.Return(found\n                ? new BlockConfiguration(groupEntity, AppWorkCtx, null, qDefBuilder, cultureResolver.CurrentCultureCode, Log)\n                    .WarnIfMissingData()\n                : new(null, AppWorkCtx, null, qDefBuilder, cultureResolver.CurrentCultureCode, Log)\n                {\n                    DataIsMissing = true\n                },\n            found ? \"found\" : \"missing\");\n    }\n\n\n    public BlockConfiguration GetOrGeneratePreviewConfig(IBlockIdentifier blockId)\n    {\n        var l = Log.Fn<BlockConfiguration>($\"grp#{blockId.Guid}, preview#{blockId.PreviewView}\");\n        // Return a \"faked\" ContentGroup if it does not exist yet (with the preview templateId)\n        var createTempBlockForPreview = blockId.Guid == Guid.Empty;\n        l.A($\"{nameof(createTempBlockForPreview)}:{createTempBlockForPreview}\");\n        var result = createTempBlockForPreview\n            ? new(null,\n                AppWorkCtx,\n                AppWorkCtx.Data.List.GetOne(blockId.PreviewView),\n                qDefBuilder,\n                cultureResolver.CurrentCultureCode,\n                Log\n            )\n            : GetBlockConfig(blockId.Guid);\n        result.BlockIdentifierOrNull = blockId;\n        return l.Return(result);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Blocks/Sys.Work/WorkBlocksMod.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\nnamespace ToSic.Sxc.Blocks.Sys.Work;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WorkBlocksMod(\n    GenWorkDb<WorkFieldList> workFieldList,\n    GenWorkDb<WorkEntityCreate> workEntCreate,\n    GenWorkDb<WorkEntityUpdate> workEntUpdate)\n    : WorkUnitBase<IAppWorkCtxWithDb>(\"AWk.EntCre\", connect: [workFieldList, workEntCreate, workEntUpdate])\n{\n    public Guid UpdateOrCreateContentGroup(BlockConfiguration blockConfiguration, int templateId)\n    {\n        var l = Log.Fn<Guid>();\n\n        if (!blockConfiguration.Exists)\n        {\n            l.A($\"doesn't exist, will create new CG with template#{templateId}\");\n            var guid = workEntCreate.New(AppWorkCtx).Create(WorkBlocks.BlockTypeName, new()\n            {\n                { ViewParts.TemplateContentType, new List<int> { templateId } },\n                { ViewParts.Content, new List<int>() },\n                { ViewParts.Presentation, new List<int>() },\n                { ViewParts.FieldHeader, new List<int>() },\n                { ViewParts.FieldHeaderPresentation, new List<int>() }\n            }).EntityGuid; // new guid\n            return l.ReturnAndLog(guid, \"created\");\n        }\n\n        l.A($\"exists, create for group#{blockConfiguration.Guid} with template#{templateId}\");\n        workEntUpdate.New(AppWorkCtx).UpdateParts(\n            blockConfiguration.Id,\n            new Dictionary<string, object> { { ViewParts.TemplateContentType, new List<int?> { templateId } } },\n            new()\n        );\n\n        return l.ReturnAndLog(blockConfiguration.Guid); // guid didn't change\n    }\n\n    public void AddEmptyItem(BlockConfiguration block, int? index, bool forceDraft)\n    {\n        workFieldList.New(AppWorkCtx.AppReader)\n            .FieldListUpdate(\n                (block as ICanBeEntity).Entity,\n                ViewParts.ContentPair,\n                forceDraft,\n                lists =>\n                {\n                    // hitting (+) if the list is empty add two demo items (because we already see one demo item)\n                    if (lists.Lists.First().Value.Count == 0) // on non, add 2 null items\n                        lists.Add(0, [null, null]);\n                    return lists.Add(index, [null, null]);\n                });\n    }\n\n\n    public int NewBlockReference(int parentId, string field, int index, string app = \"\", Guid? guid = null)\n    {\n        var l = Log.Fn<int>($\"get CB parent:{parentId}, field:{field}, order:{index}, app:{app}, guid:{guid}\");\n        var contentTypeName = AppConstants.ContentGroupRefTypeName;\n        var values = new Dictionary<string, object>\n        {\n            {BlockBuildingConstants.CbPropertyTitle, \"\"},\n            {BlockBuildingConstants.CbPropertyApp, app},\n        };\n        var newGuid = guid ?? Guid.NewGuid();\n        var entityId = CreateItemAndAddToList(parentId, field, index, contentTypeName, values, newGuid);\n\n        return l.ReturnAndLog(entityId);\n    }\n\n    private int CreateItemAndAddToList(int parentId, string field, int index, string typeName, Dictionary<string, object> values, Guid newGuid)\n    {\n        var l = Log.Fn<int>($\"{nameof(parentId)}:{parentId}, {nameof(field)}:{field}, {nameof(index)}, {index}, {nameof(typeName)}:{typeName}\");\n\n        // create the new entity \n        var entityId = workEntCreate.New(AppWorkCtx.AppReader)\n            .GetOrCreate(newGuid, typeName, values);\n\n        #region attach to the current list of items\n\n        var cbEnt = AppWorkCtx.AppReader.List.GetOne(parentId)\n            ?? throw new NullReferenceException($\"Tried to use the just-created entity with id '{parentId}' but can't find it.\");\n        var blockList = cbEnt.Children(field);\n\n        var intList = blockList\n            .Where(b => b != null)\n            .Select(b => b!.EntityId)\n            .ToList(); // must be list, as it will be modified\n\n        // add only if it's not already in the list (could happen if http requests are run again)\n        if (!intList.Contains(entityId))\n        {\n            if (index > intList.Count)\n                index = intList.Count;\n            intList.Insert(index, entityId);\n        }\n        var updateDic = new Dictionary<string, object> { { field, intList } };\n        workEntUpdate.New(AppWorkCtx.AppReader).UpdateParts(cbEnt.EntityId, updateDic, new());\n\n        #endregion\n\n        return l.ReturnAndLog(entityId);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Context.Sys/AppIdResolver.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Web.Sys.Http;\n\nnamespace ToSic.Sxc.Context.Sys;\n\n/// <summary>\n/// This helps API calls to get the app which is currently needed\n/// It does not perform security checks ATM and maybe never will\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class AppIdResolver(IHttp http, AppFinder appFinder) : ServiceBase(\"Api.FindAp\", connect: [http, appFinder])\n{\n    /// <summary>\n    /// New implementation to replace previous\n    /// </summary>\n    /// <returns></returns>\n    internal int GetAppIdFromPath(int zoneId, string appPath, bool required)\n    {\n        var l = Log.Fn<int>($\"{zoneId}, {appPath}, {required}\");\n        // get app from AppName\n        var aid = appFinder/* _zoneRuntime.Init(zoneId, Log)*/.FindAppId(zoneId, appPath, true);\n        if (aid <= KnownAppsConstants.AppIdEmpty && required)\n            throw new($\"App required but can't find App based on the name '{appPath}'\");\n\n        return l.Return(aid, $\"found app:{aid}\");\n    }\n\n\n    /// <summary>\n    /// This will detect the app based on appid/zoneid params in the URL\n    /// It's a temporary solution, because normally we want the control flow to be more obvious\n    /// </summary>\n    /// <returns></returns>\n    internal IAppIdentity? GetAppIdFromRoute()\n    {\n        var allUrlKeyValues = http.QueryStringKeyValuePairs();\n        var ok1 = int.TryParse(allUrlKeyValues.FirstOrDefault(\n                x => x.Key.Equals(ContextConstants.ZoneIdKey, StringComparison.InvariantCultureIgnoreCase)).Value, \n            out var zoneId);\n        var ok2 = int.TryParse(allUrlKeyValues.FirstOrDefault(\n                x => x.Key.Equals(ContextConstants.AppIdKey, StringComparison.InvariantCultureIgnoreCase)).Value, \n            out var appId);\n\n        if (!ok1 || !ok2)\n            return null;\n\n        Log.A($\"Params in URL detected - will use appId:{appId}, zoneId:{zoneId}\");\n        return new AppIdentity(zoneId, appId);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Context.Sys/ContextConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Context.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContextConstants\n{\n    public const string AppIdKey = \"appId\";\n    public const string ZoneIdKey = \"zoneId\";\n    public const string PageIdKey = \"pageid\";\n    public const string ModuleIdKey = \"moduleid\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Context.Sys/ContextOfBlock.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Context.Sys;\n\n/// <remarks>\n/// Important: this is the third inheritance, so it cannot create\n/// another MyServices to inherit again, as it's not supported across three level\n/// So these dependencies must be in the constructor\n/// </remarks>\n[PrivateApi(\"Internal stuff, not for public use\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ContextOfBlock(\n    IPage page,\n    IModule module,\n    LazySvc<ServiceSwitcher<IPagePublishingGetSettings>> publishingResolver,\n    IPageServiceShared pageServiceShared,\n    ContextOfApp.Dependencies appServices)\n    : ContextOfApp(appServices, \"Sxc.CtxBlk\", connect: [module, pageServiceShared, publishingResolver]), IContextOfBlock\n{\n\n    #region Override AppIdentity based on module information\n\n    protected override IAppIdentity? AppIdentity\n    {\n        get\n        {\n            if (base.AppIdentity != null)\n                return base.AppIdentity;\n            var l = Log.Fn<IAppIdentity?>();\n            var identifier = Module?.BlockIdentifier;\n            if (identifier == null)\n                return l.ReturnNull(\"no mod-block-id\");\n            AppIdentity = identifier;\n            return l.Return(base.AppIdentity);\n        }\n    }\n\n    #endregion\n\n    /// <inheritdoc />\n    public IPage Page { get; } = page;\n\n    /// <inheritdoc />\n    public IModule Module { get; } = module;\n\n    public IPageServiceShared PageServiceShared { get; } = pageServiceShared;\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public BlockPublishingSettings Publishing => field ??= publishingResolver.Value.Value.SettingsOfModule(Module?.Id ?? -1);\n\n    /// <inheritdoc />\n    public override IContextOfSite Clone(ILog parentLog)\n        => new ContextOfBlock(Page, Module, publishingResolver, PageServiceShared, AppServices)\n            .LinkLog(parentLog);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Context.Sys/ContextResolverBase.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\n\nnamespace ToSic.Sxc.Context.Sys;\n\n/// <summary>\n/// Base class for Context Resolver.\n/// Split is because of old concept where this was also in the EAV project.\n/// But as the system matured, it was only used in the setup of Blocks and Code, so not relevant for the EAV layers.\n/// </summary>\n/// <param name=\"siteCtxGenerator\"></param>\n/// <param name=\"appCtxGenerator\"></param>\n/// <param name=\"logName\"></param>\n/// <param name=\"connect\"></param>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContextResolverBase(\n    Generator<IContextOfSite> siteCtxGenerator,\n    Generator<IContextOfApp> appCtxGenerator,\n    string? logName = default,\n    object[]? connect = default)\n    : ServiceBase(logName ?? \"Eav.CtxRes\", connect: [..connect ?? [], siteCtxGenerator, appCtxGenerator])\n{\n   \n    public IContextOfSite Site() => _site.Get(siteCtxGenerator.New)!;\n    private readonly GetOnce<IContextOfSite> _site = new();\n\n\n    public IContextOfApp SetApp(IAppIdentity appIdentity)\n    {\n        var appCtx = appCtxGenerator.New();\n        appCtx.ResetApp(appIdentity);\n        AppContextFromAppOrBlock = appCtx;\n        return appCtx;\n    }\n\n    public IContextOfApp AppRequired()\n        => AppContextFromAppOrBlock ?? throw new($\"To call {nameof(AppRequired)} first call {nameof(SetApp)}\");\n\n    public IContextOfApp? AppOrNull() => AppContextFromAppOrBlock;\n\n    /// <summary>\n    /// This is set whenever an App Context or Block Context are set.\n    /// </summary>\n    protected IContextOfApp? AppContextFromAppOrBlock { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Context.Sys/IContextOfBlock.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Context.Sys;\n\n/// <summary>\n/// TODO: SHOULD actually be called ContextOfModule!\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IContextOfBlock: IContextOfApp\n{\n    /// <summary>\n    /// The page it's running on + parameters for queries, url etc.\n    /// </summary>\n    IPage Page { get; }\n\n    /// <summary>\n    /// The container for our block, basically the module\n    /// </summary>\n    IModule Module { get; }\n\n    /// <summary>\n    /// Publishing information about the current context\n    /// </summary>\n    BlockPublishingSettings Publishing { get; }\n\n    /// <summary>\n    /// WIP\n    /// </summary>\n    IPageServiceShared PageServiceShared { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Context.Sys/ISxcCurrentContextService.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Context.Sys;\n\n/// <summary>\n/// This provides other systems with a context\n/// Note that it's important to always make this **Scoped**, not transient, as there is some re-use after initialization\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ISxcCurrentContextService: ICurrentContextService, ISxcAppCurrentContextService\n{\n    /// <summary>\n    /// Return the block or throw an error\n    /// </summary>\n    IContextOfBlock BlockContextRequired();\n\n    /// <summary>\n    /// Return the block if known, or null if not\n    /// </summary>\n    /// <returns>The current block or null</returns>\n    IContextOfBlock? BlockContextOrNull();\n\n    void AttachBlock(IBlock block);\n\n    IBlock? BlockOrNull();\n\n    IBlock BlockRequired();\n\n    IBlock SwapBlockView(IView newView);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Context.Sys/SxcContextResolver_AppBlock.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Sys.Configuration;\n\nnamespace ToSic.Sxc.Context.Sys;\n\npartial class SxcCurrentContextService\n{\n    public IContextOfApp GetExistingAppOrSet(int appId)\n    {\n        var l = Log.Fn<IContextOfApp>($\"a#{appId}\");\n        // get the current block context\n        var moduleCtx = BlockContextOrNull();\n\n        // If there is no block context, then just use a \"blank\" app context\n        // This way security checks can only verify the App but not any module permissions\n        if (moduleCtx == null)\n            return l.Return(SetApp(SiteAppIdentity()));\n\n        // if there is a block context, make sure it's of the requested app (or no app was specified)\n        // then return that\n        // note: an edge case is that a block context exists, but no app was selected - then AppState is null\n\n\n        // If the app in the request matches the app in the context, everything is fine\n        // This is necessary when you come from a module which doesn't have an app yet (all apps menu).\n        // Then you access an app, so the underlying AppReader is still null. \n        if (appId == moduleCtx.AppReaderOrNull?.AppId)\n            return l.Return(moduleCtx);\n        \n        // If the app in the request doesn't match the app in the context\n        // Set the app in the context to the real one to be sure about security check\n        // We still want to preserve the ModuleContext, so security checks can\n        // still verify module permissions.\n        // Only do this if the feature is enabled, as we are opening security when we do this\n        if (!featuresService.Value.IsEnabled(SxcFeatures.PermissionPrioritizeModuleContext.NameId))\n            // Get a simpler App-Context without the module context\n            // so that module permissions will not allow editing of apps which are really in the current one.\n            return l.Return(SetApp(SiteAppIdentity()));\n\n        moduleCtx.ResetApp(SiteAppIdentity());\n        return l.Return(moduleCtx);\n\n        // Old implementation\n        //AppIdentity SiteAppIdentity() => new(Site().Site.ZoneId, appId);\n\n        // New implementation 2025-03-31\n        // Previous version had edge cases where the wrong zone/app combinations were created\n        // Which would still load the App, but would result in 2 different AppIdentities being cached\n        // leading to unexpected results.\n        IAppIdentityPure SiteAppIdentity() => appReaderFactory.Value.AppIdentity(appId);\n    }\n\n\n    public IContextOfApp SetAppOrGetBlock(string nameOrPath)\n        => SetAppOrNull(nameOrPath) ?? BlockContextRequired();\n\n\n    public IContextOfApp AppNameRouteBlock(string? nameOrPath)\n    {\n        var ctx = SetAppOrNull(nameOrPath);\n        if (ctx != null)\n            return ctx;\n\n        var identity = appIdResolverLazy.Value.GetAppIdFromRoute();\n        if (identity != null)\n            return SetApp(identity);\n\n        ctx = BlockContextOrNull();\n        return ctx ?? throw new($\"Tried to auto detect app by name '{nameOrPath}', url params or block context, all failed.\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Context.Sys/SxcCurrentContextService.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.DataSources.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Web.Sys.Http;\nusing ToSic.Sys.Users.Permissions;\n\nnamespace ToSic.Sxc.Context.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal partial class SxcCurrentContextService(\n    LazySvc<AppIdResolver> appIdResolverLazy,\n    Generator<IContextOfSite> siteCtxGenerator,\n    Generator<IContextOfApp> appCtxGenerator,\n    LazySvc<IFeaturesService> featuresService,\n    LazySvc<IAppReaderFactory> appReaderFactory,\n    LazySvc<BlockDataSourceFactory> bdsFactoryLazy,\n    LazySvc<IHttp> http)\n    : ContextResolverBase(siteCtxGenerator, appCtxGenerator, \"Sxc.CtxRes\",\n        connect: [appIdResolverLazy, siteCtxGenerator, appCtxGenerator, featuresService, http, appReaderFactory, bdsFactoryLazy]),\n        ISxcCurrentContextService\n{\n    private const string CookieTemplate = \"app-{0}-data-preview\";\n    private const string CookieLive = \"live\";\n\n    /// <summary>\n    /// Get the best possible context which can give us insights about the user permissions.\n    ///\n    /// TODO: WIP - requires that if an app is to be used, it was accessed before - not yet perfect...\n    /// </summary>\n    /// <returns></returns>\n    public EffectivePermissions UserPermissions() => _ctxUserPerm ??= GetUserPermissions();\n    private EffectivePermissions? _ctxUserPerm;\n\n    /// <summary>\n    /// Figure out user permissions based on block-context, app-context or site-context.\n    /// In addition, (new 17.10) figure out if a cookie is set to show live or draft data.\n    /// </summary>\n    /// <returns></returns>\n    private EffectivePermissions GetUserPermissions()\n    {\n        var perms = (BlockContextOrNull() ?? AppOrNull() ?? Site())?.Permissions;\n        if (perms == null)\n            return new(false);\n        if (!perms.ShowDraftData)\n            return perms;\n\n        // Check if an all-apps cookie is set\n        return CookieExpectsLive(\"*\") \n            ? perms with { ShowDraftData = false }\n            : perms;\n\n        // Check if a cookie is set to this specific app\n        // 2024-06-03 ATM this doesn't work, because the initial access\n        // to get the view etc. already needs to know this, and at that time the block isn't created yet\n        // would need quite a bit of work to get it right, so commented out for now.\n        //if (blockOrAppCtx != null && CookieExpectsLive(blockOrAppCtx.AppState.AppId.ToString()))\n        //    return new(perms.IsSiteAdmin, perms.IsContentAdmin, perms.IsContentEditor,\n        //        showDrafts: false);\n\n        bool CookieExpectsLive(string app) => http?.Value.GetCookie(string.Format(CookieTemplate, app)) == CookieLive;\n    }\n\n    public IContextOfApp? SetAppOrNull(string? nameOrPath)\n    {\n        if (string.IsNullOrWhiteSpace(nameOrPath))\n            return null;\n        var zoneId = Site().Site.ZoneId;\n        var appId = appIdResolverLazy.Value.GetAppIdFromPath(zoneId, nameOrPath!, false);\n        return appId <= KnownAppsConstants.AppIdEmpty\n            ? null\n            : SetApp(new AppIdentity(zoneId, appId));\n    }\n\n    #region Blocks\n\n    public void AttachBlock(IBlock block)\n    {\n        _block = block;\n        AppContextFromAppOrBlock = _block?.Context;\n    }\n    private IBlock? _block;\n\n    public IBlock SwapBlockView(IView newView)\n    {\n        var blockSpecs = _block as BlockSpecs\n                    ?? throw new NullReferenceException(\"Block is not attached, cannot swap view.\");\n\n        var newSpecs = blockSpecs with\n        {\n            ViewOrNull = newView,\n        };\n\n        // This call must be after set-view, since it needs the view to get the data-source\n        newSpecs = newSpecs with\n        {\n            Data = bdsFactoryLazy.Value.GetContextDataSourceFromView(newSpecs, newSpecs.AppOrNull.TryGetAppLookUpEngineOrNull())\n        };\n        _block = newSpecs;\n        return _block;\n    }\n\n    public IBlock? BlockOrNull() => _block;\n\n    public IBlock BlockRequired() => BlockOrNull()\n                                     ?? throw new(\"Block required but missing. It was not attached\");\n\n    public IContextOfBlock BlockContextRequired() => BlockContextOrNull()\n                                                     ?? throw new(\"Block context required but not known. It was not attached.\");\n\n    public IContextOfBlock? BlockContextOrNull() => _block?.Context;\n\n\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/DataSources/CmsBlock/CmsBlock.cs",
    "content": "﻿using System.Collections.Immutable;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Eav.Services;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Blocks.Sys.Work;\nusing ToSic.Sxc.Context;\n\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// This data-source delivers the core data for a CMS Block. <br/>\n/// It will look up the configuration in the CMS (like the Module-Settings in DNN) to determine what data is needed for the block. <br/>\n/// Usually it will then find a reference to a ContentBlock, from which it determines what content-items are assigned. <br/>\n/// It could also find that the template specifies a query, in which case it would retrieve that. <br/>\n/// <em>Was previously called ModuleDataSource</em>\n/// </summary>\n[PublicApi]\n[VisualQuery(\n    NiceName = \"CMS Block\",\n    UiHint = \"Data for this CMS Block (instance/module)\",\n    Icon = DataSourceIcons.RecentActor,\n    Type = DataSourceType.Source, \n    NameId = \"ce46fcac-e531-45a2-adc5-181164e742f6\",\n    NameIds =\n    [\n        \"ToSic.Sxc.DataSources.CmsBlock, ToSic.Sxc\",\n        \"ToSic.SexyContent.DataSources.ModuleDataSource, ToSic.SexyContent\"\n    ],\n    ConfigurationType = \"7c2b2bc2-68c6-4bc3-ba18-6e6b5176ba02\",\n    In = [DataSourceConstants.StreamDefaultName],\n    HelpLink = \"https://docs.2sxc.org/api/dot-net/ToSic.Sxc.DataSources.CmsBlock.html\")]\npublic sealed partial class CmsBlock : DataSourceBase, IDataSourceLinkable\n{\n    /// <summary>\n    /// The instance-id of the CmsBlock (2sxc instance, DNN ModId). <br/>\n    /// It's named Instance-Id to be more neutral as we're opening it to other platforms\n    /// </summary>\n    [Configuration(Field = BlockInstanceConstants.FieldInstanceId,\n        Fallback = $\"[{BlockInstanceConstants.InstanceLookupName}:{BlockInstanceConstants.ModuleIdKey}]\")]\n    public int? ModuleId\n    {\n        get => field ?? (int.TryParse(Configuration.GetThis(), out var listId)\n            ? listId\n            : new int?());\n        set;\n    }\n\n    #region Constructor\n\n    public new record Dependencies(\n        DataSourceBase.Dependencies ParentServices,\n        LazySvc<IModule> ModuleLazy,\n        LazySvc<IDataSourcesService> DataSourceFactory,\n        GenWorkPlus<WorkBlocks> AppBlocks)\n        : DependenciesRecord(connect: [ModuleLazy, DataSourceFactory, AppBlocks]);\n\n    public CmsBlock(Dependencies services): base(services.ParentServices, $\"SDS.CmsBks\", connect: [services])\n    {\n        _services = services;\n\n        ProvideOut(GetContent);\n        ProvideOut(GetHeader, ViewParts.StreamHeader);\n        ProvideOut(GetHeader, ViewParts.StreamHeaderOld);\n    }\n    private readonly Dependencies _services;\n    #endregion\n\n    IDataSourceLink IDataSourceLinkable.GetLink() => _link\n        ??= BreachExtensions.CreateEmptyLink(this)\n            .WithAnotherStream(name: ViewParts.StreamHeader)\n            .WithAnotherStream(name: ViewParts.StreamHeaderOld);\n\n    private IDataSourceLink? _link;\n\n\n    private IImmutableList<IEntity> GetContent()\n    {\n        // First check if BlockConfiguration works - to give better error if not\n        var blockSpecsAndErrors = ConfigAndViewOrErrors;\n        if (!blockSpecsAndErrors.IsOk)\n            return blockSpecsAndErrors.ErrorsSafe();\n\n        var parts = blockSpecsAndErrors.Result;\n        return GetStream(parts.View,\n            parts.BlockConfiguration.Content,\n            parts.View.ContentItem,\n            parts.BlockConfiguration.Presentation,\n            parts.View.PresentationItem,\n            false\n        );\n    }\n\n    private IImmutableList<IEntity> GetHeader()\n    {\n        // First check if BlockConfiguration works - to give better error if not\n        var blockSpecsAndErrors = ConfigAndViewOrErrors;\n        if (!blockSpecsAndErrors.IsOk)\n            return blockSpecsAndErrors.ErrorsSafe();\n\n        var parts = blockSpecsAndErrors.Result;\n\n\n        return GetStream(parts.View,\n            parts.BlockConfiguration.Header,\n            parts.View.HeaderItem,\n            parts.BlockConfiguration.HeaderPresentation,\n            parts.View.HeaderPresentationItem,\n            true\n        );\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/DataSources/CmsBlock/CmsBlock_ConfigAndView.cs",
    "content": "﻿using ToSic.Eav.DataSource.Sys.Errors;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\nnamespace ToSic.Sxc.DataSources;\n\npublic sealed partial class CmsBlock\n{\n    private ResultOrError<(BlockConfiguration BlockConfiguration, IView View)> ConfigAndViewOrErrors => _everything.Get(() =>\n    {\n        var config = LoadBlockConfiguration();\n        if (!config.IsOk)\n            return new ResultOrError<(BlockConfiguration BlockConfiguration, IView view)>(false, default,\n                config.ErrorsSafe());\n\n        var view = OverrideView ?? config.Result.View;\n        if (view == null)\n            return new ResultOrError<(BlockConfiguration BlockConfiguration, IView view)>(false, default,\n                Error.Create(title: \"CmsBlock View Missing\",\n                    message: \"Cannot find View configuration of current CmsBlock\"));\n        // all ok \n        return new ResultOrError<(BlockConfiguration BlockConfiguration, IView view)>(true, (config.Result, view));\n    })!;\n\n    private readonly GetOnce<ResultOrError<(BlockConfiguration blockConfiguration, IView view)>> _everything = new();\n\n    private ResultOrError<BlockConfiguration> LoadBlockConfiguration()\n    {\n        var l = Log.Fn<ResultOrError<BlockConfiguration>>();\n        if (UseSxcInstanceContentGroup)\n            return l.Return(new(true, Block.Configuration), \"need content-group, will use from Sxc Instance ContentGroup\");\n\n        // If we don't have a context, then look it up based on the InstanceId\n        l.A(\"need content-group, will construct as cannot use context\");\n        Configuration.Parse();\n        if (!ModuleId.HasValue)\n            return l.Return(new(false, null,\n                Error.Create(title: $\"{nameof(CmsBlock)} cannot find Block Configuration\",\n                    message: $\"Neither InstanceContext nor {nameof(ModuleId)} found\")), \"Error, no module-id\");\n\n        var container = _services.ModuleLazy.Value.Init(ModuleId.Value);\n        var blockId = container.BlockIdentifier;\n        var blockConfig = _services.AppBlocks.New(this).GetOrGeneratePreviewConfig(blockId);\n        return l.Return(new(true, blockConfig), \"ok\");\n    }\n\n\n    /// <summary>\n    /// This allows external settings to override the view given by the configuration. This is used to temporarily use an alternate view.\n    /// For example, when previewing a different template. \n    /// </summary>\n    public IView? OverrideView { get; set; }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/DataSources/CmsBlock/CmsBlock_GetStream.cs",
    "content": "﻿using System.Collections.Immutable;\nusing ToSic.Eav.DataSource;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing static ToSic.Eav.DataSource.DataSourceConstants;\n\nnamespace ToSic.Sxc.DataSources;\n\npublic sealed partial class CmsBlock\n{\n    private IImmutableList<IEntity> GetStream(\n        IView? view,\n        IList<IEntity?> items, \n        IEntity? cDemoItem, \n        IList<IEntity?> presList, \n        IEntity? pDemoItem, \n        bool isListHeader\n    )\n    {\n        var l = Log.Fn<IImmutableList<IEntity>>($\"content⋮{items.Count}, demo#{cDemoItem?.EntityId}, present⋮{presList?.Count}, presDemo#{pDemoItem?.EntityId}, header:{isListHeader}\");\n        try\n        {\n            // if no template is defined, return empty list\n            if (view == null)\n                return l.Return([], \"no template definition - empty list\");\n\n            // Create copy of list (not in cache) because it will get modified\n            var contentEntities = items.ToList();\n\n            // If no Content Elements exist and type is content (means, presentationList is not null), add an empty entity (demo entry will be taken for this)\n            if (items.Count == 0 && presList != null)\n            {\n                l.A(\"empty list, will add a null-item\");\n                contentEntities.Add(null);\n            }\n\n            var entitiesToDeliver = new List<IEntity>();\n            var originals = GetInOrAutoCreate();\n            int i = 0, entityId = 0, prevIdForErrorReporting = 0;\n            try\n            {\n                for (; i < contentEntities.Count; i++)\n                {\n                    // new 2019-09-18 trying to mark demo-items for better detection in output #1792\n                    var isDemoItem = false;\n\n                    // get the entity, if null: try to substitute with the demo item\n                    var contentEntity = contentEntities[i];\n\n                    // check if it \"exists\" in the in-stream. if not, then it's probably unpublished\n                    // so try revert back to the demo-item (assuming it exists...)\n                    if (contentEntity == null || !originals.Contains(contentEntity.EntityId))\n                    {\n                        contentEntity = cDemoItem;\n                        isDemoItem = true;  // mark demo-items for demo-item detection in template #1792\n                    }\n\n                    // now check again...\n                    // ...we can't deliver entities that are not delivered by base (original stream), so continue\n                    if (contentEntity == null || !originals.Contains(contentEntity.EntityId))\n                        continue;\n\n                    // use demo-entities where available\n                    entityId = contentEntity.EntityId;\n\n                    var presentationEntity = GetPresentationEntity(originals, presList, i, entityId)\n                                             ?? pDemoItem;\n\n                    try\n                    {\n                        var itm = originals.GetOne(entityId)!;\n                        entitiesToDeliver.Add(EntityInBlockDecorator.Wrap(\n                            entity: itm,\n                            fieldName: null,\n                            index: isListHeader ? -1 : i,\n                            presentation: presentationEntity,\n                            isDemoItem: isDemoItem,\n                            parent: null\n                        ));\n                    }\n                    catch (Exception ex)\n                    {\n                        throw new(\"trouble adding to output-list, id was \" + entityId, ex);\n                    }\n                    prevIdForErrorReporting = entityId;\n                }\n            }\n            catch (Exception ex)\n            {\n                throw l.Ex(new Exception($\"problems looping items - had to stop on id {i}; current entity is {entityId}; prev is {prevIdForErrorReporting}\", ex));\n            }\n\n            return l.Return(entitiesToDeliver.ToImmutableOpt(), $\"stream:{(isListHeader ? \"list\" : \"content\")} - items⋮{entitiesToDeliver.Count}\");\n        }\n        catch (Exception ex)\n        {\n            throw new(\"Error loading items of a module - probably the module-id is incorrect - happens a lot with test-values on visual queries.\", ex);\n        }\n    }\n\n    private IImmutableList<IEntity> GetInOrAutoCreate()\n    {\n        var l = Log.Fn<IImmutableList<IEntity>>();\n        // Check if in not connected, in which case we must find it yourself\n        if (!In.ContainsKey(StreamDefaultName))\n        {\n            l.A(\"In not attached, will auto-attach\");\n            var publishing = _services.DataSourceFactory.Value.CreateDefault(new DataSourceOptions\n            {\n                AppIdentityOrReader = this,\n                LookUp = Configuration.LookUpEngine,\n            });\n            Attach(publishing);\n        }\n\n        return l.Return(In[StreamDefaultName].List.ToImmutableOpt(), \"ok\");\n    }\n\n    private static IEntity? GetPresentationEntity(IImmutableList<IEntity> originals, IList<IEntity?>? presItems, int itemIndex, int entityId)\n    {\n        try\n        {\n            if (presItems == null)\n                return null;\n\n            // Try to find presentationList entity\n            var presentationId =\n                presItems.Count - 1 >= itemIndex && presItems[itemIndex] != null &&\n                originals.Contains(presItems[itemIndex]!.EntityId)\n                    ? presItems[itemIndex]!.EntityId\n                    : new int?();\n\n            // If there is no presentationList entity, take default entity\n            if (presentationId.HasValue)\n                return originals.GetOne(presentationId.Value);\n\n            return null;\n        }\n        catch (Exception ex)\n        {\n            throw new(\"trouble adding presentationList of \" + entityId, ex);\n        }\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/DataSources/CmsBlock/CmsBlock_InstanceBlock.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.LookUp.Sys;\nusing LookUpConstants = ToSic.Sxc.LookUp.Sys.LookUpConstants;\n\nnamespace ToSic.Sxc.DataSources;\n\npublic sealed partial class CmsBlock\n{\n    /// <summary>\n    /// The block for which this DataSource is needed - provides context and configuration\n    /// </summary>\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal IBlock Block\n    {\n        get\n        {\n            if (field != null)\n                return field;\n\n            if (!Configuration.LookUpEngine.HasSource(LookUpConstants.InstanceContext))\n                throw new(\"value provider didn't have sxc provider - can't use module data source\");\n\n            var instanceProvider = Configuration.LookUpEngine.FindSource(LookUpConstants.InstanceContext) as LookUpCmsBlock;\n            field = instanceProvider?.Block\n                    ?? throw new(\"value provider didn't have sxc provider - can't use module data source\");\n\n            return field;\n        }\n    }\n\n    internal bool UseSxcInstanceContentGroup = false;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/DataSources/CmsBlock/ContextData.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSources;\nusing ToSic.Sxc.Blocks.Sys.Views;\n\n// 2025-06 removed for v20\n//#if NETFRAMEWORK\n//using ToSic.Eav.Apps;\n//using CodeInfoService = ToSic.Sys.Code.InfoSystem.CodeInfoService;\n//#endif\n\nnamespace ToSic.Sxc.DataSources;\n\n// TODO: MAKE class INTERNAL AGAIN AFTER MOVING TO ToSic.Sxc.Custom\n\n/// <summary>\n/// The main data source for Blocks. Internally often uses <see cref=\"CmsBlock\"/> to find what it should provide.\n/// </summary>\n/// <remarks>\n/// It's based on the <see cref=\"PassThrough\"/> data source, because it's just a coordination-wrapper.\n/// In v19 we removed the implementation of IBlockInstance as it was identical to IDataSource.\n/// ...so if anybody had code using that name, it could break, but we assume this is never the case since people would always just use the `Data` object without casting a variable.\n/// </remarks>\n[PrivateApi(\"used to be Internal... till 16.01, then changed to private to hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n// ReSharper disable once PartialTypeWithSinglePart\npublic partial class ContextData(DataSourceBase.Dependencies services) : PassThrough(services, \"Sxc.BlckDs\")\n{\n\n    #region New v16\n\n    // TODO: MAKE class INTERNAL AGAIN AFTER MOVING TO ToSic.Sxc.Custom\n    public IEnumerable<IEntity> MyItems => _myContent.Get(() => _blockSource.GetStream(emptyIfNotFound: true)!.List)!;\n    private readonly GetOnce<IEnumerable<IEntity>> _myContent = new();\n\n    // TODO: MAKE class INTERNAL AGAIN AFTER MOVING TO ToSic.Sxc.Custom\n    public IEnumerable<IEntity> MyHeaders => _header.Get(() => _blockSource.GetStream(ViewParts.StreamHeader, emptyIfNotFound: true)!.List)!;\n    private readonly GetOnce<IEnumerable<IEntity>> _header = new();\n        \n    #endregion\n\n\n    internal void SetOut(IQuery querySource)\n        => _querySource = querySource;\n    private IQuery? _querySource;\n    internal void SetBlock(CmsBlock blockSource)\n        => _blockSource = blockSource;\n    private CmsBlock _blockSource = null!;\n\n    public override IReadOnlyDictionary<string, IDataStream> Out => _querySource?.Out ?? base.Out;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/DataSources/CmsBlock/ContextData_Obsolete.cs",
    "content": "﻿// 2025-06 removed for v20\n\n//#if NETFRAMEWORK\n//using ToSic.Eav.Apps;\n//using ToSic.Sxc.DataSources.Internal.Compatibility;\n//using ToSic.Sys.Code.InfoSystem;\n//using static ToSic.Sys.Code.Infos.CodeInfoObsolete;\n\n//namespace ToSic.Sxc.DataSources;\n\n//partial class ContextData: IBlockDataSource\n//{\n//    private readonly LazySvc<CodeInfoService> _codeChanges;\n\n//    private readonly IAppReaderFactory _appReaders;\n\n//#pragma warning disable 618\n//    [Obsolete(\"Old property on this data source, should really not be used at all. Must add warning in v13, and remove ca. v15\")]\n//    [PrivateApi]\n//    [field: AllowNull, MaybeNull]\n//    public CacheWithGetContentType Cache\n//    {\n//        get\n//        {\n//            if (field != null)\n//                return field;\n//            // on first access report problem\n//            _codeChanges.Value.Warn(CaV8To17(\"Data.Cache\", \"https://go.2sxc.org/brc-13-datasource-cache\"));\n//            return field = new(_appReaders.Get(this));\n//        }\n//    }\n\n//    [PrivateApi(\"older use case, probably don't publish\")]\n//    public DataPublishing Publish { get; } = new();\n//#pragma warning restore 618\n    \n//}\n\n//#endif\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/DataSources/Sys/BlockDataSourceFactory.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Eav.Services;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.DataSources.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockDataSourceFactory(LazySvc<IDataSourcesService> dataSourceFactory, Generator<Query> queryLazy)\n    : ServiceBase(\"Sxc.BDsFct\", connect: [dataSourceFactory, queryLazy])\n{\n\n    internal IDataSource GetContextDataSourceFromView(BlockSpecs block, ILookUpEngine? configLookUp)\n    {\n        var view = block.View;\n        var l = Log.Fn<IDataSource>($\"mid:{block.Context.Module.Id}, userMayEdit:{block.Context.Permissions.IsContentAdmin}, view:{view?.Name}\");\n\n        l.A(\"Will get Default data source\");\n        var dsFactory = dataSourceFactory.Value;\n        var options = new DataSourceOptions\n        {\n            AppIdentityOrReader = block.PureIdentity(),\n            LookUp = configLookUp,\n        };\n        var initialSource = dsFactory.CreateDefault(options);\n        var blockDataSource = dsFactory.Create<CmsBlock>(/*attach: initialSource*/ options with { Attach = initialSource });\n\n        blockDataSource.OverrideView = view;\n        blockDataSource.UseSxcInstanceContentGroup = true;\n\n        // If the Template has a Data-Pipeline, use an empty upstream to attach later, else use the ModuleDataSource created above\n        var viewDataSourceUpstream = view?.Query == null\n            ? blockDataSource\n            : null;\n        l.A($\"use query upstream:{viewDataSourceUpstream != null}\");\n\n        l.A($\"Will get ModuleDataSource, aka {nameof(ContextData)}\");\n        var contextDataSource = dsFactory.Create<ContextData>(/*attach: viewDataSourceUpstream,*/\n            options: options with { Attach = viewDataSourceUpstream });\n        contextDataSource.SetBlock(blockDataSource);\n\n        // Take Publish-Properties from the View-Template\n        if (view != null)\n        {\n            l.A($\"use query from  view, query#{view.Query?.Id}\");\n\n            // Append Streams of the Data-Query (this doesn't require a change of the viewDataSource itself)\n            if (view.Query == null)\n                return l.ReturnAsOk(contextDataSource);\n\n            l.A(\"Generate query\");\n            var query = queryLazy.New();\n            query.Init(block.App.ZoneId, block.App.AppId, (view.Query as ICanBeEntity).Entity, configLookUp, contextDataSource);\n            l.A(\"attaching\");\n            contextDataSource.SetOut(query);\n        }\n        else\n            l.A(\"no template override\");\n\n        return l.ReturnAsOk(contextDataSource);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Engines/RenderEngineResult.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.ClientAssets;\n\nnamespace ToSic.Sxc.Engines;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record RenderEngineResult: RenderEngineResultRaw\n{\n    public required bool ActivateJsApi { get; init; }\n\n    [field: AllowNull, MaybeNull]\n    public List<ClientAsset> Assets\n    {\n        get => field ??= [];\n        init;\n    }\n\n    public string? ErrorCode { get; init; }\n}\n\npublic record RenderEngineResultRaw\n{\n    public required string Html { get; init; }\n    public List<Exception>? ExceptionsOrNull { get; init; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using ToSic.Eav.Apps.Sys.Work;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Performance;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Integration.Modules/BasicModuleUpdater.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Integration.Modules;\n\n/// <summary>\n/// Empty constructor for DI\n/// </summary>\ninternal class BasicModuleUpdater(WarnUseOfUnknown<BasicModuleUpdater> _) : ServiceBase($\"{LogScopes.NotImplemented}.MapA2I\"), IPlatformModuleUpdater\n{\n    public void SetAppId(IModule instance, int? appId)\n    {\n        // do nothing\n    }\n\n    public void SetPreview(int instanceId, Guid previewTemplateGuid)\n    {\n        // do nothing\n    }\n\n    public void SetContentGroup(int instanceId, bool wasCreated, Guid guid)\n    {\n        // do nothing\n    }\n\n    public void UpdateTitle(IBlock block, IEntity titleItem)\n    {\n        // do nothing\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Integration.Modules/IPlatformModuleUpdater.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Integration.Modules;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPlatformModuleUpdater: IHasLog\n{\n    /// <summary>\n    /// Set the App of a Container / Module\n    /// </summary>\n    /// <param name=\"instance\"></param>\n    /// <param name=\"appId\"></param>\n    void SetAppId(IModule instance, int? appId);\n\n    /// <summary>\n    /// Set the preview view of the Container / Module\n    /// </summary>\n    /// <param name=\"instanceId\"></param>\n    /// <param name=\"previewView\"></param>\n    void SetPreview(int instanceId, Guid previewView);\n\n    /// <summary>\n    /// Persist the Content-Group once created. \n    /// </summary>\n    /// <param name=\"instanceId\"></param>\n    /// <param name=\"blockExists\"></param>\n    /// <param name=\"guid\"></param>\n    void SetContentGroup(int instanceId, bool blockExists, Guid guid);\n\n    /// <summary>\n    /// Update the title in the platform\n    /// </summary>\n    /// <param name=\"block\"></param>\n    /// <param name=\"titleItem\"></param>\n    void UpdateTitle(IBlock block, IEntity titleItem);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/LookUp.Sys/LookUpCmsBlock.cs",
    "content": "﻿using ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.LookUp.Sys;\n\n/// <inheritdoc />\n/// <summary>\n/// special \"fake\" value provider, which also transports the Sxc-dependency to underlying layers\n/// </summary>\n/// <inheritdoc />\n/// <remarks>\n/// The class constructor, can optionally take a dictionary to reference with, otherwise creates a new one\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class LookUpCmsBlock(string name, IBlock block) : LookUpInDictionary(name, new Dictionary<string, string>\n    {\n        { QueryConstants.ParamsShowDraftsKey, block.Context.Permissions.IsContentAdmin.ToString() }\n    }, \"LookUp in Cms Block - mainly to check if it should show drafts\")\n{\n    public IBlock Block = block;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/LookUp.Sys/LookUpEngineResolver.cs",
    "content": "﻿using ToSic.Eav.LookUp;\n\nnamespace ToSic.Sxc.LookUp.Sys;\n\n/// <summary>\n/// Resolves / builds the LookUp Engine.\n/// This is the default implementation and used in Oqtane.\n/// Dnn has its own implementation.\n/// </summary>\n/// <param name=\"builtInSources\"></param>\ninternal class LookUpEngineResolver(LazySvc<IEnumerable<ILookUp>> builtInSources)\n    : LookUpEngineResolverBase(builtInSources, $\"{SxcLogName}.LUpEnR\");"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/LookUp.Sys/LookUpEngineResolverBase.cs",
    "content": "﻿using ToSic.Eav.LookUp;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Eav.LookUp.Sys;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.LookUp.Sys;\n\npublic abstract class LookUpEngineResolverBase(LazySvc<IEnumerable<ILookUp>> builtInSources, string logName, NoParamOrder npo = default, object[]? connect = default)\n    : ServiceBase(logName, npo, connect), ILookUpEngineResolver\n{\n    /// <summary>\n    /// Get the lookup engine - if possible from cache, otherwise create a new one\n    /// </summary>\n    /// <param name=\"moduleId\"></param>\n    /// <returns></returns>\n    public virtual ILookUpEngine GetLookUpEngine(int moduleId)\n    {\n        var l = Log.Fn<ILookUpEngine>($\"{nameof(moduleId)}:{moduleId}\");\n\n        // Try Cached first\n        // if we already have a list of shared sources, return that\n        // as the sources don't change per request, but per module\n        if (TryReuseFromCache(moduleId, out var cached))\n            return l.Return(cached, $\"reuse {cached.Sources.Count()} sources\");\n\n        var luEngine = BuildLookupEngine(moduleId);\n        return l.Return(AddToCache(moduleId, luEngine), \"created and cached for reuse\");\n    }\n\n    /// <summary>\n    /// Build a new lookup engine - to be overriden in Dnn and other implementations\n    /// </summary>\n    /// <param name=\"moduleId\"></param>\n    /// <returns></returns>\n    protected virtual LookUpEngine BuildLookupEngine(int moduleId)\n    {\n        var l = Log.Fn<LookUpEngine>($\"{nameof(moduleId)}:{moduleId}\");\n        var sources = AddHttpAndDiSources([]);\n        var luEngine = new LookUpEngine(Log, sources: sources);\n        //AddHttpAndDiSources(/*luEngine,*/ []).DoIfNotNull(luEngine.Add);\n        return l.Return(luEngine);\n    }\n\n    /// <summary>\n    /// Cache sources by module ID, so we don't have to re-create them every time.\n    /// They remain the same throughout a request.\n    /// </summary>\n    protected readonly Dictionary<int, List<ILookUp>> SourcesByModuleId = [];\n\n    protected LookUpEngine AddToCache(int moduleId, LookUpEngine engine)\n    {\n        SourcesByModuleId[moduleId] = [.. engine.Sources];\n        return engine;\n    }\n\n    protected bool TryReuseFromCache(int moduleId, [NotNullWhen(true)] out LookUpEngine? engine)\n    {\n        if (!SourcesByModuleId.TryGetValue(moduleId, out var sources))\n        {\n            engine = null;\n            return false;\n        }\n\n        engine = new(Log, sources: sources);\n        return true;\n    }\n\n\n    /// <summary>\n    /// Get all http sources which are available in the current context.\n    /// But only if they have not already been added to the list.\n    /// - QueryString\n    /// - Query\n    /// - Form (Dnn only)\n    /// </summary>\n    /// <returns></returns>\n    protected List<ILookUp> AddHttpAndDiSources(/*LookUpEngine existingList,*/ List<ILookUp> sources)\n    {\n        sources ??= [];\n        var l = Log.Fn<List<ILookUp>>($\"provider: {sources.Count}\");\n\n        l.A(\"Found Http-Context, will ty to add params for querystring, server etc.\");\n\n        // Prepare additions to return\n        var additions = builtInSources.Value\n            //.Where(lu => !existingList.HasSource(lu.Name))\n            .Where(lu => !sources.HasSource(lu.Name))\n            .ToList();\n\n        // add \"query\" if it was not already added previously (Oqt has it) based on \"querystring\"\n        //if (!existingList.HasSource(LookUpConstants.SourceQuery))\n        if (!sources.HasSource(LookUpConstants.SourceQuery))\n            additions\n                .FirstOrDefault(lu => lu.Name.EqualsInsensitive(LookUpConstants.SourceQueryString))\n                .DoIfNotNull(qsl => additions.Add(new LookUpInLookUps(LookUpConstants.SourceQuery, [qsl])));\n\n        return l.Return(additions, $\"{additions.Count} additions\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/LookUp.Sys/SxcAppDataConfigProvider.cs",
    "content": "﻿using System.Globalization;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.LookUp;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Eav.LookUp.Sources.Sys;\nusing ToSic.Eav.LookUp.Sys;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Web.Sys.Http;\n\nnamespace ToSic.Sxc.LookUp.Sys;\n\n/// <summary>\n/// Service to find the configuration for the AppData, especially the lookup...\n/// </summary>\n/// <param name=\"getEngineLazy\"></param>\n/// <param name=\"httpLazy\"></param>\npublic class SxcAppDataConfigProvider(LazySvc<ILookUpEngineResolver> getEngineLazy, LazySvc<IHttp> httpLazy)\n    : ServiceBase(\"Sxc.CnfPrv\", connect: [getEngineLazy, httpLazy]), IAppDataConfigProvider\n{\n    public IAppDataConfiguration GetDataConfiguration(SxcAppBase app, AppDataConfigSpecs specs)\n    {\n        var block = (specs as SxcAppDataConfigSpecs)?.BlockForLookupOrNull;\n        var lookup = GetLookupEngineForContext(block?.Context, app as IApp, block);\n        return new AppDataConfiguration(lookup, specs.ShowDrafts);\n    }\n\n\n    // note: not sure yet where the best place for this method is, so it's here for now\n    // will probably move again some day\n    internal LookUpEngine GetLookupEngineForContext(IContextOfSite? context, IApp? appForLookup, IBlock? blockForLookupOrNull)\n    {\n        var l = Log.Fn<LookUpEngine>($\"module: {(context as ContextOfBlock)?.Module.Id}, app: {appForLookup?.AppId} ..., ...\");\n        var modId = (context as ContextOfBlock)?.Module.Id ?? 0;\n\n        // Find the standard DNN property sources if PortalSettings object is available\n        var envLookups = getEngineLazy.Value.GetLookUpEngine(modId);\n        var existSources = envLookups.Sources.ToList();\n        l.A($\"Environment provided {existSources.Count} sources\");\n\n        // Create a new lookup engine and add the standard sources as inner-sources\n        var newSources = new List<ILookUp>();\n        if (appForLookup != null)\n            newSources.Add(new LookUpInAppProperty(\"app\", appForLookup));\n\n        // add module if it was not already added previously\n        if (!existSources.HasSource(BlockInstanceConstants.InstanceLookupName))\n        {\n            var modulePropertyAccess = new LookUpInDictionary(BlockInstanceConstants.InstanceLookupName, new Dictionary<string, string>\n            {\n                [BlockInstanceConstants.ModuleIdKey] = modId.ToString(CultureInfo.InvariantCulture),\n            });\n            newSources.Add(modulePropertyAccess);\n        }\n\n        // provide the current SxcInstance to the children where necessary\n        if (!existSources.HasSource(LookUpConstants.InstanceContext) && blockForLookupOrNull != null)\n        {\n            var blockBuilderLookUp = new LookUpCmsBlock(LookUpConstants.InstanceContext, blockForLookupOrNull);\n            newSources.Add(blockBuilderLookUp);\n        }\n\n        // Provide the settings & resources stack lookup\n        if (context is IContextOfApp contextOfApp)\n        {\n            l.A(\"Inside an App-Context, will add stack sources for settings/resources\");\n            var dims = contextOfApp.Site.SafeLanguagePriorityCodes();\n            newSources.Add(new LookUpInStack(contextOfApp.AppSettings, dims));\n            newSources.Add(new LookUpInStack(contextOfApp.AppResources, dims));\n        }\n        else\n            l.A(\"Not in App context, will not add stack for settings/resources\");\n\n        var provider = new LookUpEngine(envLookups, Log, sources: newSources);\n\n        return l.Return(provider, $\"{provider.Sources.Count()}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/LookUp.Sys/SxcAppDataConfigSpecs.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.LookUp.Sys;\n\npublic class SxcAppDataConfigSpecs: AppDataConfigSpecs\n{\n    public IBlock? BlockForLookupOrNull { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Properties/SxcBlocksAssemblyVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Render\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Engines\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/StartupSxcBlocks.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Blocks.Sys.BlockEditor;\nusing ToSic.Sxc.Blocks.Sys.Work;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.DataSources.Sys;\nusing ToSic.Sxc.Integration.Modules;\nusing ToSic.Sxc.LookUp.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Users.Permissions;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcBlocks\n{\n    public static IServiceCollection AddSxcBlocks(this IServiceCollection services)\n    {\n        // Note: not sure if this is the best way, it's connected to the blocks needing services\n        services.TryAddTransient<BlockOfModule>();\n        services.TryAddTransient<BlockOfEntity>();\n        services.TryAddTransient<BlockGeneratorHelpers>();\n\n        services.TryAddTransient<BlockEditorSelector>();\n\n        // Block Editors\n        services.TryAddTransient<BlockEditorForEntity>();\n        services.TryAddTransient<BlockEditorForModule>();\n        services.TryAddTransient<BlockEditorBase.Dependencies>();\n\n        // Block functionality\n        services.TryAddTransient<BlockDataSourceFactory>();\n        services.TryAddTransient<DataSources.CmsBlock.Dependencies>(); // new v15\n\n        services.TryAddTransient<IAppDataConfigProvider, SxcAppDataConfigProvider>(); // new v17\n\n        // Context stuff in general\n        services.TryAddTransient<IContextOfBlock, ContextOfBlock>();\n\n\n\n        // Context stuff, which is explicitly scoped\n        services.TryAddTransient<IContextOfApp, ContextOfApp>();\n        services.TryAddTransient<ContextOfApp.Dependencies>();\n        services.TryAddScoped<ISxcCurrentContextService, SxcCurrentContextService>();\n        // must be the same instance, so it must get the original, scoped SxcContextResolver\n        services.TryAddTransient<ISxcAppCurrentContextService>(sp => sp.GetRequiredService<ISxcCurrentContextService>());\n\n\n        // New v15.04 WIP\n        services.TryAddScoped<ICurrentContextService>(x => x.GetRequiredService<ISxcCurrentContextService>());\n        services.TryAddScoped<ICurrentContextUserPermissionsService>(x => x.GetRequiredService<ISxcCurrentContextService>());\n        services.TryAddScoped<AppIdResolver>();\n\n        // Integration stuff - must be implemented by each platform\n        services.TryAddTransient<IPlatformModuleUpdater, BasicModuleUpdater>();\n\n        // Work\n        services.TryAddTransient<WorkBlocks>();\n        services.TryAddTransient<WorkBlocksMod>();\n        services.TryAddTransient<WorkBlockViewsGet>();\n\n        services.AddSxcBlocksFallbacks();\n\n        return services;\n    }\n\n    public static IServiceCollection AddSxcBlocksFallbacks(this IServiceCollection services)\n    {\n\n        services.TryAddTransient<IModuleAndBlockBuilder, ModuleAndBlockBuilderUnknown>();\n\n        // This is more of a fallback, in DNN it's pre-registered so it won't use this\n        services.TryAddTransient<ILookUpEngineResolver, LookUpEngineResolver>();\n\n        return services;\n    }\n\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.ExecutionContext/ExecutionContextExtensions.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context.Sys;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic static class ExecutionContextExtensions\n{\n    public static IBlock GetBlock(this IExecutionContext exCtx)\n        => exCtx.GetState<IBlock>();\n\n    public static IContextOfBlock GetContextOfBlock(this IExecutionContext exCtx)\n        => exCtx.GetState<IContextOfBlock>();\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageContext/HeadChange.cs",
    "content": "﻿using ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Sys.Render.PageContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic struct HeadChange\n{\n    public PageChangeModes ChangeMode { get; init; }\n\n    public IHtmlTag Tag { get; init; }\n\n    /// <summary>\n    /// This is part of the original property, which would be replaced.\n    /// </summary>\n    public string? ReplacementIdentifier { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageContext/Helpers.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Sys.Render.PageContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class Helpers\n{\n    public static string UpdateProperty(string original, PagePropertyChange change)\n    {\n        change = InjectOriginalInValue(change, original);\n        if (string.IsNullOrEmpty(original))\n            return change.Value ?? original;\n\n        if (change.ReplacementIdentifier.HasValue())\n        {\n            var pos = original.IndexOf(change.ReplacementIdentifier, StringComparison.InvariantCultureIgnoreCase);\n            if (pos >= 0)\n            {\n                var suffixPos = pos + change.ReplacementIdentifier.Length;\n                var suffix = (suffixPos < original.Length ? original.Substring(suffixPos) : \"\");\n                return original.Substring(0, pos) + change.Value + suffix;\n            }\n\n            if (change.ChangeMode == PageChangeModes.ReplaceOrSkip)\n                return original;\n        }\n\n        switch (change.ChangeMode)\n        {\n            case PageChangeModes.Default:\n            case PageChangeModes.Auto:\n            case PageChangeModes.Replace:\n                return change.Value ?? original;\n            case PageChangeModes.Append:\n                return original + change.Value;\n            case PageChangeModes.Prepend:\n                return change.Value + original;\n            case PageChangeModes.ReplaceOrSkip:\n                return original;\n            default:\n                throw new ArgumentOutOfRangeException();\n        }\n    }\n\n    /// <summary>\n    /// If new value has placeholder token [original], token will be replaced\n    /// with old value, effectively injecting old value in new value\n    /// </summary>\n    /// <param name=\"original\"></param>\n    /// <param name=\"originalValue\">old value</param>\n    public static PagePropertyChange InjectOriginalInValue(PagePropertyChange original, string originalValue)\n    {\n        // If it doesn't have the [Original] token, we're done\n        if (string.IsNullOrEmpty(original.Value) || original.Value!.IndexOf(OriginalToken, StringComparison.OrdinalIgnoreCase) == -1)\n            return original;\n\n        var clone = original with\n        {\n            Value = original.Value.ReplaceIgnoreCase(OriginalToken, originalValue),\n            ChangeMode = PageChangeModes.Replace,\n        };\n\n\n        return clone;\n    }\n\n    private const string OriginalToken = \"[original]\"; // new value can have [original] placeholder to inject old value in that position\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageContext/HttpHeader.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Render.PageContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record HttpHeader(string Name, string Value);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageContext/IChangeQueue.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Render.PageContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IChangeQueue\n{\n    /// <summary>\n    /// Once processed clean up, in case the same object (scoped) is used again, and we want to ensure it won't be processed again\n    /// </summary>\n    /// <returns></returns>\n    IList<PagePropertyChange> GetPropertyChangesAndFlush(ILog log);\n        \n    /// <summary>\n    /// Once processed clean up, in case the same object (scoped) is used again, and we want to ensure it won't be processed again\n    /// </summary>\n    /// <returns></returns>\n    IList<HeadChange> GetHeadChangesAndFlush(ILog log);\n\n    /// <summary>\n    /// Status code to set (if possible) to the page which loads this block\n    /// </summary>\n    int? HttpStatusCode { get; set; }\n\n    /// <summary>\n    /// Status message to set (if possible) to the page which loads this block\n    /// </summary>\n    string? HttpStatusMessage { get; set; }\n\n    public PagePropertyChange Queue(PageProperties property, string? value, PageChangeModes change, string? token);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageContext/IPageServiceShared.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.ClientAssets;\n\nnamespace ToSic.Sxc.Sys.Render.PageContext;\n\npublic interface IPageServiceShared: IChangeQueue\n{\n    List<ClientAsset> GetAssetsAndFlush();\n    void AddAssets(RenderEngineResult result);\n    IPageFeatures PageFeatures { get; }\n\n    string CspEphemeralMarker { get; }\n\n    /// <summary>\n    /// How the changes given to this object should be processed.\n    /// </summary>\n    PageChangeModes ChangeMode { get; set; }\n\n    List<HeadChange> Headers { get; }\n\n    List<HttpHeader> HttpHeaders { get; }\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"tag\"></param>\n    /// <param name=\"identifier\"></param>\n    /// <returns>The thing added to the head - or null if nothing added because tag was null</returns>\n    HeadChange? Add(IHtmlTag tag, string? identifier = null);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageContext/PageChangeModes.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Render.PageContext;\n\n[PrivateApi(\"not final yet, probably will not be implemented like this\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic enum PageChangeModes\n{\n    /// <summary>\n    /// Default - similar to Auto\n    /// </summary>\n    Default,\n        \n    /// <summary>\n    /// Auto - so a change will be applied as best seen fit\n    /// </summary>\n    Auto,\n        \n    /// <summary>\n    /// Replace the original implementation.\n    /// </summary>\n    Replace,\n        \n    /// <summary>\n    /// Attempt to replace, otherwise don't apply the change.\n    /// </summary>\n    ReplaceOrSkip,\n        \n    /// <summary>\n    /// Append the change.\n    /// </summary>\n    Append,\n        \n    /// <summary>\n    /// Prepend the change. \n    /// </summary>\n    Prepend,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageContext/PageProperties.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Render.PageContext;\n\npublic enum PageProperties\n{\n    Title,\n    Description,\n    Keywords,\n    Base,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageContext/PagePropertyChange.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Render.PageContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record PagePropertyChange\n{\n    public PageChangeModes ChangeMode { get; init; }\n        \n    public PageProperties Property { get; init; }\n\n    public string? Value { get; init; }\n\n    /// <summary>\n    /// This is part of the original property, which would be replaced.\n    /// </summary>\n    public string? ReplacementIdentifier { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageFeatures/IPageFeature.cs",
    "content": "﻿using ToSic.Sys.Requirements;\n\nnamespace ToSic.Sxc.Sys.Render.PageFeatures;\n\n// TODO: Probably remove this interface, as using the record directly is probably better.\n[PrivateApi(\"Internal / not final - neither name, namespace or anything\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPageFeature : IHasIdentityNameId, IHasRequirements\n{\n    /// <summary>\n    /// Primary identifier to activate the feature\n    /// </summary>\n#pragma warning disable CS0108, CS0114\n    string NameId { get; }\n#pragma warning restore CS0108, CS0114\n\n    /// <summary>\n    /// Name of this feature. \n    /// </summary>\n    string Name { get; }\n\n    /// <summary>\n    /// Nice description of the feature.\n    /// </summary>\n    string Description { get; }\n\n    string? Html { get; }\n\n    /// <summary>\n    /// List of other features required to run this feature.\n    /// </summary>\n    IEnumerable<string> Needs { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageFeatures/IPageFeatures.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Render.PageFeatures;\n\n/// <summary>\n/// Part of the <see cref=\"ToSic.Sxc.Services.IPageService\"/> to activate features on the page.\n/// </summary>\n[PrivateApi(\"should never be public, could be confused with the IPageService\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPageFeatures\n{\n    /// <summary>\n    /// Register the feature keys to be activated on the page.\n    /// </summary>\n    /// <param name=\"keys\"></param>\n    /// <returns>The keys it just activated (after trim/filter for empty)</returns>\n    IEnumerable<string> Activate(string[] keys);\n        \n    /// <summary>\n    /// Get a list of all features incl. dependent features for adding to the page\n    /// </summary>\n    /// <param name=\"log\"></param>\n    /// <returns></returns>\n    List<IPageFeature> GetFeaturesWithDependentsAndFlush(ILog log);\n\n\n    /// <summary>\n    /// Internal helper to expand a set of keys to the features.\n    /// It must be callable separately, because we also need it to expand features which are from another source. \n    /// </summary>\n    /// <param name=\"features\"></param>\n    /// <param name=\"log\"></param>\n    /// <returns></returns>\n    List<IPageFeature> GetWithDependents(List<string> features, ILog log);\n\n    /// <summary>\n    /// Add a manual feature (having custom HTML)\n    /// </summary>\n    /// <param name=\"newFeature\"></param>\n    void FeaturesFromSettingsAdd(PageFeatureFromSettings newFeature);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageFeatures/PageFeature.cs",
    "content": "﻿using ToSic.Sys.Requirements;\n\nnamespace ToSic.Sxc.Sys.Render.PageFeatures;\n\n/// <summary>\n/// A feature describes something that can be enabled on a page. It can be a script, some css, an inline JS or combinations thereof.\n/// This is just the information which is prepared. It will be in a list of features to activate.\n/// </summary>\n[PrivateApi(\"Internal / not final - neither name, namespace or anything\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record PageFeature : IPageFeature\n{\n    public const string ConditionIsPageFeature = \"pagefeature\";\n        \n    /// <summary>\n    /// Primary identifier to activate the feature\n    /// </summary>\n    public required string NameId { get; init; }\n\n    /// <summary>\n    /// Name of this feature. \n    /// </summary>\n    public string Name { get; init; } = \"\";\n\n    public string? Html { get; init; }\n\n    /// <summary>\n    /// Nice description of the feature.\n    /// </summary>\n    public string Description { get; init; } = \"\";\n\n    /// <summary>\n    /// List of other features required to run this feature.\n    /// </summary>\n    public IEnumerable<string> Needs { get; init; } = [];\n\n    [field: AllowNull, MaybeNull]\n    public Requirement Requirement => field ??= new(ConditionIsPageFeature, NameId);\n\n    public List<Requirement> Requirements { get; init; } = [];\n\n    /// <summary>\n    /// Temporary URL for internal features which need to store the URL someplace\n    /// This is not a final solution, in future it should probably\n    /// be more sophisticated, like contain a list of configuration objects to construct the url.\n    /// </summary>\n    public string? UrlInDist { get; init; }\n\n    /// <summary>\n    /// ToString for easier debugging\n    /// </summary>\n    public override string ToString()\n        => $\"{base.ToString()}({NameId})\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageFeatures/PageFeatureFromSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Render.PageFeatures;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record PageFeatureFromSettings : PageFeature\n{\n    public bool AutoOptimize { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Sys.Render/PageFeatures/SxcPageFeatures.cs",
    "content": "﻿using ToSic.Sys.Requirements;\nusing static ToSic.Sys.Capabilities.Features.BuiltInFeatures;\n\nnamespace ToSic.Sxc.Sys.Render.PageFeatures;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcPageFeatures\n{\n    /// <summary>\n    /// JQuery feature\n    /// </summary>\n    /// <remarks>\n    /// Published the key 'jQuery' in v12.02, do not change\n    /// </remarks>\n    public static PageFeature JQuery = new()\n    {\n        NameId = \"jQuery\",\n        Name = \"jQuery\"\n    };\n        \n    /// <summary>\n    /// Internal feature, not published ATM\n    /// </summary>\n    public static PageFeature ContextPage = new()\n    {\n        NameId = \"2sxc.ContextPage\",\n        Name = \"the $2sxc headers in the page so everything works\"\n    };\n\n    /// <summary>\n    /// Internal feature, not published ATM\n    /// </summary>\n    public static PageFeature ContextModule = new()\n    {\n        NameId = \"2sxc.ContextModule\",\n        Name = \"the $2sxc headers in the module tag\"\n    };\n\n    public static PageFeature JsApiOnModule = new()\n    {\n        NameId = \"2sxc.JsApiOnModule\",\n        Name = \"the $2sxc headers in the module tag\"\n    };\n\n    /// <summary>\n    /// The core 2sxc JS libraries\n    /// </summary>\n    /// <remarks>\n    /// Published the key '2sxc.JsCore' in v13.00, do not change\n    /// </remarks>\n    public static PageFeature JsCore = new()\n    {\n        NameId = \"2sxc.JsCore\",\n        Name = \"2sxc core js APIs\",\n        Needs = [ContextPage.NameId],\n        UrlInDist = \"js/2sxc.api.min.js\"\n    };\n\n    /// <summary>\n    /// The INTERNAL USE 2sxc JS libraries for cms / edit actions.\n    /// This one doesn't check requirements, and is the one which is added automatically. \n    /// </summary>\n    public static PageFeature JsCmsInternal = new()\n    {\n        NameId = \"Internal.JsCms\",\n        Name = \"2sxc inpage editing APIs - internal version without checks\",\n        Needs =\n        [\n            JsCore.NameId,\n            ContextModule.NameId\n        ],\n        UrlInDist = \"dist/inpage/inpage.min.js\"\n    };\n\n    private static readonly List<Requirement> RequiresPublicEditForm = [PublicEditForm.Requirement];\n\n    /// <summary>\n    /// The 2sxc JS libraries for cms / edit actions\n    /// </summary>\n    /// <remarks>\n    /// Published the key '2sxc.JsCms' in v13.00, do not change\n    /// </remarks>\n    public static PageFeature JsCms = new()\n    {\n        NameId = \"2sxc.JsCms\",\n        Name = \"2sxc inpage editing APIs\",\n        Needs = [JsCmsInternal.NameId],\n        Requirements = RequiresPublicEditForm\n    };\n\n    /// <summary>\n    /// The 2sxc JS libraries for cms / edit actions\n    /// </summary>\n    /// <remarks>\n    /// Published the key '2sxc.Toolbars' in v13.00, do not change\n    /// </remarks>\n    public static PageFeature ToolbarsInternal = new()\n    {\n        NameId = \"Internal.Toolbars\",\n        Name = \"2sxc InPage editing UIs / Toolbar\",\n        Needs =\n        [\n            JsCmsInternal.NameId,\n            ContextPage.NameId,\n        ],\n        UrlInDist = \"dist/inpage/inpage.min.css\"\n    };\n\n    /// <summary>\n    /// The 2sxc JS libraries for cms / edit actions\n    /// </summary>\n    /// <remarks>\n    /// Published the key '2sxc.Toolbars' in v13.00, do not change\n    /// </remarks>\n    public static PageFeature Toolbars = new()\n    {\n        NameId = \"2sxc.Toolbars\",\n        Name = \"2sxc InPage editing UIs / Toolbar\",\n        Needs = [ToolbarsInternal.NameId],\n        Requirements = RequiresPublicEditForm\n    };\n\n    /// <summary>\n    /// WIP - this will probably be moved to local only in future, ATM it's global though\n    /// </summary>\n    public static PageFeature ToolbarsAutoInternal = new()\n    {\n        NameId = \"Internal.ToolbarsAuto\",\n        Name = \"Ensure that the toolbars automatically appear\",\n        Needs =\n        [\n            ContextPage.NameId,\n            ToolbarsInternal.NameId\n        ]\n    };\n\n    /// <summary>\n    /// WIP - this will probably be moved to local only in future, ATM it's global though\n    /// </summary>\n    public static PageFeature ToolbarsAuto = new()\n    {\n        NameId = \"2sxc.ToolbarsAuto\",\n        Name = \"Ensure that the toolbars automatically appear\",\n        Needs = [ToolbarsAutoInternal.NameId],\n        Requirements = RequiresPublicEditForm\n    };\n\n    /// <summary>\n    /// turnOn feature\n    /// </summary>\n    /// <remarks>\n    /// Published the key 'turnOn' in v12.02, do not change\n    /// </remarks>\n    public static PageFeature TurnOn = new()\n    {\n        NameId = \"turnOn\",\n        Name = \"turnOn JS library\",\n        UrlInDist = \"dist/turnOn/turn-on.js\"\n    };\n\n    /// <summary>\n    /// turnOn feature\n    /// </summary>\n    /// <remarks>\n    /// Added in v15.01\n    /// </remarks>\n    public static PageFeature CmsWysiwyg = new()\n    {\n        NameId = \"Cms.Wysiwyg\",\n        Name = \"Wysiwyg helpers / css for better rich content\",\n        UrlInDist = \"dist/cms/wysiwyg.min.css\"\n    };\n\n    /// <summary>\n    /// Fancybox4 - just for use in the lightbox feature\n    /// </summary>\n    public static readonly PageFeature WebResourceFancybox4 = new()\n    {\n        NameId = \"fancybox4\",\n        Name = \"Fancybox 4 lightbox\"\n    };\n\n    public static PageFeature Lightbox = new()\n    {\n        NameId = \"lightbox\",\n        Name = \"The currently defined lightbox, whatever it is\",\n        Needs = [WebResourceFancybox4.NameId]\n    };\n\n\n    public static PageFeature EncryptFormData = new()\n    {\n        NameId = \"Network.EncryptBody\",\n        Name = \"Encrypts the form data before sending it to the server\",\n        Needs =\n        [\n            // Needs the 2sxc js-api on the module to work\n            JsApiOnModule.NameId,\n        ],\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/ToSic.Sxc.Blocks.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Blocks</AssemblyName>\n  </PropertyGroup>\n\n  <!--TODO: @2dm - RazorBlade only used for String methods, try to remove dependency -->\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Cms\\ToSic.Sxc.Cms.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/ToSic.Sxc.Blocks.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datasources_005Ccmsblock/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Blocks/Web.Sys.ClientAssets/ClientAsset.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.ClientAssets;\n\npublic record ClientAsset\n{\n    /// <summary>\n    /// Asset ID for use in HTML - ideally should ensure that this asset is only loaded once\n    /// </summary>\n    public string? Id { get; init; }\n        \n    public bool IsJs { get; init; }= true;\n    public string? Url { get; init; }\n    public int Priority {get; init; }\n    public string PosInPage { get; init; } = \"body\";\n\n    public bool IsExternal { get; init; } = true;\n    public string? Content { get; init; } = null;\n\n    public bool WhitelistInCsp { get; init; } = false;\n\n    /// <summary>\n    /// Used to store all other html attributes from html tag.\n    /// </summary>\n    public IDictionary<string, string>? HtmlAttributes { get; init; } = null;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Blocks.Sys/BlockIdentifier.cs",
    "content": "﻿namespace ToSic.Sxc.Blocks.Sys;\n\n/// <inheritdoc />\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockIdentifier(int zoneId, int appId, string? appDebugNameId, Guid guid, Guid viewOverride)\n    : IBlockIdentifier\n{\n    /// <inheritdoc />\n    public int ZoneId { get; } = zoneId;\n\n    /// <inheritdoc />\n    public int AppId { get; } = appId;\n\n    public string? AppDebugNameId { get; } = appDebugNameId;\n\n    /// <inheritdoc />\n    public Guid Guid { get; } = guid;\n\n    /// <inheritdoc />\n    public Guid PreviewView { get; } = viewOverride;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Blocks.Sys/IBlockIdentifier.cs",
    "content": "﻿using ToSic.Eav.Apps;\n\nnamespace ToSic.Sxc.Blocks.Sys;\n\n/// <summary>\n/// Identifies a content-block with all the parameters necessary to find it in the system\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IBlockIdentifier: IAppIdentity\n{\n    /// <summary>\n    /// The App NameId - only used in scenarios where the app isn't found, and we need the NameId to show an error\n    /// </summary>\n    public string? AppDebugNameId { get; }\n\n    /// <summary>\n    /// The block identifier\n    /// </summary>\n    Guid Guid { get; }\n\n    /// <summary>\n    /// The preview-view identifies a view in an App\n    /// It's only used when there is no content-block yet (so Guid is empty)\n    /// Once an app has been fully added to the page, the PreviewView isn't used any more\n    /// </summary>\n    Guid PreviewView { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/IFileModel.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets;\nusing ToSic.Sxc.Cms.Assets.Sys;\n\nnamespace ToSic.Sxc.Cms.Assets;\n\n/// <summary>\n/// BETA: A File Model which describes a file as returned by the <see cref=\"DataSources.AppAssets\"/> DataSource.\n/// </summary>\n/// <remarks>\n/// History\n/// \n/// * Introduced (BETA) in v19.00 for the <see cref=\"DataSources.AppAssets\"/> DataSource.\n/// * Not to be seen as final, since we may rename this type when we also\n/// * This is similar to the <see cref=\"Adam.IFile\"/> but still a bit different.\n/// For example, it has a <see cref=\"Folder\"/> property which is different from the <see cref=\"IFile.Folder\"/> property.\n/// </remarks>\n[ModelSpecs(Use = typeof(FileModelOfEntity))]\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"Still tweaking details and naming v19.0x\")]\npublic interface IFileModel: IModelFromData\n{\n    /// <inheritdoc cref=\"IFileModelSync.Name\" />\n    string? Name { get; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Extension\" />\n    string? Extension { get; }\n\n    /// <inheritdoc cref=\"IFileModelSync.FullName\" />\n    string? FullName { get; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Path\" />\n    string? Path { get; }\n\n    /// <summary>\n    /// Reference to the folder this file is in.\n    /// Returns `null` on the root folder.\n    /// </summary>\n    IFolderModel Folder { get; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Size\" />\n    int Size { get; }\n\n    ISizeInfo SizeInfo { get; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Url\" />\n    string? Url { get; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Created\" />\n    DateTime Created { get; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Modified\" />\n    DateTime Modified { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/IFolderModel.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Cms.Assets.Sys;\n\nnamespace ToSic.Sxc.Cms.Assets;\n\n/// <summary>\n/// BETA: A Folder Model which describes a folder as returned by the <see cref=\"DataSources.AppAssets\"/> DataSource.\n/// </summary>\n/// <remarks>\n/// History\n/// \n/// * Introduced (BETA) in v19.01 for the <see cref=\"DataSources.AppAssets\"/> DataSource.\n/// * Not to be seen as final, since we may rename this type when we also\n/// * This is similar to the <see cref=\"IFolder\"/> but still a bit different. For example, it has a <see cref=\"Folder\"/> property.\n/// </remarks>\n[ModelSpecs(Use = typeof(FolderModelOfEntity))]\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"Still tweaking details and naming v19.0x\")]\npublic interface IFolderModel: IModelFromData\n{\n    /// <inheritdoc cref=\"IFolderModelSync.Name\" />\n    string? Name { get; }\n\n    /// <inheritdoc cref=\"IFolderModelSync.FullName\" />\n    string? FullName { get; }\n\n    /// <inheritdoc cref=\"IFolderModelSync.Path\" />\n    string? Path { get; }\n\n    /// <summary>\n    /// Reference to the parent folder.\n    /// Returns `null` on the root folder.\n    /// </summary>\n    IFolderModel Folder { get; }\n\n    /// <summary>\n    /// All sub folders in this folder.\n    /// </summary>\n    IEnumerable<IFolderModel> Folders { get; }\n\n    /// <summary>\n    /// All files in this folder.\n    /// </summary>\n    IEnumerable<IFileModel> Files { get; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Url\" />\n    string? Url { get; }\n\n    /// <inheritdoc cref=\"IFolderModelSync.Created\" />\n    DateTime Created { get; }\n\n    /// <inheritdoc cref=\"IFolderModelSync.Modified\" />\n    DateTime Modified { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/Archive/FileModelOfEntity.cs",
    "content": "﻿//using ToSic.Eav.Apps.Assets;\n//using ToSic.Eav.Apps.Assets.Sys;\n//using ToSic.Sxc.Data.Models;\n\n//namespace ToSic.Sxc.Cms.Assets.Sys;\n\n//[PrivateApi(\"Still tweaking details and naming v19.0x\")]\n//internal class FileModelOfEntity: ModelFromEntity, IFileModelSync, IFileModel\n//{\n//    ///// <summary>\n//    ///// The ID of this asset (file/folder).\n//    ///// \n//    ///// In the case of App files/folders, these IDs will usually be negative, to indicate that they are not stable and can change at any time.\n//    ///// </summary>\n//    //public int Id => ((ITypedItem)this).Id;\n\n//    ///// <summary>\n//    ///// An empty Guid, since files/folders don't have a Guid.\n//    ///// </summary>\n//    //public Guid Guid => ((ITypedItem)this).Guid;\n\n\n//    public string? Name => GetThis<string>(null);\n\n//    public string? Extension => GetThis<string>(null);\n\n//    public string? FullName => GetThis<string>(null);\n\n//    public string? Path => GetThis<string>(null);\n\n//    [field: AllowNull, MaybeNull]\n//    public IFolderModel Folder => field ??= As<FolderModelOfEntity>(_entity.Children(field: nameof(Folder)).FirstOrDefault())!;\n\n//    public int Size => GetThis(0);\n\n//    [field: AllowNull, MaybeNull]\n//    public ISizeInfo SizeInfo => field ??= new SizeInfo(Size);\n\n//    public string? Url => GetThis<string>(null);\n\n//    public DateTime Created => _entity.Created;\n\n//    public DateTime Modified => _entity.Modified;\n\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/Archive/FolderModelOfEntity.cs",
    "content": "﻿//using ToSic.Sxc.Data.Models;\n\n//namespace ToSic.Sxc.Cms.Assets.Sys;\n\n//[PrivateApi(\"Still tweaking details and naming v19.0x\")]\n//internal class FolderModelOfEntity: ModelFromEntity, IFolderModelSync, IFolderModel\n//{\n//    ///// <inheritdoc cref=\"FileTyped.Id\"/>\n//    //public int Id => ((ITypedItem)this).Id;\n\n//    ///// <inheritdoc cref=\"FileTyped.Guid\"/>\n//    //public Guid Guid => ((ITypedItem)this).Guid;\n\n//    public string? Name => GetThis<string>(null);\n//    public string? FullName => GetThis<string>(null);\n//    public string? Path => GetThis<string>(null);\n\n//    [field: AllowNull, MaybeNull]\n//    public IFolderModel Folder => field\n//        ??= As<FolderModelOfEntity>(_entity.Children(field: nameof(Folder)).FirstOrDefault())!;\n\n//    [field: AllowNull, MaybeNull]\n//    public IEnumerable<IFolderModel> Folders => field \n//        ??= AsList<FolderModelOfEntity>(_entity.Children(field: nameof(Folders)))!;\n\n//    [field: AllowNull, MaybeNull]\n//    public IEnumerable<IFileModel> Files => field\n//        ??= AsList<FileModelOfEntity>(_entity.Children(field: nameof(Files)))!;\n\n//    public string? Url => GetThis<string>(null);\n//    public DateTime Created => _entity.Created;\n//    public DateTime Modified => _entity.Modified;\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/FileFolderBase.cs",
    "content": "﻿using ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\n\nnamespace ToSic.Sxc.Cms.Assets.Sys;\n\n[PrivateApi(\"Was InternalApi till v17 - hide till we know how to handle to-typed-conversions\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract record FileFolderBase: IRawEntity, IHasRelationshipKeys\n{\n    /// <inheritdoc />\n    [ContentTypeAttributeSpecs(Description = \"DO NOT USE. This is a temporary, random ID calculated at runtime and will return different values all the time.\")]\n    public int Id => 0;\n\n    /// <inheritdoc />\n    [ContentTypeAttributeSpecs(Description = \"DO NOT USE. This is a temporary, random ID calculated at runtime and will return different values all the time.\")]\n    public Guid Guid => default;\n\n    public abstract string? Name { get; init; }\n\n    /// <summary>\n    /// The full name with extension.\n    /// If it's a folder or there is no extension, then it's identical to the <see cref=\"Name\"/>\n    /// </summary>\n    [ContentTypeAttributeSpecs(Description = \"The full name with extension.\")]\n    public string? FullName { get; init; }\n\n    /// <summary>\n    /// This is just for internal lookup\n    /// </summary>\n    [ContentTypeAttributeIgnore]\n    public string? ParentFolderInternal { get; init; }\n\n    /// <summary>\n    /// Starting in the App-Root\n    /// </summary>\n    [ContentTypeAttributeSpecs(IsTitle = true, Description = \"Full path. It starts at the root of the app or whatever other system you're asking for. Always end with slash, so root is `/` and it's easy to distinguish folders and files.\")]\n    public string? Path { get; init; }\n\n    /// <inheritdoc />\n    [ContentTypeAttributeSpecs(Description = \"When the file/folder was created.\")]\n    public DateTime Created { get; init; }\n\n    /// <inheritdoc />\n    [ContentTypeAttributeSpecs(Description = \"When the file/folder was modified.\")]\n    public DateTime Modified { get; init; }\n\n    /// <summary>\n    /// The full url starting at the root of the site. Absolute but without protocol/domain.\n    /// </summary>\n    [ContentTypeAttributeSpecs(Description = \"The full url starting at the root of the site. Absolute but without protocol/domain.\")]\n    public string? Url { get; init; }\n\n    [ContentTypeAttributeSpecs(Type = ValueTypes.Entity, Description = \"Reference to the parent folder.\")]\n    public RawRelationship Folder => new(key: $\"Folder:{ParentFolderInternal}\");\n\n    /// <summary>\n    /// Data but without Id, Guid, Created, Modified\n    /// </summary>\n    [PrivateApi]\n    public virtual IDictionary<string, object?> Attributes(RawConvertOptions options)\n        => new Dictionary<string, object?>\n        {\n            { nameof(Name), Name },\n            { nameof(FullName), FullName },\n            { nameof(Path), Path },\n            { nameof(Url), Url },\n            { nameof(Folder), Folder },\n\n            // For debugging\n            //{ nameof(ParentFolderInternal), ParentFolderInternal },\n        };\n\n    [PrivateApi]\n    public abstract IEnumerable<object> RelationshipKeys(RawConvertOptions options);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/FileModelOfEntity.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets;\nusing ToSic.Eav.Apps.Assets.Sys;\n\nnamespace ToSic.Sxc.Cms.Assets.Sys;\n\n[PrivateApi(\"Still tweaking details and naming v19.0x\")]\ninternal record FileModelOfEntity: ModelFromEntity, IFileModelSync, IFileModel\n{\n    ///// <summary>\n    ///// The ID of this asset (file/folder).\n    ///// \n    ///// In the case of App files/folders, these IDs will usually be negative, to indicate that they are not stable and can change at any time.\n    ///// </summary>\n    //public int Id => ((ITypedItem)this).Id;\n\n    ///// <summary>\n    ///// An empty Guid, since files/folders don't have a Guid.\n    ///// </summary>\n    //public Guid Guid => ((ITypedItem)this).Guid;\n\n\n    public string? Name => GetThis<string>(null);\n\n    public string? Extension => GetThis<string>(null);\n\n    public string? FullName => GetThis<string>(null);\n\n    public string? Path => GetThis<string>(null);\n\n    [field: AllowNull, MaybeNull]\n    public IFolderModel Folder => field\n        ??= Entity.Children(field: nameof(Folder)).FirstOrDefault()?.ToModel<FolderModelOfEntity>(skipTypeCheck: true)!;\n\n    public int Size => GetThis(0);\n\n    [field: AllowNull, MaybeNull]\n    public ISizeInfo SizeInfo => field ??= new SizeInfo(Size);\n\n    public string? Url => GetThis<string>(null);\n\n    public DateTime Created => Entity.Created;\n\n    public DateTime Modified => Entity.Modified;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/FileModelRaw.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Sys.ContentTypes;\n\nnamespace ToSic.Sxc.Cms.Assets.Sys;\n\n/// <summary>\n/// Internal class to hold all the information about the App files,\n/// until it's converted to an IEntity in the <see cref=\"AppAssets\"/> DataSource.\n///\n/// Important: this is an internal object.\n/// We're just including it in the docs to better understand where the properties come from.\n/// We'll probably move it to another namespace some day.\n/// </summary>\n/// <remarks>\n/// Make sure the property names never change, as they are critical for the created Entity.\n/// </remarks>\n[PrivateApi(\"Was InternalApi till v17 - hide till we know how to handle to-typed-conversions\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ContentTypeSpecs(\n    Guid = \"3cf0822f-d276-469a-bbd1-cc84fd6ff748\",\n    Description = \"File in an App\",\n    Name = TypeName\n)]\npublic record FileModelRaw: FileFolderBase, IFileModelSync\n{\n    internal const string TypeName = \"File\";\n\n    internal static DataFactoryOptions Options = new()\n    {\n        TitleField = nameof(Path),\n        Type = typeof(FileModelRaw)\n    };\n\n    /// <inheritdoc cref=\"IFileModelSync.Name\"/>\n    [ContentTypeAttributeSpecs(Description = \"The file name without extension, like my-image\")]\n    public override string? Name { get; init; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Extension\"/>\n    public string? Extension { get; init; }\n\n    /// <inheritdoc cref=\"IFileModelSync.Size\"/>\n    public int Size { get; init; }\n\n    /// <summary>\n    /// Data but without ID, Guid, Created, Modified\n    /// </summary>\n    [PrivateApi]\n    public override IDictionary<string, object?> Attributes(RawConvertOptions options)\n        => new Dictionary<string, object?>(base.Attributes(options))\n        {\n            { nameof(Extension), Extension },\n            { nameof(Size), Size },\n        };\n\n    [PrivateApi]\n    public override IEnumerable<object> RelationshipKeys(RawConvertOptions options)\n        => new List<object>\n        {\n            // For relationships looking for files in this folder\n            $\"FileIn:{ParentFolderInternal}\"\n        };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/FolderModelOfEntity.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Assets.Sys;\n\n[PrivateApi(\"Still tweaking details and naming v19.0x\")]\ninternal record FolderModelOfEntity: ModelFromEntity, IFolderModelSync, IFolderModel\n{\n    ///// <inheritdoc cref=\"FileTyped.Id\"/>\n    //public int Id => ((ITypedItem)this).Id;\n\n    ///// <inheritdoc cref=\"FileTyped.Guid\"/>\n    //public Guid Guid => ((ITypedItem)this).Guid;\n\n    public string? Name => GetThis<string>(null);\n    public string? FullName => GetThis<string>(null);\n    public string? Path => GetThis<string>(null);\n\n    [field: AllowNull, MaybeNull]\n    public IFolderModel Folder => field\n        ??= Entity.Children(field: nameof(Folder)).FirstOrDefault()?.ToModel<FolderModelOfEntity>(skipTypeCheck: true)!;\n\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<IFolderModel> Folders => field \n        ??= Entity.Children(field: nameof(Folders)).ToModels<FolderModelOfEntity>();\n\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<IFileModel> Files => field\n        ??= Entity.Children(field: nameof(Files)).ToModels<FileModelOfEntity>()!;\n\n    public string? Url => GetThis<string>(null);\n    public DateTime Created => Entity.Created;\n    public DateTime Modified => Entity.Modified;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/FolderModelRaw.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\n\nnamespace ToSic.Sxc.Cms.Assets.Sys;\n\n/// <summary>\n/// Internal class to hold all the information about the App folders,\n/// until it's converted to an IEntity in the <see cref=\"AppAssets\"/> DataSource.\n///\n/// Important: this is an internal object.\n/// We're just including in the docs to better understand where the properties come from.\n/// We'll probably move it to another namespace some day.\n/// </summary>\n/// <remarks>\n/// Make sure the property names never change, as they are critical for the created Entity.\n/// </remarks>\n[PrivateApi(\"Was InternalApi till v17 - hide till we know how to handle to-typed-conversions\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ContentTypeSpecs(\n    Guid = \"96cda931-b677-4589-9eb2-df5a38cefff0\",\n    Description = \"Folder in an App\",\n    Name = TypeName\n)]\npublic record FolderModelRaw: FileFolderBase, IFolderModelSync\n{\n    internal const string TypeName = \"Folder\";\n\n    internal static DataFactoryOptions Options = new()\n    {\n        TypeName = TypeName,\n        TitleField = nameof(Path)\n    };\n\n    /// <inheritdoc cref=\"IFolderModelSync.Name\"/>\n    [ContentTypeAttributeSpecs(Description = \"The folder name or blank when it's the root.\")]\n    public override string? Name { get; init; }\n\n    [ContentTypeAttributeSpecs(Type = ValueTypes.Entity, Description = \"Folders in this folder.\")]\n    public RawRelationship Folders => new(key: $\"FolderIn:{Path}\");\n\n    [ContentTypeAttributeSpecs(Type = ValueTypes.Entity, Description = \"Files in this folder.\")]\n    public RawRelationship Files => new(key: $\"FileIn:{Path}\");\n\n    [PrivateApi]\n    public override IDictionary<string, object?> Attributes(RawConvertOptions options)\n        => new Dictionary<string, object?>(base.Attributes(options))\n        {\n            { nameof(Folders), Folders },\n            { nameof(Files), Files },\n        };\n\n    [PrivateApi]\n    public override IEnumerable<object> RelationshipKeys(RawConvertOptions options)\n        => new List<object>\n        {\n            // For Relationships looking for this folder\n            $\"Folder:{Path}\",\n            // For Relationships looking for folders having a specific parent\n            $\"FolderIn:{ParentFolderInternal}\",\n        };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/IFileModelSync.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Assets.Sys;\n\ninternal interface IFileModelSync\n{\n    /// <summary>\n    /// The file name without extension.\n    /// </summary>\n    string? Name { get; }\n\n    /// <summary>\n    /// The file name extension, without any dot.\n    /// Purpose is to do switching between extensions.\n    /// If you want to have a safe, merged file name, just take the `FullName`.\n    /// </summary>\n    string? Extension { get; }\n\n    /// <summary>\n    /// The size in bytes.\n    /// </summary>\n    int Size { get; }\n\n    /// <summary>\n    /// The full name with extension.\n    /// If it's a folder or there is no extension, then it's identical to the <see cref=\"Name\"/>\n    /// </summary>\n    string? FullName { get; }\n\n    /// <summary>\n    /// Starting in the App-Root\n    /// </summary>\n    string? Path { get; }\n\n    /// <summary>\n    /// The full url starting at the root of the site. Absolute but without protocol/domain.\n    /// </summary>\n    string? Url { get; }\n\n    /// <summary>\n    /// When the file/folder was created.\n    /// </summary>\n    DateTime Created { get; }\n\n    /// <summary>\n    /// When the file/folder was modified.\n    /// </summary>\n    DateTime Modified { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Assets/Sys/IFolderModelSync.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Assets.Sys;\n\ninternal interface IFolderModelSync\n{\n    /// <summary>\n    /// The folder name - or blank when it's the root.\n    /// </summary>\n    string? Name { get; }\n\n    /// <summary>\n    /// The full name with extension.\n    /// If it's a folder or there is no extension, then it's identical to the `Name`\n    /// </summary>\n    string? FullName { get; }\n\n    /// <summary>\n    /// Starting in the App-Root\n    /// </summary>\n    string? Path { get; }\n\n    /// <summary>\n    /// The full url starting at the root of the site. Absolute but without protocol/domain.\n    /// </summary>\n    string? Url { get; }\n\n    /// <summary>\n    /// When the file/folder was created.\n    /// </summary>\n    public DateTime Created { get; }\n\n    /// <summary>\n    /// When the file/folder was modified.\n    /// </summary>\n    public DateTime Modified { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Notes/INoteModel.cs",
    "content": "﻿using ToSic.Sxc.Cms.Notes.Sys;\n\nnamespace ToSic.Sxc.Cms.Notes;\n\n/// <summary>\n/// Note on anything - such as a site, page, entity, etc.\n/// </summary>\n/// <remarks>\n/// History\n/// \n/// * Introduced in v21.02\n/// </remarks>\n[ModelSpecs(Use = typeof(NoteModelOfEntity))]\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"WIP v21.02\")]\npublic interface INoteModel : IModelFromEntity, IModelFromData\n{\n    /// <summary>\n    /// The note ID.\n    /// </summary>\n    int Id { get; }\n\n    /// <summary>\n    /// The note GUID.\n    /// </summary>\n    Guid Guid { get; }\n\n    /// <summary>\n    /// The note creation date/time.\n    /// </summary>\n    DateTime Created { get; }\n\n    /// <summary>\n    /// The note modification date/time.\n    /// </summary>\n    DateTime Modified { get; }\n\n    /// <summary>\n    /// The note.\n    /// </summary>\n    string? Note { get; }\n\n    string? NoteType { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Notes/Sys/NoteModelOfEntity.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Notes.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ModelSpecs(ContentType = ContentTypeNameId)]\ninternal record NoteModelOfEntity : ModelFromEntity, INoteModel\n{\n    public const string ContentTypeNameId = \"5e958dc6-2922-4d68-835c-7b9711538b12\";\n    internal const string TypeName = \"Note\";\n\n    public int Id => Entity.EntityId;\n    public Guid Guid => Entity.EntityGuid;\n    public DateTime Created => Entity.Created;\n    public DateTime Modified => Entity.Modified;\n\n    public string? Note => GetThis<string>(null);\n\n    public string? NoteType => GetThis(fallback: \"note\");\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Pages/IPageModel.cs",
    "content": "﻿using ToSic.Sxc.Cms.Pages.Sys;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Cms.Pages;\n\n/// <summary>\n/// BETA Data Model as is returned by the <see cref=\"Pages\"/> DataSource.\n/// </summary>\n/// <remarks>\n///\n/// For detailed documentation, check the docs of the underlying objects:\n///\n/// * [Dnn TabInfo](https://docs.dnncommunity.org/api/DotNetNuke.Entities.Tabs.TabInfo.html)\n/// * [Oqtane Page](https://docs.oqtane.org/api/Oqtane.Models.Page.html)\n///\n/// History\n/// \n/// * Released v19.01\n/// * the previous internal implementation had a property called `Visible` which we finalized to `IsNavigation` to better clarify it purpose.\n/// * the previous internal implementation had a property called `Clickable` which we finalized to `IsClickable` to better clarify it purpose.\n/// </remarks>\n[ModelSpecs(Use = typeof(PageModelOfEntity))]\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic interface IPageModel : IModelFromData\n{\n    /// <summary>\n    /// The page ID.\n    ///\n    /// * In Dnn it's from `TabInfo.TabID`\n    /// * In Oqtane it's `Page.PageId`\n    /// </summary>\n    int Id { get; }\n\n    /// <summary>\n    /// The parent page ID.\n    ///\n    /// It's usually `0` if it's a top level page.\n    ///\n    /// * In Dnn it's from `TabInfo.ParentId`\n    /// * in Oqtane it's from `Page.ParentId`\n    /// </summary>\n    int ParentId { get; }\n\n    /// <summary>\n    /// The page GUID.\n    ///\n    /// * In Dnn it's from `TabInfo.UniqueId`\n    /// * In Oqtane it's `Guid.Empty` as Oqtane doesn't have page GUIDs\n    /// </summary>\n    Guid Guid { get; }\n\n    /// <summary>\n    /// The page title.\n    ///\n    /// * In Dnn it's from `TabInfo.Title`\n    /// * in Oqtane it's from `Page.Title`\n    /// </summary>\n    string? Title { get; }\n\n    /// <summary>\n    /// The page name.\n    ///\n    /// * In Dnn it's from `TabInfo.Name`\n    /// * in Oqtane it's from `Page.Name`\n    /// </summary>\n    string? Name { get; }\n\n    /// <summary>\n    /// Determines if this item is clickable in the menu.\n    ///\n    /// * In Dnn it's from `!TabInfo.DisableLink`\n    /// * in Oqtane it's from `Page.IsClickable`\n    /// </summary>\n    /// <remarks>\n    /// Added in v15.01\n    /// </remarks>\n    bool IsClickable { get; }\n\n    /// <summary>\n    /// Order of this item in a menu.\n    /// It is 1 based, so the first item has Order 1.\n    ///\n    /// * In Dnn it's from `TabInfo.TabOrder`\n    /// * in Oqtane it's from `Page.Order`\n    /// </summary>\n    /// <remarks>\n    /// Added in v15.01\n    /// </remarks>\n    int Order { get; }\n\n    /// <summary>\n    /// The page visibility - if it should be shown in the menu.\n    ///\n    /// * In Dnn it's from `TabInfo.IsVisible`\n    /// * in Oqtane it's from `Page.IsNavigation`\n    /// </summary>\n    bool IsNavigation { get; }\n\n    /// <summary>\n    /// Info if the page has sub-pages. \n    ///\n    /// * In Dnn it's from `TabInfo.HasChildren`\n    /// * in Oqtane it's from `Page.HasChildren`\n    /// </summary>\n    /// <remarks>\n    /// Added in v15.01\n    /// </remarks>\n    bool HasChildren { get; }\n\n    /// <summary>\n    /// How deep this page is in the breadcrumb.\n    /// The number is 1 based, so the top level is 1.\n    ///\n    /// * In Dnn it's from `TabInfo.Level` (+1)\n    /// * in Oqtane it's from `Page.Level` (+1)\n    /// </summary>\n    /// <remarks>\n    /// Added in v15.01\n    /// </remarks>\n    int Level { get; }\n\n    /// <summary>\n    /// WIP\n    /// * In Dnn it's from `TabInfo.TabSettings[\"LinkNewWindow\"]`and will be either `_blank` or `` (empty string)\n    /// * In Oqtane it's _not implemented_ an will be an empty string\n    /// </summary>\n    /// <remarks>\n    /// Added in v15.02\n    /// </remarks>\n    string? LinkTarget { get; }\n\n    /// <summary>\n    /// The path with slashes to this page.\n    /// \n    /// * In Dnn it's from `TabInfo.TabPath`\n    /// * in Oqtane it's from `Page.Path`\n    /// </summary>\n    string? Path { get; }\n\n    /// <summary>\n    /// The public url to this page (without any trailing slashes)\n    ///\n    /// * In Dnn it's from `TabInf.FullUrl` (last slash removed)\n    /// * in Oqtane it's a combination of protocol, site-alias and path\n    /// </summary>\n    string? Url { get; }\n\n    /// <summary>\n    /// The page creation date/time.\n    ///\n    /// * In Dnn it's from `TabInfo.CreatedOnDate`\n    /// * in Oqtane it's from `Page.CreatedOn`\n    /// </summary>\n    DateTime Created { get; }\n\n    /// <summary>\n    /// The page modification date/time.\n    ///\n    /// * In Dnn it's from `TabInfo.LastModifiedOnDate`\n    /// * in Oqtane it's from `Page.ModifiedOn`\n    /// </summary>\n    DateTime Modified { get; }\n\n    /// <summary>\n    /// The page delete-status.\n    /// Normally you will only see not-deleted pages, so it should usually be false.\n    ///\n    /// * In Dnn it's from `TabInfo.IsDeleted`\n    /// * in Oqtane it's from `Page.IsDeleted`\n    /// </summary>\n    /// <remarks>\n    /// Added in v15.01\n    /// </remarks>\n    bool IsDeleted { get; }\n\n    // Not implemented, and not sure if we should, since it would potentially introduce a lot of prefetch data\n    //IEnumerable<IPageModel> Children { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Pages/Sys/PageModelOfEntity.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Pages.Sys;\n\npublic record PageModelOfEntity: ModelFromEntity, IPageModel\n{\n    public int Id => Entity.EntityId;\n    public int ParentId => GetThis(0);\n    public Guid Guid => Entity.EntityGuid;\n    public string? Title => GetThis<string>(null);\n    public string? Name => GetThis<string>(null);\n    public bool IsClickable => GetThis(false);\n    public int Order => GetThis(0);\n    public bool IsNavigation => GetThis(false);\n    public bool HasChildren => GetThis(false);\n    public int Level => GetThis(0);\n    public string? LinkTarget => GetThis<string>(null);\n    public string? Path => GetThis<string>(null);\n    public string? Url => GetThis<string>(null);\n    public DateTime Created => Entity.Created;\n    public DateTime Modified => Entity.Modified;\n    public bool IsDeleted => GetThis(false);\n\n    public IEnumerable<IPageModel> Children =>\n        Entity.Children(field: nameof(Children)).ToModels<PageModelOfEntity>();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Pages/Sys/PageModelRaw.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\n\nnamespace ToSic.Sxc.Cms.Pages.Sys;\n\n/// <summary>\n/// Internal class to hold all the information about the page,\n/// until it's converted to an IEntity in the <see cref=\"DataSources.Pages\"/> DataSource.\n///\n/// * [Dnn TabInfo](https://docs.dnncommunity.org/api/DotNetNuke.Entities.Tabs.TabInfo.html)\n/// * [Oqtane Page](https://docs.oqtane.org/api/Oqtane.Models.Page.html)\n/// </summary>\n[PrivateApi(\"Was InternalApi till v17 - hide till we know how to handle to-typed-conversions\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ContentTypeSpecs(\n    Guid = \"c648a91d-b650-42bf-ad6a-9582015c165e\",\n    Description = \"Page in the site\",\n    Name = TypeName\n)]\npublic record PageModelRaw: IRawEntity, IPageModel, IHasRelationshipKeys\n{\n    #region IRawEntity\n\n    private const string TypeName = \"Page\";\n\n    internal static DataFactoryOptions Option = new()\n    {\n        TitleField = nameof(Title),\n        Type = typeof(PageModelRaw)\n    };\n\n    IDictionary<string, object?> IRawEntity.Attributes(RawConvertOptions options)\n        => new Dictionary<string, object?>\n        {\n            // v14+\n            { nameof(Title), Title },\n            { nameof(Name), Name },\n            { nameof(ParentId), ParentId },\n            { nameof(IsNavigation), IsNavigation },\n            { nameof(Path), Path },\n            { nameof(Url), Url },\n            // New in v15.01\n            { nameof(IsClickable), IsClickable },\n            { nameof(Order), Order },\n            { nameof(IsDeleted), IsDeleted },\n            { nameof(Level), Level },\n            { nameof(HasChildren), HasChildren },\n            // New in v15.02\n            { nameof(LinkTarget), LinkTarget },\n\n            { \"Children\", ChildrenRaw }\n        };\n\n    private const string ParentPrefix = \"ParentId:\";\n\n    private RawRelationship ChildrenRaw => new(key: $\"{ParentPrefix}{Id}\");\n\n\n    IEnumerable<object> IHasRelationshipKeys.RelationshipKeys(RawConvertOptions options)\n        => new List<object>\n        {\n            // For relationships looking for files in this folder\n            $\"{ParentPrefix}{ParentId}\"\n        };\n    #endregion\n\n\n    /// <inheritdoc cref=\"IPageModel.Id\"/>\n    public int Id { get; init; }\n\n    /// <inheritdoc />\n    public int ParentId { get; init; }\n\n    /// <inheritdoc cref=\"IPageModel.Guid\"/>\n    public Guid Guid { get; init; }\n\n    /// <inheritdoc cref=\"IPageModel.Title\"/>\n    public string? Title { get; init; }\n\n    /// <inheritdoc />\n    public string? Name { get; init; }\n\n    /// <inheritdoc />\n    public bool IsClickable { get; init; }\n\n\n    /// <inheritdoc />\n    public int Order { get; init; }\n\n    /// <inheritdoc />\n    public bool IsNavigation { get; init; }\n\n    /// <inheritdoc />\n    public bool HasChildren { get; init; }\n\n    /// <inheritdoc />\n    public int Level { get; init; }\n\n    /// <inheritdoc />\n    public string? LinkTarget { get; init; }\n\n\n    /// <inheritdoc />\n    public string? Path { get; init; }\n\n    /// <inheritdoc />\n    public string? Url { get; init; }\n\n    /// <inheritdoc cref=\"IPageModel.Created\" />\n    public DateTime Created { get; init; }\n\n    /// <inheritdoc cref=\"IPageModel.Modified\" />\n    public DateTime Modified { get; init; }\n\n    /// <inheritdoc />\n    public bool IsDeleted { get; init; }\n\n    // Not implemented, and not sure if we should, since it would potentially introduce a lot of prefetch data\n    //[ContentTypeAttributeSpecs(Type = ValueTypes.Entity, Description = \"Reference to the child pages.\")]\n    //public IEnumerable<IPageModel> Children { get; init; }\n    \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/BasicPagePublishing.cs",
    "content": "﻿using ToSic.Eav.Context;\n\nnamespace ToSic.Sxc.Cms.Publishing.Sys;\n\ninternal class BasicPagePublishing : ServiceBase, IPagePublishing\n{\n    public BasicPagePublishing(WarnUseOfUnknown<BasicPagePublishing> _) : base($\"{LogScopes.NotImplemented}.Publsh\") { }\n\n    public void DoInsidePublishing(IContextOfSite context, Action<VersioningActionInfo> action)\n    {\n        var l = Log.Fn();\n        var versioningActionInfo = new VersioningActionInfo();\n        action.Invoke(versioningActionInfo);\n        l.Done();\n    }\n\n\n\n    public int GetLatestVersion(int instanceId) => 0;\n\n    public int GetPublishedVersion(int instanceId) => 0;\n\n\n    public void Publish(int instanceId, int version)\n    {\n        Log.A($\"Publish(m:{instanceId}, v:{version})\");\n        Log.A(\"publish never happened \");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/IPagePublishing.cs",
    "content": "﻿using ToSic.Eav.Context;\n\nnamespace ToSic.Sxc.Cms.Publishing.Sys;\n\n// Note: maybe some day this should go into a .Cms namespace\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPagePublishing: IHasLog\n{\n    /// <summary>\n    /// Wraps an action and performs pre/post processing related to versioning of the environment.\n    /// </summary>\n    /// <param name=\"context\"></param>\n    /// <param name=\"action\"></param>\n    void DoInsidePublishing(IContextOfSite context, Action<VersioningActionInfo> action);\n\n    ///// <summary>\n    ///// Wraps an action inside publish of latest version.\n    ///// NOTE: Should be called by the business-controller of the module. The controller must implement the IVersionable.\n    ///// </summary>\n    ///// <param name=\"moduleId\"></param>\n    //void DoInsidePublishLatestVersion(int moduleId, Action<VersioningActionInfo> action);\n\n    ///// <summary>\n    ///// Wraps an action inside delete/discard of latest version.\n    ///// NOTE: Should be called by the business-controller of the module. The controller must implement the IVersionable.\n    ///// </summary>\n    ///// <param name=\"moduleId\"></param>\n    //void DoInsideDeleteLatestVersion(int moduleId, Action<VersioningActionInfo> action);\n\n    int GetLatestVersion(int instanceId);\n\n    int GetPublishedVersion(int instanceId);\n\n    void Publish(int instanceId, int version);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/IPagePublishingGetSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Publishing.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPagePublishingGetSettings: IHasLog, ISwitchableService\n{\n    BlockPublishingSettings SettingsOfModule(int moduleId);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/NoPagePublishing.cs",
    "content": "﻿using ToSic.Eav.Context;\n\nnamespace ToSic.Sxc.Cms.Publishing.Sys;\n\n/// <summary>\n/// This is the fallback page publishing strategy, which basically says that page publishing isn't enabled\n/// NOTE: It is currently not in use, and that's ok. \n/// </summary>\n// ReSharper disable once UnusedMember.Global\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class NoPagePublishing() : ServiceBase(\"Eav.NoPubl\"), IPagePublishing\n{\n    public void DoInsidePublishing(IContextOfSite context, Action<VersioningActionInfo> action)\n    {\n        var info = new VersioningActionInfo();\n        action.Invoke(info);\n    }\n\n    //public void DoInsidePublishLatestVersion(int instanceId, Action<VersioningActionInfo> action)\n    //{\n    //    // NOTE: Do nothing!\n    //}\n\n    //public void DoInsideDeleteLatestVersion(int instanceId, Action<VersioningActionInfo> action)\n    //{\n    //    // NOTE: Do nothing!\n    //}\n\n    public int GetLatestVersion(int instanceId)\n    {\n        return 0;\n    }\n\n    public int GetPublishedVersion(int instanceId)\n    {\n        return 0;\n    }\n\n    public void Publish(int instanceId, int version)\n    {\n        // ignore\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/PagePublishingGetSettingsBase.cs",
    "content": "﻿using System.Collections.Concurrent;\n\nnamespace ToSic.Sxc.Cms.Publishing.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class PagePublishingGetSettingsBase(string logPrefix)\n    : ServiceBase(logPrefix + \".PubRes\"), IPagePublishingGetSettings\n{\n    private PublishingMode Requirements(int instanceId)\n    {\n        var l = Log.Fn<PublishingMode>($\"{instanceId}\");\n        if (instanceId < 0)\n            return l.Return(PublishingMode.DraftOptional, \"no instance\");\n        if (Cache.TryGetValue(instanceId, out var value))\n            return l.Return(value, \"in cache\");\n\n        var decision = LookupRequirements(instanceId);\n        Cache.TryAdd(instanceId, decision);\n        return l.Return(decision, $\"decision:{decision}\");\n    }\n    protected static readonly ConcurrentDictionary<int, PublishingMode> Cache = new();\n\n    /// <summary>\n    /// The lookup must be implemented for each platform\n    /// </summary>\n    /// <param name=\"moduleId\"></param>\n    /// <returns></returns>\n    protected abstract PublishingMode LookupRequirements(int moduleId);\n\n    public BlockPublishingSettings SettingsOfModule(int moduleId)\n    {\n        var mode = Requirements(moduleId);\n        return new()\n        {\n            AllowDraft = mode != PublishingMode.DraftForbidden,\n            ForceDraft = mode == PublishingMode.DraftRequired, \n            Mode = mode\n        };\n    }\n\n    #region SwitchableService\n\n\n    public virtual string NameId => \"Default\";\n\n    public virtual bool IsViable() => true;\n\n    public virtual int Priority => (int)PagePublishingPriorities.Default;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/PagePublishingGetSettingsForbidden.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Cms.Publishing.Sys;\n\n/// <summary>\n/// This is the fallback page publishing strategy, which basically says that page publishing isn't enabled\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PagePublishingGetSettingsForbidden(IFeaturesService featuresService)\n    : ServiceBase(\"Cms.PubForb\", connect: [featuresService]), IPagePublishingGetSettings\n{\n    public BlockPublishingSettings SettingsOfModule(int moduleId) => new()\n    {\n        AllowDraft = false,\n        ForceDraft = false,\n        Mode = PublishingMode.DraftForbidden\n    };\n\n    public string NameId => \"DraftForbidden\";\n\n    public bool IsViable() => featuresService.IsEnabled(BuiltInFeatures.EditUiDisableDraft.NameId);\n\n    public int Priority => (int)PagePublishingPriorities.DraftForbidden;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/PagePublishingGetSettingsOptional.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Publishing.Sys;\n\n/// <summary>\n/// This is the fallback page publishing strategy, which basically says that page publishing isn't enabled\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PagePublishingGetSettingsOptional() : ServiceBase(\"Cms.PubNone\"), IPagePublishingGetSettings\n{\n\n    public BlockPublishingSettings SettingsOfModule(int moduleId) => new()\n    {\n        AllowDraft = true,\n        ForceDraft = false,\n        Mode = PublishingMode.DraftOptional\n    };\n\n    public string NameId => \"NoPublishing\";\n\n    public bool IsViable() => true;\n\n    public int Priority => (int)PagePublishingPriorities.Unknown;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/PagePublishingGetSettingsUnknown.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Publishing.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PagePublishingGetSettingsUnknown : PagePublishingGetSettingsBase\n{\n    public PagePublishingGetSettingsUnknown(WarnUseOfUnknown<PagePublishingGetSettingsUnknown> _) : base(LogScopes.NotImplemented) { }\n\n    protected override PublishingMode LookupRequirements(int moduleId) \n        => PublishingMode.DraftOptional;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/PagePublishingPriorities.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Publishing.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic enum PagePublishingPriorities\n{\n    Unknown = 0,\n    Default = 1, \n\n    // Platform implementation, like Dnn\n    Platform = 10,\n\n    // Override forbidden\n    DraftForbidden = 100,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/PagePublishingSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Publishing.Sys;\n\n/// <summary>\n/// Tell the save operations if saving should trigger change-detection at page level to start work flows\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockPublishingSettings\n{\n    public bool AllowDraft = true;\n\n    public bool ForceDraft = false;\n\n    public PublishingMode Mode = PublishingMode.DraftOptional;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/PublishingMode.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Publishing.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic enum PublishingMode\n{\n    DraftOptional,\n    DraftRequired,\n    DraftForbidden,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Publishing.Sys/VersioningActionInfo.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Publishing.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class VersioningActionInfo\n{\n    // TODO: Add properties required (like the latest version)\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/SiteSettingNames.cs",
    "content": "﻿namespace ToSic.Sxc.Cms;\n\n/// <summary>\n/// Contains special constants for setting-names stored in the Dnn/Oqtane site settings.\n/// </summary>\n/// <remarks>\n/// Note that for historical reasons, the keys where different in Dnn and Oqtane until 2025-08-19.\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SiteSettingNames\n{\n    // Important note: always use static-readonly, NOT constant\n    // This prevents the value from being compiled into other DLLs,\n    // So if a value ever changes, it will always be retrieved from here\n\n    /// <summary>\n    /// This site setting pointing to the zone of site.\n    /// The value must contain the int.\n    /// </summary>\n    /// <remarks>\n    /// \"EavZone\" in Oqtane until 2025-08-19\n    /// </remarks>\n    public static readonly string SiteKeyForZoneId = \"TsDynDataZoneId\";\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Sites/ISiteModel.cs",
    "content": "﻿using ToSic.Sxc.Cms.Sites.Sys;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Cms.Sites;\n\n/// <summary>\n/// BETA Site model for entities returned by the <see cref=\"Sites\"/> DataSource.\n/// </summary>\n/// <remarks>\n/// For detailed documentation, check the docs of the underlying objects:\n///\n/// * [Dnn Site](https://docs.dnncommunity.org/api/DotNetNuke.Entities.Portals.PortalInfo.html)\n/// * [Oqtane Site](https://docs.oqtane.org/api/Oqtane.Models.Site.html)\n///\n/// History\n/// \n/// * Introduced in v19.01\n/// </remarks>\n[ModelSpecs(Use = typeof(SiteModelOfEntity))]\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic interface ISiteModel : IModelFromData\n{\n    /// <summary>\n    /// The site ID.\n    ///\n    /// * In Dnn it's from `PortalInfo.PortalID`\n    /// * In Oqtane it's `Site.SiteId`\n    /// </summary>\n    int Id { get; }\n\n    /// <summary>\n    /// The site GUID.\n    ///\n    /// * In Dnn it's from `PortalInfo.GUID`\n    /// * In Oqtane it's `Guid.Empty` as Oqtane doesn't have site GUIDs\n    /// </summary>\n    Guid Guid { get; }\n\n    /// <summary>\n    /// The site creation date/time.\n    ///\n    /// * In Dnn it's from `PortalInfo.CreatedOnDate`\n    /// * in Oqtane it's from `Site.CreatedOn`\n    /// </summary>\n    DateTime Created { get; }\n\n    /// <summary>\n    /// The site modification date/time.\n    ///\n    /// * In Dnn it's from `PortalInfo.LastModifiedOnDate`\n    /// * in Oqtane it's from `Site.ModifiedOn`\n    /// </summary>\n    DateTime Modified { get; }\n\n    /// <summary>\n    /// The site name.\n    ///\n    /// * In Dnn it's from `PageInfo.PortalName`\n    /// * in Oqtane it's from `Site.Name`\n    /// </summary>\n    string? Name { get; }\n\n    /// <summary>\n    /// The public url to this site (without any trailing slashes)\n    ///\n    /// * In Dnn it's from `PortalAliasInfo.FullUrl` (last slash removed)\n    /// * in Oqtane it's a combination of protocol, site-alias and path\n    /// </summary>\n    string? Url { get; }\n\n    /// <summary>\n    /// The site languages, comma separated.\n    /// Can be empty ever if a <see cref=\"DefaultLanguage\"/> is set, if the site itself is not multi-language.\n    /// </summary>\n    string? Languages { get; }\n\n    /// <summary>\n    /// The site Culture Code.\n    ///\n    /// * In Dnn it's from `PortalInfo.CultureCode`\n    /// * in Oqtane it's from `Site.CultureCode`\n    /// </summary>\n    string? DefaultLanguage { get; }\n\n    /// <summary>\n    /// The Zone ID, which is the ID of the 2sxc/EAV zone which applies to this site.\n    /// It's usually different from the site ID, and in rare cases can be shared among multiple sites.\n    /// </summary>\n    int ZoneId { get; }\n\n    /// <summary>\n    /// The Content App Id of this Site and Zone.\n    /// </summary>\n    int ContentAppId { get; }\n\n    /// <summary>\n    /// The (technical) primary App, which contains things such as site metadata.\n    /// </summary>\n    int PrimaryAppId { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Sites/Sys/SiteModel.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\n\nnamespace ToSic.Sxc.Cms.Sites.Sys;\n\n/// <summary>\n/// Internal class to hold all the information about the site,\n/// until it's converted to an IEntity in the <see cref=\"Sites\"/> DataSource.\n/// \n/// TODO:\n/// </summary>\n[PrivateApi(\"Was InternalApi till v17 - hide till we know how to handle to-typed-conversions\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ContentTypeSpecs(\n    Guid = \"89ef9f2c-98d3-42e9-a190-b9b3fc814284\",\n    Description = \"Site information\",\n    Name = TypeName\n)]\npublic record SiteModel: IRawEntity, ISiteModel\n{\n    #region IRawEntity\n\n    internal const string TypeName = \"Site\";\n\n    internal static DataFactoryOptions Options => new()\n    {\n        AutoId = false,\n        TitleField = nameof(Name),\n        Type = typeof(SiteModel)\n    };\n\n    IDictionary<string, object?> IRawEntity.Attributes(RawConvertOptions options)\n        => new Dictionary<string, object?>\n        {\n            { nameof(Name), Name },\n            { nameof(Url), Url },\n            { nameof(Languages), Languages },\n            { nameof(DefaultLanguage), DefaultLanguage },\n            { nameof(ZoneId), ZoneId },\n            { nameof(ContentAppId), ContentAppId },\n            { nameof(PrimaryAppId), PrimaryAppId },\n        };\n\n    #endregion\n\n    /// <inheritdoc cref=\"ISiteModel.Id\" />\n    public int Id { get; init; }\n\n    /// <inheritdoc cref=\"ISiteModel.Guid\" />\n    public Guid Guid { get; init; }\n\n    /// <inheritdoc />\n    public string? Name { get; init; }\n\n    /// <inheritdoc />\n    public string? Url { get; init; }\n\n    /// <inheritdoc />\n    public string? Languages { get; init; }\n\n    /// <inheritdoc />\n    public string? DefaultLanguage { get; init; }\n\n    /// <inheritdoc cref=\"ISiteModel.Created\" />\n    public DateTime Created { get; init; }\n\n    /// <inheritdoc cref=\"ISiteModel.Modified\" />\n    public DateTime Modified { get; init; }\n\n\n    /// <inheritdoc />\n    public int ZoneId { get; init; }\n\n    /// <inheritdoc />\n    public int ContentAppId { get; init; }\n\n    /// <inheritdoc />\n    public int PrimaryAppId { get; init; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Sites/Sys/SiteModelOfEntity.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Sites.Sys;\n\npublic record SiteModelOfEntity: ModelFromEntity, ISiteModel\n{\n    public int Id => Entity.EntityId;\n    public Guid Guid => Entity.EntityGuid;\n    public DateTime Created => Entity.Created;\n    public DateTime Modified => Entity.Modified;\n    public string? Name => GetThis<string>(null);\n    public string? Url => GetThis<string>(null);\n    public string? Languages => GetThis<string>(null);\n    public string? DefaultLanguage => GetThis<string>(null);\n    public int ZoneId => GetThis(0);\n    public int ContentAppId => GetThis(0);\n    public int PrimaryAppId => GetThis(0);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Sites/Sys/SitesDataSourceProvider.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\n\nnamespace ToSic.Sxc.Cms.Sites.Sys;\n\n/// <summary>\n/// Base class to provide data to the Sites DataSource.\n///\n/// Must be overriden in each platform.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class SitesDataSourceProvider(SitesDataSourceProvider.Dependencies services, string logName)\n    : ServiceBase<SitesDataSourceProvider.Dependencies>(services, logName)\n{\n    public record Dependencies(LazySvc<IZoneMapper> ZoneMapperLazy, IAppsCatalog AppsCatalog)\n        : DependenciesRecord(connect: [ZoneMapperLazy, AppsCatalog]);\n\n    /// <summary>\n    /// So the core data source doesn't have settings to configure this\n    /// </summary>\n    /// <returns></returns>\n    public abstract List<SiteModel> GetSitesInternal();\n\n    public int GetZoneId(int siteId) => Services.ZoneMapperLazy.Value.GetZoneId(siteId);\n\n    public int GetDefaultAppId(int siteId) => Services.AppsCatalog.DefaultAppIdentity(GetZoneId(siteId)).AppId;\n\n    public int GetPrimaryAppId(int siteId) => Services.AppsCatalog.PrimaryAppIdentity(GetZoneId(siteId)).AppId;\n\n    public string GetLanguages(int siteId)\n    {\n        var languages = Services.AppsCatalog.Zone(GetZoneId(siteId)).Languages;\n        return string.Join(\",\", languages.Select(l => l.EnvironmentKey.ToLower()));\n        //return Deps.AppStates\n        //    .Languages(GetZoneId(siteId), true)\n        //    .ToDictionary(d => d.EnvironmentKey.ToLower(), d => d.Name);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Sites/Sys/SitesDataSourceProviderUnknown.cs",
    "content": "﻿#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Cms.Sites.Sys;\n\ninternal class SitesDataSourceProviderUnknown(SitesDataSourceProvider.Dependencies services, WarnUseOfUnknown<SitesDataSourceProviderUnknown> _) : SitesDataSourceProvider(services, $\"{SxcLogName}.{LogConstants.NameUnknown}\")\n{\n    public override List<SiteModel> GetSitesInternal() => [];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/IUserModel.cs",
    "content": "﻿using ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Cms.Users;\n\n/// <summary>\n/// BETA User Model for data returned by the <see cref=\"Users\"/> DataSource or other sources.\n/// </summary>\n/// <remarks>\n///\n/// For detailed documentation, check the docs of the underlying objects:\n///\n/// * [Dnn UserInfo](https://docs.dnncommunity.org/api/DotNetNuke.Entities.Users.UserInfo.html)\n/// * [Oqtane User](https://docs.oqtane.org/api/Oqtane.Models.User.html)\n///\n/// History\n/// \n/// * Introduced in v19.01\n/// </remarks>\n[ModelSpecs(Use = typeof(UserModelOfEntity))]\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic interface IUserModel : IModelFromData\n{\n    /// <inheritdoc cref=\"IUser.Email\"/>\n    string? Email { get; }\n\n    /// <inheritdoc cref=\"IUser.Id\"/>>\n    int Id { get; }\n\n    /// <inheritdoc cref=\"IUser.Guid\"/>\n    Guid Guid { get; }\n\n    /// <summary>\n    /// When the user was first created.\n    /// </summary>\n    DateTime Created { get; }\n\n    /// <summary>\n    /// When the user was last modified.\n    /// </summary>\n    DateTime Modified { get; }\n\n    /// <summary>\n    /// True if the user is anonymous / not logged in. \n    /// </summary>\n    bool IsAnonymous { get; }\n\n    /// <summary>\n    /// True if the user is admin - allowing full content-management and user-management.\n    /// </summary>\n    bool IsSiteAdmin { get; }\n\n    /// <summary>\n    /// True if the user is a content admin / editor.\n    /// If the user only has this role, then he/she can only edit pages and content, but not users. \n    /// </summary>\n    bool IsContentAdmin { get; }\n\n    /// <summary>\n    /// Determines if the user is a content editor.\n    /// In DNN 10, ContentEditors cannot publish pages (unless they are also ContentAdmins).\n    /// </summary>\n    bool IsContentEditor { get; }\n\n    // TODO:\n    string? NameId { get; }\n\n    /// <summary>\n    /// True if the user has super-user rights.\n    /// This kind of user can do everything, incl. create apps. \n    /// </summary>\n    bool IsSystemAdmin { get; }\n\n    /// <summary>\n    /// True if a user is in the SxcDesigners group.\n    /// Such a person can actually do a lot more, like access the advanced toolbars. \n    /// </summary>\n    bool IsSiteDeveloper { get; }\n\n    /// <inheritdoc cref=\"IUser.Name\"/>\n    string? Name { get; }\n\n    /// <inheritdoc cref=\"IUser.Username\"/>\n    string? Username { get; }\n\n    /// <summary>\n    /// Roles of the user.\n    /// </summary>\n    /// <remarks>\n    /// Added ca. v20, but not quite sure when exactly.\n    /// </remarks>\n    IEnumerable<IUserRoleModel> Roles { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/IUserRoleModel.cs",
    "content": "﻿using ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.DataSources;\n\nnamespace ToSic.Sxc.Cms.Users;\n\n/// <summary>\n/// BETA Model to return role information as provided by the <see cref=\"UserRoles\"/> DataSource.\n/// </summary>\n/// <remarks>\n/// For detailed documentation, check the docs of the underlying objects:\n///\n/// * [Dnn RoleInfo](https://docs.dnncommunity.org/api/DotNetNuke.Security.Roles.RoleInfo.html)\n/// * [Oqtane UserRole](https://docs.oqtane.org/api/Oqtane.Models.UserRole.html)\n/// \n/// History\n/// \n/// * Introduced in v19.01\n/// </remarks>\n[ModelSpecs(Use = typeof(UserRoleModelOfEntity))]\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic interface IUserRoleModel : IModelFromData\n{\n    /// <summary>\n    /// The Role ID in the database.\n    /// </summary>\n    int Id { get; }\n\n    /// <summary>\n    /// The Role Name as it is displayed everywhere.\n    /// </summary>\n    string Name { get; }\n\n    /// <summary>\n    /// When the user role was first created.\n    /// </summary>\n    DateTime Created { get; }\n\n    /// <summary>\n    /// When the user role was last modified.\n    /// </summary>\n    DateTime Modified { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/Archive/UserModelOfEntity.cs",
    "content": "﻿//using ToSic.Sxc.Data.Models;\n\n//namespace ToSic.Sxc.Cms.Users.Sys;\n\n\n//internal class UserModelOfEntity : ModelFromEntity, IUserModel\n//{\n\n//    public string? Email => GetThis<string>(null);\n\n//    public int Id => _entity.EntityId;\n\n//    public Guid Guid => _entity.EntityGuid;\n\n//    public DateTime Created => _entity.Created;\n\n//    public DateTime Modified => _entity.Modified;\n\n//    public bool IsAnonymous => GetThis(false);\n\n//    public bool IsSiteAdmin => GetThis(false);\n\n//    public bool IsContentAdmin => GetThis(false);\n\n//    public bool IsContentEditor => GetThis(false);\n\n//    public string? NameId => GetThis<string>(null);\n\n//    public bool IsSystemAdmin => GetThis(false);\n\n//    public bool IsSiteDeveloper => GetThis(false);\n\n//    //IMetadata ICmsUser.Metadata => null;\n\n//    public string? Name => GetThis<string>(null);\n\n//    public string? Username => GetThis<string>(null);\n\n//    //IMetadataOf IHasMetadata.Metadata => null;\n\n//    public IEnumerable<IUserRoleModel> Roles => AsList<UserRoleModelOfEntity>(_entity.Children(field: nameof(Roles)))!;\n\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/Archive/UserRoleModelOfEntity.cs",
    "content": "﻿//using ToSic.Sxc.Data.Models;\n\n//namespace ToSic.Sxc.Cms.Users.Sys;\n\n//public class UserRoleModelOfEntity: ModelFromEntity, IUserRoleModel\n//{\n//    public int Id => _entity.EntityId;\n//    public string Name => _entity.Get<string>(nameof(Name)) ?? \"unknown\";\n//    public DateTime Created => _entity.Created;\n//    public DateTime Modified => _entity.Modified;\n\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/CmsUserElevationExtensions.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sys.Users;\nusing ToSic.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Cms.Users.Sys;\n\npublic static class CmsUserElevationExtensions\n{\n    public static UserElevation GetElevation(this ICmsUser user)\n    {\n        var underlyingUser = ((Wrapper<IUser>)user).GetContents()!;\n        return underlyingUser.GetElevation();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/IUsersProvider.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Users.Sys;\n\n/// <summary>\n/// Provider user data from platform.\n///\n/// Must be overriden in each platform.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IUsersProvider\n{\n    public string PlatformIdentityTokenPrefix { get; }\n\n    /// <summary>\n    /// Get user information from platform\n    /// </summary>\n    /// <param name=\"userId\"></param>\n    /// <param name=\"siteId\"></param>\n    /// <returns></returns>\n    public IUserModel? GetUser(int userId, int siteId);\n\n    /// <summary>\n    /// The inner list retrieving the users.\n    /// </summary>\n    /// <param name=\"specs\"></param>\n    /// <returns></returns>\n    public IEnumerable<UserModel> GetUsers(UsersGetSpecs specs);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/SxcUserConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Users.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcUserConstants\n{\n    public const string Anonymous = \"anonymous\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/UserConstants.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Cms.Users.Sys;\n\npublic class UserConstants\n{\n    #region Constant user objects for Unknown/Anonymous\n\n    public static readonly UserModel AnonymousUser = new()\n    {\n        Id = -1,\n        Name = SxcUserConstants.Anonymous,\n        Roles = [],\n    };\n\n    public static readonly UserModel UnknownUser = new()\n    {\n        Id = -2,\n        Name = EavConstants.NullNameId,\n        Roles = [],\n    };\n\n    #endregion\n\n    #region Other Constants\n\n    internal const char Separator = ',';\n    internal const int NullInteger = -1;\n    public const string IncludeRequired = \"required\";\n    public const string IncludeOptional = \"true\";\n    public const string IncludeForbidden = \"false\";\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/UserModel.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\n\nnamespace ToSic.Sxc.Cms.Users.Sys;\n\n/// <summary>\n/// Internal class to hold all the information about the user,\n/// until it's converted to an IEntity in the <see cref=\"Users\"/> DataSource.\n///\n/// * TODO:\n/// </summary>\n[PrivateApi(\"this is only internal - public access is always through interface\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ContentTypeSpecs(\n    Guid = \"612f9341-ff91-443d-be58-500e55bec2d8\",\n    Description = \"User Information\",\n    Name = TypeName\n)]\npublic record UserModel : IRawEntity, IHasIdentityNameId, IUserModel\n{\n    #region Types and Names for Raw Entities\n\n    internal const string TypeName = \"User\";\n    internal static DataFactoryOptions Options = new()\n    {\n        TitleField = nameof(Name),\n        Type = typeof(UserModel)\n    };\n\n    IDictionary<string, object?> IRawEntity.Attributes(RawConvertOptions options)\n    {\n        var data = new Dictionary<string, object?>\n        {\n            { nameof(Name), Name },\n            { nameof(NameId), NameId },\n            { nameof(IsSystemAdmin), IsSystemAdmin },\n            { nameof(IsSiteAdmin), IsSiteAdmin },\n            { nameof(IsContentAdmin), IsContentAdmin },\n            { nameof(IsAnonymous), IsAnonymous },\n            { nameof(Username), Username },\n            { nameof(Email), Email },\n        };\n\n        if (options.ShouldAddKey(nameof(IUserModel.Roles)))\n            data.Add(\n                nameof(IUserModel.Roles),\n                new RawRelationship(keys: Roles?.Select(object (r) => $\"{RoleRelationshipPrefix}{r.Id}\").ToList() ?? [])\n            );\n\n        return data;\n    }\n\n    internal const string RoleRelationshipPrefix = \"Role:\";\n\n    ///// <summary>\n    ///// Role ID List.\n    ///// Important: Internally we use a list to do checks etc.\n    ///// But for creating the entity we need the raw ID list.\n    ///// </summary>\n    //internal List<int> RolesRaw { get; init; }\n\n    #endregion\n\n    public int Id { get; init; }\n    public Guid Guid { get; init; }\n    public DateTime Created { get; init; } = DateTime.Now;\n    public DateTime Modified { get; init; } = DateTime.Now;\n\n\n#pragma warning disable CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes).\n    public string? NameId { get; init; }\n#pragma warning restore CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes).\n\n    public bool IsSystemAdmin { get; init; }\n    public bool IsSiteAdmin { get; init; }\n    public bool IsContentAdmin { get; init; }\n    public bool IsContentEditor { get; init; }\n    public bool IsSiteDeveloper => IsSystemAdmin;\n\n    public bool IsAnonymous { get; init; } = true;  // Default is true, everything else is default false.\n\n    ///// <summary>\n    ///// Ignore, just included for IUser compatibility\n    ///// </summary>\n    //string IUser.IdentityToken => null;\n\n    public string? Username { get; init; }\n    public string? Email { get; init; } // aka PreferredEmail\n    public string? Name { get; init; } // aka DisplayName\n\n    public IEnumerable<IUserRoleModel> Roles { get; init; } = [];\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/UserModelOfEntity.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Users.Sys;\n\n\ninternal record UserModelOfEntity : ModelFromEntity, IUserModel\n{\n\n    public string? Email => GetThis<string>(null);\n\n    public int Id => Entity.EntityId;\n\n    public Guid Guid => Entity.EntityGuid;\n\n    public DateTime Created => Entity.Created;\n\n    public DateTime Modified => Entity.Modified;\n\n    public bool IsAnonymous => GetThis(false);\n\n    public bool IsSiteAdmin => GetThis(false);\n\n    public bool IsContentAdmin => GetThis(false);\n\n    public bool IsContentEditor => GetThis(false);\n\n    public string? NameId => GetThis<string>(null);\n\n    public bool IsSystemAdmin => GetThis(false);\n\n    public bool IsSiteDeveloper => GetThis(false);\n\n    //IMetadata ICmsUser.Metadata => null;\n\n    public string? Name => GetThis<string>(null);\n\n    public string? Username => GetThis<string>(null);\n\n    //IMetadataOf IHasMetadata.Metadata => null;\n\n    public IEnumerable<IUserRoleModel> Roles =>\n        Entity.Children(field: nameof(Roles)).ToModels<UserRoleModelOfEntity>();\n        //AsList<UserRoleModelOfEntity>(Entity.Children(field: nameof(Roles)))!;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/UserRoleModel.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Cms.Users.Sys;\n\n/// <summary>\n/// Internal class to hold all the information about the role.\n/// until it's converted to an IEntity in the <see cref=\"UserRoles\"/> DataSource.\n///\n/// TODO:\n/// </summary>\n[PrivateApi(\"Was InternalApi till v17 - hide till we know how to handle to-typed-conversions\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ContentTypeSpecs(\n    Guid = \"dc104414-e61a-4a59-bda8-455772ceb0cc\",\n    Description = \"User-Role in the site\",\n    Name = TypeName\n)]\npublic record UserRoleModel: IRawEntity, IRole, IUserRoleModel\n{\n    #region IRawEntity\n\n    internal const string TypeName = \"Role\";\n\n    internal static DataFactoryOptions Options = new()\n    {\n        AutoId = false,\n        TitleField = nameof(Name),\n        Type = typeof(UserRoleModel)\n    };\n\n    IDictionary<string, object?> IRawEntity.Attributes(RawConvertOptions options)\n        => new Dictionary<string, object?>\n        {\n            { nameof(Name), Name },\n        };\n\n    Guid IRawEntity.Guid => Guid.Empty;\n\n    #endregion\n\n    public int Id { get; init; }\n    public DateTime Created { get; init; } = DateTime.Now;\n    public DateTime Modified { get; init; } = DateTime.Now;\n\n    public string Name { get; init; } = \"unknown\";\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/UserRoleModelOfEntity.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Users.Sys;\n\ninternal record UserRoleModelOfEntity: ModelFromEntity, IUserRoleModel\n{\n    public int Id => Entity.EntityId;\n\n    public string Name =>\n        Entity.Get<string>(nameof(Name), fallback: \"unknown\");\n\n    public DateTime Created => Entity.Created;\n\n    public DateTime Modified => Entity.Modified;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/UserRolesProviderUnknown.cs",
    "content": "﻿using ToSic.Sxc.DataSources;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Cms.Users.Sys;\n\ninternal class UserRolesProviderUnknown(WarnUseOfUnknown<UserRolesProviderUnknown> _)\n    : ServiceBase($\"{SxcLogName}.{LogConstants.NameUnknown}\"),\n        IUserRolesProvider\n{\n    public IEnumerable<UserRoleModel> GetRoles()\n        => [];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/UsersGetSpecs.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Users.Sys;\n\npublic record UsersGetSpecs\n{\n    /// <summary>\n    /// Optional Users (single value or comma-separated guids or integers) filter,\n    /// include users based on guid or id\n    /// </summary>\n    public string? UserIds { get; init; }\n\n    /// <summary>\n    /// Optional exclude Users (single value or comma-separated guids or integers) filter,\n    /// exclude users based on guid or id\n    /// </summary>\n    public string? ExcludeUserIds { get; init; }\n\n    /// <summary>\n    /// Optional IncludeRolesFilter (single value or comma-separated integers) filter,\n    /// include users that have any of roles from filter\n    /// </summary>\n    public string? RoleIds { get; init; }\n\n    /// <summary>\n    /// Optional ExcludeRolesFilter (single value or comma-separated integers) filter,\n    /// exclude users that have any of roles from filter\n    /// </summary>\n    public string? ExcludeRoleIds { get; init; }\n\n    /// <summary>\n    /// Optional SystemAdmins filter.\n    /// \n    /// * `true` - with System Admins\n    /// * `false` - without System Admins\n    /// * `required` - only System Admins (no normal users)\n    /// </summary>\n    public string? IncludeSystemAdmins { get; init; }\n\n    /// <summary>\n    /// Add property `Roles` as a relationship to role entities.\n    /// </summary>\n    public bool AddRoles { get; init; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Cms/Users/Sys/UsersProviderUnknown.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Cms.Users.Sys;\n\ninternal class UsersProviderUnknown(WarnUseOfUnknown<UsersProviderUnknown> _) : ServiceBase($\"{SxcLogName}.{LogConstants.NameUnknown}\"), IUsersProvider\n{\n    public string PlatformIdentityTokenPrefix => $\"{EavConstants.NullNameId}:\";\n\n    public IUserModel GetUser(int userId, int siteId) => new UserModel();\n\n    public IEnumerable<UserModel> GetUsers(UsersGetSpecs specs) => new List<UserModel>();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsBlock.cs",
    "content": "﻿using ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// Information about the block - similar to a module.\n/// The block is the 2sxc-internal definition of a unit of content.\n/// In most cases each module has one block, but there are edge cases such as:\n///\n/// * modules which show the same block - different module-id, same block-id\n/// * modules showing multiple blocks such as inner-content.\n/// </summary>\n/// <remarks>\n/// Was added somewhere in 2sxc 13, but not documented/published till 2sxc 17.\n/// </remarks>\n[PublicApi]\npublic interface ICmsBlock: IHasMetadata\n{\n    /// <summary>\n    /// The ID of this Block - corresponds to the EntityId in 2sxc which stores the block.\n    /// </summary>\n    /// <remarks>\n    /// If exported and re-imported, this ID will change, so consider using the Guid instead.\n    /// </remarks>\n    int Id { get; }\n\n    /// <summary>\n    /// The Guid of this Block - corresponds to the EntityGuid in 2sxc which stores the block.\n    /// </summary>\n    /// <remarks>\n    /// * Added in v17.08.\n    /// * If exported and re-imported, this Guid will stay the same, so it's a better reference than the Id.\n    /// </remarks>\n    Guid Guid { get; }\n\n    /// <summary>\n    /// Determines if this is the root block, meaning it's the main block inside a module.\n    /// Will be true in most cases, but false on inner-content\n    /// </summary>\n    bool IsRoot { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsContext.cs",
    "content": "﻿namespace ToSic.Sxc.Context;\n\n/// <summary>\n/// This is the runtime context of your code in the CMS. It can tell you about the site, page, module etc. that you're on.\n/// Note that it _Platform Agnostic_ so it's the same on Dnn, Oqtane etc.\n///\n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyContext`, but many objects are directly available, like `MyPage`\n/// </summary>\n[PublicApi]\npublic interface ICmsContext\n{\n    /// <summary>\n    /// Information about languages / culture of the current request\n    /// </summary>\n    ICmsCulture Culture { get; }\n\n    /// <summary>\n    /// Information about the Module / Container which holds a 2sxc content block in the CMS\n    /// </summary>\n    ICmsModule Module { get; }\n\n    /// <summary>\n    /// Information about the current Page (called Tab in DNN).\n    /// It's especially useful to get current URL Parameters.\n    /// </summary>\n    ICmsPage Page { get; }\n\n    /// <summary>\n    /// Information about the platform that's currently running.\n    /// </summary>\n    ICmsPlatform Platform { get; }\n\n    /// <summary>\n    /// Information about the Site (called Portal in DNN)\n    /// </summary>\n    ICmsSite Site { get; }\n\n    /// <summary>\n    /// Information about the current user.\n    /// It's especially useful to see if the user has any kind of Admin privileges.\n    /// </summary>\n    ICmsUser User { get; }\n        \n        \n    /// <summary>\n    /// View-information such as the view Name, Identity or Edition.\n    /// </summary>\n    /// <remarks>New in v12.02</remarks>\n    ICmsView View { get; }\n\n\n    /// <summary>\n    /// Information about the current block, similar to the module but a bit different.\n    /// </summary>\n    /// <remarks>\n    /// Added ca. v13, but not documented/published till v17.\n    /// </remarks>\n    ICmsBlock Block { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsCulture.cs",
    "content": "﻿namespace ToSic.Sxc.Context;\n\n/// <summary>\n/// Information about the cultures/languages used.\n/// \n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext.Culture`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyContext.Culture`\n/// </summary>\n[PublicApi]\npublic interface ICmsCulture\n{\n    /// <summary>\n    /// The default language code like \"en-us\" or \"\" (empty string).\n    /// If the system is single-language, it will often just be an empty string \"\".\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Culture.DefaultCode`  \n    /// 🪒 Use in Typed Razor: `MyContext.Culture.DefaultCode`\n    /// </summary>\n    /// <remarks>\n    /// 1. It's always lower-case.\n    /// 1. In the case of DNN, this corresponds to PortalSettings.DefaultCulture\n    /// </remarks>\n    string DefaultCode { get; }\n\n    /// <summary>\n    /// The current culture / language code like \"de-ch\". It's the language-code used by the translation environment. \n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Culture.CurrentCode`  \n    /// 🪒 Use in Typed Razor: `MyContext.Culture.CurrentCode`\n    /// </summary>\n    /// <remarks>\n    /// 1. It's always lower-case.\n    /// 1. In the case of DNN, this corresponds to PortalSettings.CurrentAlias.CultureCode\n    /// </remarks>\n    string CurrentCode { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsModule.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// Information about the module context the code is running in.\n/// \n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext.Module`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyContext.Module`\n/// </summary>\n/// <remarks>\n/// Note that the module context is the module for which the code is currently running.\n/// In some scenarios (like Web-API scenarios) the code is running _for_ this module but _not on_ this module,\n/// as it would then be running on a WebApi.\n/// </remarks>\n[PublicApi]\npublic interface ICmsModule: IHasMetadata\n{\n    /// <summary>\n    /// The module id on the page. \n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Module.Id`  \n    /// 🪒 Use in Typed Razor: `MyContext.Module.Id`\n    ///\n    /// > [!TIP]\n    /// > This Module ID is often used to give DOM elements a unique name.\n    /// > For example: `id=\"my-app-wrapper-@CmsContext.Module.Id\"`.\n    /// > But since v16.04 there is a new property `UniqueKey` which is better suited for this.\n    /// </summary>\n    /// <remarks>\n    /// Corresponds to the Dnn ModuleId or the Oqtane Module Id.\n    /// \n    /// In some systems a module can be re-used on multiple pages, and possibly have different settings for re-used modules.\n    /// 2sxc doesn't use that, so the module id corresponds to the Dnn ModuleId and not the PageModuleId.  \n    /// </remarks>\n    /// <returns>The ID, unless unknown, in which case it's a negative number</returns>\n    int Id { get; }\n\n    /// <summary>\n    /// Information about the **root** block in the module.\n    /// </summary>\n    /// <remarks>\n    /// Added ca. v13, but not documented/published till 2sxc 17.\n    /// </remarks>\n    ICmsBlock Block { get; }\n\n    [PrivateApi(\"WIP\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    [JsonIgnore] // prevent serialization as it's not a normal property\n#pragma warning disable CS0108, CS0114\n    ITypedMetadata Metadata { get; }\n#pragma warning restore CS0108, CS0114\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsPage.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// Information about the page which is the context for the currently running code.\n/// \n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext.Page`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyPage`\n/// </summary>\n/// <remarks>\n/// Note that the module context is the module for which the code is currently running.\n/// In some scenarios (like Web-API scenarios) the code is running _for_ this page but _not on_ this page,\n/// as it would then be running on a WebApi.\n/// </remarks>\n[PublicApi]\npublic interface ICmsPage: IHasMetadata\n{\n    /// <summary>\n    /// The Id of the page.\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Page.Id`  \n    /// 🪒 Use in Typed Razor: `MyPage.Id`\n    /// </summary>\n    /// <remarks>\n    /// Corresponds to the Dnn `TabId` or the Oqtane `Page.PageId`\n    /// </remarks>\n    int Id { get; }\n\n    /// <summary>\n    /// The page parameters, cross-platform.\n    /// Use this for easy access to url parameters like ?id=xyz\n    /// with `CmsContext.Page.Parameters[\"id\"]` as a replacement for `Request.QueryString[\"id\"]`\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Page.Parameters`  \n    /// 🪒 Use in Typed Razor: `MyPage.Parameters`\n    /// </summary>\n    IParameters Parameters { get; }\n\n    /// <summary>\n    /// The resource specific Url, like the one to this page or portal.\n    ///\n    /// 🪒 Use in Dynamic Razor: `CmsContext.Page.Url`  \n    /// 🪒 Use in Typed Razor: `MyPage.Url`\n    /// </summary>\n    /// <remarks>\n    /// Added ca. v12.\n    /// </remarks>\n    string Url { get; }\n    // ^^^ note: property added ca. v12 but was not visible in docs till 16.04\n\n    /// <summary>\n    /// Metadata of the current page\n    /// </summary>\n    /// <remarks>\n    /// Added in v13.12\n    /// </remarks>\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    new ITypedMetadata Metadata { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsPlatform.cs",
    "content": "﻿namespace ToSic.Sxc.Context;\n\n/// <summary>\n/// General platform information\n/// \n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext.Platform`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyContext.Platform`\n/// </summary>\n[PublicApi]\npublic interface ICmsPlatform\n{\n    /// <summary>\n    /// The platform type Id from the enumerator - so stored as an int.\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Platform.Type`  \n    /// 🪒 Use in Typed Razor: `MyContext.Platform.Type`\n    /// </summary>\n    PlatformType Type { get; }\n\n    /// <summary>\n    /// A nice name ID, like \"Dnn\" or \"Oqtane\"\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Platform.Name`  \n    /// 🪒 Use in Typed Razor: `MyContext.Platform.Name`\n    /// </summary>\n    /// <remarks>\n    /// Please be aware that platform names may change with time - like Dnn was once DotNetNuke\n    /// So to safely ensure you are detecting the right platform you should focus on the Type attribute. \n    /// </remarks>\n    string Name { get; }\n\n    /// <summary>\n    /// The platform version\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Platform.Version`  \n    /// 🪒 Use in Typed Razor: `MyContext.Platform.Version`\n    /// </summary>\n    /// <remarks>Added in v13</remarks>\n    Version Version { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsSite.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// The site context of the code - so basically which website / portal it's running on. \n/// \n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext.Site`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyContext.Site`\n/// </summary>\n[PublicApi]\npublic interface ICmsSite: IHasMetadata\n{\n    /// <summary>\n    /// The Id of the site in systems like DNN and Oqtane.\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Site.Id`  \n    /// 🪒 Use in Typed Razor: `MyContext.Site.Name`\n    /// </summary>\n    /// <remarks>\n    /// In DNN this is the same as the `PortalId`\n    /// </remarks>\n    int Id { get; }\n\n    /// <summary>\n    /// The site url with protocol. Can be variation of any such examples:\n    /// \n    /// - https://website.org\n    /// - https://www.website.org\n    /// - https://website.org/products\n    /// - https://website.org/en-us\n    /// - https://website.org/products/en-us\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Site.Url`  \n    /// 🪒 Use in Typed Razor: `MyContext.Site.Url`\n    /// </summary>\n    string Url { get; }\n\n    /// <summary>\n    /// The url root which identifies the current site / portal as is. It does not contain a protocol, but can contain subfolders.\n    /// This is mainly used to clearly identify a site in a multi-site system or a language-variation in a multi-language setup.\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Site.UrlRoot`  \n    /// 🪒 Use in Typed Razor: `MyContext.Site.UrlRoot`\n    /// </summary>\n    /// <remarks>\n    /// introduced in 2sxc 13\n    /// </remarks>\n    string UrlRoot { get; }\n\n    /// <summary>\n    /// Metadata of the current site\n    /// </summary>\n    /// <remarks>\n    /// Added in v13.12\n    /// </remarks>\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    new ITypedMetadata Metadata { get; }\n\n    //[PrivateApi]\n    //ICmsSite Init(CmsContext parent, IAppStateInternal appState);\n\n    // 2023-08-24 2dm hide for now, not sure if we want to publish like this, or just provide appIdentity to get it yourself\n    //[PrivateApi(\"WIP v13/14\")]\n    //IApp App { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsUser.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// The user context of your code - so it's information about the user your code is using. \n/// </summary>\n/// <example>\n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext.User`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyUser`\n/// </example>\n/// <remarks>\n/// History\n/// * v12 first release\n/// * v14.08/v14.09 added ca. 5 properties\n/// * v18 enhanced to serialize - so it can be returned by a WebApi Controller\n/// * v20 inheriting from <see cref=\"IUserModel\"/> now, so most properties are from there and many properties were added\n/// * v20 especially the <see cref=\"IUserModel.Roles\"/> is new and useful\n/// </remarks>\n[PublicApi]\npublic interface ICmsUser: IUserModel, IHasMetadata\n{\n    /// <summary>\n    /// The user e-mail.\n    /// If anonymous/not logged in, would be an empty string.\n    /// </summary>\n    /// \n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.Email`  \n    /// 🪒 Use in Typed Razor: `MyUser.Email`\n    /// </example>\n    /// \n    /// <remarks>\n    ///\n    /// History: Added in v.14.09\n    /// </remarks>\n    new string Email { get; }\n\n    /// <summary>\n    /// User Id as int. Works in DNN and Oqtane.\n    /// </summary>\n    /// \n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.UrlRoot`  \n    /// 🪒 Use in Typed Razor: `MyUser.Id`\n    /// </example>\n    /// \n    /// <returns>The ID or 0 (zero) if anonymous</returns>\n    new int Id { get; }\n\n    /// <summary>\n    /// Information if the user is anonymous (not logged in)\n    /// </summary>\n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.IsAnonymous`  \n    /// 🪒 Use in Typed Razor: `MyUser.IsAnonymous`\n    /// </example>\n    /// <remarks>\n    /// History: Added in v14.08\n    /// </remarks>\n    new bool IsAnonymous { get; }\n\n    /// <summary>\n    /// Information if the current user is Site Administrator.\n    /// </summary>\n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.IsSiteAdmin`  \n    /// 🪒 Use in Typed Razor: `MyUser.IsSiteAdmin`\n    /// </example>\n    /// <remarks>\n    /// Basically this means a user has very high permissions - incl. the ability\n    /// to create users in a site etc.\n    /// But these are not the highest possible privileges\n    /// \n    /// * For the site it would be IsSiteDeveloper\n    /// * For the entire system that would be IsSystemAdmin.\n    /// \n    /// History: Added in 2sxc 12\n    /// </remarks>\n    new bool IsSiteAdmin { get; }\n\n\n    /// <summary>\n    /// Information if the current user is Site Content Administrator.\n    /// </summary>\n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.IsContentAdmin`  \n    /// 🪒 Use in Typed Razor: `MyUser.IsContentAdmin`\n    /// </example>\n    /// <remarks>\n    /// Basically this means a user has Admin permissions, but may not have all admin permissions if excluded through special 2sxc-groups.\n    /// These are not the highest possible privileges\n    /// \n    /// * For the site it would be IsSiteDeveloper\n    /// * For the entire system that would be IsSystemAdmin.\n    /// \n    /// History: Added in 2sxc 14.09\n    /// </remarks>\n    new bool IsContentAdmin { get; }\n\n    /// <summary>\n    /// Information if the current user is Site Content Editor.\n    /// </summary>\n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.IsContentEditor`  \n    /// 🪒 Use in Typed Razor: `MyUser.IsContentEditor`\n    /// </example>\n    /// <remarks>\n    /// Basically this means a user has Edit permissions, may not be able to publish the content they created.\n    /// \n    /// History: Added in 2sxc 20.01 for new feature in DNN 10\n    /// </remarks>\n    new bool IsContentEditor { get; }\n\n    /// <summary>\n    /// Information if the current user is System Administrator.\n    /// </summary>\n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.IsSystemAdmin`  \n    /// 🪒 Use in Typed Razor: `MyUser.IsSystemAdmin`\n    /// </example>\n    /// <remarks>\n    /// Basically this means a user has maximum permissions - incl. the ability\n    /// to install additional components or do dangerous things like edit razor.\n    /// \n    /// History: Added in 2sxc 12\n    /// </remarks>\n    new bool IsSystemAdmin { get; }\n\n\n    /// <summary>\n    /// Information if the current user is Developer on the current site.\n    /// </summary>\n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.IsSiteDeveloper`  \n    /// 🪒 Use in Typed Razor: `MyUser.IsSiteDeveloper`\n    /// </example>\n    /// <remarks>\n    /// Basically this means a user has maximum site permissions - incl. the ability\n    /// to install additional components or do dangerous things like edit razor.\n    /// These are almost the highest possible privileges\n    /// \n    /// * For the entire system that would be IsSystemAdmin.\n    /// \n    /// History: Added in 2sxc 12\n    /// </remarks>\n    new bool IsSiteDeveloper { get; }\n\n    /// <summary>\n    /// Metadata of the current user\n    /// </summary>\n    /// <remarks>\n    /// History: Added in v13.12\n    /// </remarks>\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    new ITypedMetadata Metadata { get; }\n\n    /// <summary>\n    /// The username as should be displayed. \n    /// </summary>\n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.Name`  \n    /// 🪒 Use in Typed Razor: `MyUser.Name`\n    /// </example>\n    /// <remarks>\n    /// History: Added in v.14.09\n    /// </remarks>\n    /// <returns>The name or an empty string if anonymous</returns>\n    new string Name { get; }\n\n\n    /// <summary>\n    /// The username used on the login.\n    /// </summary>\n    /// <example>\n    /// 🪒 Use in Dynamic Razor: `CmsContext.User.Username`  \n    /// 🪒 Use in Typed Razor: `MyUser.Username`\n    /// </example>\n    /// <remarks>\n    /// History: Added in v.14.09\n    /// </remarks>\n    /// <returns>The username or an empty string if anonymous</returns>\n    new string Username { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Interfaces/ICmsView.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// View context information.\n///\n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext.View`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyView`\n/// </summary>\n/// <remarks>\n/// Added in 2sxc 12.02\n/// </remarks>\n[PublicApi]\npublic interface ICmsView: IHasMetadata\n{\n    /// <summary>\n    /// View configuration ID\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.View.Id`  \n    /// 🪒 Use in Typed Razor: `MyView.Id`\n    /// </summary>\n    int Id { get; }\n\n    /// <summary>\n    /// Name of the view as configured - note that because of i18n it could be different depending on the language.\n    /// To clearly identify a view, use the <see cref=\"Identifier\"/> or use `Settings`\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.View.Name`  \n    /// 🪒 Use in Typed Razor: `MyView.Name`\n    /// </summary>\n    string Name { get; }\n\n    /// <summary>\n    /// An optional identifier which the View configuration can provide.\n    /// Use this when you want to use the same template but make minor changes based on the View selected (like change the number of columns).\n    /// Usually you will use either this OR the `Settings`\n    /// \n    /// 🪒 Use in Razor: `CmsContext.View.Identifier`  \n    /// 🪒 Use in Typed Razor: `MyView.Identifier`\n    /// </summary>\n    string Identifier { get; }\n\n    /// <summary>\n    /// Edition used - if any. Otherwise, empty string. \n    /// \n    /// 🪒 Use in Razor: `CmsContext.View.Edition`  \n    /// 🪒 Use in Typed Razor: `MyView.Edition`\n    /// </summary>\n    string Edition { get; }\n\n    /// <summary>\n    /// Metadata of the current view\n    /// </summary>\n    /// <remarks>\n    /// Added in v13.12\n    /// </remarks>\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    new ITypedMetadata Metadata { get; }\n\n    /// <summary>\n    /// The path to this view.\n    /// For URLs which should load js/css from a path beneath the view.\n    ///\n    /// This is different from the `App.Path`, because it will also contain the edition (if there is an edition)\n    /// </summary>\n    /// <remarks>\n    /// Added in v15.04\n    /// </remarks>\n    [Obsolete(\"Obsolete in v16, pls use Folder.Url instead\")]\n    [PrivateApi(\"Hidden in 16.04, because we want people to use the Folder. Can't remove it though, because there are many apps that already published this.\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    [JsonIgnore] // old property\n    string Path { get; }\n\n    /// <summary>\n    /// This is the preferred way to get the Url or Path to the current view.\n    ///\n    /// This is different from the `App.Folder`, because it will also contain the edition (if there is an edition)\n    /// \n    /// 🪒 Use in Razor: `CmsContext.View.Folder` - like `CmsContext.View.Folder.Url`  \n    /// 🪒 Use in Typed Razor: `MyView.Edition` - like `MyView.Folder.Url`\n    /// </summary>\n    /// <remarks>\n    /// Added in v16.04\n    /// </remarks>\n    IFolder Folder { get; }\n\n    /// <summary>\n    /// Settings of this view.\n    /// This property only works in the new typed code.\n    ///\n    /// Note that many views don't have their own settings, so this would be empty = `null`.\n    /// </summary>\n    ITypedItem? Settings { get; }\n\n    /// <summary>\n    /// Settings of this view.\n    /// This property only works in the new typed code.\n    ///\n    /// Note that many views don't have their own settings, so this would be empty = `null`.\n    /// </summary>\n    /// <remarks>Resources added to API in v17.04</remarks>\n    ITypedItem? Resources { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Module/IModule.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// A unit / block within the CMS. Contains all necessary identification to pass around.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IModule\n{\n    [PrivateApi(\"Workaround till we have DI to inject the current container\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IModule Init(int id);\n\n    int Id { get; }\n\n\n    /// <summary>\n    /// Determines if this is the primary App (the content-app) as opposed to any additional app\n    /// </summary>\n    [PrivateApi(\"don't think this should be here! also not sure if it's the primary - or the contentApp! reason seems to be that we detect it by the DNN module name\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    bool IsContent { get; }\n\n    /// <summary>\n    /// Identifies the content-block which should be shown in this container\n    /// </summary>\n    [PrivateApi(\"still experimental\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IBlockIdentifier BlockIdentifier { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Page/IPage.cs",
    "content": "﻿namespace ToSic.Sxc.Context;\n\n// ReSharper disable once PossibleInterfaceMemberAmbiguity\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPage\n{\n    /// <summary>\n    /// The Id of the page.\n    /// \n    /// 🪒 Use in Razor: `CmsContext.Page.Type`\n    /// </summary>\n    /// <remarks>\n    /// Corresponds to the Dnn `TabId` or the Oqtane `Page.PageId`\n    /// </remarks>\n    int Id { get; }\n\n    /// <summary>\n    /// The page parameters, cross-platform.\n    /// Use this for easy access to url parameters like ?id=xyz\n    /// with `CmsContext.Page.Parameters[\"id\"]` as a replacement for `Request.QueryString[\"id\"]`\n    /// \n    /// 🪒 Use in Razor: `CmsContext.Page.Parameters[\"id\"]`\n    /// </summary>\n    IParameters Parameters { get; }\n\n\n    IPage Init(int id);\n\n\n    // unsure if used\n    /// <summary>\n    /// The resource specific url, like the one to this page or portal\n    /// </summary>\n    string Url { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Platform/IPlatform.cs",
    "content": "﻿namespace ToSic.Sxc.Context;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPlatform: ICmsPlatform;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Platform/PlatformType.cs",
    "content": "﻿namespace ToSic.Sxc.Context;\n\n/// <summary>\n/// The types of platforms which 2sxc could be running on\n/// </summary>\n[PublicApi]\n[Flags]\npublic enum PlatformType : long\n{\n    /// <summary>\n    /// Unknown platform - this should never occur\n    /// </summary>\n    Unknown = 0,\n        \n    /// <summary>\n    /// No platform - this should never occur\n    /// </summary>\n    None = 1 << 0,\n        \n    /// <summary>\n    /// All platforms / hybrid. This should never be used to publish what a platform is, but to mark things that work on all platforms\n    /// </summary>\n    Hybrid = 1 << 1,\n        \n    /// <summary>\n    /// Dnn aka. DotNetNuke - see https://dnncommunity.org/\n    /// </summary>\n    Dnn = 1 << 2,\n\n    /// <summary>\n    /// Oqtane using .net Core 5 - see https://oqtane.org/\n    /// </summary>\n    Oqtane = 1 << 3,\n\n    /// <summary>\n    /// NopCommerce using .net Core 5 (not implemented yet) - see https://www.nopcommerce.com/\n    /// </summary>\n    NopCommerce = 1 << 4,\n\n    /// <summary>\n    /// Custom platform - this should never occur in production code but could during automated testing\n    /// </summary>\n    Custom = 1L << 56,\n\n    /// <summary>\n    /// Test platform - this should never occur in production code but could during automated testing\n    /// </summary>\n    Test = 1L << 57,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Sys/Parameters.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Specialized;\nusing System.Runtime.CompilerServices;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.GetByName;\n\nnamespace ToSic.Sxc.Context.Sys;\n\n/// <summary>\n/// This should provide cross-platform, neutral way to have page parameters in the Razor\n/// </summary>\n/// <remarks>\n/// This MUST be public, because in dyn-code you could have Parameters.Set(\"key\", something).Set(...).Set(...).\n/// If any parameter (like 'something') is dynamic, the second Set(...) would fail, because it can't find the method on `object`.\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial record Parameters : IParameters\n{\n    /// <summary>\n    /// Initial NVC, but null-corrected.\n    /// This is the only place where the initial NVC is stored.\n    /// </summary>\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    public NameValueCollection Nvc\n    {\n        get => field ??= [];\n        init;\n    }\n\n    #region Get (new v15.04)\n\n    /// <summary>\n    /// All access to parameters should run through this, so we can determine which keys are used\n    /// to determine how the cache should behave / vary.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// DO NOT use this method for checking if a key exists, as it will log the key as used.\n    /// </remarks>\n    private bool TryGetAndLog(string name, out string? value)\n    {\n        if (!OriginalsAsDic.TryGetValue(name, out value))\n            return false;\n        UsedKeys.Add(name.ToLowerInvariant());\n        return true;\n    }\n\n    /// <summary>\n    /// The used keys - only lower-cased keys may be added.\n    /// </summary>\n    internal HashSet<string> UsedKeys = [];\n\n    public string? Get(string name)\n        => TryGetAndLog(name, out var value) ? value : null;\n\n    public TValue? Get<TValue>(string name)\n        => GetV<TValue>(name, npo: default, fallback: default);\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default) \n        => GetV(name, npo, fallback);\n\n    TValue? ITyped.Get<TValue>(string name, NoParamOrder npo, TValue? fallback, bool? required, string? language)\n        where TValue : default\n        => GetV(name, npo, fallback);\n\n    // ReSharper disable once UnusedParameter.Local\n    private TValue? GetV<TValue>(string name, NoParamOrder npo, TValue? fallback, bool? required = default, [CallerMemberName] string? cName = default)\n        => TryGetAndLog(name, out var value)\n            ? value.ConvertOrFallback(fallback)\n            : required ?? false\n                ? throw new ArgumentException($\"Can't find {name} and {nameof(required)} is true; use {nameof(required)}: false if this is intended\")\n                : fallback;\n\n    #endregion\n\n    [field: AllowNull, MaybeNull]\n    private IReadOnlyDictionary<string, string> OriginalsAsDic {\n        get\n        {\n            if (field != null)\n                return field;\n\n            // var temp = initialNvc\n\n            var newDic = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);\n            foreach (var key in Nvc.Keys)\n            {\n                // key is usually as string, but sometimes it's null\n                // we're not sure if DNN is breaking this, or if it should really be like this\n                if (key is string stringKey)\n                    newDic[stringKey] = Nvc[stringKey]!;\n                else\n                {\n                    var nullValues = Nvc[null];\n                    if (nullValues == null) continue;\n                    foreach (var nullKey in nullValues.CsvToArrayWithoutEmpty())\n                        if (!newDic.ContainsKey(nullKey))\n                            newDic[nullKey] = null!;\n                }\n            }\n            return field = newDic;\n        }\n    }\n\n    #region Basic Dictionary Properties\n\n    public IEnumerator<KeyValuePair<string, string>> GetEnumerator()\n        => OriginalsAsDic.GetEnumerator();\n\n    IEnumerator IEnumerable.GetEnumerator()\n        => OriginalsAsDic.GetEnumerator();\n\n    public int Count => OriginalsAsDic.Count;\n\n    public bool ContainsKey(string key)\n        => OriginalsAsDic.ContainsKey(key);\n\n    public bool TryGetValue(string key, out string value)\n        => TryGetAndLog(key, out value!);\n\n    public string this[string name] => Get(name)!;\n\n    public IEnumerable<string> Keys => OriginalsAsDic.Keys;\n\n    public IEnumerable<string> Values => OriginalsAsDic.Values;\n\n    #endregion\n\n    public IParameters Prioritize(string? fields = default)\n        => new Parameters(this)\n        {\n            PriorityFields = fields\n        };\n\n    private string? PriorityFields { get; init; }\n\n    public override string ToString() => _toString ??= ToString(sort: true);\n    private string? _toString;\n\n    /// <inheritdoc/>\n    public string ToString(NoParamOrder npo = default, bool sort = false)\n        => sort\n            ? _sorted ??= Nvc.Sort(PriorityFields).NvcToString()\n            : Nvc.NvcToString();\n    private string? _sorted;\n\n\n    #region Toggle and Filter\n\n    private IParameters Toggle(string name, string? value)\n    {\n        var oldValue = Get(name);\n        return oldValue.EqualsInsensitive(value)\n            ? Remove(name)\n            : Set(name, value);\n\n        // Maybe: implement detailed replace if multiple values exist?\n        // most of this kind of already works, but we don't have all edge cases covered\n        // since it's not sure if we ever need this, it's not implemented yet\n        //var values = Nvc.GetValues(key);\n\n        //if (value == default)\n        //{\n        //    return Set(key);\n        //}\n\n        //if (values == null || values.Length == 0)\n        //    return Set(key, value);\n\n        //if (values.Any(v => v.EqualsInsensitive(value)))\n        //    return Remove(key);\n\n        //return Set(key, value);\n    }\n\n    public IParameters Toggle(string name, object value)\n        => Toggle(name, ValueToUrlValue(value));\n\n    public IParameters Filter(string? names)\n    {\n        // Only exit early if null. If empty string, basically drop the list.\n        if (names is null or \"*\")\n            return this;\n\n        if (names.IsEmptyOrWs())\n            return new Parameters(this) { Nvc = [] };\n\n        var keysToKeep = names.CsvToArrayWithoutEmpty();\n\n        var removeKeys = Nvc.AllKeys\n            .Where(k => !keysToKeep.Contains(k, StringComparer.InvariantCultureIgnoreCase))\n            .ToList();\n        var copy = new NameValueCollection(Nvc);\n        foreach (var k in removeKeys)\n            copy.Remove(k);\n        return new Parameters { Nvc = copy };\n    }\n\n    public IParameters Flush() => new Parameters(this) { Nvc = [] };\n\n    #endregion\n\n    #region Basic Add/Set/Remove with key only or string-value\n\n    public IParameters Add(string key)\n    {\n        var copy = new NameValueCollection(Nvc) { { key, null } };\n        return new Parameters { Nvc = copy };\n    }\n\n    public IParameters Add(string key, string? value)\n    {\n        var copy = new NameValueCollection(Nvc) { { key, value } };\n        return new Parameters { Nvc = copy };\n    }\n\n    public IParameters Set(string name, string? value)\n    {\n        var copy = new NameValueCollection(Nvc);\n        copy.Set(name, value!);\n        return new Parameters { Nvc = copy };\n    }\n\n    public IParameters Set(string name) => Set(name, null);\n\n    public IParameters Remove(string name)\n    {\n        // Skip cloning if the key doesn't exist or is already null\n        if (Nvc[name] == null) return this;\n\n        var copy = new NameValueCollection(Nvc);\n        copy.Remove(name);\n        return new Parameters { Nvc = copy };\n    }\n\n    private IParameters Remove(string name, string? value)\n    {\n        var values = Nvc.GetValues(name);\n        if (values == null || values.Length == 0)\n            return this;\n\n        var copy = new NameValueCollection(Nvc);\n        copy.Remove(name);\n        var rest = values\n            .Where(v => !v.EqualsInsensitive(value))\n            .ToList();\n        if (rest.Count == 0)\n            return new Parameters { Nvc = copy };\n\n        foreach (var r in rest)\n            copy.Add(name, r);\n        return new Parameters { Nvc = copy };\n    }\n\n    public IParameters Remove(string name, object value)\n        => Remove(name, ValueToUrlValue(value));\n\n    #endregion\n\n\n    #region New Object Add/Set\n\n    public IParameters Add(string key, object value)\n        => Add(key, ValueToUrlValue(value));\n\n    public IParameters Set(string name, object value)\n        => Set(name, ValueToUrlValue(value));\n\n    private string? ValueToUrlValue(object? value)\n    {\n        if (value is null)\n            return null;\n        if (value is string sVal)\n            return sVal;\n        if (value is bool bVal)\n            return bVal.ToString().ToLower();\n        if (value.IsNumeric())\n            return Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture);\n        if (value is DateTime dtmVal)\n        {\n            var result = DateTime.SpecifyKind(dtmVal, DateTimeKind.Utc).ToString(\"s\", System.Globalization.CultureInfo.InvariantCulture);\n            // if the time is zero, trim that\n            if (result.EndsWith(\"T00:00:00\"))\n                return result.Substring(0, result.IndexOf('T'));\n            return result;\n        }\n        return value.ToString();\n    }\n\n    #endregion\n\n    /// <summary>\n    /// Get by name should never throw an error, as it's used to get null if not found.\n    /// </summary>\n    object? ICanGetByName.Get(string name)\n        => (this as ITyped).Get(name, required: false);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Context/Sys/Parameters_Typed.cs",
    "content": "﻿using System.Net;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Context.Sys;\n\npartial record Parameters: ITyped\n{\n    [PrivateApi]\n    bool ITyped.ContainsKey(string name)\n        => OriginalsAsDic.ContainsKey(name);\n\n    [PrivateApi]\n    public bool IsEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => !OriginalsAsDic.TryGetValue(name, out var result) || HasKeysHelper.IsEmpty(result, default);\n\n    [PrivateApi]\n    public bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => OriginalsAsDic.TryGetValue(name, out var result) && HasKeysHelper.IsNotEmpty(result, default);\n\n    [PrivateApi]\n    IEnumerable<string> ITyped.Keys(NoParamOrder npo, IEnumerable<string>? only)\n        => TypedHelpers.FilterKeysIfPossible(npo, only, OriginalsAsDic?.Keys);\n    [PrivateApi]\n    IEnumerable<string> IHasKeys.Keys(NoParamOrder npo, IEnumerable<string>? only)\n        => TypedHelpers.FilterKeysIfPossible(npo, only, OriginalsAsDic?.Keys);\n\n\n    [PrivateApi]\n    object? ITyped.Get(string name, NoParamOrder npo, bool? required, string? language /* ignore */)\n        => TryGetAndLog(name, out var value) ? value : null;\n\n    [PrivateApi]\n    bool ITyped.Bool(string name, NoParamOrder npo, bool fallback, bool? required)\n        => GetV(name, npo: npo, fallback: fallback);\n\n    [PrivateApi]\n    DateTime ITyped.DateTime(string name, NoParamOrder npo, DateTime fallback, bool? required)\n        => GetV(name, npo: npo, fallback: fallback);\n\n    [PrivateApi]\n    string? ITyped.String(string name, NoParamOrder npo, string? fallback, bool? required, object? scrubHtml)\n    {\n        var value = GetV(name, npo: npo, fallback: fallback);\n        if (scrubHtml != default)\n            throw new NotSupportedException($\"{nameof(scrubHtml)} is not supported on this object\");\n        return value;\n    }\n\n    [PrivateApi]\n    int ITyped.Int(string name, NoParamOrder npo, int fallback, bool? required)\n        => GetV(name, npo: npo, fallback: fallback);\n\n    [PrivateApi]\n    long ITyped.Long(string name, NoParamOrder npo, long fallback, bool? required)\n        => GetV(name, npo: npo, fallback: fallback);\n\n    [PrivateApi]\n    float ITyped.Float(string name, NoParamOrder npo, float fallback, bool? required)\n        => GetV(name, npo: npo, fallback: fallback);\n\n    [PrivateApi]\n    decimal ITyped.Decimal(string name, NoParamOrder npo, decimal fallback, bool? required)\n        => GetV(name, npo: npo, fallback: fallback);\n\n    [PrivateApi]\n    double ITyped.Double(string name, NoParamOrder npo, double fallback, bool? required)\n        => GetV(name, npo: npo, fallback: fallback);\n\n    [PrivateApi]\n    string ITyped.Url(string name, NoParamOrder npo, string? fallback, bool? required)\n    {\n        var url = GetV(name, npo: npo, fallback);\n        return Tags.SafeUrl(url).ToString();\n    }\n\n    [PrivateApi]\n    IRawHtmlString? ITyped.Attribute(string name, NoParamOrder npo, string? fallback, bool? required)\n    {\n        // Note: we won't do special date processing, since all values in the Parameters are strings\n        var value = GetV(name, npo: npo, fallback: fallback);\n        return value is null ? null : new RawHtmlString(WebUtility.HtmlEncode(value));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/AdamFiles.cs",
    "content": "﻿using System.Collections.Immutable;\nusing ToSic.Eav.DataSource;\n\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\n\n// Important Info to people working with this\n// It depends on abstract provider, that must be overriden in each platform\n// In addition, each platform must make sure to register a TryAddTransient with the platform specific provider implementation\n// This is because any constructor DI should be able to target this type, and get the real provider implementation\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Deliver a list of App files and folders from the current platform (Dnn or Oqtane).\n///\n/// As of now there are no parameters to set.\n///\n/// To figure out the properties returned and what they match up to, see <see cref=\"AdamItemDataRaw\"/> TODO\n/// </summary>\n[VisualQuery(\n    NiceName = \"Adam\",\n    UiHint = \"Files and folders in the Adam\",\n    NameId = \"ee1d0cb6-5086-4d59-b16a-d0dc7b594bf2\",\n    HelpLink = \"https://go.2sxc.org/ds-adam\",\n    Icon = DataSourceIcons.Tree,\n    Type = DataSourceType.Lookup,\n    Audience = Audience.Advanced,\n    In = [DataSourceConstants.InStreamDefaultRequired],\n    ConfigurationType = \"\" // TODO: ...\n)]\n[PrivateApi(\"Was till v17 InternalApi_DoNotUse_MayChangeWithoutNotice(still wip / finishing specs etc.)\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamFiles : CustomDataSourceAdvanced\n{\n    private readonly AdamDataSourceProvider<int, int> _provider;\n\n    #region Configuration properties\n\n    /// <summary>\n    /// Uses the [immutable convention](xref:NetCode.Conventions.Immutable).\n    /// </summary>\n    [Configuration]\n    public string? EntityIds => Configuration.GetThis();\n\n    /// <summary>\n    /// Uses the [immutable convention](xref:NetCode.Conventions.Immutable).\n    /// </summary>\n    [Configuration]\n    public string? EntityGuids => Configuration.GetThis();\n\n    /// <summary>\n    /// Uses the [immutable convention](xref:NetCode.Conventions.Immutable).\n    /// </summary>\n    [Configuration]\n    public string? Fields => Configuration.GetThis();\n\n    /// <summary>\n    /// Uses the [immutable convention](xref:NetCode.Conventions.Immutable).\n    /// </summary>\n    [Configuration(Fallback = \"*.*\")]\n    public string? Filter => Configuration.GetThis();\n\n    #endregion\n\n    #region Constructor\n\n    [PrivateApi]\n    public AdamFiles(Dependencies services, AdamDataSourceProvider<int, int> provider) : base(services, \"CDS.Adam\", connect: [provider])\n    {\n        _provider = provider;\n\n        ProvideOut(GetInternal);\n        ProvideOut(GetFolders, \"Folders\");\n        ProvideOut(GetFiles, \"Files\");\n    }\n    #endregion\n\n    private IImmutableList<IEntity> GetFolders() => GetInternal()\n        .Where(e => e.Get<bool>(\"IsFolder\"))\n        .ToImmutableOpt();\n\n    private IImmutableList<IEntity> GetFiles() => GetInternal()\n        .Where(e => !e.Get<bool>(\"IsFolder\"))\n        .ToImmutableOpt();\n\n    private IImmutableList<IEntity> GetInternal() => _getInternal.Get(() =>\n    {\n        var l = Log.Fn<IImmutableList<IEntity>>(timer: true);\n        Configuration.Parse();\n\n        // Make sure we have an In - otherwise error\n        var source = TryGetIn();\n        if (source is null)\n            return l.Return(Error.TryGetInFailed(), \"error\");\n\n        _provider.Configure(appId: AppId, entityIds: EntityIds, entityGuids: EntityGuids, fields: Fields,\n            filter: Filter);\n        var find = _provider.GetInternal();\n\n        var adamFactory = DataFactory.SpawnNew(options: AdamItemDataRaw.Options with { AppId = AppId });\n\n        var entities = adamFactory.Create(source.SelectMany(o => find(o)));\n\n        return l.Return(entities, \"ok\");\n    })!;\n    private readonly GetOnce<IImmutableList<IEntity>> _getInternal = new();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/AppAssets/AppAssets.cs",
    "content": "﻿using System.Collections.Immutable;\nusing ToSic.Eav.DataSource;\n\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Sxc.Cms.Assets;\nusing ToSic.Sxc.Cms.Assets.Sys;\nusing ToSic.Sxc.DataSources.Sys.AppAssets;\nusing static System.StringComparer;\n\n// Important Info to people working with this\n// It depends on abstract provider, that must be overriden in each platform\n// In addition, each platform must make sure to register a TryAddTransient with the platform specific provider implementation\n// This is because any constructor DI should be able to target this type, and get the real provider implementation\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Deliver a list of App files and folders from the current platform (Dnn or Oqtane).\n/// </summary>\n/// <remarks>\n///\n/// This provides 4 streams:\n///\n/// * All: Stream containing both files and folders\n/// * Default: All files <see cref=\"IFileModel\"/>\n/// * Files: All Files <see cref=\"IFileModel\"/>\n/// * Folders: All folders <see cref=\"IFolderModel\"/>\n///\n/// To figure out the properties returned and what they match up to, see <see cref=\"IFileModel\"/> and <see cref=\"IFolderModel\"/>.\n/// \n/// History\n/// \n/// * Started v18.02 for the first time - in the Picker Source App Assets.\n/// * officially documented for v19.00, but API not fully final/stable, names may change.\n/// </remarks>\n[VisualQuery(\n    NiceName = \"App Assets\",\n    Type = DataSourceType.Source,\n    ConfigurationType = \"477d5de4-5ffa-43ef-8553-37354cb27660\",\n    NameId = \"3fe6c215-4c37-45c1-8883-b4b2a47162a7\",\n    HelpLink = \"https://go.2sxc.org/ds-appassets\",\n    Icon = DataSourceIcons.Tree,\n    Audience = Audience.Advanced,\n    UiHint = \"Files and folders in the App folder\")]\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppAssets: CustomDataSourceAdvanced\n{\n    private readonly AppAssetsDataSourceProvider _appAssetsSource;\n\n    private const string StreamFiles = \"Files\";\n    private const string StreamFolders = \"Folders\";\n    private const string StreamAll = \"All\";\n\n    #region Configuration properties\n\n    /// <summary>\n    /// The root folder to start from, beginning in the app root.\n    /// Uses the [immutable convention](xref:NetCode.Conventions.Immutable).\n    /// </summary>\n    [Configuration(Fallback = \"/\")]\n    public string RootFolder => Configuration.GetThis(fallback: \"/\");\n\n    /// <summary>\n    /// The file name filter, such as \"*.jpg\".\n    /// Uses the [immutable convention](xref:NetCode.Conventions.Immutable).\n    /// </summary>\n    [Configuration(Fallback = \"*.*\")]\n    public string FileFilter => Configuration.GetThis(fallback: \"*.*\");\n\n    // TODO: not implemented yet!\n    [PrivateApi(\"TODO: NOT IMPLEMENTED YET\")]\n    [Configuration(Fallback = false)]\n    public bool SearchSubfolders => Configuration.GetThis(false);\n\n    private AppAssetsGetSpecs Specs => new()\n    {\n        RootFolder = RootFolder,\n        FileFilter = FileFilter,\n        //SearchSubfolders = SearchSubfolders\n    };\n\n    #endregion\n\n    #region Constructor\n\n    [PrivateApi]\n    public AppAssets(Dependencies services, AppAssetsDataSourceProvider appAssetsSource) : base(services, \"CDS.AppFiles\", connect: [appAssetsSource])\n    {\n        _appAssetsSource = appAssetsSource;\n\n        ProvideOut(() => Get(DataSourceConstants.StreamDefaultName));\n        ProvideOut(() => Get(StreamFolders), StreamFolders);\n        ProvideOut(() => Get(StreamFiles), StreamFiles);\n        ProvideOut(() => Get(StreamAll), StreamAll);\n    }\n    #endregion\n\n    /// <summary>\n    /// Mini-cache.\n    /// Reason is that we can only generate the streams together, so this ensures that after generating them once,\n    /// other streams requested at the same time won't re-trigger stream generation.\n    /// </summary>\n    private IImmutableList<IEntity> Get(string streamName)\n    {\n        // check in both values\n        var toCheck = RootFolder + \" \" + FileFilter;\n        if (toCheck.Contains(\"..\"))\n            return Error.Create(title: \"Invalid characters in RootFolder or FileFilter\", message: \"The sequence '..' is not allowed in the path or file filter.\", streamName: streamName);\n\n        var all = GetAll();\n        return all.TryGetValue(streamName, out var stream)\n            ? stream()\n            : Error.TryGetOutFailed(name: streamName);\n    }\n\n    /// <summary>\n    /// Mini-cache.\n    /// Reason is that we can only generate the streams together, so this ensures that after generating them once,\n    /// other streams requested at the same time won't re-trigger stream generation.\n    /// </summary>\n    private IDictionary<string, Func<IImmutableList<IEntity>>> GetAll() => _all.Get(() =>\n    {\n        var (folders, files) = GetInternal();\n        return new(OrdinalIgnoreCase)\n        {\n            { DataSourceConstants.StreamDefaultName, () => files },\n            { StreamAll, () => folders.Concat(files).ToImmutableOpt() },\n            { StreamFolders, () => folders },\n            { StreamFiles, () => files }\n        };\n    })!;\n    private readonly GetOnce<Dictionary<string, Func<IImmutableList<IEntity>>>> _all = new();\n\n    /// <summary>\n    /// Get both the files and folders stream\n    /// </summary>\n    /// <returns></returns>\n    private (IImmutableList<IEntity> folders, IImmutableList<IEntity> files) GetInternal()\n    {\n        var l = Log.Fn<(IImmutableList<IEntity> folders, IImmutableList<IEntity> files)>(timer: true);\n\n        var specs = Specs with\n        {\n            AppId = Specs.AppId == int.MinValue ? AppId : Specs.AppId,\n            ZoneId = Specs.ZoneId == int.MinValue ? ZoneId : Specs.ZoneId,\n        };\n        \n        _appAssetsSource.Configure(specs);\n\n        // Get pages from underlying system/provider\n        var (rawFolders, rawFiles) = _appAssetsSource.GetAll();\n        if (!rawFiles.Any() && !rawFolders.Any())\n            return l.Return(([], []), \"null/empty\");\n\n        // Convert Folders to Entities\n        var folderFactory = DataFactory.SpawnNew(options: FolderModelRaw.Options with\n        {\n            AppId = AppId,\n            IdSeed = -100001,\n            Type = typeof(FolderModelRaw),\n        });\n        var folders = folderFactory.Create(rawFolders);\n\n        // Convert Files to Entities\n        var fileFactory = DataFactory.SpawnNew(options: FileModelRaw.Options with\n        {\n            AppId = AppId,\n            IdSeed = -1,\n            Type = typeof(FileModelRaw),\n            // Make sure we share relationships source with folders, as files need folders and folders need files\n            Relationships = folderFactory.Relationships,\n        });\n        var files = fileFactory.Create(rawFiles);\n\n        return l.Return((folders, files), $\"folders: {folders.Count}, files: {files.Count}\");\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/AppAssets/AppAssetsGetSpecs.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Sys.Work;\n\nnamespace ToSic.Sxc.DataSources;\n\npublic record AppAssetsGetSpecs: IWorkSpecs\n{\n    public int AppId { get; init; } = int.MinValue;\n\n    public int ZoneId { get; init; } = int.MinValue;\n\n    [Configuration(Fallback = \"/\")]\n    public string? RootFolder { get; init; } = null;\n\n    [Configuration(Fallback = \"*.*\")]\n    public string? FileFilter { get; init; } = null;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Pages.cs",
    "content": "﻿using System.Collections.Immutable;\nusing ToSic.Eav.DataSource;\n\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Sxc.Cms.Pages;\nusing ToSic.Sxc.Cms.Pages.Sys;\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.DataSources.Sys.Pages;\n\n// Important Info to people working with this\n// It depends on abstract provider, that must be overriden in each platform\n// In addition, each platform must make sure to register a TryAddTransient with the platform specific provider implementation\n// This is because any constructor DI should be able to target this type, and get the real provider implementation\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Get a list of pages from the current platform (Dnn or Oqtane).\n/// </summary>\n/// <remarks>\n/// You can cast the result to <see cref=\"IPageModel\"/> for typed use in your code.\n/// To figure out the returned properties, best also consult the <see cref=\"IPageModel\"/>.\n/// \n/// \n/// History\n/// \n/// * Created ca. v.16 early 2023 but not officially communicated\n/// * Models <see cref=\"IUserModel\"/> and <see cref=\"IUserRoleModel\"/> created in v19.01 and officially released\n/// </remarks>\n[PublicApi]\n[VisualQuery(\n    ConfigurationType = \"3d970d2b-32cb-4ecb-aeaf-c49fbcc678a5\",\n    NameId = \"e35031b2-3e99-41fe-a5ac-b79f447d5800\",\n    HelpLink = \"https://go.2sxc.org/ds-pages\",\n    Icon = DataSourceIcons.PageFind,\n    NiceName = \"Pages\",\n    Type = DataSourceType.Source,\n    UiHint = \"Pages in this site\")]\npublic class Pages: CustomDataSourceAdvanced\n{\n    private readonly PagesDataSourceProvider _provider;\n\n    #region Configuration properties\n\n    /// <summary>\n    /// Include hidden pages.\n    /// Default is `false`\n    /// </summary>\n    /// <remarks>\n    /// * new in 15.04\n    /// * uses the [immutable convention](xref:NetCode.Conventions.Immutable)\n    /// </remarks>\n    [Configuration]\n    public bool IncludeHidden => Configuration.GetThis(false);\n\n    /// <summary>\n    /// Include deleted pages in the recycle bin.\n    /// Default is `false`\n    /// </summary>\n    /// <remarks>\n    /// * new in 15.04\n    /// * uses the [immutable convention](xref:NetCode.Conventions.Immutable)\n    /// </remarks>\n    [Configuration]\n    public bool IncludeDeleted => Configuration.GetThis(false);\n\n    /// <summary>\n    /// Include admin pages such as site files.\n    /// Default is `false`\n    /// </summary>\n    /// <remarks>\n    /// * new in 15.04\n    /// * uses the [immutable convention](xref:NetCode.Conventions.Immutable)\n    /// </remarks>\n    [Configuration]\n    public bool IncludeAdmin => Configuration.GetThis(false);\n\n    /// <summary>\n    /// Include system pages such as modules management.\n    /// Default is `false`\n    /// </summary>\n    /// <remarks>\n    /// * new in 15.04\n    /// * uses the [immutable convention](xref:NetCode.Conventions.Immutable)\n    /// </remarks>\n    [Configuration]\n    public bool IncludeSystem => Configuration.GetThis(false);\n\n    /// <summary>\n    /// Include link-reference pages (which are usually used in menus, and not themselves a real page).\n    /// Default is `true`\n    /// </summary>\n    /// <remarks>\n    /// * new in 15.04\n    /// * uses the [immutable convention](xref:NetCode.Conventions.Immutable)\n    /// </remarks>\n    [Configuration]\n    public bool IncludeLinks => Configuration.GetThis(true);\n\n    /// <summary>\n    /// Require that the current user has view permissions on all pages.\n    /// Default is `true`\n    /// </summary>\n    /// <remarks>\n    /// * new in 15.04\n    /// * uses the [immutable convention](xref:NetCode.Conventions.Immutable)\n    /// </remarks>\n    [Configuration]\n    public bool RequireViewPermissions => Configuration.GetThis(true);\n\n    /// <summary>\n    /// Require that the current user has edit permissions on all pages.\n    /// Default is `false`\n    /// </summary>\n    /// <remarks>\n    /// * new in 15.04\n    /// * uses the [immutable convention](xref:NetCode.Conventions.Immutable)\n    /// </remarks>\n    [Configuration]\n    public bool RequireEditPermissions => Configuration.GetThis(false);\n\n    #endregion\n\n    #region Constructor\n\n    [PrivateApi]\n    public Pages(Dependencies services, PagesDataSourceProvider provider) : base(services, \"CDS.Pages\", connect: [provider])\n    {\n        _provider = provider;\n\n        ProvideOut(GetPages);\n    }\n    #endregion\n\n    private IImmutableList<IEntity> GetPages()\n    {\n        var l = Log.Fn<IImmutableList<IEntity>>();\n        Configuration.Parse();\n\n        // Get pages from underlying system/provider\n        var pagesFromSystem = _provider.GetPagesInternal(\n            includeHidden: IncludeHidden,\n            includeDeleted: IncludeDeleted,\n            includeAdmin: IncludeAdmin,\n            includeSystem: IncludeSystem,\n            includeLinks: IncludeLinks,\n            requireViewPermissions: RequireViewPermissions,\n            requireEditPermissions: RequireEditPermissions\n        );\n\n        if (pagesFromSystem == null || pagesFromSystem.Count == 0)\n            return l.Return([], \"null/empty\");\n\n        // Convert to Entity-Stream\n        var pageFactory = DataFactory.SpawnNew(options: PageModelRaw.Option);\n\n        var pages = pageFactory.Create(pagesFromSystem);\n\n        return l.Return(pages, $\"{pages.Count}\");\n        //// Try to add Navigation properties\n        //try\n        //{\n        //    var asTree = _treeMapper.AddParentChild(pages, Attributes.EntityIdPascalCase, \"ParentId\");\n        //    return l.Return(asTree, $\"As Tree: {asTree.Count}\");\n        //}\n        //catch (Exception ex)\n        //{\n        //    l.Ex(ex);\n        //    return l.Return(pages, $\"Just pages (tree had error): {pages.Count}\");\n        //}\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sites.cs",
    "content": "﻿using ToSic.Eav.DataSource;\n\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Sxc.Cms.Sites;\nusing ToSic.Sxc.Cms.Sites.Sys;\n\n// Important Info to people working with this\n// It depends on abstract provider, that must be overriden in each platform\n// In addition, each platform must make sure to register a TryAddTransient with the platform specific provider implementation\n// This is because any constructor DI should be able to target this type, and get the real provider implementation\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Deliver a list of sites from the Oqtane\n/// </summary>\n/// <remarks>\n/// You can cast the result to <see cref=\"ISiteModel\"/> for typed use in your code.\n/// To figure out the returned properties, best also consult the <see cref=\"ISiteModel\"/>.\n///\n/// As of now there are no parameters to set.\n/// \n/// History\n///\n/// * Not sure when it was first created, probably early 2023 with the name `Roles`, and not officially communicated.\n/// * Model <see cref=\"ISiteModel\"/> created in v19.01 and officially released\n/// </remarks>\n\n[PublicApi]\n[VisualQuery(\n    ConfigurationType = \"\",\n    NameId = \"a11c28fb-7d8d-40a2-a22c-50beaa019e41\",\n    HelpLink = \"https://go.2sxc.org/ds-sites\",\n    Icon = DataSourceIcons.Globe,\n    NiceName = \"Sites\",\n    Type = DataSourceType.Source,\n    UiHint = \"Sites in this system\")]\npublic class Sites: CustomDataSource\n{\n    [PrivateApi]\n    public Sites(Dependencies services, SitesDataSourceProvider sitesProvider) : base(services, logName: \"CDS.Sites\", connect: [sitesProvider])\n    {\n        ProvideOutRaw(sitesProvider.GetSitesInternal, options: () => SiteModel.Options);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sys.AdamFiles/AdamDataSourceProvider.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Base class to provide data to the Adam DataSource.\n///\n/// Must be overriden in each platform.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamDataSourceProvider<TFolderId, TFileId> : ServiceBase<AdamDataSourceProvider<TFolderId, TFileId>.Dependencies>\n{\n    private IContextOfApp _context = null!;\n\n    public record Dependencies(LazySvc<AdamContext> AdamContext, ISxcAppCurrentContextService CtxService)\n        : DependenciesRecord(connect: [AdamContext, CtxService]);\n\n    protected AdamDataSourceProvider(Dependencies services) : base(services, $\"{SxcLogName}.AdamDs\")\n    { }\n\n    public AdamDataSourceProvider<TFolderId, TFileId> Configure(\n        NoParamOrder npo = default,\n        int appId = default,\n        string? entityIds = default,\n        string? entityGuids = default,\n        string? fields = default,\n        string? filter = default\n    )\n    {\n        var l = Log.Fn<AdamDataSourceProvider<TFolderId, TFileId>>($\"a:{appId}; entityIds:{entityIds}, entityGuids:{entityGuids}, fields:{fields}, filter:{filter}\");\n        _context = appId > 0\n            ? Services.CtxService.GetExistingAppOrSet(appId)\n            : Services.CtxService.AppNameRouteBlock(null);\n        _entityIds = entityIds;\n        _entityGuids = entityGuids;\n        _fields = fields;\n        _filter = filter;\n        return l.Return(this);\n    }\n\n    private string? _entityIds;\n    private string? _entityGuids;\n    private string? _fields;\n    private string? _filter;\n\n\n    public Func<IEntity, IEnumerable<AdamItemDataRaw>> GetInternal()\n        => GetAdamListOfItems;\n\n    private IEnumerable<AdamItemDataRaw> GetAdamListOfItems(IEntity entity)\n    {\n        var l = Log.Fn<IEnumerable<AdamItemDataRaw>>();\n        // This will contain the list of items\n        var list = new List<AdamItemDataRaw>();\n\n        // TODO: this is just tmp code to get some data...\n        Services.AdamContext.Value\n            .Init(_context, entity.Type.Name, string.Empty, entity.EntityGuid, false);\n\n        // get root and at the same time auto-create the core folder in case it's missing (important)\n        var root = Services.AdamContext.Value.AdamRoot.RootFolder(false);\n\n        // if no root exists then quit now\n        if (root == null)\n            return l.Return([], \"null/empty\");\n\n        AddAdamItemsFromFolder(root, list);\n\n        return l.Return(list, $\"found:{list.Count}\");\n    }\n\n    private void AddAdamItemsFromFolder(IFolder folder, List<AdamItemDataRaw> list)\n    {\n        list.AddRange(folder.Folders.Select(f => new AdamItemDataRaw\n        {\n            Name = f.Name,\n            ReferenceId = (f as IHasMetadata).Metadata.Target.KeyString,\n            Url = f.Url,\n            Type = f.Type,\n            IsFolder = true,\n            Size = 0,\n            Path = f.Path,\n            Created = f.Created,\n            Modified = f.Modified\n        }));\n        list.AddRange(folder.Files.Select(f => new AdamItemDataRaw\n        {\n            Name = f.Name,\n            ReferenceId = (f as IHasMetadata).Metadata.Target.KeyString,\n            Url = f.Url,\n            Type = f.Type,\n            IsFolder = false,\n            Size = f.Size,\n            Path = f.Path,\n            Created = f.Created,\n            Modified = f.Modified\n        }));\n        foreach (var subFolder in folder.Folders) \n            AddAdamItemsFromFolder(subFolder, list);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sys.AdamFiles/AdamItemDataRaw.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw;\nusing ToSic.Eav.Data.Raw.Sys;\n\nnamespace ToSic.Sxc.DataSources;\n\n[PrivateApi(\"Was InternalApi till v17 - hide till we know how to handle to-typed-conversions\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamItemDataRaw: IRawEntity\n{\n    public const string TypeName = \"AdamItem\";\n\n    public static DataFactoryOptions Options = new()\n    {\n        TypeName = TypeName,\n        TitleField = nameof(Name)\n    };\n\n    public int Id { get; set; }\n    public Guid Guid { get; set; }\n\n    /// <summary>\n    /// The file name\n    /// </summary>\n    public string? Name { get; set; }\n\n    /// <summary>\n    /// This contains the code like \"file:2742\"\n    /// </summary>\n    public string? ReferenceId { get; set; }\n\n    /// <summary>\n    /// Normal url to access the resource\n    /// </summary>\n    public string? Url { get; set; }\n\n    /// <summary>\n    /// The Adam type, such as \"folder\", \"image\" etc.\n    /// </summary>\n    public string? Type { get; set; }\n\n    public bool IsFolder { get; set; }\n\n    public int Size { get; set; }\n    public string? Path { get; set; }\n        \n\n    public DateTime Created { get; set; }\n    public DateTime Modified { get; set; }\n\n\n    /// <summary>\n    /// Data but without Id, Guid, Created, Modified\n    /// </summary>\n    [PrivateApi]\n    public virtual IDictionary<string, object?> Attributes(RawConvertOptions options)\n        => new Dictionary<string, object?>\n        {\n            { nameof(Name), Name },\n            { nameof(ReferenceId), ReferenceId },\n            { nameof(Url), Url },\n            { nameof(Type), Type },\n            { nameof(IsFolder), IsFolder },\n            { nameof(Size), Size },\n            { nameof(Path), Path }\n        };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sys.AppAssets/AppAssetsDataSourceProvider.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Cms.Assets.Sys;\n\nnamespace ToSic.Sxc.DataSources.Sys.AppAssets;\n\n/// <summary>\n/// Base class to provide data to the AppFiles DataSource.\n///\n/// Must be overriden in each platform.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppAssetsDataSourceProvider(AppAssetsDataSourceProvider.Dependencies services)\n    : ServiceBase<AppAssetsDataSourceProvider.Dependencies>(services, $\"{SxcLogName}.AppFls\")\n{\n\n    public record Dependencies(\n        IAppReaderFactory AppReaders,\n        IAppPathsMicroSvc AppPathMicroSvc,\n        // Note that we will use Generators for safety, because in rare cases the dependencies could be re-used to create a sub-data-source\n        Generator<AppFileManager> FileManagerGenerator)\n        : DependenciesRecord(connect: [AppReaders, AppPathMicroSvc, FileManagerGenerator]);\n\n    public AppAssetsDataSourceProvider Configure(\n        AppAssetsGetSpecs specs,\n        NoParamOrder npo = default\n        //int zoneId = default,\n        //int appId = default\n        //string root = default,\n        //string filter = default\n    )\n    {\n        var root = specs.RootFolder;\n        var filter = specs.FileFilter;\n        var l = Log.Fn<AppAssetsDataSourceProvider>($\"a:{specs.AppId}; z:{specs.ZoneId}, root:{root}, filter:{filter}\");\n        _root = root.TrimPrefixSlash().Backslash();\n        _filter = filter;\n\n        var appReader = Services.AppReaders.Get(new AppIdentity(specs.ZoneId, specs.AppId));\n        _appPaths = Services.AppPathMicroSvc.Get(appReader);\n        \n        _appFileManager = Services.FileManagerGenerator.New().SetFolder(specs.AppId, _appPaths.PhysicalPath, _root);\n        return l.Return(this);\n    }\n\n    private string? _root;\n    private string? _filter;\n    private AppFileManager _appFileManager = null!;\n    private IAppPaths _appPaths = null!;\n\n    /// <summary>\n    /// FYI: The filters are not actually implemented yet.\n    /// So the core data source doesn't have settings to configure this\n    /// </summary>\n    /// <returns></returns>\n    public (List<FolderModelRaw> Folders, List<FileModelRaw> Files) GetAll()\n        => Log.Quick(() => (Folders, Files));\n\n    public List<FileModelRaw> Files => _files.Get(GetFiles)!;\n\n    private readonly GetOnce<List<FileModelRaw>> _files = new();\n\n    public List<FileModelRaw> GetFiles()\n    {\n        var l = Log.Fn<List<FileModelRaw>>();\n        var pathsFromRoot = PreparePaths(_appPaths, \"\");\n\n        var files = _appFileManager.GetAllTransferableFiles(_filter)\n            .Select(p => new FileInfo(p))\n            .Select(f =>\n            {\n                var fullNameFromAppRoot = FullNameWithoutAppFolder(f.FullName, pathsFromRoot);\n                var name = Path.GetFileNameWithoutExtension(f.FullName);\n                var path = fullNameFromAppRoot.TrimPrefixSlash();\n                return new FileModelRaw\n                {\n                    Name = name,\n                    Extension = f.Extension.TrimStart('.'), // Extension is without the dot\n                    FullName = $\"{name}{f.Extension}\",\n                    ParentFolderInternal = path.BeforeLast(\"/\").SuffixSlash(),\n                    Path = path,\n                    // TODO convert characters for safe HTML\n                    Url = $\"{_appPaths.Path}{fullNameFromAppRoot}\",\n\n                    Size = (int)f.Length,\n                    Created = f.CreationTime,\n                    Modified = f.LastWriteTime\n                };\n            })\n            .ToList();\n\n        return l.Return(files, $\"files:{files.Count}\");\n    }\n\n    public List<FolderModelRaw> Folders => _folders.Get(GetFolders)!;\n\n    private List<FolderModelRaw> GetFolders()\n    {\n        var l = Log.Fn<List<FolderModelRaw>>();\n        var pathsFromRoot = PreparePaths(_appPaths, \"\");\n\n        var folders = _appFileManager.GetAllTransferableFolders(/*filter*/)\n            .Select(p => new DirectoryInfo(p))\n            .Select(d => ToFolderData(d, pathsFromRoot))\n            .ToList();\n\n        // if the root is just \"/\" then we need to add the root folder, otherwise not\n        var root = new DirectoryInfo(\n            $\"{_appPaths.PhysicalPath}/{_root}\"\n                .FlattenMultipleForwardSlashes()\n                .TrimLastSlash()\n        );\n        folders.Insert(0, ToFolderData(root, pathsFromRoot) with\n        {\n            Name = \"\",                  // Make name blank, since it's the root folder\n            ParentFolderInternal = \"\",  // reset the ParentFolder, otherwise the root thinks it's a subfolder of itself\n        });\n\n        return l.Return(folders, $\"found:{folders.Count}\");\n    }\n\n    private FolderModelRaw ToFolderData(DirectoryInfo d, PreparedPaths pathsFromRoot)\n    {\n        var fullNameFromAppRoot = FullNameWithoutAppFolder(d.FullName, pathsFromRoot);\n\n        var name = Path.GetFileName(d.FullName);\n\n        return new()\n        {\n            Name = name,\n            FullName = name,\n            ParentFolderInternal = fullNameFromAppRoot.TrimPrefixSlash().BeforeLast(\"/\").SuffixSlash(),\n            Path = fullNameFromAppRoot.TrimPrefixSlash().SuffixSlash(),\n            Created = d.CreationTime,\n            Modified = d.LastWriteTime,\n            Url = $\"{_appPaths.Path}{fullNameFromAppRoot}\",\n        };\n    }\n\n    private readonly GetOnce<List<FolderModelRaw>> _folders = new();\n\n\n    /// <summary>\n    /// </summary>\n    /// <returns></returns>\n    private static string FullNameWithoutAppFolder(string? path, PreparedPaths paths)\n    {\n        if (path == null)\n            return string.Empty;\n\n        var name = path.Replace(paths.AppSitePath, string.Empty);\n        if (string.IsNullOrEmpty(name))\n            return string.Empty;\n        if (paths.HasShared) \n            name = name.Replace(paths.AppSharedPath, string.Empty);\n        return name.ForwardSlash();\n    }\n\n    private static PreparedPaths PreparePaths(IAppPaths appPaths, string root)\n    {\n        var hasShared = appPaths.PhysicalPathShared != null! /* paranoid */;\n        var appSharedPath = hasShared\n            ? Path.Combine(appPaths.PhysicalPathShared!, root)\n            : \"\";\n        return new(Path.Combine(appPaths.PhysicalPath, root), hasShared, appSharedPath);\n    }\n\n    private record PreparedPaths(string AppSitePath, bool HasShared, string AppSharedPath);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sys.Pages/PagesDataSourceProvider.cs",
    "content": "﻿using ToSic.Sxc.Cms.Pages.Sys;\n\nnamespace ToSic.Sxc.DataSources.Sys.Pages;\n\n/// <summary>\n/// Base class to provide data to the Pages DataSource.\n///\n/// Must be overriden in each platform.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class PagesDataSourceProvider(string logName, object[]? connect = default) : ServiceBase(logName, connect: connect)\n{\n    public const int NoParent = 0;\n\n    /// <summary>\n    /// FYI: The filters are not actually implemented yet.\n    /// So the core data source doesn't have settings to configure this\n    /// </summary>\n    /// <returns></returns>\n    public abstract List<PageModelRaw> GetPagesInternal(\n        NoParamOrder npo = default,\n        bool includeHidden = default,\n        bool includeDeleted = default,\n        bool includeAdmin = default,\n        bool includeSystem = default,\n        bool includeLinks = default,\n        bool requireViewPermissions = true,\n        bool requireEditPermissions = true\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sys.Pages/PagesDataSourceProviderUnknown.cs",
    "content": "﻿using ToSic.Sxc.Cms.Pages.Sys;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.DataSources.Sys.Pages;\n\ninternal class PagesDataSourceProviderUnknown(WarnUseOfUnknown<PagesDataSourceProviderUnknown> _) : PagesDataSourceProvider($\"{SxcLogName}.{LogConstants.NameUnknown}\")\n{\n    public override List<PageModelRaw> GetPagesInternal(NoParamOrder npo = default,\n        bool includeHidden = default, bool includeDeleted = default, bool includeAdmin = default,\n        bool includeSystem = default, bool includeLinks = default, bool requireViewPermissions = true,\n        bool requireEditPermissions = true) => [];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sys.Sources/EntityPicker.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Apps.Sys.Work;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.Sys.Streams;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Security.Permissions;\nusing ToSic.Sys.Users;\nusing static ToSic.Eav.DataSource.DataSourceConstants;\n\nnamespace ToSic.Sxc.DataSources.Sys.Sources;\n\n/// <inheritdoc />\n/// <summary>\n/// Keep only entities of a specific content-type\n/// </summary>\n[PrivateApi]\n[VisualQuery(\n    NiceName = \"Entity-Picker (internal)\",\n    UiHint = \"Special DataSource for the standard Entity-Picker\",\n    Icon = DataSourceIcons.RouteAlt,\n    Type = DataSourceType.Filter,\n    Audience = Audience.Advanced,\n    NameId = \"32369814-8f6d-47d8-a648-ce5372de78a8\",\n    DynamicOut = true,\n    // ConfigurationType = \"not yet defined\", // ATM we don't expect a configuration\n    HelpLink = \"https://go.2sxc.org/todo\")]\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\n// ReSharper disable once UnusedMember.Global\npublic class EntityPicker : DataSourceBase\n{\n    #region Configuration-properties\n\n    /// <summary>\n    /// The name of the types to filter for.\n    /// Either the normal name or the 'StaticName' which is usually a GUID.\n    ///\n    /// Can be many, comma separated\n    /// </summary>\n    [Configuration(Fallback = \"[QueryString:TypeNames]\")]\n    public string? TypeNames => Configuration.GetThis();\n\n    /// <summary>\n    /// List of IDs to filter against - reducing the final set to just a few items\n    /// </summary>\n    [Configuration(Fallback = \"[QueryString:ItemIds]\")]\n    public string? ItemIds => Configuration.GetThis();\n\n    #endregion\n\n    /// <inheritdoc />\n    /// <summary>\n    /// Constructs a new EntityTypeFilter\n    /// </summary>\n    [PrivateApi]\n    public EntityPicker(\n        GenWorkPlus<WorkEntities> workEntities,\n        ICurrentContextService ctxService,\n        Generator<MultiPermissionsApp, MultiPermissionsApp.Options> appPermissions,\n        Generator<MultiPermissionsTypes, MultiPermissionsTypes.Options> typePermissions,\n        IUser user,\n        IAppReaderFactory appReaders,\n        Dependencies services\n    ) : base(services, \"Api.EntPck\", connect: [workEntities, appPermissions, typePermissions, ctxService, appReaders])\n    {\n        _workEntities = workEntities;\n        _ctxService = ctxService;\n        _appPermissions = appPermissions;\n        _typePermissions = typePermissions;\n        _user = user;\n        _appReaders = appReaders;\n        ProvideOut(GetList);\n    }\n\n    private readonly GenWorkPlus<WorkEntities> _workEntities;\n    private readonly ICurrentContextService _ctxService;\n    private readonly IUser _user;\n    private readonly IAppReaderFactory _appReaders;\n    private readonly Generator<MultiPermissionsApp, MultiPermissionsApp.Options> _appPermissions;\n    private readonly Generator<MultiPermissionsTypes, MultiPermissionsTypes.Options> _typePermissions;\n\n    #region Dynamic Out\n\n    /// <summary>\n    /// Override Out to provide the Default stream as well as additional streams for each content-type\n    /// </summary>\n    public override IReadOnlyDictionary<string, IDataStream> Out => _out.Get(() =>\n    {\n        // 0. If no names specified, then out is same as base out\n        if (TypeNames.IsEmptyOrWs())\n            return base.Out;\n        var typesWithoutDefault = ContentTypes?\n            .Where(ct => !ct.Name.EqualsInsensitive(StreamDefaultName))\n            .ToList();\n        if (typesWithoutDefault.SafeNone())\n            return base.Out;\n\n        // 1. Create a new StreamDictionary with the Default\n        var outList = new StreamDictionary(this, Services.CacheService);\n        outList.Add(StreamDefaultName, base.Out[StreamDefaultName]);\n\n        // 2. Generate additional streams based on the content-types requested\n        var list = base.Out[StreamDefaultName].List;\n        foreach (var contentType in typesWithoutDefault)\n        {\n            var name = contentType.Name;\n            var outStream = new DataStream(Services.CacheService, this, name, () => list.GetAll(contentType), true);\n            outList.Add(name, outStream);\n        }\n\n        return outList.AsReadOnly();\n    })!;\n\n    private readonly GetOnce<IReadOnlyDictionary<string, IDataStream>> _out = new();\n\n    #endregion\n\n    private IEnumerable<IEntity> GetList()\n    {\n        // Open the log after config-parse, so we have type names\n        var l = Log.Fn<IEnumerable<IEntity>>($\"get list with type:{TypeNames}\");\n\n        // Get the context - must be pre-set by the caller\n\n        var context = _ctxService.AppOrNull();\n        if (context == null)\n        {\n            l.E(\"No App context\");\n            return l.Return(Error.Create(title: \"No App context\", message: \"No context found, cannot continue\"), \"no context\");\n        }\n\n        // Case 1: No Type Names - return all entities in the Content-Scope\n        if (TypeNames.IsEmptyOrWs())\n        {\n            // App permission checker\n            var permCheckApp = _appPermissions.New(new() { SiteContext = context, App = this.PureIdentity() });\n\n            // First do security check with no-type name\n            if (!permCheckApp.EnsureAll(GrantSets.ReadSomething, out _))\n                return l.ReturnAsError(Error.Create(title: \"No permissions on App, get all entities denied\"));\n\n            // Check if we provide drafts as well\n            var withDrafts = permCheckApp.EnsureAny(GrantSets.ReadDraft);\n\n            var entitiesSvc = _workEntities.New(this, showDrafts: withDrafts);\n            var entities = entitiesSvc.OnlyContent(withConfiguration: _user.IsSystemAdmin).ToList();\n            entities = FilterByIds(entities);\n            return l.Return(entities, $\"no type filter: {entities.Count}\");\n        }\n\n        try\n        {\n            var types = ContentTypes;\n            if (types == null! /* paranoid */)\n                return l.ReturnAsError(Error.Create(title: \"TypeList==null, something threw an error there.\"));\n            if (!types.Any())\n                return l.Return(new List<IEntity>(), \"no valid types found, empty list\");\n\n            // Find all Entities of the specified types\n            var result = new List<IEntity>();\n            foreach (var type in types)\n            {\n                var lType = l.Fn($\"Adding all of '{type.Name}'\");\n\n                var permCheckType = _typePermissions.New(new() { SiteContext = context, App = context.AppReaderRequired, ContentTypes = [type.Name] });\n\n                if (permCheckType.EnsureAll(GrantSets.ReadSomething, out _))\n                {\n                    var withDrafts = permCheckType.EnsureAny(GrantSets.ReadDraft);\n                    var entitiesSvc = _workEntities.New(this, showDrafts: withDrafts);\n                    var ofType = entitiesSvc.AppWorkCtx.Data.List.GetAll(type).ToList();\n                    result.AddRange(ofType);\n                    lType.Done($\"{ofType.Count}\");\n                }\n                else\n                {\n                    var errorItem = Error.Create(title: $\"No permissions for Type {type.Name}\");\n                    result.AddRange(errorItem);\n                    lType.Done($\"added error for {type.Name}\");\n                }\n            }\n\n            if (result.Any())\n                result = FilterByIds(result);\n\n            return l.Return(result, $\"typed/filtered: {result.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            /* ignore */\n            return l.Return(Error.Create(title: \"Something went wrong\", message: \"Unknown problem\", exception: ex), \"error\");\n        }\n\n    }\n\n    // TODO: CONTINUE\n    // 1. Get the AppState from elsewhere, not the WorkEntities\n    // 2. Get the ContentTypes to return both the types and a perm checker\n    // 3. ...\n    // CHANGE detection of type names to use the ContentTypes array ?\n\n    /// <summary>\n    /// List of ContentTypes to filter by\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    private List<IContentType> ContentTypes => field ??= GetContentTypes();\n    private List<IContentType> GetContentTypes()\n    {\n        var l = Log.Fn<List<IContentType>>();\n\n        try\n        {\n            var typeNames = TypeNames\n                .CsvToArrayWithoutEmpty()\n                .ToList();\n\n            l.A($\"found {typeNames.Count} type names, before verifying if they exist\");\n\n            if (!typeNames.Any())\n                return l.Return([]);\n\n            var appReader = _appReaders.Get(this.PureIdentity());\n\n            var types = typeNames\n                .Select(appReader.TryGetContentType)\n                .Where(t => t != null)\n                .Cast<IContentType>()\n                .ToList();\n\n            return l.Return(types, $\"found {types.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            /* ignore */\n            return l.ReturnAsError([]);\n        }\n    }\n\n    private List<IEntity> FilterByIds(List<IEntity> list)\n    {\n        var l = Log.Fn<List<IEntity>>($\"started with {list.Count}\");\n        var rawIds = ItemIds;\n        if (rawIds.IsEmptyOrWs())\n            return l.Return(list, \"no filter, return all\");\n\n        var untyped = rawIds.CsvToArrayWithoutEmpty().ToList();\n\n        if (!untyped.Any())\n            return l.Return(list, \"empty filter, return all\");\n\n        var result = new List<IEntity>();\n        foreach (var id in untyped)\n        {\n            IEntity? found = null;\n            // check if id is int or guid\n            if (Guid.TryParse(id, out var guid))\n                found = list.GetOne(guid);\n            else if (int.TryParse(id, out var intId))\n                found = list.GetOne(intId);\n            if (found != null)\n                result.Add(found);\n        }\n        return l.Return(result, $\"filtered to {result.Count}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sys.Users/IUserRolesProvider.cs",
    "content": "﻿using ToSic.Sxc.Cms.Users.Sys;\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Base class to provide data to the RolesDataSourceProvider.\n///\n/// Must be overriden in each platform.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IUserRolesProvider\n{\n    /// <summary>\n    /// The inner list retrieving roles. \n    /// </summary>\n    /// <returns></returns>\n    IEnumerable<UserRoleModel> GetRoles();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Sys.Users/UsersGetSpecsParsed.cs",
    "content": "﻿using ToSic.Sxc.Cms.Users.Sys;\n\nnamespace ToSic.Sxc.DataSources;\n\npublic record UsersGetSpecsParsed(UsersGetSpecs Specs)\n{\n    #region Configuration\n\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<int> UserIdFilter => field ??= ParseCsvToIntList(Specs.UserIds);\n\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<Guid> UserGuidFilter => field ??= ParseCsvToGuidList(Specs.UserIds);\n\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<int> ExcludeUserIdsFilter => field ??= ParseCsvToIntList(Specs.ExcludeUserIds);\n\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<Guid> ExcludeUserGuidsFilter => field ??= ParseCsvToGuidList(Specs.ExcludeUserIds);\n\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<int> RolesFilter => field ??= ParseCsvToIntList(Specs.RoleIds);\n\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<int> ExcludeRolesFilter => field ??= ParseCsvToIntList(Specs.ExcludeRoleIds);\n\n    #endregion\n\n    private static List<int> ParseCsvToIntList(string? stringList)\n        => !stringList.HasValue()\n            ? []\n            : stringList.Split(UserConstants.Separator)\n                .Select(u => int.TryParse(u.Trim(), out var userId) ? userId : UserConstants.NullInteger)\n                .Where(u => u != -1)\n                .ToList();\n\n    private static List<Guid> ParseCsvToGuidList(string? stringList)\n        => !stringList.HasValue()\n            ? []\n            : stringList.Split(UserConstants.Separator)\n                .Select(u => Guid.TryParse(u.Trim(), out var userGuid) ? userGuid : Guid.Empty)\n                .Where(u => u != Guid.Empty)\n                .ToList();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/UserRoles.cs",
    "content": "﻿using System.Collections.Immutable;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Cms.Users.Sys;\n\n// Important Info to people working with this\n// It depends on abstract provider, that must be overriden in each platform\n// In addition, each platform must make sure to register a TryAddTransient with the platform specific provider implementation\n// This is because any constructor DI should be able to target this type, and get the real provider implementation\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Will get all (or just some) user roles of the current site.\n/// </summary>\n/// <remarks>\n/// You can cast the result to <see cref=\"IUserRoleModel\"/> for typed use in your code.\n/// To figure out the returned properties, best also consult the <see cref=\"IUserRoleModel\"/>.\n/// \n/// History\n///\n/// * Not sure when it was first created, probably early 2023 with the name `Roles`, and not officially communicated.\n/// * Model <see cref=\"IUserRoleModel\"/> created in v19.01 and officially released\n/// * Renamed to `UserRoles` for consistency in v19.0 as we believe nobody has been actively using it yet, since the models were missing.\n/// </remarks>\n[PublicApi]\n[VisualQuery(\n    NiceName = \"User Roles\",\n    Icon = DataSourceIcons.UserCircled,\n    UiHint = \"User Roles in this site\",\n    HelpLink = \"https://go.2sxc.org/ds-roles\",\n    NameId = \"eee54266-d7ad-4f5e-9422-2d00c8f93b45\",\n    Type = DataSourceType.Source,\n    ConfigurationType = \"1b9fd9d1-dde0-40ad-bb66-5cd7f30de18d\"\n)]\npublic class UserRoles : CustomDataSourceAdvanced\n{\n    private readonly IUserRolesProvider _provider;\n\n    #region Other Constants\n\n    private const char Separator = ',';\n\n    #endregion\n\n    #region Configuration-properties\n\n    /// <summary>\n    /// Optional (single value or comma-separated integers) filter,\n    /// include roles based on roleId\n    /// </summary>\n    [Configuration]\n    public string? RoleIds\n    {\n        get => field ?? Configuration.GetThis();\n        set;\n    }\n\n    /// <summary>\n    /// Optional (single value or comma-separated integers) filter,\n    /// exclude roles based on roleId\n    /// </summary>\n    [Configuration]\n    public string? ExcludeRoleIds\n    {\n        get => field ?? Configuration.GetThis();\n        set;\n    }\n\n    #endregion\n\n\n    #region Constructor\n\n    /// <summary>\n    /// Constructor to tell the system what out-streams we have\n    /// </summary>\n    [PrivateApi]\n    public UserRoles(Dependencies services, IUserRolesProvider provider)\n        : base(services, \"SDS.Roles\", connect: [provider])\n    {\n        _provider = provider;\n\n        ProvideOut(GetList);\n    }\n\n    #endregion\n\n    private IImmutableList<IEntity> GetList()\n    {\n        var l = Log.Fn<IImmutableList<IEntity>>();\n        var roles = _provider.GetRoles()?.ToList();\n        l.A($\"found {roles?.Count} roles\");\n\n        if (roles.SafeNone()) \n            return l.Return([], \"null/empty\");\n\n        // This will resolve the tokens before starting\n        Configuration.Parse();\n\n        var includeRolesPredicate = KeepRolesCondition();\n        l.A($\"includeRoles: {includeRolesPredicate == null}\");\n        if (includeRolesPredicate != null)\n            roles = roles\n                .Where(includeRolesPredicate)\n                .ToList();\n\n        var excludeRolesPredicate = DropRolesCondition();\n        l.A($\"excludeRoles: {excludeRolesPredicate == null}\");\n        if (excludeRolesPredicate != null)\n            roles = roles\n                .Where(excludeRolesPredicate)\n                .ToList();\n\n        var rolesFactory = DataFactory.SpawnNew(options: UserRoleModel.Options);\n\n        var result = rolesFactory.Create(roles);\n\n        return l.Return(result, $\"found {result.Count} roles\");\n    }\n\n    private Func<UserRoleModel, bool>? KeepRolesCondition()\n    {\n        var includeRolesFilter = RolesCsvListToInt(RoleIds);\n        return includeRolesFilter.Any()\n            ? r => includeRolesFilter.Contains(r.Id)\n            : null;\n    }\n\n    private Func<UserRoleModel, bool>? DropRolesCondition()\n    {\n        var excludeRolesFilter = RolesCsvListToInt(ExcludeRoleIds);\n        return excludeRolesFilter.Any()\n            ? r => !excludeRolesFilter.Contains(r.Id)\n            : null;\n    }\n\n    [PrivateApi]\n    internal static List<int> RolesCsvListToInt(string? stringList)\n        => !stringList.HasValue()\n            ? []\n            : stringList.Split(Separator)\n                .Select(r => int.TryParse(r.Trim(), out var roleId) ? roleId : int.MinValue)\n                .Where(r => r != int.MinValue)\n                .ToList();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/DataSources/Users.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Sys.Entities.Sources;\nusing ToSic.Eav.DataSource;\n\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Eav.Services;\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sys.Users;\n\n// Important Info to people working with this\n// It depends on abstract provider, that must be overriden in each platform\n// In addition, each platform must make sure to register a TryAddTransient with the platform specific provider implementation\n// This is because any constructor DI should be able to target this type, and get the real provider implementation\n\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Will get all (or just some) users of the current site.\n/// </summary>\n/// <remarks>\n/// You can cast the result to <see cref=\"IUserModel\"/> for typed use in your code.\n/// To figure out the returned properties, best also consult the <see cref=\"IUserModel\"/>.\n/// \n/// The resulting Entity will almost match the <see cref=\"IUser\"/> interface.\n/// \n/// History\n/// \n/// * Created ca. v.16 early 2023 but not officially communicated\n/// * Models <see cref=\"IUserModel\"/> and <see cref=\"IUserRoleModel\"/> created in v19.01 and officially released\n/// </remarks>\n[PublicApi]\n[VisualQuery(\n    NiceName = \"Users\",\n    Icon = DataSourceIcons.UserCircled,\n    UiHint = \"Users in this site\",\n    HelpLink = \"https://go.2sxc.org/ds-users\",\n    NameId = \"93ac53c6-adc6-4218-b979-48d1071a5765\", // random & unique Guid\n    Type = DataSourceType.Source,\n    ConfigurationType = \"ac11fae7-1916-4d2d-8583-09872e1e6966\"\n)]\npublic class Users : CustomDataSourceAdvanced\n{\n    private readonly IDataSourceGenerator<UserRoles> _rolesGenerator;\n    private readonly IUsersProvider _provider;\n\n    #region Configuration-properties\n\n    /// <summary>\n    /// Optional Users (single value or comma-separated guids or integers) filter,\n    /// include users based on guid or id\n    /// </summary>\n    [Configuration]\n    public string? UserIds\n    {\n        get => field ?? Configuration.GetThis();\n        set;\n    }\n\n    /// <summary>\n    /// Optional exclude Users (single value or comma-separated guids or integers) filter,\n    /// exclude users based on guid or id\n    /// </summary>\n    [Configuration]\n    public string? ExcludeUserIds\n    {\n        get => field ?? Configuration.GetThis();\n        set;\n    }\n\n    /// <summary>\n    /// Optional IncludeRolesFilter (single value or comma-separated integers) filter,\n    /// include users that have any of roles from filter\n    /// </summary>\n    [Configuration]\n    public string? RoleIds\n    {\n        get => field ?? Configuration.GetThis();\n        set;\n    }\n\n    /// <summary>\n    /// Optional ExcludeRolesFilter (single value or comma-separated integers) filter,\n    /// exclude users that have any of roles from filter\n    /// </summary>\n    [Configuration]\n    public string? ExcludeRoleIds\n    {\n        get => field ?? Configuration.GetThis();\n        set;\n    }\n\n    /// <summary>\n    /// Optional SystemAdmins filter.\n    /// \n    /// * `true` - with System Admins\n    /// * `false` - without System Admins\n    /// * `required` - only System Admins (no normal users)\n    /// </summary>\n    /// <remarks>\n    /// * Changed to be string in v15.03 (before bool) to allow more options such as `required`\n    /// </remarks>\n    [Configuration]\n    public string? IncludeSystemAdmins\n    {\n        get => field ?? Configuration.GetThis();\n        set;\n    }\n\n    /// <summary>\n    /// Add property `Roles` as a relationship to role entities.\n    /// </summary>\n    /// <remarks>\n    /// * Added v15.03 - minimal breaking change, before the source return a non-standard `RoleIds` string-array.\n    /// </remarks>\n    [Configuration(Fallback = true)]\n    public bool AddRoles\n    {\n        get => _addRoles ?? Configuration.GetThis(true);\n        set => _addRoles = value;\n    }\n    private bool? _addRoles;\n\n    #endregion\n\n    private UsersGetSpecs Specs => new()\n    {\n        UserIds = UserIds,\n        ExcludeUserIds = ExcludeUserIds,\n        RoleIds = RoleIds,\n        ExcludeRoleIds = ExcludeRoleIds,\n        IncludeSystemAdmins = IncludeSystemAdmins,\n        AddRoles = AddRoles\n    };\n\n\n    #region Constructor\n\n    /// <summary>\n    /// Constructor to tell the system what out-streams we have\n    /// </summary>\n    [PrivateApi]\n    public Users(Dependencies services, IUsersProvider provider, IDataSourceGenerator<UserRoles> rolesGenerator)\n        : base(services, \"SDS.Users\", connect: [provider, rolesGenerator])\n    {\n        _provider = provider;\n        _rolesGenerator = rolesGenerator;\n\n        ProvideOut(() => UsersAndRoles.Users); // default out, if accessed, will deliver GetList\n        ProvideOut(() => UsersAndRoles.UserRoles, \"Roles\");\n    }\n\n    #endregion\n\n    private (IEnumerable<IEntity> Users, IEnumerable<IEntity> UserRoles) UsersAndRoles => _usersAndRoles ??= GetUsersAndRoles();\n    private (IEnumerable<IEntity> Users, IEnumerable<IEntity> UserRoles)? _usersAndRoles;\n\n    private (IEnumerable<IEntity> Users, IEnumerable<IEntity> UserRoles) GetUsersAndRoles()\n    {\n        var l = Log.Fn<(IEnumerable<IEntity> Users, IEnumerable<IEntity> UserRoles)>();\n\n        // Get raw users from provider, then generate entities\n        var usersRaw = GetUsersAndFilter();\n\n        // Figure out options to be sure we have the roles/roleids\n        var relationships = new LazyLookup<object, IEntity>();\n        var userFactory = DataFactory.SpawnNew(options: UserModel.Options with\n        {\n            // Option to tell the entity conversion to add the \"Roles\" to each user\n            RawConvertOptions = new(addKeys: [\"Roles\"]),\n            Relationships = relationships,\n        });\n\n        var users = userFactory.Create(usersRaw);\n        List<IEntity> roles = [];\n\n        // If we should include the roles, create them now and attach\n        if (!AddRoles)\n            return l.Return((users, []), $\"users {users.Count}; no roles\");\n\n        try\n        {\n            // Get roles and extend with the property necessary for Users to map to the roles\n            roles = GetRolesStream(usersRaw);\n            relationships.Add(roles.Select(r =>\n                new KeyValuePair<object, IEntity>($\"{UserModel.RoleRelationshipPrefix}{r.EntityId}\", r)));\n            return l.Return((users, roles), $\"users {users.Count}; roles {roles.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.A(\"Error trying to add roles\");\n            l.Ex(ex);\n            /* ignore for now */\n            return l.Return((users, roles), $\"users {users.Count}; roles error: {roles.Count}\");\n        }\n\n    }\n\n    private List<UserModel> GetUsersAndFilter()\n    {\n        var l = Log.Fn<List<UserModel>>();\n        var users = _provider.GetUsers(Specs)?.ToList();\n        if (users == null || users.Count == 0)\n            return l.Return([], \"null/empty\");\n\n        return l.Return(users, $\"found {users.Count}\");\n    }\n\n\n    /// <summary>\n    /// Retrieve roles and create lookup for relationship-mapper\n    /// </summary>\n    /// <param name=\"usersRaw\"></param>\n    /// <returns></returns>\n    private List<IEntity> GetRolesStream(List<UserModel> usersRaw)\n    {\n        // Get list of all role IDs which are to be used\n        var roleIds = usersRaw\n            .SelectMany(u => u.Roles)\n            .Select(r => r.Id)\n            .Distinct()\n            .ToList();\n\n        // Get roles, use the current data source to provide aspects such as lookups etc.\n        var rolesDs = _rolesGenerator.New( /*attach: this,*/ options:\n            //new DataSourceOptionConverter().Create(\n            new DataSourceOptions\n            {\n                AppIdentityOrReader = this.PureIdentity(),\n                Attach = this,\n                MyConfigValues = new\n                    {\n                        // Set filter parameter to only get roles we'll need\n                        RoleIds = string.Join(\",\", roleIds),\n                    }\n                    .ToDicInvariantInsensitive()\n                    .ToDicStringStringImInv()\n            }\n            //, new\n            //{\n            //    // Set filter parameter to only get roles we'll need\n            //    RoleIds = string.Join(\",\", roleIds),\n            //})\n        );\n        \n        return rolesDs.List.ToList();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/ExportImport.Sys/SxcXmlExporter.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.ImportExport.Sys.Xml;\nusing ToSic.Eav.ImportExport.Sys.XmlExport;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.ExportImport.Sys;\n\n/// <summary>\n/// Xml Exporter which is aware of the Sxc context, and can therefore export apps and entities.\n/// </summary>\n/// <param name=\"xmlSerializer\"></param>\n/// <param name=\"appsCatalog\"></param>\n/// <param name=\"currentContextService\"></param>\n/// <param name=\"logPrefix\"></param>\n/// <param name=\"connect\"></param>\npublic abstract class SxcXmlExporter(XmlSerializer xmlSerializer, IAppsCatalog appsCatalog, ICurrentContextService currentContextService, string logPrefix, object[]? connect = default)\n    : XmlExporter(xmlSerializer, appsCatalog, logPrefix, connect: [..connect ?? [], currentContextService])\n{\n\n    protected ICurrentContextService CurrentContextService { get; } = currentContextService;\n\n    /// <summary>\n    /// Not that the overload of this must take care of creating the EavAppContext and calling the Constructor\n    /// </summary>\n    /// <returns></returns>\n    public override XmlExporter Init(AppExportSpecs specs, IAppReader appRuntime, bool appExport, string[] attrSetIds, string[] entityIds)\n    {\n        CurrentContextService.SetApp(new AppIdentity(specs.ZoneId, specs.AppId));\n        var ctxOfApp = CurrentContextService.AppRequired();\n        PostContextInit(ctxOfApp);\n        Constructor(specs, appRuntime, ctxOfApp.AppReaderRequired.Specs.NameId, appExport, attrSetIds, entityIds, ctxOfApp.Site.DefaultCultureCode);\n\n        return this;\n    }\n\n    /// <summary>\n    /// Post context init the caller must be able to init Adam, which is not part of this project, so we're handling it as a callback\n    /// </summary>\n    /// <param name=\"appContext\"></param>\n    protected abstract void PostContextInit(IContextOfApp appContext);\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Eav.Models;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Performance;\nglobal using ToSic.Sys.Utils;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Properties/SxcCmsInternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.UnitTests\")]"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/StartupSxcCms.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Cms.Sites.Sys;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.DataSources;\nusing ToSic.Sxc.DataSources.Sys.AppAssets;\nusing ToSic.Sxc.DataSources.Sys.Pages;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcCms\n{\n    public static IServiceCollection AddSxcCms(this IServiceCollection services)\n    {\n        services.TryAddTransient<IPagePublishing, BasicPagePublishing>();\n\n        // This must never have a TRY! but only an AddTransient, as many can be registered by this type\n        services.AddTransient<IPagePublishingGetSettings, PagePublishingGetSettingsOptional>(); // new v13 BETA #SwitchServicePagePublishingResolver\n        services.AddTransient<IPagePublishingGetSettings, PagePublishingGetSettingsForbidden>();\n\n        // v15 DataSource\n        services.TryAddTransient<PagesDataSourceProvider, PagesDataSourceProviderUnknown>();\n        services.TryAddTransient<IUsersProvider, UsersProviderUnknown>();\n        services.TryAddTransient<IUserRolesProvider, UserRolesProviderUnknown>();\n        services.TryAddTransient<SitesDataSourceProvider.Dependencies>();\n        services.TryAddTransient<SitesDataSourceProvider, SitesDataSourceProviderUnknown>();\n\n        services.TryAddTransient<AppAssetsDataSourceProvider>();\n        services.TryAddTransient<AppAssetsDataSourceProvider.Dependencies>();\n        services.TryAddTransient(typeof(AdamDataSourceProvider<,>));\n        services.TryAddTransient(typeof(AdamDataSourceProvider<,>.Dependencies));\n\n\n        return services;\n    }\n\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/Sys.ExecutionContext/ExecutionContextExtensions.cs",
    "content": "﻿using ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic static class ExecutionContextExtensions\n{\n    public static ICmsContext GetCmsContext(this IExecutionContext context)\n        => context.GetState<ICmsContext>();\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/ToSic.Sxc.Cms.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Cms</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Cms/ToSic.Sxc.Cms.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cms_005Cusers/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=context_005Cinterfaces/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=context_005Cmodule/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=context_005Cpage/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datasources_005Cadamfiles/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datasources_005Cadamfiles_002Esys/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datasources_005Cappassets/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datasources_005Csys_002Eadamfiles/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datasources_005Csys_002Eusers/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datasources_005Cusers/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/AppCode/_Help.cs",
    "content": "﻿\n// ReSharper disable once CheckNamespace\nnamespace AppCode;\n\n/// <summary>\n/// EXPERIMENTAL v17\n/// \n/// This class is a placeholder to provide help in the docs.\n///\n/// The namespace <see cref=\"AppCode\"/> is reserved for custom code in your app.\n/// As such, it doesn't have any code in the public docs, but will contain classes and code from your app.\n///\n/// To use, see TODO: Add link to docs\n/// </summary>\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n// ReSharper disable once UnusedType.Global\n// ReSharper disable once InconsistentNaming\n#pragma warning disable IDE1006\npublic class _Help;\n#pragma warning restore IDE1006\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Customizer/Customizer.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys.CmsContext;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Customizer;\n\n/// <inheritdoc cref=\"ICodeCustomizer\" />\ninternal class Customizer(): ServiceWithContext(SxcLogName + \".CdeCst\"), ICodeCustomizer\n{\n    public IAppTyped<TSettings, TResources> App<TSettings, TResources>()\n        where TSettings : class, IModelFromData, new()\n        where TResources : class, IModelFromData, new()\n    {\n        // check if cache exists and was created with the sames specs\n        if (_app is IAppTyped<TSettings, TResources> typed)\n            return typed;\n\n        // Get and cache for next time\n        var created = ExCtx.GetService<IAppTyped<TSettings, TResources>>(reuse: true);\n        _app = created;\n        return created;\n    }\n    private object? _app;\n\n    public ICmsView<TSettings, TResources> MyView<TSettings, TResources>()\n        where TSettings : class, IModelFromData, new()\n        where TResources : class, IModelFromData, new()\n    {\n        // check if cache exists and was created with the sames specs\n        if (_view is ICmsView<TSettings, TResources> typed)\n            return typed;\n\n        // Get and cache for reuse\n        var cmsContext = (CmsContext)ExCtx.GetCmsContext();\n        var created = new CmsView<TSettings, TResources>(cmsContext, cmsContext.BlockInternal, false);\n        _view = created;\n        return created;\n    }\n\n    private ICmsView? _view;\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= ExCtx.GetCdf();\n\n    public TCustomType? MyItem<TCustomType>()\n        where TCustomType : class, IModelFromData, new()\n    {\n        // check if cache exists and was created with the sames specs\n        if (_myItem is TCustomType typed)\n            return typed;\n\n        var firstEntity = ExCtx.GetContextData()?.MyItems.FirstOrDefault();\n        var created = Cdf.AsCustom<TCustomType>(firstEntity);\n        _myItem = created;\n        return created;\n    }\n    private object? _myItem;\n\n    public IEnumerable<TCustomType> MyItems<TCustomType>()\n        where TCustomType : class, IModelFromData, new()\n    {\n        // check if cache exists and was created with the sames type as is now requested\n        if (_myItems is IEnumerable<TCustomType> typed)\n            return typed;\n        \n        // Get and cache for reuse\n        var items = ExCtx.GetContextData()?.MyItems ?? [];\n        var created = Cdf.AsCustomList<TCustomType>(items, default, nullIfNull: false);\n        _myItems = created;\n        return created;\n    }\n    private object? _myItems; // not typed, since we don't know the type yet, but we know it will be IEnumerable<TCustomType> when used\n\n    public TCustomType? MyHeader<TCustomType>()\n        where TCustomType : class, IModelFromData, new()\n    {\n        // check if cache exists and was created with the sames specs\n        if (_myHeader is TCustomType typed)\n            return typed;\n\n        // Get and cache for reuse\n        var header = ExCtx.GetContextData()?.MyHeaders.FirstOrDefault();\n        var created = Cdf.AsCustom<TCustomType>(header);\n        _myHeader = created;\n        return created;\n    }\n    private object? _myHeader;\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Customizer/ICodeCustomizer.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// Helper object to use on Razor, Code, APIs to create more app-specific helper objects.\n/// Like the `App` object, `View` object etc.\n///\n/// It will usually be provided on a protected `Customize` property on RazorTyped etc.\n/// </summary>\n/// <remarks>\n/// New v17.03 (BETA!)\n/// </remarks>\n[PublicApi]\npublic interface ICodeCustomizer\n{\n    /// <summary>\n    /// Create (and cache for reuse) a strongly typed App instance for the App object.\n    /// </summary>\n    /// <typeparam name=\"TSettings\">Type to use for Settings.</typeparam>\n    /// <typeparam name=\"TResources\">Type to use for Resources</typeparam>\n    IAppTyped<TSettings, TResources> App<TSettings, TResources>()\n        where TSettings : class, IModelFromData, new()\n        where TResources : class, IModelFromData, new();\n\n    /// <summary>\n    /// Create (and cache for reuse) a strongly typed View instance for the MyView object.\n    /// </summary>\n    /// <typeparam name=\"TSettings\">Type to use for Settings.</typeparam>\n    /// <typeparam name=\"TResources\">Type to use for Resources</typeparam>\n    ICmsView<TSettings, TResources> MyView<TSettings, TResources>()\n        where TSettings : class, IModelFromData, new()\n        where TResources : class, IModelFromData, new();\n\n    /// <summary>\n    /// Create (and cache for reuse) a strongly typed Item instance for the MyItem object.\n    /// </summary>\n    /// <typeparam name=\"TCustomType\">Type to use for MyItem.</typeparam>\n    /// <returns></returns>\n    public TCustomType? MyItem<TCustomType>()\n        where TCustomType : class, IModelFromData, new();\n\n    /// <summary>\n    /// Create (and cache for reuse) a strongly typed Items instance for the MyItems object.\n    /// </summary>\n    /// <typeparam name=\"TCustomType\">Type to use for MyItems.</typeparam>\n    /// <returns></returns>\n    public IEnumerable<TCustomType> MyItems<TCustomType>()\n        where TCustomType : class, IModelFromData, new();\n\n    /// <summary>\n    /// Create (and cache for reuse) a strongly typed Header instance for the MyHeader object.\n    /// </summary>\n    /// <typeparam name=\"TCustomType\">Type to use for MyHeader.</typeparam>\n    TCustomType? MyHeader<TCustomType>()\n        where TCustomType : class, IModelFromData, new();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/DevTools/DevTools.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\nnamespace ToSic.Sxc.Code;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class DevTools(CompileCodeHelperSpecs specs, ILog parentLog) : HelperBase(parentLog, $\"{SxcLogName}.DevTls\"), IDevTools\n{\n    private string RequireMsg(string requires, string but, string[] names) =>\n        $\"Partial Razor '{specs.CodeFileName}' requires {requires} of the following parameters, but {but} were provided: \" +\n        string.Join(\", \", (names ?? []).Select(s => $\"'{s}'\"));\n\n    public void Debug(object target, NoParamOrder npo = default, bool debug = true)\n    {\n        var l = Log.Fn($\"{nameof(target)}: '{target?.GetType()}', {nameof(debug)}: {debug}\");\n        \n        if (target is not ICanDebug canDebug)\n            throw new ArgumentException($\"Can't enable debug on {nameof(target)} as it doesn't support {nameof(ICanDebug)}\");\n        canDebug.Debug = debug;\n        l.Done();\n    }\n\n    //public bool HasAll(params string[] names)\n    //{\n    //    if (names == null || names.Length == 0) return true;\n    //    return names.All(n => _paramsDictionary.ContainsKey(n));\n    //}\n\n    //public bool HasAny(params string[] names)\n    //{\n    //    if (names == null || names.Length == 0) return true;\n    //    return names.Any(n => _paramsDictionary.ContainsKey(n));\n    //}\n\n    //public string RequireAny(params string[] names)\n    //{\n    //    if (HasAny(names)) return null;\n    //    throw new ArgumentException(RequireMsg(\"one or more\", \"none\", names));\n    //}\n    //public string RequireAll(params string[] names)\n    //{\n    //    if (HasAll(names)) return null;\n    //    throw new ArgumentException(RequireMsg(\"all\", \"not all\", names));\n    //}\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/DevTools/IDevTools.cs",
    "content": "﻿namespace ToSic.Sxc.Code;\n\n/// <summary>\n/// WIP!!!\n///\n/// This should provide special APIs to assist developers.\n/// It will probably change from version to version, so the use should be limited to quick debugs and similar,\n/// but never remain in the code.\n/// </summary>\n[WorkInProgressApi(\"Not yet in use\")]\npublic interface IDevTools\n{\n    /// <summary>\n    /// Enable debugging on a specific object, if it supports it.\n    /// </summary>\n    /// <param name=\"target\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"debug\"></param>\n    void Debug(object target, NoParamOrder npo = default, bool debug = true);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/DynamicCode/IDynamicCode12.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing IFolder = ToSic.Sxc.Adam.IFolder;\n// Disable warnings that properties should be marked as new\n// Because we need them here as additional definition because of Razor problems with inherited interfaces\n#pragma warning disable CS0108, CS0114\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// Interface for Dynamic Code with enhancements after v12. It extends <see cref=\"IDynamicCode\"/>\n/// \n/// Dynamic Code is the API for files like Razor or WebApis.\n/// Supports many properties like App, etc. to ensure that the dynamic code has everything you need. <br />\n/// Also provides many Conversions between <see cref=\"IEntity\"/> and <see cref=\"IDynamicEntity\"/>.\n/// Important for dynamic code files like Razor or WebApi. Note that there are many overloads to ensure that AsDynamic and AsEntity \"just work\" even if you give them the original data.\n/// </summary>\n/// <remarks>\n/// This interface is only used by developers who use the <see cref=\"IDynamicCodeService\"/> to retrieve the object which helps them access things such as the App.\n/// </remarks>\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDynamicCode12 : IDynamicCode, ICreateInstance, ICompatibilityLevel, IHasLog\n{\n    #region IDynamicCode Repeats - keep this in sync\n    // **************************************************\n    // WARNING\n    // **************************************************\n    // Razor has a small problem with interfaces inheriting interfaces. \n    // If an object is of an interface which inherits another interface\n    // then Razor will not find methods of the root interface and give errors like\n    // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'ToSic.Sxc.Code.IDynamicCode12' does not contain a definition for 'AsList' at CallSite.Target\n    //\n    // Because of this, we repeat the ENTIRE definition for IDynamicCode here\n    // Make sure they remain in-sync\n    // **************************************************\n\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    TService GetService<TService>() where TService : class;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    IApp App { get; }\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    IDataSource Data { get; }\n\n    #region Content and Header\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    dynamic? Content { get; }\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    dynamic? Header { get; }\n\n    #endregion\n\n    #region AsAdam, Linking, Edit\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    IFolder AsAdam(ICanBeEntity item, string fieldName);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    ILinkService Link { get; }\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    IEditService Edit { get; }\n\n    #endregion\n\n    #region AsDynamic for Strings\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n\n    dynamic? AsDynamic(string json, string? fallback = default);\n\n    #endregion \n\n    #region AsDynamic for Entities\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    dynamic? AsDynamic(IEntity entity);\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    dynamic? AsDynamic(object dynamicEntity);\n\n\n    #endregion\n\n    #region AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    IEntity AsEntity(object dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    IEnumerable<dynamic>? AsList(object list);\n\n    #endregion\n\n\n    #region Create Data Sources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    T CreateSource<T>(IDataStream source) where T : IDataSource;\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource;\n\n    #endregion\n\n    #region Context\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    ICmsContext CmsContext { get; }\n\n    #endregion\n\n\n\n    #endregion\n\n\n\n    #region Stuff added by DynamicCode12\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    dynamic? AsDynamic(params object[] entities);\n\n\n    #region Convert-Service\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Convert\" />\n    IConvertService Convert { get; }\n\n    #endregion\n\n    #region Resources and Settings\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    dynamic? Resources { get; }\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    dynamic? Settings { get; }\n\n    #endregion\n\n\n    #region DevTools\n\n    [PrivateApi(\"Still WIP\")]\n    IDevTools DevTools { get; }\n\n    #endregion\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/DynamicCode/Sys/IDynamicCode.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing IFolder = ToSic.Sxc.Adam.IFolder;\n\nnamespace ToSic.Sxc.Code.Sys;\n\n/// <summary>\n/// Dynamic code files like Razor or WebApis.\n/// Supports many properties like App, etc. to ensure that the dynamic code has everything you need. <br />\n/// Also provides many Conversions between <see cref=\"IEntity\"/> and <see cref=\"IDynamicEntity\"/>.\n/// Important for dynamic code files like Razor or WebApi. Note that there are many overloads to ensure that AsDynamic and AsEntity \"just work\" even if you give them the original data. \n/// </summary>\n[PrivateApi(\"Was public till v17\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDynamicCode: ICreateInstance, ICompatibilityLevel, IHasLog // inherit from old namespace to ensure compatibility\n{\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    TService GetService<TService>() where TService : class;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\"/>\n    IApp App { get; }\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\"/>\n    IDataSource Data { get; }\n\n    #region Content and Header\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\"/>\n    dynamic? Content { get; }\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\"/>\n    dynamic? Header { get; }\n\n    #endregion\n\n    #region AsAdam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\"/>\n    IFolder AsAdam(ICanBeEntity item, string fieldName);\n\n    #endregion\n\n    #region Linking\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\"/>\n    ILinkService Link { get; }\n\n    #endregion\n\n    #region Edit\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\"/>\n    IEditService Edit { get; }\n    #endregion\n\n    #region AsDynamic for Strings\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\"/>\n    dynamic? AsDynamic(string json, string? fallback = default);\n\n    #endregion \n\n    #region AsDynamic for Entities\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\"/>\n    dynamic? AsDynamic(IEntity entity);\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\"/>\n    dynamic? AsDynamic(object dynamicEntity);\n\n\n    #endregion\n\n    #region AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity(object)\"/>\n    IEntity? AsEntity(object dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList(object)\"/>\n    IEnumerable<dynamic>? AsList(object list);\n\n    #endregion\n\n\n    #region Create Data Sources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\"/>\n    T CreateSource<T>(IDataStream source) where T: IDataSource;\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\"/>\n    T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource;\n\n    #endregion\n\n\n    #region Context\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\"/>\n    ICmsContext CmsContext { get; }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/DynamicCode/Sys/IDynamicCode12Docs.cs",
    "content": "﻿using ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\n\n// Disable warnings that properties should be marked as new\n// Because we need them here as additional definition because of Razor problems with inherited interfaces\n#pragma warning disable CS0108, CS0114\n\nnamespace ToSic.Sxc.Code.Sys;\n\n/// <summary>\n/// Just docs\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDynamicCode12Docs\n{\n\n    #region Stuff added by DynamicCode12\n\n    /// <summary>\n    /// Convert one or many Entities and Dynamic entities into an <see cref=\"IDynamicStack\"/>\n    /// </summary>\n    /// <param name=\"entities\">one or more source object</param>\n    /// <returns>a dynamic object for easier coding</returns>\n    /// <remarks>\n    /// New in 12.05\n    /// </remarks>\n    dynamic? AsDynamic(params object[] entities);\n\n\n    #region Convert-Service\n\n    /// <summary>\n    /// Conversion helper for common data conversions in Razor and WebAPIs\n    /// </summary>\n    /// <remarks>\n    /// Added in 2sxc 12.05\n    /// </remarks>\n    IConvertService Convert { get; }\n\n    #endregion\n\n    #region Resources and Settings\n\n    /// <summary>\n    /// Resources for this Scenario. This is a dynamic object based on the <see cref=\"IDynamicStack\"/>.\n    ///\n    /// It will combine both the Resources of the View and the App. The View-Resources will have priority. In future it may also include some global Resources. \n    /// \n    /// 🪒 Use in Razor: `@Resources.CtaButtonLabel`\n    /// </summary>\n    /// <remarks>New in 12.03</remarks>\n    dynamic? Resources { get; }\n\n    /// <summary>\n    /// Settings for this Scenario. This is a dynamic object based on the <see cref=\"IDynamicStack\"/>.\n    /// \n    /// It will combine both the Settings of the View and the App. The View-Settings will have priority. In future it may also include some global Settings. \n    /// \n    /// 🪒 Use in Razor: `@Settings.ItemsPerRow`\n    /// </summary>\n    /// <remarks>New in 12.03</remarks>\n    dynamic? Settings { get; }\n\n    #endregion\n\n\n    #region DevTools\n\n    [PrivateApi(\"Still WIP\")]\n    IDevTools DevTools { get; }\n\n    #endregion\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/DynamicCode/Sys/IDynamicCodeDocs.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing IFolder = ToSic.Sxc.Adam.IFolder;\n\nnamespace ToSic.Sxc.Code.Sys;\n\n/// <summary>\n/// Just a class to hold the docs for other things.\n/// It's primary purpose is to make sure that the real code isn't referenced hundreds of times\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDynamicCodeDocs\n{\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    TService GetService<TService>() where TService : class;\n\n    /// <summary>\n    /// A fully prepared <see cref=\"IApp\"/> object letting you access all the data and queries in the current app. \n    /// </summary>\n    /// <returns>The current app</returns>\n    IApp App { get; }\n\n    /// <summary>\n    /// The data prepared for the current Code. Usually user data which was manually added to the instance, but can also be a query.\n    /// </summary>\n    /// <returns>\n    /// A standard <see cref=\"IDataSource\"/>.</returns>\n    IDataSource Data { get; }\n\n    #region Content and Header\n    /// <summary>\n    /// The content object of the current razor view - IF the current view has content.\n    /// If the view is a list, it will return the first item. \n    /// Will be null otherwise.\n    /// To tell if it's the demo/default item, use <see cref=\"IDynamicEntity.IsDemoItem\"/>.\n    /// </summary>\n    /// <returns>A <see cref=\"IDynamicEntity\"/> object with the current content - or null.</returns>\n    dynamic? Content { get; }\n\n    /// <summary>\n    /// The header object of the current razor view, if it's a list and has a header object.\n    /// If it's a list and doesn't have a header (and no default), it will return null.\n    /// To tell if it's the demo/default item, use <see cref=\"IDynamicEntity.IsDemoItem\"/>.\n    /// </summary>\n    /// <returns>A <see cref=\"IDynamicEntity\"/> object with the current content.</returns>\n    /// <remarks>\n    /// Introduced in 2sxc 10.10 - previously it was called ListContent, now deprecated.\n    /// </remarks>\n    dynamic? Header { get; }\n\n    #endregion\n\n    #region AsAdam\n\n    /// <summary>\n    /// Provides an Adam instance for this item and field\n    /// </summary>\n    /// <param name=\"item\">The item - an IEntity, IDynamicEntity, ITypedItem etc. often Content or similar</param>\n    /// <param name=\"fieldName\">The field name, like \"Gallery\" or \"Pics\"</param>\n    /// <returns>An Adam object for navigating the assets</returns>\n    IFolder AsAdam(ICanBeEntity item, string fieldName);\n\n    #endregion\n\n    #region Linking\n\n    /// <summary>\n    /// Link helper object to create the correct links\n    /// </summary>\n    /// <returns>\n    /// A <see cref=\"ILinkService\"/> object.\n    /// </returns>\n    ILinkService Link { get; }\n\n    #endregion\n\n    #region Edit\n\n    /// <summary>\n    /// Helper commands to enable in-page editing functionality\n    /// Use it to check if edit is enabled, generate context-json infos and provide toolbar buttons\n    /// </summary>\n    /// <returns>\n    /// An <see cref=\"IEditService\"/> object.\n    /// </returns>\n    IEditService Edit { get; }\n    #endregion\n\n    #region AsDynamic for Strings\n\n    /// <summary>\n    /// Take a json and provide it as a dynamic object to the code\n    /// </summary>\n    /// <remarks>Added in 2sxc 10.22.00</remarks>\n    /// <param name=\"json\">the original json string</param>\n    /// <param name=\"fallback\">\n    /// Alternate string to use, if the original json can't parse.\n    /// Can also be null or the word \"error\" if you would prefer an error to be thrown.</param>\n    /// <returns>A dynamic object representing the original json.\n    /// If it can't be parsed, it will parse the fallback, which by default is an empty empty dynamic object.\n    /// If you provide null for the fallback, then you will get null back.\n    /// </returns>\n    dynamic? AsDynamic(string json, string? fallback = default);\n\n    #endregion \n\n    #region AsDynamic for Entities\n\n    /// <summary>\n    /// Wraps an entity into a <see cref=\"IDynamicEntity\"/>\n    /// </summary>\n    /// <param name=\"entity\">the original object</param>\n    /// <returns>a dynamic object for easier coding</returns>\n    dynamic? AsDynamic(IEntity entity);\n\n\n    /// <summary>\n    /// Convert a dynamic entity and return itself again. This is so coders don't have to worry if the original object was an <see cref=\"IEntity\"/> or a <see cref=\"IDynamicEntity\"/> in the first place. \n    /// </summary>\n    /// <param name=\"dynamicEntity\">the original object</param>\n    /// <returns>a dynamic object for easier coding</returns>\n    dynamic? AsDynamic(object dynamicEntity);\n\n        \n    #endregion\n\n    #region AsEntity\n\n    /// <summary>\n    /// Unwraps a dynamic entity or <see cref=\"ITypedItem\"/> back into the underlying <see cref=\"IEntity\"/>\n    /// </summary>\n    /// <param name=\"dynamicEntity\">the wrapped IEntity</param>\n    /// <returns>A normal IEntity</returns>\n    IEntity? AsEntity(object dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <summary>\n    /// Converts a list of <see cref=\"IEntity\"/> objects into a list of <see cref=\"IDynamicEntity\"/> objects. \n    /// </summary>\n    /// <param name=\"list\">typically a List/IEnumerable of Entities or DynamicEntities. <br/>\n    /// Can also be a <see cref=\"IDataSource\"/> in which case it uses the default stream. </param>\n    /// <remarks>Added in 2sxc 10.21.00</remarks>\n    /// <returns>a list of <see cref=\"IDynamicEntity\"/> objects</returns>\n    IEnumerable<dynamic>? AsList(object list);\n\n    #endregion\n\n\n    #region Create Data Sources\n\n    /// <summary>\n    /// Create a <see cref=\"IDataSource\"/> which will process data from the given stream.\n    /// </summary>\n    /// <param name=\"source\">The stream which will be the default In of the new data-source.</param>\n    /// <typeparam name=\"T\">A data-source type - must be inherited from IDataSource</typeparam>\n    /// <returns>A typed DataSource object</returns>\n    T CreateSource<T>(IDataStream source) where T: IDataSource;\n\n\n    /// <summary>\n    /// Create a <see cref=\"IDataSource\"/> which will process data from the given stream.\n    /// </summary>\n    /// <param name=\"inSource\">The data source which will be the default In of the new data-source.</param>\n    /// <param name=\"configurationProvider\">An alternate configuration provider for the DataSource</param>\n    /// <typeparam name=\"T\">A data-source type - must be inherited from IDataSource</typeparam>\n    /// <returns>A typed DataSource object</returns>\n    T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource;\n\n    #endregion\n\n\n    #region Context\n\n    /// <summary>\n    /// This Context tells you about the environment, such as\n    ///\n    /// * the current User\n    /// * the Page\n    /// * the View\n    /// * the Site\n    /// \n    /// It's supposed to replace direct access to Dnn or Oqtane object in Razor and WebAPI code,\n    /// allowing hybrid code that works everywhere.\n    /// </summary>\n    /// <remarks>\n    /// New in v11.11\n    /// </remarks>\n    ICmsContext CmsContext { get; }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Logging/CodeLog.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n// TODO: MAKE INTERNAL AGAIN AFTER MOVING TO ToSic.Sxc.Custom\n\n// ReSharper disable ExplicitCallerInfoArgument\n\nnamespace ToSic.Sxc.Code;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeLog(ILog log) : Wrapper<ILog>(log), ICodeLog\n{\n    /// <inheritdoc />\n    public string Add(string message, [CallerFilePath] string? cPath = null, [CallerMemberName] string? cName = null, [CallerLineNumber] int cLine = 0)\n    {\n        GetContents().A(message, cPath, cName, cLine);\n        return message;\n    }\n\n    /// <inheritdoc />\n    public void Warn(string message, [CallerFilePath] string? cPath = null, [CallerMemberName] string? cName = null, [CallerLineNumber] int cLine = 0) \n        => GetContents().W(message, cPath, cName, cLine);\n\n    public void Exception(Exception ex, [CallerFilePath] string? cPath = null, [CallerMemberName] string? cName = null, [CallerLineNumber] int cLine = 0)\n        => GetContents().Ex(ex, cPath, cName, cLine);\n\n\n    /// <inheritdoc />\n    public Action<string> Call(string? parameters = null, string? message = null, bool useTimer = false,\n        [CallerFilePath] string? cPath = null, [CallerMemberName] string? cName = null, [CallerLineNumber] int cLine = 0)\n    {\n        // must call the opener first, then return the closing function\n        var call = GetContents().Fn(parameters, message, timer: useTimer, cPath: cPath, cName: cName, cLine: cLine);\n        return finalMsg => call.Done(finalMsg);\n    }\n\n    /// <inheritdoc />\n    public Func<T, string, T> Call<T>(string? parameters = null, string? message = null, bool useTimer = false,\n        [CallerFilePath] string? cPath = null, [CallerMemberName] string? cName = null, [CallerLineNumber] int cLine = 0)\n    {\n        // must call the opener first, then return the closing function\n        var call = GetContents().Fn<T>(parameters, message, timer: useTimer, cPath: cPath, cName: cName, cLine: cLine);\n        return (data, finalMsg) => call.Return(data, finalMsg);\n    }\n\n    /// <inheritdoc />\n    public bool Preserve\n    {\n        get => (GetContents() as Log)?.Preserve ?? false; // default to false if there is no log\n        set { if (GetContents() is Log log1) log1.Preserve = value; }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Logging/ICodeLog.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// A special logger for dynamic code (Razor, WebApi).\n/// It is always available to add messages to insights. \n/// </summary>\n/// <remarks>\n/// Added in v15, replaces the then removed `ILog` interface.\n/// </remarks>\n[PublicApi]\npublic interface ICodeLog: IWrapper<ILog>\n{\n\n    /// <summary>\n    /// Add a message log entry\n    /// </summary>\n    /// <param name=\"message\">Message to log</param>\n    /// <param name=\"cPath\">auto pre filled by the compiler - the path to the code file</param>\n    /// <param name=\"cName\">auto pre filled by the compiler - the method name</param>\n    /// <param name=\"cLine\">auto pre filled by the compiler - the code line</param>\n    string Add(string message,\n        [CallerFilePath] string? cPath = null,\n        [CallerMemberName] string? cName = null,\n        [CallerLineNumber] int cLine = 0\n    );\n\n    /// <summary>\n    /// Add a warning log entry\n    /// </summary>\n    /// <param name=\"message\"></param>\n    /// <param name=\"cPath\">auto pre filled by the compiler - the path to the code file</param>\n    /// <param name=\"cName\">auto pre filled by the compiler - the method name</param>\n    /// <param name=\"cLine\">auto pre filled by the compiler - the code line</param>\n    void Warn(string message,\n        [CallerFilePath] string? cPath = null,\n        [CallerMemberName] string? cName = null,\n        [CallerLineNumber] int cLine = 0\n    );\n\n\n    /// <summary>\n    /// Add an exception as special log entry\n    /// </summary>\n    /// <param name=\"ex\">The Exception object</param>\n    /// <param name=\"cPath\">auto pre filled by the compiler - the path to the code file</param>\n    /// <param name=\"cName\">auto pre filled by the compiler - the method name</param>\n    /// <param name=\"cLine\">auto pre filled by the compiler - the code line</param>\n    void Exception(Exception ex,\n        [CallerFilePath] string? cPath = null,\n        [CallerMemberName] string? cName = null,\n        [CallerLineNumber] int cLine = 0\n    );\n\n\n    /// <summary>\n    /// Add a log entry for method call, returning a method to call when done\n    /// </summary>\n    /// <param name=\"parameters\">what was passed to the call in the brackets</param>\n    /// <param name=\"message\">the message to log</param>\n    /// <param name=\"useTimer\">enable a timer from call/close</param>\n    /// <param name=\"cPath\">auto pre filled by the compiler - the path to the code file</param>\n    /// <param name=\"cName\">auto pre filled by the compiler - the method name</param>\n    /// <param name=\"cLine\">auto pre filled by the compiler - the code line</param>\n    Action<string> Call(\n        string? parameters = null,\n        string? message = null,\n        bool useTimer = false,\n        [CallerFilePath] string? cPath = null,\n        [CallerMemberName] string? cName = null,\n        [CallerLineNumber] int cLine = 0\n    );\n\n    /// <summary>\n    /// Add a log entry for method call, returning a method to call when done\n    /// </summary>\n    /// <param name=\"parameters\">what was passed to the call in the brackets</param>\n    /// <param name=\"message\">the message to log</param>\n    /// <param name=\"useTimer\">enable a timer from call/close</param>\n    /// <param name=\"cPath\">auto pre filled by the compiler - the path to the code file</param>\n    /// <param name=\"cName\">auto pre filled by the compiler - the method name</param>\n    /// <param name=\"cLine\">auto pre filled by the compiler - the code line</param>\n    /// <remarks>\n    /// Not used much, but major change in V15 - the first value in the result is the data, the second is the string to log.\n    /// Before in the `ILog` it was (message, data), new is (data, message)\n    /// </remarks>\n    Func<T, string, T> Call<T>(\n        string? parameters = null,\n        string? message = null,\n        bool useTimer = false,\n        [CallerFilePath] string? cPath = null,\n        [CallerMemberName] string? cName = null,\n        [CallerLineNumber] int cLine = 0\n    );\n\n    /// <summary>\n    /// Determines if this log should be preserved in the short term.\n    /// Like for live-analytics / live-insights.\n    /// Default is true.\n    ///\n    /// In scenarios like search-indexing it will default to false.\n    /// You can then do `Log.Preserve = true;` to temporarily activate it while debugging.\n    /// </summary>\n    bool Preserve { get; set; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Logging/IHasCodeLog.cs",
    "content": "﻿namespace ToSic.Sxc.Code;\n\n/// <summary>\n/// Marks all Razor / WebAPI classes which provide logging functionality\n/// </summary>\n[PrivateApi(\"Was InternalAPI till v17 - This is internal for documentation only, you should never access this interface\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IHasCodeLog\n{\n    /// <summary>\n    /// The logger for the current Razor / WebApi which allows you to add logs to Insights.\n    /// </summary>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    ICodeLog Log { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Razor/IRazorConfiguration.cs",
    "content": "﻿using ToSic.Sxc.Services.Cache;\n\nnamespace ToSic.Sxc.Code.Razor;\n\n/// <summary>\n/// Configure Razor - for example output caching.\n/// </summary>\n[WorkInProgressApi(\"not yet public or final, WIP v20.00.0x\")]\npublic interface IRazorConfiguration\n{\n    /// <summary>\n    /// Configure output of Razor partials caching.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"seconds\">sliding seconds to keep the cache, like `60`, `300`, `3600`</param>\n    /// <param name=\"watch\">what to watch for to flush the cache - recommended: `data,folder`</param>\n    /// <param name=\"varyBy\">what to vary the cache by, like `user,module,language`, default is nothing. all cached output will be the same</param>\n    /// <param name=\"model\">when caching by model properties, the model property names like `id,key`, default is nothing.</param>\n    /// <param name=\"url\">url parameters to vary by</param>\n    /// <param name=\"tweak\">extended / custom configuration of the cache - use for advanced config like elevation based variants</param>\n    /// <returns>always returns `null` so it can be used inline in Razor.</returns>\n    /// <remarks>\n    /// Will only have an effect if the feature [LightSpeedOutputCachePartials](https://patrons.2sxc.org/features/feat/LightSpeedOutputCachePartials) is enabled.\n    /// </remarks>\n    string? PartialCache(NoParamOrder npo = default,\n        int? seconds = null,\n        string? watch = null,\n        string? varyBy = null,\n        string? url = null,\n        string? model = null,\n        Func<ICacheSpecs, ICacheSpecs>? tweak = default);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Razor/Sys/RazorConfiguration.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Services.Cache;\nusing ToSic.Sxc.Services.Cache.Sys;\nusing ToSic.Sxc.Services.Cache.Sys.CacheKey;\n\nnamespace ToSic.Sxc.Code.Razor.Sys;\n\n[PrivateApi(\"not yet public or final, WIP v20.00.0x, will have to create interface\")]\npublic class RazorConfiguration(RenderSpecs renderSpecs, ILog parentLog): HelperBase(parentLog, \"Rzr.Config\"), IRazorConfiguration\n{\n    // This class is a placeholder for future Razor configuration settings.\n    // It is currently empty and serves as a temporary structure for potential future use.\n    // The class may be expanded with properties and methods as needed in the future.\n\n    public string? PartialCache(NoParamOrder npo = default,\n        int? seconds = null,\n        string? watch = null,\n        string? varyBy = null,\n        string? url = null,\n        string? model = null,\n        Func<ICacheSpecs, ICacheSpecs>? tweak = default)\n    {\n        if (Parent == null)\n            return null;\n\n        var l = Log.Fn<string?>($\"{nameof(seconds)}: '{seconds}', {nameof(watch)}: '{watch}', {nameof(varyBy)}: '{varyBy}', {nameof(url)}: '{url}', {nameof(model)}: '{model}'\");\n        var hasParams = new[] { seconds as object, watch, varyBy, url, model }.Any(x => x != null);\n        if (hasParams)\n        {\n            l.A(\"Set aspects using values\");\n            var config = new CacheKeyConfig(seconds: seconds, varyBy: varyBy, url: url, model: model);\n            var writeConfig = new CacheWriteConfig(watch: watch);\n            Parent.CacheSpecs = Parent.CacheSpecs.RestoreAll(config, writeConfig);\n        }\n\n        if (tweak == null)\n            return l.ReturnNull();\n\n        try\n        {\n            l.A(\"Set aspects using tweak function\");\n            Parent.CacheSpecs = tweak(Parent.CacheSpecs);\n        }\n        catch (Exception ex)\n        {\n            Log.Ex(ex);\n        }\n\n        return l.ReturnNull();\n    }\n\n    private RenderPartialSpecsWithCaching? Parent\n    {\n        get\n        {\n            if (field is not null)\n                return field;\n\n            // paranoid, on main entry razor it doesn't exist ATM 2025-08-19\n            if (renderSpecs?.PartialSpecs is not RenderPartialSpecsWithCaching typed)\n                return null;\n\n            // On first use, enable caching since it was off at first\n            typed.CacheSpecs = typed.CacheSpecs.Enable();\n            return field = typed;\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys/ICreateInstance.cs",
    "content": "﻿\nnamespace ToSic.Sxc.Code.Sys;\n\n/// <summary>\n/// Marks objects - usually DynamicCode - which can create instances of other C# files. <br/>\n/// A special feature is that it must store a reference to the path it's in (provided by the compiler that created this instance).\n/// This is important, so that CreateInstance knows what path to start in. \n/// </summary>\n[PrivateApi(\"Hidden now, as all implementing objects show the API. Before 16.02 2023-07 it was public!\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ICreateInstance: IGetCodePath\n{\n    /// <summary>\n    /// Create an instance of code lying in a file near this\n    /// </summary>\n    /// <param name=\"virtualPath\">path to the other code file to compile</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"name\">Override the class name to compile - usually not required as it should match the file name</param>\n    /// <param name=\"relativePath\">optional relative path, will usually use the <see cref=\"IGetCodePath.CreateInstancePath\"/></param>\n    /// <param name=\"throwOnError\">throw errors if compiling fails, recommended</param>\n    /// <returns>An object of the class in the file</returns>\n    /// <remarks>\n    /// Note that the C# code which we are creating inherits from a standard base class such as `Code12` or `DynamicCode`\n    /// then it will automatically be initialized to support App, AsDynamic etc.\n    /// </remarks>\n    dynamic? CreateInstance(string virtualPath,\n        NoParamOrder npo = default,\n        string? name = null,\n        string? relativePath = null,\n        bool throwOnError = true);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApi/CodeAnyApiHelper.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApi;\n\ninternal abstract class CodeAnyApiHelper(ExecutionContext exCtx) : ICodeAnyApiHelper\n{\n    protected ExecutionContext ExCtx = exCtx;\n\n    public IBlock Block => ExCtx.Block!; // If accessed, the code doing it must have the block\n\n    public ICmsContext CmsContext => ExCtx.CmsContext;\n    public IDataSource Data => ExCtx.Block!.Data; // If accessed, it must be working\n\n    public TService GetService<TService>(NoParamOrder npo = default, bool reuse = false, Type? type = default)\n        where TService : class\n        => ExCtx.GetService<TService>(npo, reuse, type);\n\n    public IDevTools DevTools => ExCtx.DevTools;\n\n    public ICodeDataFactory Cdf => ExCtx.Cdf;\n    public ILinkService Link => ExCtx.Link;\n\n    public IConvertService Convert => ExCtx.Convert;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApi/CodeDynamicApiHelper.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApi;\n\ninternal class CodeDynamicApiHelper(ExecutionContext exCtx) : CodeAnyApiHelper(exCtx), ICodeDynamicApiHelper\n{\n    public dynamic? Content => ExCtx.Content;\n    public dynamic? Header => ExCtx.Header;\n    public IApp App => ExCtx.App;\n    public IDynamicStack Resources => ExCtx.Resources;\n    public IDynamicStack Settings => ExCtx.Settings;\n\n    [field: AllowNull, MaybeNull]\n    public IEditService Edit => field\n        ??= ExCtx.GetService<IEditService>(reuse: true);\n\n    public IFolder AsAdam(ICanBeEntity item, string fieldName)\n        => ExCtx.AsAdam(item, fieldName);\n\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => ExCtx.CreateSource<T>(source);\n\n    public T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource\n        => ExCtx.CreateSource<T>(inSource, configurationProvider);\n\n    public ServiceKit14 ServiceKit14 => ExCtx.GetKit<ServiceKit14>();\n\n    public string CreateInstancePath\n    {\n        get => ExCtx.CreateInstancePath;\n        set => ExCtx.CreateInstancePath = value;\n    }\n\n    public dynamic? CreateInstance(string virtualPath, NoParamOrder npo = default, string? name = null,\n        string? relativePath = null, bool throwOnError = true) =>\n        ExCtx.CreateInstance(virtualPath, npo, name, relativePath, throwOnError);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApi/CodeTypedApiHelper.cs",
    "content": "﻿using ToSic.Sxc.Apps;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApi;\n\ninternal class CodeTypedApiHelper(ExecutionContext exCtx) : CodeAnyApiHelper(exCtx), ICodeTypedApiHelper\n{\n    public IAppTyped AppTyped => ExCtx.AppTyped;\n    public ITypedStack AllSettings => ExCtx.AllSettings;\n    public ITypedStack AllResources => ExCtx.AllResources;\n    public ServiceKit16 ServiceKit16 => ExCtx.GetKit<ServiceKit16>();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApi/ExecutionContextExtensions.cs",
    "content": "﻿using ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApi;\n\npublic static class ExecutionContextExtensions\n{\n    public static ICodeTypedApiHelper GetTypedApi(this IExecutionContext exCtx) =>\n        exCtx is not ExecutionContext exCtxReal\n            ? throw ExCtxWrongType()\n            : exCtxReal.TypedApi;\n\n    public static ICodeDynamicApiHelper GetDynamicApi(this IExecutionContext exCtx) =>\n        exCtx is not ExecutionContext exCtxReal\n            ? throw ExCtxWrongType()\n            : exCtxReal.DynamicApi;\n\n    public static int GetAppId(this IExecutionContext exCtx) =>\n        exCtx is not ExecutionContext exCtxReal\n            ? throw ExCtxWrongType()\n            : exCtxReal.App.AppId;\n\n    private static InvalidOperationException ExCtxWrongType() => new($\"ExecutionContext must be of type {nameof(ExecutionContext)}\");\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApi/ICodeAnyApiHelper.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApi;\n\npublic interface ICodeAnyApiHelper\n{\n    #region TODO: WHEN READY and moved deeper in the structure\n    // 1. Block\n    // 2. Convert\n    // 3. Re-Type the Resources and Settings\n\n    IBlock Block { get; }\n\n\n    #endregion\n\n    #region Context & Data\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    ICmsContext CmsContext { get; }\n\n    /// <inheritdoc cref=\"Razor.Html5.Data\" />\n    IDataSource Data { get; }\n\n\n    #endregion\n\n    /// <summary>\n    /// Special GetService which can cache the found service so any other use could get the same instance.\n    /// This should ensure that an Edit service requested through Kit14 and Kit16 are both the same, etc.\n    /// </summary>\n    /// <typeparam name=\"TService\"></typeparam>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"reuse\">if true, then a service requested multiple times will return the same instance</param>\n    /// <param name=\"type\">rare option: type name of the service to create; probably not relevant any more today</param>\n    /// <returns></returns>\n    [PrivateApi(\"new v17.02\")]\n    TService GetService<TService>(NoParamOrder npo = default, bool reuse = false, Type? type = default) where TService : class;\n\n    #region Helpers / Tools\n\n    [PrivateApi(\"Still WIP\")]\n    IDevTools DevTools { get; }\n\n    [PrivateApi(\"internal use only\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    ICodeDataFactory Cdf { get; }\n\n    #endregion\n\n    #region Common Services (Link)\n\n    /// <inheritdoc cref=\"Razor.Html5.Link\" />\n    ILinkService Link { get; }\n\n    IConvertService Convert { get; }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApi/ICodeDynamicApiHelper.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApi;\n\n/// <summary>\n/// WIP\n/// </summary>\npublic interface ICodeDynamicApiHelper: ICodeAnyApiHelper, ICreateInstance\n{\n\n    #region Content, Header, App, Data, Resources, Settings\n\n    dynamic? Content { get; }\n\n    /// <inheritdoc cref=\"Razor.Html5.Header\" />\n    dynamic? Header { get; }\n\n    /// <inheritdoc cref=\"Eav.DataSources.App\" />\n    IApp App { get; }\n\n    /// <summary>\n    /// Almost every use \n    /// </summary>\n    IDynamicStack Resources { get; }\n    IDynamicStack Settings { get; }\n\n\n    #endregion\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    IEditService Edit { get; }\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    IFolder AsAdam(ICanBeEntity item, string fieldName);\n\n    #region Create Data Sources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    T CreateSource<T>(IDataStream source) where T : IDataSource;\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource;\n\n    #endregion\n\n    ServiceKit14 ServiceKit14 { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApi/ICodeTypedApiHelper.cs",
    "content": "﻿using ToSic.Sxc.Apps;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApi;\n\n/// <summary>\n/// WIP\n/// </summary>\npublic interface ICodeTypedApiHelper: ICodeAnyApiHelper\n{\n    #region Content, Header, App, Data, Resources, Settings\n\n    IAppTyped AppTyped { get; }\n\n    public ITypedStack AllSettings { get; }\n\n    public ITypedStack AllResources { get; }\n\n    #endregion\n\n    ServiceKit16 ServiceKit16 { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApiService/CasObsolete.cs",
    "content": "﻿#if NETFRAMEWORK\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApiService;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeApiServiceObsolete(IExecutionContext dynCode)\n{\n    [PrivateApi(\"obsolete\")]\n    [Obsolete(\"you should use the CreateSource<T> instead. Deprecated ca. v4 (but not sure), changed to error in v15.\")]\n    public IDataSource CreateSource(string typeName = \"\", IDataSource? links = null, ILookUpEngine? configuration = null)\n    {\n        // 2023-03-12 2dm\n        // Completely rewrote this, because I got rid of some old APIs in v15 on the DataFactory\n        // This has never been tested but probably works, but we won't invest time to be certain.\n\n        var dataSources = ((ExecutionContext)dynCode).DataSources;\n\n        try\n        {\n            // try to find with assembly name, or otherwise with GlobalName / previous names\n            var app = dynCode.GetApp();\n            var type = dataSources.Catalog.Value.FindDataSourceInfo(typeName, app.AppId)?.Type;\n            configuration ??= dataSources.LookUpEngine;\n            var cnf2Wip = new DataSourceOptions\n            {\n                AppIdentityOrReader = null, // #WipAppIdentityOrReader must become not null\n                LookUp = configuration,\n                Attach = links,\n            };\n            if (links != null)\n                return dataSources.DataSources.Value.Create(type: type!, /*attach: links,*/ options: cnf2Wip);\n\n            var initialSource = dataSources.DataSources.Value.CreateDefault(new DataSourceOptions\n            {\n                AppIdentityOrReader = app,\n                LookUp = dataSources.LookUpEngine,\n            });\n            return typeName != \"\"\n                ? dataSources.DataSources.Value.Create(type: type!, /*attach: initialSource,*/ options: cnf2Wip with { Attach = initialSource })\n                : initialSource;\n        }\n        catch (Exception ex)\n        {\n            const string errMessage = $\"The razor code is calling a very old method {nameof(CreateSource)}.\" +\n                                      $\" In this version, you used the type name as a string {nameof(CreateSource)}(string typeName, ...).\" +\n                                      $\" This has been deprecated since ca. v4 and has been removed now. \" +\n                                      $\" Please use the newer {nameof(CreateSource)}<Type>(...) overload.\";\n\n            throw new(errMessage, ex);\n        }\n    }\n\n\n    // #RemovedV20 #Element\n    //#pragma warning disable 618\n    //[PrivateApi]\n    //[Obsolete(\"This is an old way used to loop things - shouldn't be used any more - will be removed in 2sxc v10\")]\n    //[field: AllowNull, MaybeNull]\n    //public List<Element> ElementList => field ??= TryToBuildElementList();\n\n    //[field: AllowNull, MaybeNull]\n    //private ICodeDataFactory Cdf => field ??= dynCode.GetCdf();\n\n    // #RemovedV20 #Element\n    ///// <remarks>\n    ///// This must be lazy-loaded, otherwise initializing the AppAndDataHelper will break when the Data-object fails \n    ///// - this would break API even though the List etc. are never accessed\n    ///// </remarks>\n    //private List<Element> TryToBuildElementList()\n    //{\n    //    dynCode.Log.A(\"try to build old List\");\n\n    //    var block = dynCode.GetBlock();\n    //    if (!block.DataIsReady || !block.ViewIsReady)\n    //        return [];\n\n    //    var data = dynCode.GetState<IDataSource>();\n    //    if (data == null! /* paranoid */ || !data.Out.ContainsKey(DataSourceConstants.StreamDefaultName))\n    //        return [];\n\n    //    var entities = data.List.ToList();\n\n    //    return entities.Select(GetElementFromEntity).ToList();\n\n    //    Element GetElementFromEntity(IEntity e)\n    //    {\n    //        var el = new Element\n    //        {\n    //            EntityId = e.EntityId,\n    //            Content = Cdf.CodeAsDyn(e)\n    //        };\n\n    //        var editDecorator = e.GetDecorator<EntityInBlockDecorator>();\n\n    //        if (editDecorator != null)\n    //        {\n    //            el.Presentation = editDecorator.Presentation == null ? null : Cdf.CodeAsDyn(editDecorator.Presentation);\n    //            el.SortOrder = editDecorator.SortOrder;\n    //        }\n\n    //        return el;\n    //    }\n    //}\n    //#pragma warning restore 618\n\n}\n\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApiService/CodeCreateDataSourceSvc.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Sys.Catalog;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Eav.Services;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApiService;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeCreateDataSourceSvc(LazySvc<IDataSourcesService> dataSources, LazySvc<DataSourceCatalog> catalog)\n{\n    public readonly LazySvc<IDataSourcesService> DataSources = dataSources;\n    public readonly LazySvc<DataSourceCatalog> Catalog = catalog;\n\n    public CodeCreateDataSourceSvc Setup(IAppIdentity appIdentity, Func<ILookUpEngine> getLookup)\n    {\n        AppIdentity = appIdentity;\n        _getLookup = getLookup;\n        return this;\n    }\n\n    public IAppIdentity AppIdentity { get; private set; } = null!;\n\n    public ILookUpEngine? LookUpEngine => _lookupEngine.Get(() => _getLookup?.Invoke());\n    private readonly GetOnce<ILookUpEngine?> _lookupEngine = new();\n    private Func<ILookUpEngine>? _getLookup;\n\n    // note: this code is almost identical to the IDataService code, except that `immutable` is a parameter\n    // because old code left the DataSources to be mutable\n    public T CreateDataSource<T>(bool immutable, NoParamOrder npo = default, IDataSourceLinkable? attach = null, object? options = default) where T : IDataSource\n    {\n        // If no in-source was provided, make sure that we create one from the current app\n        attach ??= DataSources.Value.CreateDefault(new DataSourceOptions\n        {\n            AppIdentityOrReader = AppIdentity,\n            LookUp = LookUpEngine,\n            Immutable = true,\n        });\n        var typedOptions = new DataSourceOptionConverter().Create(new DataSourceOptions\n        {\n            AppIdentityOrReader = AppIdentity,\n            LookUp = LookUpEngine,\n            Immutable = immutable,\n            Attach = attach,\n        }, options);\n        return DataSources.Value.Create<T>(/*attach: attach,*/ options: typedOptions);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApiService/DynamicCodeStandalone.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApiService;\n\ninternal class DynamicCodeStandalone(IExecutionContext exCtx, ICodeDynamicApiHelper apiHelper): IDynamicCode12\n{\n    public ILog Log => exCtx.Log!;\n\n    public string CreateInstancePath\n    {\n        get => ((IGetCodePath)exCtx).CreateInstancePath;\n        set\n        {\n            if (exCtx is not IGetCodePath getCodePath)\n                throw new InvalidOperationException(\"CreateInstancePath can only be set on a DynamicCode12Proxy which implements IGetCodePath\");\n            getCodePath.CreateInstancePath = value;\n        }\n    }\n\n    public dynamic? CreateInstance(string virtualPath, NoParamOrder npo = default, string? name = null,\n        string? relativePath = null, bool throwOnError = true)\n        => (\n                apiHelper\n                //(ICreateInstance)exCtx\n                ?? throw new InvalidOperationException(\n                    \"CreateInstance can only be set on a DynamicCode12Proxy which implements ICreateInstance\")\n            )\n            .CreateInstance(virtualPath, npo, name, relativePath, throwOnError);\n\n    public int CompatibilityLevel => apiHelper.Cdf?.CompatibilityLevel ?? CompatibilityLevels.CompatibilityLevel12;\n\n    public TService GetService<TService>() where TService : class\n        => exCtx.GetService<TService>();\n\n    public IApp App => apiHelper.App;\n\n    public IDataSource Data => apiHelper.Data;\n\n    public dynamic? Content => apiHelper.Content;\n\n    public dynamic? Header => apiHelper.Header;\n\n    IFolder IDynamicCode.AsAdam(ICanBeEntity item, string fieldName)\n        => apiHelper.AsAdam(item, fieldName);\n\n    IFolder IDynamicCode12.AsAdam(ICanBeEntity item, string fieldName)\n        => apiHelper.AsAdam(item, fieldName);\n\n    public ILinkService Link => apiHelper.Link;\n\n    public IEditService Edit => apiHelper.Edit;\n\n    dynamic? IDynamicCode.AsDynamic(string json, string? fallback)\n        => apiHelper.Cdf.Json2Jacket(json, fallback);\n\n    dynamic IDynamicCode12.AsDynamic(IEntity entity)\n        => apiHelper.Cdf.CodeAsDyn(entity);\n\n    dynamic? IDynamicCode12.AsDynamic(object dynamicEntity)\n        => apiHelper.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    IEntity IDynamicCode12.AsEntity(object dynamicEntity)\n        => apiHelper.Cdf.AsEntity(dynamicEntity);\n\n    IEnumerable<dynamic>? IDynamicCode12.AsList(object list)\n        => apiHelper.Cdf.CodeAsDynList(list);\n\n    T IDynamicCode12.CreateSource<T>(IDataStream source)\n        => apiHelper.CreateSource<T>(source);\n\n    T IDynamicCode12.CreateSource<T>(IDataSource? inSource, ILookUpEngine? configurationProvider)\n        => apiHelper.CreateSource<T>(inSource, configurationProvider);\n\n    dynamic? IDynamicCode12.AsDynamic(string json, string? fallback)\n        => apiHelper.Cdf.Json2Jacket(json, fallback);\n\n    dynamic IDynamicCode.AsDynamic(IEntity entity)\n        => apiHelper.Cdf.CodeAsDyn(entity);\n\n    dynamic? IDynamicCode.AsDynamic(object dynamicEntity)\n        => apiHelper.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    IEntity IDynamicCode.AsEntity(object dynamicEntity)\n        => apiHelper.Cdf.AsEntity(dynamicEntity); // ((IDynamicCode)exCtx).AsEntity(dynamicEntity);\n\n    IEnumerable<dynamic>? IDynamicCode.AsList(object list)\n        => apiHelper.Cdf.CodeAsDynList(list);// ((IDynamicCode)exCtx).AsList(list);\n\n    T IDynamicCode.CreateSource<T>(IDataStream source)\n        => apiHelper.CreateSource<T>(source);\n\n    T IDynamicCode.CreateSource<T>(IDataSource? inSource, ILookUpEngine? configurationProvider)\n        => apiHelper.CreateSource<T>(inSource, configurationProvider);\n\n    public ICmsContext CmsContext\n        => apiHelper.CmsContext;\n\n    public dynamic? AsDynamic(params object[] entities)\n        => apiHelper.Cdf.MergeDynamic(entities);\n\n    public IConvertService Convert => ((ExecutionContext)exCtx).Convert;\n\n    public dynamic Resources => apiHelper.Resources;\n\n    public dynamic Settings => apiHelper.Settings;\n\n    public IDevTools DevTools => apiHelper.DevTools;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeApiService/ExecutionContextFactory.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys.CodeApiService;\n\n/// <summary>\n/// Special helper which will create the code-root based on the parent class requesting it.\n/// If the parent is generic supporting IDynamicModel[Model, Kit] it will create the generic root\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExecutionContextFactory(IServiceProvider serviceProvider)\n    : ServiceBase($\"{SxcLogName}.ExCtxF\", connect: [/* never! serviceProvider */]), IExecutionContextFactory\n{\n\n    /// <inheritdoc/>\n    public IExecutionContext New(ExecutionContextOptions options)\n    {\n        var l = Log.Fn<ExecutionContext>($\"{nameof(options.Compatibility)}: {options.Compatibility}\");\n\n        // New v14 case - the Razor component implements IDynamicData<model, Kit>\n        // which specifies what kit version to use.\n        // Try to respect that or null if error or not such interface\n        var executionContext = options.OwnerOrNull != null\n            ? TryBuildCodeApiServiceForDynamic(options.OwnerOrNull.GetType())\n            : null;\n\n        // Default or old case - just a non-generic DnnDynamicCodeRoot\n        // Also applies if previous call didn't succeed\n        executionContext ??= serviceProvider.Build<ExecutionContext>();\n\n        executionContext.Setup(options);\n\n        return l.ReturnAsOk(executionContext);\n    }\n\n    /// <summary>\n    /// Special helper for new Kit-based Razor templates in v14\n    /// </summary>\n    /// <returns>`null` if not applicable, otherwise the typed DynamicRoot</returns>\n    private ExecutionContext? TryBuildCodeApiServiceForDynamic(Type customType)\n    {\n        var l = Log.Fn<ExecutionContext>();\n        try\n        {\n            var requiredDynCode = typeof(IHasKit<>);\n\n            // 1. Detect if it's an IDynamicCode<TModel, TServiceKit>\n            var interfaceOnCode = customType\n                .GetInterfaces()\n                .FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == requiredDynCode);\n\n            if (interfaceOnCode == null)\n                return l.ReturnNull();\n\n            var typesArgs = interfaceOnCode.GetGenericArguments();\n            if (typesArgs.Length != requiredDynCode.GetGenericArguments().Length)\n                return null;\n\n            var kitType = typesArgs[typesArgs.Length - 1];\n            if (!kitType.IsSubclassOf(typeof(ServiceKit)))\n                return null;\n\n            // 2. If yes, generate a CodeApiService<TModel, TServiceKit> using the same types\n            var finalType = typeof(ExecutionContext<,>).MakeGenericType(typeof(object), kitType);\n\n            // 3. return that\n            var exCtx = serviceProvider.Build<ExecutionContext>(finalType);\n            return l.ReturnAsOk(exCtx);\n        }\n        catch (Exception ex)\n        {\n            l.Done(ex);\n            return null;\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/CodeChangeServiceExtensions.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sys.Code.Infos;\nusing CodeInfoService = ToSic.Sys.Code.InfoSystem.CodeInfoService;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\ninternal static class CodeChangeServiceExtensions\n{\n    public static void WarnSxc(this CodeInfoService svc, CodeUse change, IBlock? block = default)\n    {\n        if (block != null)\n            change = change.UsedAs(more: LogBlockDetails(block));\n        svc.Warn(change);\n    }\n\n    //public static void LogBlockDetails(IBlock block, ILog log)\n    //{\n    //    if (block == null)\n    //        return;\n    //    log.A($\"Site ({block.Context?.Site?.Id}): {block.Context?.Site?.UrlRoot}\");\n    //    log.A($\"Page ({block.Context?.Page?.Id}): {block.Context?.Page?.Url}\");\n    //    log.A($\"App ({block.AppOrNull?.AppId}) Name: {block.AppOrNull?.Name}\");\n    //    log.A($\"View ({block.View?.Id}): {block.View?.Name}\");\n\n    //}\n\n    public static string[] LogBlockDetails(IBlock? block) => block != null\n        ?\n        [\n            $\"Site ({block.Context?.Site?.Id}): {block.Context?.Site?.UrlRoot}\",\n            $\"Page ({block.Context?.Page?.Id}): {block.Context?.Page?.Url}\",\n            $\"App ({block.AppOrNull?.AppId}) Name: {block.AppOrNull?.Name}\",\n            $\"View ({block.View?.Id}): {block.View?.Name}\"\n        ]\n        : [];\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/CodeErrorHelpService.cs",
    "content": "﻿#if NETFRAMEWORK\nusing HttpCompileException = System.Web.HttpCompileException;\n#else\n// TODO: @STV What's the real compile exception type? we need it, so that the errors are better\nusing HttpCompileException = System.Exception;\n#endif\nusing System.Text.RegularExpressions;\nusing Microsoft.CSharp.RuntimeBinder;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sys.Code.Help;\nusing ToSic.Sys.Exceptions;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeErrorHelpService: ServiceBase\n{\n    public CodeErrorHelpService() : base(\"Sxc.CErrHS\")\n    {\n        Log.A(\"Trying to add help to error, something must have happened\");\n    }\n\n    public Exception AddHelpForCompileProblems(Exception ex, CodeFileInfo fileInfo)\n    {\n        var l = Log.Fn<Exception>();\n        try\n        {\n            // Check if it already has help included\n            if (ex is IExceptionWithHelp) \n                return l.Return(ex, \"already has help\");\n\n            if (!fileInfo.Help.SafeAny())// !CodeHelpDb.CompileHelp.TryGetValue(fileInfo, out var list))\n                return l.Return(ex, \"no additional help found\");\n\n            var help = FindManyOrNull(ex, fileInfo.Help);\n            return help == null \n                ? l.Return(ex)\n                : l.Return(new ExceptionWithHelp(help, ex), \"added help\");\n        }\n        catch (Exception myEx)\n        {\n            Log.Ex(\"Something went wrong, inner error\", myEx);\n            return l.Return(ex, \"just return original exception\");\n        }\n    }\n\n    public Exception AddHelpIfKnownError(Exception ex, object? mainCodeObject)\n    {\n        var l = Log.Fn<Exception>();\n        try\n        {\n            // Check if it already has help included\n            if (ex is IExceptionWithHelp)\n                return l.Return(ex, \"already has help\");\n\n            var help = FindHelp(ex);\n            if (help != null)\n                return l.Return(new ExceptionWithHelp(help, ex), \"added help\");\n\n            if (mainCodeObject is IHasCodeHelp withHelp && withHelp.ErrorHelpers.SafeAny())\n                help = FindHelp(ex, withHelp.ErrorHelpers);\n\n            return help == null\n                ? l.Return(ex)\n                : l.Return(new ExceptionWithHelp(help, ex), \"added help\");\n        }\n        catch (Exception myEx)\n        {\n            Log.Ex(\"Something went wrong, inner error\", myEx);\n            return l.Return(ex, \"just return original exception\");\n        }\n\n    }\n\n    internal CodeHelp? FindHelp(Exception ex)\n    {\n        switch (ex)\n        {\n            // Check if we already wrapped it\n            case ExceptionWithHelp:\n                return null;\n            //case NamedArgumentException nae:\n            //    return new CodeHelp(\"named-parameters\", null,\n            //        Parameters.HelpLink,\n            //        uiMessage: \" \", detailsHtml: nae.Intro.Replace(\"\\n\", \"<br>\") + (nae.ParamNames.HasValue() ? $\"<br>Param Names: <code>{nae.ParamNames}</code>\": \"\"));\n            case RuntimeBinderException _:\n                return FindHelp(ex, HelpDbRazor.HelpForRuntimeProblems);\n            case InvalidCastException _:\n                return FindHelp(ex, HelpDbRazor.CompileInvalidCastExceptions);\n            case HttpCompileException _:\n                return FindHelp(ex, HelpDbRazor.HelpForHttpCompileExceptions);\n            default:\n                return null;\n        }\n    }\n\n    private static CodeHelp? FindHelp(Exception? ex, List<CodeHelp> errorList)\n    {\n        var msg = $\"{ex?.Message}{ex?.StackTrace}\";\n        return msg.IsEmpty()\n            ? null\n            : errorList.FirstOrDefault(help\n                => help.Detect.HasValue()\n                   && (help.DetectRegex\n                       ? Regex.IsMatch(msg, help.Detect)\n                       : msg.Contains(help.Detect ?? \"@#423-dummy-should-never-find\"))\n            );\n    }\n    private static List<CodeHelp>? FindManyOrNull(Exception? ex, List<CodeHelp> errorList)\n    {\n        var msg = ex?.Message;\n        if (msg.IsEmptyOrWs())\n            return null;\n        var list = errorList\n            .Where(help =>\n                help.Detect.HasValue()\n                && (help.DetectRegex ? Regex.IsMatch(msg, help.Detect) : msg.Contains(help.Detect))\n            )\n            .ToList();\n        return list.Any() ? list : null;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/CodeHelpBuilder.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CodeHelpBuilder\n{\n    /// <summary>\n    /// Get a list containing the first help and various derived helps\n    /// </summary>\n    /// <param name=\"first\"></param>\n    /// <param name=\"generators\"></param>\n    /// <returns></returns>\n    public static List<CodeHelp> BuildVariations(CodeHelp first, params Func<CodeHelp, CodeHelp>[] generators)\n    {\n        var result = new List<CodeHelp> { first };\n        result.AddRange(generators.Select(func => func(first)));\n        return result;\n    }\n\n\n    /// <summary>\n    /// Generate a list of help using help-objects, generator objects or list of help\n    /// </summary>\n    /// <param name=\"parts\"></param>\n    /// <returns></returns>\n    [return: NotNullIfNotNull(nameof(parts))]\n    public static List<CodeHelp>? BuildListFromDiverseSources(params object[] parts)\n        => parts?.SelectMany(r => r switch\n            {\n                CodeHelp ch => [ch],\n                GenNotExist gen => [gen.Generate()],\n                IEnumerable<CodeHelp> list => list,\n                _ => []\n            })\n            .ToList();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/DynamicCode16Warnings.cs",
    "content": "﻿using ToSic.Sys.Code.Infos;\nusing static ToSic.Sys.Code.Infos.CodeInfoWarning;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DynamicCode16Warnings\n{\n    public static ICodeInfo AvoidSettingsResources = Warn(\"no-settings-resources-on-code16\",\n        message: \"Don't use Settings or Resources - use App.Settings/App.Resources or SettingsStack / ResourcesStack\");\n\n    public static ICodeInfo NoDataMyContent = Warn(\"no-data-my-content-code16\",\n        message: \"Don't use Data.MyContent - use new MyItem or MyItems\");\n    public static ICodeInfo NoDataMyHeader = Warn(\"no-data-my-header-code16\",\n        message: \"Don't use Data.MyHeader - use new MyHeader\");\n    public static ICodeInfo NoDataMyData = Warn(\"no-data-my-data-code16\",\n        message: \"Don't use Data.MyData - use new TODO!\");\n\n\n    public static ICodeInfo NoTypedModel = Warn(\"no-typed-model\",\n        message: \"Don't use TypedModel - use new MyModel\");\n\n    public static ICodeInfo NoCmsContext = Warn(\"no-cms-context\",\n        message: \"Don't use CmsContext - use new MyContext\");\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/GenChangeOn.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class GenChangeOn(string fullNamespace, string name, (string Code, string? Comment)[] alt)\n    : GenNotExist(name, alt)\n{\n\n    public GenChangeOn(string fullNamespace, string name, string alt) : this(fullNamespace, name, [(alt, null)])\n    { }\n\n    public readonly string FullNameSpace = fullNamespace;\n    public string? MsgWhichWasCommon;\n    public string? NotOn;\n\n    protected override string HtmlRecommendations() => Alt.Length == 1\n        ? HtmlRec((\".\" + Alt[0].Code, Alt[0].Comment))\n        : $\"<ol>{string.Join(\"\\n\", Alt.Select(a => HtmlRec((\".\" + a.Code, a.Comment))))}</ol>\";\n\n    public override CodeHelp Generate()\n    {\n        return new()\n        {\n            Name = $\"{FullNameSpace}-{Name}-DoesNotExist\",\n            Detect = DetectTypeDoesNotContain(FullNameSpace, Name),\n            LinkCode = LinkCode,\n            UiMessage = $@\"\nYou are calling the '{Name}' property {MsgWhichWasCommon}, but not available on {NotOn} (RazorTyped). {Comments}\nYou should probably use '{Alt[0].Code}' {Alt[0].Comment}\n\",\n            DetailsHtml = $@\"\nYou are probably calling <code>.{Name}</code>.\n{(Comments.HasValue() ? $\"<br><em>{Comments}</em><br>\" : \"\")}\nThe property <code>.{Name}</code> is replaced with: \n{HtmlRecommendations()}\n\"\n        };\n\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/GenNotExist.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class GenNotExist(string name, (string Code, string? Comment)[]? alt)\n{\n    public GenNotExist(string name, params string[] alt) : this(name, alt?.Select(r => (r, null as string)).ToArray()) { }\n    public GenNotExist(string name, (string Code, string Comment) alt) : this(name, [alt]) { }\n\n    protected virtual string HtmlRecommendations() => Alt.Length == 1\n        ? HtmlRec(Alt[0])\n        : $\"<ol>{string.Join(\"\\n\", Alt.Select(HtmlRec))}</ol>\";\n\n    public readonly string Name = name;\n    public string? Comments;\n    public (string Code, string? Comment)[] Alt = alt.SafeAny() ? alt : new (string, string?)[] { (\"unknown\", null) };\n    public string? LinkCode;\n    public string? MsgNotSupportedIn;\n\n    public virtual CodeHelp Generate()\n    {\n        var recHtml = HtmlRecommendations();\n        return new()\n        {\n            Name = $\"Object-{Name}-DoesNotExist\",\n            Detect = $\"error CS0103: The name '{Name}' does not exist in the current context\",\n            LinkCode = LinkCode,\n            UiMessage = $@\"\nYou are calling the '{Name}' object which {MsgNotSupportedIn}. {Comments}\nYou should probably use '{Alt[0].Code}' {Alt[0].Comment}\n\",\n            DetailsHtml = $@\"\nYou are probably calling <code>{Name}</code>.\n{(Comments.HasValue() ? $\"<br><em>{Comments}</em><br>\" : \"\")}\nThe property <code>{Name}</code> {MsgNotSupportedIn}. \nProbably better: \n{recHtml}\n\"\n        };\n    }\n\n    /// <summary>\n    /// Build detection string for errors which say ... does not contain...\n    /// </summary>\n    internal static string DetectTypeDoesNotContain(string typeName, string property) =>\n        $\"error CS1061: '{typeName}' does not contain a definition for '{property}' and no extension method '{property}' accepting a first argument of type '{typeName}' could be found\";\n\n    protected static string HtmlRec((string Code, string? Comment) r)\n        => $\"<li>{(r.Comment.HasValue() ? r.Comment + \" - \" : \"\")}<code>{r.Code}</code></li>\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n/// <summary>\n/// This class contains a bunch of lists of various error detections and corresponding help.\n/// </summary>\n/// <remarks>\n/// It is quite challenging to manage the help, to ensure that the lists match the needs.\n/// So make sure you follow these conventions:\n///\n/// 1. Only the first / main file `HelpDbRazor` can contain lists which are shared (internal)\n/// 2. All other parts of this class MUST contain private! lists, so we know they are not used outside of this\n/// 3. Clearly separate between lists which contain the definitions, and lists which merge them for a specific use.\n/// 4. Never stack partial lists in lists, it makes it very hard to see where a help is being used\n/// 5. But stacking these lists is allowed for consistency (in this file only)\n/// </remarks>\npublic partial class HelpDbRazor\n{\n    /// <summary>\n    /// All issues for v12 Razor only\n    /// </summary>\n    internal static List<CodeHelp> CompileRazorOrCode12 =>\n    [\n        ..DnnMissingInHybrid,\n        ..RemovedV20,\n        ..TryingToUseV8ApiIn12Plus,\n    ];\n\n\n    [field: AllowNull, MaybeNull]\n    internal static List<CodeHelp> CompileRazorOrCode14 => field ??=\n    [\n        ..DnnMissingInHybrid,\n        ..RemovedV20,\n\n        // use `Convert`\n        ..ChangesInV14LikeConvert,\n\n        ..TryingToUseV16InV14AsItWasTemporarilyMixed,\n\n    ];\n\n    /// <summary>\n    /// Compile Help for RazorTyped etc.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public static List<CodeHelp> Compile16 => field ??=\n    [\n        ..DnnMissingInHybrid,\n        ..RemovedV20,\n\n        // use old `Convert` object\n        ..ChangesInV14LikeConvert,\n\n        ..Compile16Wip,\n\n        ..CompileV16AndOthers,\n\n        // razor compile errors\n        ..CompileUnknownOnly,\n\n        // New v20\n        ..CompileRemovedApisInV20ForAllRazorClasses,\n    ];\n\n\n    [field: AllowNull, MaybeNull]\n    public static List<CodeHelp> HelpForRuntimeProblems => field ??=\n    [\n        ..RemovedV12,\n        ..RemovedV20,\n        ..RuntimeProblemsOnly,\n    ];\n\n\n    [field: AllowNull, MaybeNull]\n    internal static List<CodeHelp> CompileVersionUnknown => field ??=\n    [\n        // razor compile errors where the file type isn't known\n        ..CompileUnknownOnly,\n\n        ..CompileRemovedApisInV20ForAllRazorClasses,\n        \n        ..CompilerErrorsWhenOldAutomaticWebConfigIsMissing,\n\n        ..RemovedV20,\n    ];\n\n    [field: AllowNull, MaybeNull]\n    public static List<CodeHelp> HelpForHttpCompileExceptions => field ??=\n    [\n        // Inherited from above\n        ..CompileVersionUnknown,\n\n        ..RemovedV12,\n        ..CompileProblemsGeneral,\n        ..CompileProblemsDynamic,\n    ];\n\n    [field: AllowNull, MaybeNull]\n    public static List<CodeHelp> CompileInvalidCastExceptions => field ??=\n    [\n        ..RemovedV12,\n    ];\n\n\n    /// <summary>\n    /// This is used directly in the DNN code when the base class doesn't match what's expected.\n    /// Not reused anywhere else.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public static CodeHelp AutoInheritsMissingAfterV20 => field ??= new()\n    {\n        Name = \"auto-inherits-missing-after-v20\",\n        Detect = \"The webpage at\",\n        UiMessage = \"\"\"\n\n                    In v20, auto inheritance is removed. Make sure your template inherits from the correct base class and check the docs for updated usage.\n\n                    \"\"\",\n        DetailsHtml = \"\"\"\n\n                      This is likely because your template is missing the correct <code>@inherits</code> statement.\n                      <br>\n                      <strong>Solution:</strong> <br>\n                      Ensure your Razor file has the correct <code>@inherits</code> statement for v20. See the docs for more info.\n                      <br>\n                      <code>@inherits ToSic.SexyContent.Razor.SexyContentWebPage</code>\n                      <br>\n                      See the docs for more info.\n\n                      \"\"\",\n        LinkCode = \"brc-20-stop-auto-inherits\",\n    };\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor_Compile.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\npublic partial class HelpDbRazor\n{\n    /// <summary>\n    /// General problems, such as NoParamOrder - apply to everything\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> CompileProblemsGeneral => field ??=\n    [\n        new()\n        {\n            Name = \"Advanced APIs should use Parameter-Names and not Param-Order\",\n            // real error is ca. :error CS1503: Argument 2: cannot convert from 'bool' to 'ToSic.Lib.Coding.NoParamOrder' at System.Web.Compilation.AssemblyBuilder.Compile()\n            Detect = \"to 'ToSic.Sys.Coding.NoParamOrder'\",\n            LinkCode = \"named-params\",\n            UiMessage = \"Many methods have optional parameters - these must be named, otherwise you see this error.\",\n            DetailsHtml =\n                \"Many methods have optional parameters - these must be named, otherwise you see this error. <br>\" +\n                \"Example: <br>\" +\n                \"<code>Kit.Page.AssetAttributes(true)</code> \" +\n                \"should be <br><code>Kit.Page.AssetAttributes(optimize: true)</code>.\",\n        },\n\n    ];\n\n\n    /// <summary>\n    /// Compile problems which should only apply to dynamic code\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> CompileProblemsDynamic => field ??=\n    [\n        new()\n        {\n            Name = \"Can't use Lambda\",\n            Detect =\n                \"error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type\",\n            LinkCode = \"ErrLambda\",\n            UiMessage = \"Lambdas have difficulties with dynamic objects.\"\n        },\n\n        new()\n        {\n            Name = \"DynamicEntity not found\",\n            Detect = \"error CS0246: The type or namespace name 'DynamicEntity' could not be found\",\n            LinkCode = \"ErrDynamicEntity\",\n            UiMessage = \"The type DynamicEntity shouldn't be used.\",\n        },\n    ];\n\n    /// <summary>\n    /// Errors which are only typical for situations where the Razor Base Class isn't known.\n    /// This could be because it's not provided, or because the code is so broken that it can't detect it.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> CompileUnknownOnly => field ??=\n    [\n\n        // Help when compiling with a namespace which is not known\n        new()\n        {\n            Name = \"unknown-ns\",\n            Detect = \"error CS0234: The type or namespace name\",\n            UiMessage = \"\"\"\n\n                        Your code seems to have an invalid namespace - like as a '@using xxx' or '@inherits xxx'. Check and fix your code.\n\n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          Your code seems to have an invalid namespace - like as a <code>@using xxx</code> or <code>@inherits xxx</code>. Check and fix your code.\n\n                          \"\"\"\n        },\n        \n        // Help when the new Roslyn compiler runs into a conversion problem because of a semicolon at the end of the inherits-statement\n        new()\n        {\n            Name = \"inherits-breaks-with-semicolon\",\n            // full message is like \"error CS1003: Syntax error, ',' expected at System.Web.Compilation.AssemblyBuilder.Compile()\"\n            // but only a part of it is in the initial exception, so we only check for the part that is there\n            Detect = \"Syntax error, ',' expected\",\n            UiMessage = \"\"\"\n\n                        Your Razor code probably has a semicolon ';' in the wrong place, which breaks the new Roslyn Razor Compiler. Check and fix your code.\n\n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          The new Roslyn compiler incorrectly handles <code>@inherits</code> with a trailing semicolon. Remove the semicolon and it should work. \n                          <br>\n                          <strong>Example</strong>: <br>\n                          <code>@inherits Custom.Hybrid.RazorTyped;</code> <br>\n                          should be <br>\n                          <code>@inherits Custom.Hybrid.RazorTyped</code>\n\n                          \"\"\"\n        },\n\n        // Help when the new Roslyn compiler runs into a conversion problem because of a comment at the end of the inherits-statement\n        new()\n        {\n            Name = \"inherits-breaks-with-comment\",\n            // full message is like \"Error: { expected ..., Error: } expected ..., Error: Type or namespace definition, or end-of-file expected\"\n            // but only a part of it is in the initial exception, so we only check for the part that is there\n            Detect = @\"Error: { expected\",\n            UiMessage = \"\"\"\n\n                        Your Razor code probably has a comments '//' in the wrong place, which breaks the new Roslyn Razor Compiler. Check and fix your code.\n\n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          The new Roslyn compiler incorrectly handles <code>@inherits</code> with a trailing comments. Remove the comments and it should work. \n                          <br>\n                          <strong>Example</strong>: <br>\n                          <code>@inherits Custom.Hybrid.RazorTyped // comment</code> <br>\n                          should be <br>\n                          <code>@inherits Custom.Hybrid.RazorTyped</code>\n\n                          \"\"\"\n        }\n    ];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor_CompileV20.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n/// <summary>\n/// Help for compile errors before the Razor base class is known.\n/// </summary>\npartial class HelpDbRazor\n{\n\n\n\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> CompileRemovedApisInV20ForAllRazorClasses => field ??=\n    [\n        // New v20\n        \n        // v20 CustomizeData() removed, so this is no longer relevant\n        new()\n        {\n            Name = \"CustomizeDataRemoved\",\n            Detect = \"CustomizeData()': no suitable method found to override\",\n            UiMessage = \"\"\"\n\n                        CustomizeData(...) has been removed in v20.\n\n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          <code>CustomizeData(...)</code> is an old API which has been removed in v20. It was used to customize the data passed to Razor templates, but now this is done differently.\n\n                          \"\"\",\n            LinkCode = \"brc-20-customizedata\",\n        },\n\n        // v20 CustomizeSearch() removed, so this is no longer relevant\n        new()\n        {\n            Name = \"CustomizeSearchRemoved\",\n            Detect = \"CustomizeSearch(Dictionary\", // just the extract, since there are multiple overloads\n            UiMessage = \"\"\"\n\n                        CustomizeSearch(...) has been removed in v20.\n\n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          <code>CustomizeSearch(...)</code> is an old API which has been removed in v20. It was used to customize the data passed to Razor templates, but now this is done differently.\n\n                          \"\"\",\n            LinkCode = \"brc-20-customizedata\",\n        },\n        \n        // v20 CustomizeSearch() removed, so this is no longer relevant\n        new()\n        {\n            Name = \"CustomizeSearchRemovedISearchItemDetection\",\n            Detect = \"The type or namespace name 'ISearchItem' could not be found\",\n            UiMessage = \"\"\"\n\n                        ISearchItem should not be used in v20.\n\n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          <code>ISearchItem(...)</code> should not be used in Razor any more. It was used to customize data for the search indexer, now this is done differently.\n\n                          \"\"\",\n            LinkCode = \"brc-20-customizedata\",\n        },\n    ];\n\n\n\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> CompilerErrorsWhenOldAutomaticWebConfigIsMissing => field ??=\n    [\n\n        // Help for missing AsDynamic after v20 auto-inherits removal\n        GenHelpForMissingWebConfigAutoInherits(\"AsDynamic\"),\n\n        // Help for missing CreateInstance after v20 auto-inherits removal\n        GenHelpForMissingWebConfigAutoInherits(\"CreateInstance\"),\n\n        // Help for missing Link after v20 auto-inherits removal\n        GenHelpForMissingWebConfigAutoInherits(\"Link\"),\n\n        // Help for missing Edit after v20 auto-inherits removal\n        GenHelpForMissingWebConfigAutoInherits(\"Edit\"),\n\n        // Help for missing 'Module' property on DnnHelper after v20 changes\n        new()\n        {\n            Name = \"dnnhelper-missing-after-v20\",\n            Detect = \"CS1061: 'DnnHelper<dynamic>' does not contain a definition for\",\n            UiMessage = \"\"\"\n\n                        Your Razor code is trying to use 'Module', 'Portal', etc, but this property is not available. In v20, APIs and base classes changed. Make sure your template inherits from the correct base class and check the docs for updated usage.\n\n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          The <code>Module</code> or <code>Portal</code> or etc property is not available on <code>DnnHelper&lt;dynamic&gt;</code> in v20. This is likely because your template is missing the correct <code>@inherits</code> statement or is using an outdated API. \n                          <br>\n                          <strong>Solution:</strong> <br>\n                          Ensure your Razor file has the correct <code>@inherits</code> statement for v20. See the docs for more info.\n                          <br>\n                          <code>@inherits ToSic.SexyContent.Razor.SexyContentWebPage</code>\n                          <br>\n                          See the docs for more info.\n\n                          \"\"\",\n            LinkCode = \"brc-20-stop-auto-inherits\",\n        },\n\n        \n        // New v20 - removal of #RemovedV20 #Element resulting in `List` being mistaken for LINQ Lists\n        new()\n        {\n            Name = \"List not available on SexyContentWebPage, resulting in c# thinking it could want to access List<T>\",\n            Detect = \"error CS0305: Using the generic type 'List<T>' requires 1 type arguments\",\n            LinkCode = \"brc-20-list-element\",\n            UiMessage = \"The old List (of Element) object had to be removed.\"\n        },\n    ];\n\n\n    /// <summary>\n    /// Factory to generate CodeHelp for missing methods after v20 auto-inherits removal\n    /// </summary>\n    private static CodeHelp GenHelpForMissingWebConfigAutoInherits(string methodName) => new()\n    {\n        Name = $\"{methodName.ToLowerInvariant()}-missing-after-auto-inherits-removed\",\n        Detect = $\"error CS0103: The name '{methodName}' does not exist in the current context\",\n        UiMessage = $\"\"\"\n\n                     Your Razor code is using '{methodName}', but the base class is missing. In v20, automatic @inherits was removed. Add the correct @inherits statement to your .cshtml file.\n\n                     \"\"\",\n        DetailsHtml = $\"\"\"\n\n                       Your Razor template uses <code>{methodName}</code>, but the required base class is missing. In v20, automatic <code>@inherits</code> was removed for security and clarity. You must now add the correct <code>@inherits</code> statement at the top of your .cshtml file.\n                       <br>\n                       <strong>Example</strong>: <br>\n                       <code>@inherits ToSic.SexyContent.Razor.SexyContentWebPage</code>\n                       <br>\n                       See the docs for more info.\n\n                       \"\"\",\n        LinkCode = \"brc-20-stop-auto-inherits\",\n    };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor_Dnn.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n/// <summary>\n/// The help DB for Razor issues related to DNN only. \n/// </summary>\npartial class HelpDbRazor\n{\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> DnnMissingInHybrid => field ??=\n    [\n        new()\n        {\n            Name = \"Object-Dnn-Not-In-Hybrid\",\n            Detect = @\"error CS0118: 'Dnn' is a 'namespace' but is used like a 'variable'\",\n            UiMessage = $\"\"\"\n                         You are probably trying to use the 'Dnn' object which is not supported in 'Custom.Hybrid.Razor' templates. \n\n                         \"\"\",\n            DetailsHtml = $\"\"\"\n                           You are probably trying to use the <code>Dnn</code> object which is not supported in <code>Custom.Hybrid.Razor</code> templates. Use: \n                           <ol>\n                               <li>Other APIs such as <code>CmsContext</code> to get page/module etc. information</li>\n                               <li>If really necessary (not recommended) use the standard Dnn APIs to get the necessary objects.</li>\n                           </ol>\n\n                           \"\"\"\n        },\n    ];\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor_Runtime.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\npublic partial class HelpDbRazor\n{\n\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> RuntimeProblemsOnly => field ??=\n    [\n        new()\n        {\n            // Dynamic: Error when it doesn't find a method because the object is null; \n            Name = \"Method on Object not found\",\n            Detect = \"Cannot perform runtime binding on a null reference\",\n            LinkCode = \"err-binding-on-null-reference\",\n            UiMessage = \"Method not found - typically on a dynamic object.\",\n        },\n    ];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor_Typed.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sys.Code.Help;\nusing static ToSic.Sxc.Code.Sys.CodeErrorHelp.CodeHelpBuilder;\n\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\npartial class HelpDbRazor\n{\n    #region Methods to help build the data\n\n    internal const string IsNotSupportedIn16Plus = \"is not supported in RazorTyped / CodeTyped\";\n\n    private static CodeHelp NotExists(string property, params string[] replacement)\n        => new GenNotExist(property, replacement) { MsgNotSupportedIn = IsNotSupportedIn16Plus }.Generate();\n\n\n    #endregion\n\n\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> Compile16Wip => field ??=\n    [\n        // use `CreateSource(name)\n        NotExists(\"CreateSource\", \"Kit.Data.CreateSource(...)\"),\n        NotExists(\"CreateInstance\", \"GetCode(...)\"),\n\n        // Use AsDynamic(...)\n        new GenNotExist(\"AsDynamic\", [\n            (\"AsItem(...)\", \"to get a standard ITypedItem\"),\n            (\"AsItemList(...)\", \"to get a list of ITypedItem\"),\n            (\"AsTyped(...)\", \"to get a ITyped from an anonymous object\"),\n            (\"AsStack(...)\", \"to get a typed stack which merges various objects\"),\n            (\"Kit.Json.ToTyped(string)\", \"to get an ITyped from a json string\")\n        ])\n        {\n            MsgNotSupportedIn = IsNotSupportedIn16Plus,\n        }.Generate(),\n\n        // Access .List\n        // TODO: Resulting API NAMING NOT FINAL\n        ..BuildVariations(\n            NotExists(\"List\", \"MyItems\", \"AsItems(MyData.Get())\"),\n            h => h with\n            {\n                Detect = \"does not contain a definition for 'List'\"\n            },\n            h => h with\n            {\n                Detect = \"error CS0305: Using the generic type \" +\n                         \"'System.Collections.Generic.List<T>' requires 1 type arguments\"\n            }\n        ),\n\n        // Core data objects like Content, Presentation, List...\n        NotExists(\"Content\", \"MyItem\"),\n        NotExists(\"Header\", \"MyHeader\"),\n        NotExists(\"Presentation\", \"MyItem.Presentation\"),\n        NotExists(\"ListContent\", \"MyHeader\"),\n        NotExists(\"ListPresentation\", \"MyHeader.Presentation\"),\n\n        // Settings / Resources\n        NotExists(\"Settings\", \"App.Settings\", \"AllSettings\"),\n\n\n        ..BuildVariations(\n            NotExists(\"Resources\", \"App.Resources\", \"AllResources\"),\n            h => h with\n            {\n                Detect = \"does not exist in the namespace \" +\n                         \"'Resources' (are you missing an assembly reference?)\"\n            },\n            h => h with\n            {\n                Detect = \"error CS0118: 'Resources' is a \" +\n                         \"'namespace' but is used like a 'variable'\"\n            },\n            h => h with\n            {\n                DetectRegex = true,\n                Detect = \"error CS0234: The type or namespace name \" +\n                         \"'.*' does not exist in the namespace 'Resources' \\\\(are you missing an assembly reference\\\\?\\\\)\"\n            }\n        ),\n\n        // Edit object removed in RazorTyped\n        new GenNotExist(\"Edit\", [\n            (\"Kit.Toolbar.Default()...\", \"to build a standard toolbar\"),\n            (\"Kit.Toolbar.Empty()...\", \"to start with an empty toolbar\"),\n            (\"MyUser.IsContentAdmin\", \"to find out if edit is enabled\"),\n            (\"Kit.Edit\", \"to really use the Edit object (not often needed, as the replacements are better)\")\n        ])\n        {\n            MsgNotSupportedIn = IsNotSupportedIn16Plus,\n        }.Generate(),\n\n\n        // AsAdam(...) removed in RazorTyped\n        new GenNotExist(\"AsAdam\", (\"object.Folder(\\\"FieldName\\\")\", \"Use the Folder(...) method on an Item\"))\n        {\n            Comments = \"AsAdam isn't needed any more, since there is an easier syntax.\",\n            MsgNotSupportedIn = IsNotSupportedIn16Plus,\n        }.Generate(),\n\n        // Data replaced with MyData\n        NotExists(\"Data\", \"MyData\"),\n\n        // Various renamed properties\n        ..BuildListFromDiverseSources(\n\n            // Renamed properties on ITypedItem\n            new GenChangeOn(\"ToSic.Sxc.Data.ITypedItem\", AttributeNames.EntityIdPascalCase, alt: \"Id\"),\n            new GenChangeOn(\"ToSic.Sxc.Data.ITypedItem\", AttributeNames.EntityGuidPascalCase, alt: \"Guid\"),\n            new GenChangeOn(\"ToSic.Sxc.Data.ITypedItem\", \"EntityTitle\", alt: \"Title\"),\n\n            // Renamed properties on IAppTyped: Path, Folder\n            new GenChangeOn(\"ToSic.Sxc.Apps.IAppTyped\", \"Path\",\n                alt: $\".{nameof(IAppTyped.Folder)}.{nameof(IAsset.Url)}\"),\n            new GenChangeOn(\"ToSic.Sxc.Apps.IAppTyped\", \"PhysicalPath\",\n                alt: $\".{nameof(IAppTyped.Folder)}.{nameof(Eav.Apps.Assets.IAsset.PhysicalPath)}\"),\n            new GenChangeOn(\"ToSic.Sxc.Apps.IAppTyped\", \"PathShared\",\n                alt: $\".{nameof(IAppTyped.FolderAdvanced)}(location: \\\"shared\\\").{nameof(IAsset.Url)}\"),\n            new GenChangeOn(\"ToSic.Sxc.Apps.IAppTyped\", \"PhysicalPathShared\",\n                alt:\n                $\".{nameof(IAppTyped.FolderAdvanced)}(location: \\\"shared\\\").{nameof(Eav.Apps.Assets.IAsset.PhysicalPath)}\"),\n\n            new GenChangeOn(\"ToSic.Sxc.Context.ICmsView\", \"PathShared\",\n                alt: $\"MyView.{nameof(ICmsView.Folder)}.{nameof(Eav.Apps.Assets.IAsset.PhysicalPath)}\"),\n            new GenChangeOn(\"ToSic.Sxc.Context.ICmsView\", \"PhysicalPath\",\n                alt: $\"MyView.{nameof(ICmsView.Folder)}.{nameof(Eav.Apps.Assets.IAsset.PhysicalPath)}\"),\n            new GenChangeOn(\"ToSic.Sxc.Context.ICmsView\", \"PhysicalPathShared\",\n                alt: $\"MyView.{nameof(ICmsView.Folder)}.{nameof(Eav.Apps.Assets.IAsset.PhysicalPath)}\")\n\n        ),\n\n\n\n    ];\n\n    /// <summary>\n    /// Compile Help for RazorTyped etc.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> CompileV16AndOthers => field ??=\n    [\n        // Help when a generic expression like @Command<Type>(MyItem) in Razor is mistaken for an HTML tag by the compiler.\n        new()\n        {\n            Name = \"generic-expression-as-html\",\n            // Assuming the detectable error message might hint at an unexpected HTML element or similar parsing issue\n            Detect = @\"cannot convert from 'method group' to 'HelperResult'\",\n            UiMessage = \"\"\"\n\n                        It looks like you're trying to use a generic method lke @Method<Type>(...) in Razor, but it's being mistaken for an HTML tag. Enclose the method call in parentheses to correct this issue.\n\n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          When using generic methods in Razor syntax, such as <code>@Method&lt;Type&gt;(...)</code>, the Razor compiler can mistake the angle brackets for an HTML tag. \n                          This results in a compilation error. To prevent this, the entire expression should be enclosed in parentheses, indicating to the compiler that it's a C# expression to be evaluated, not HTML.\n                          <br>\n                          <strong>Example</strong>: <br>\n                          Incorrect: <code>@Method&lt;Type&gt;(...)</code> <br>\n                          Correct: <code>@(Method&lt;Type&gt;(...))</code> <br>\n                          Wrap your generic method calls in parentheses to ensure they are correctly interpreted by the Razor compiler.\n\n                          \"\"\"\n        },\n\n        // Help when a developer accidentally casts an ITypedItem to dynamic, and tries to use methods not accessible through dynamic due to explicit interface implementation.\n        new()\n        {\n            Name = \"incorrect-dynamic-usage\",\n            // Detection based on the specific runtime error message parts\n            Detect =\n                @\"does not contain a definition for '(\\S+)'\\s+at CallSite.Target\\(Closure , CallSite , Object , String \\)\",\n            DetectRegex = true,\n            UiMessage = $\"\"\"\n\n                         It seems like you're trying to use methods such as .Get(...) or .String(...) on a dynamically casted object of type '{nameof(WrapObjectTyped)}' or similar, which does not work due to explicit interface implementation. Use a strongly typed approach instead.\n\n                         \"\"\",\n            DetailsHtml = $\"\"\"\n\n                           When working with objects like <code>{nameof(WrapObjectTyped)}</code> or <code>{nameof(TypedItemOfEntity)}</code>, casting them to <code>dynamic</code> and attempting to use methods like <code>.Get(...)</code> or <code>.String(...)</code> will result in a <code>RuntimeBinderException</code>. This happens because these methods are explicitly implemented by the interface and are not accessible through a dynamic type reference.\n                           <br><br>\n                           <strong>Solution:</strong> Instead of casting to <code>dynamic</code>, keep the object's type as <code>ITypedItem</code> or cast it to the specific type that implements the interface. This way, you can access all methods as intended.\n                           <br><br>\n                           <strong>Example</strong>: <br>\n                           Incorrect: <code>dynamic testItem = MyItem;</code><br>\n                           Correct: <code>var testItem = MyItem;</code><br>\n\n                           \"\"\"\n        },\n    ];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor_V12.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\nusing static ToSic.Sxc.Code.Sys.CodeErrorHelp.CodeHelpBuilder;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class HelpDbRazor\n{\n    #region Methods to build Help DB\n\n    internal const string IsNotSupportedIn12Plus = \"is not supported in Razor12+\";\n\n    private static CodeHelp HelpNotExists12(string property, params string[] replacement)\n        => new GenNotExist(property, replacement)\n        {\n            MsgNotSupportedIn = IsNotSupportedIn12Plus\n        }.Generate();\n\n    #endregion\n\n    [field: AllowNull, MaybeNull]\n    public static List<CodeHelp> RemovedV12 => field ??=\n    [\n        new()\n        {\n            // Very old use of ToSic.Eav.IEntity\n            Name = \"ToSic.Eav.IEntity\",\n            Detect = \"error CS0234: The type or namespace name 'IEntity' does not exist in the namespace 'ToSic.Eav\",\n            LinkCode = \"ErrIEntity\",\n            UiMessage = \"IEntity is used on the wrong namespace, correct would be ToSic.Eav.Data.IEntity.\"\n        },\n    ];\n\n\n    /// <summary>\n    /// List re-used in v12 and v14\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> TryingToUseV8ApiIn12Plus => field ??=\n    [\n        // Access .List\n        ..BuildVariations(\n            HelpNotExists12(\"List\", \"AsDynamic(Data)\"),\n            h => h with\n            {\n                Detect = \"does not contain a definition for 'List'\",\n            },\n            h => h with\n            {\n                Detect =\n                @\"error CS0305: Using the generic type 'System.Collections.Generic.List<T>' requires 1 type arguments\",\n            }\n        ),\n\n        // Access .ListContent\n        HelpNotExists12(\"ListContent\", \"Header\"),\n        HelpNotExists12(\"ListPresentation\", \"Header.Presentation\"),\n\n        // .Presentation\n        HelpNotExists12(\"Presentation\", \"Content.Presentation\"),\n\n        // .CreateSource(string) - Obsolete\n        new CodeHelp\n        {\n            Name = \"CreateSource-String-Obsolete\",\n            Detect =\n                @\"error CS0411: The type arguments for method .*\\.CreateSource.*cannot be inferred from the usage\",\n            DetectRegex = true,\n            LinkCode =\n                \"https://docs.2sxc.org/api/dot-net/ToSic.Sxc.Services.IDataService.html#ToSic_Sxc_Services_IDataService_GetSource_\",\n            UiMessage = $\"\"\"\n\n                         You are probably calling CreateSource(stringNameOfSource, ...) which {IsNotSupportedIn12Plus}. \n\n                         \"\"\",\n            DetailsHtml = $\"\"\"\n\n                           You are probably calling <code>CreateSource(stringNameOfSource, ...)</code> which {IsNotSupportedIn12Plus}. Use: \n                           <ol>\n                               <li>Kit.Data.GetSource&lt;TypeName&gt;(...)</li>\n                               <li>Kit.Data.GetSource(appDataSourceName, ...)</li>\n                           </ol>\n\n                           \"\"\"\n        }\n\n        // Not handled - can't because the AsDynamic accepts IEntity which works in Razor14\n        // dynamic AsDynamic(ToSic.Eav.Interfaces.IEntity entity)\n        // dynamic AsDynamic(KeyValuePair<int, ToSic.Eav.Interfaces.IEntity> entityKeyValuePair)\n        // IEnumerable<dynamic> AsDynamic(IEnumerable<ToSic.Eav.Interfaces.IEntity> entities)\n        // dynamic AsDynamic(KeyValuePair<int, IEntity> entityKeyValuePair) => Obsolete10.AsDynamicKvp();\n\n        // Skipped, as can't be detected - they are all IEnumerable...\n        //[PrivateApi] public IEnumerable<dynamic> AsDynamic(IDataStream stream) => Obsolete10.AsDynamicForList();\n        //[PrivateApi] public IEnumerable<dynamic> AsDynamic(IDataSource source) => Obsolete10.AsDynamicForList();\n        //[PrivateApi] public IEnumerable<dynamic> AsDynamic(IEnumerable<IEntity> entities) => Obsolete10.AsDynamicForList();\n    ];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor_V14.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\npartial class HelpDbRazor\n{\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> ChangesInV14LikeConvert => field ??=\n    [\n        new()\n        {\n            Name = \"System.Convert-Incorrect-Use\",\n            Detect = \"error CS0117: 'System.Convert' does not contain a definition for\",\n            LinkCode = null,\n            UiMessage = \"\"\"\n\n                        You are probably calling Convert.ToXXX(...), so you probably want to use either 'System.Convert' or the Sxc 'IConvertService'. \n                        Older Razor/WebApi classes provided the IConvertService on an an object called 'Convert' which caused confusions, which could be why you see this error. \n                        \"\"\",\n            DetailsHtml = \"\"\"\n\n                          You seem to be calling <code>Convert.To...(...)</code>, so you probably want to use either 'System.Convert' or the Sxc 'IConvertService'. <br>\n                          Older Razor/WebApi classes provided the IConvertService on an an object called 'Convert' which caused confusions. <br>\n                          <ol>\n                              <li>If you want <code>System.Convert</code> make sure your code is correct (see MS docs) </li>\n                              <li>If you want the <code>IConvertService</code> use <code>Kit.Convert.To...(...)</code> </li>\n                          </ol>\n                          \"\"\"\n        }\n    ];\n\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> TryingToUseV16InV14AsItWasTemporarilyMixed => field ??=\n    [\n        // v16.01 AsTyped / AsTypedList\n        HelpRemoved14(\"AsTyped\", \"brc-1602\", null),\n        HelpRemoved14(\"AsTypedList\", \"brc-1602\", null),\n\n    ];\n\n\n    private static CodeHelp HelpRemoved14(string property, string linkCode, params (string Code, string? Comment)[]? alt)\n        => new GenNotExist(property, alt)\n        {\n            LinkCode = linkCode,\n            MsgNotSupportedIn = \"was a bad design choice in Razor14 and had to be removed - see link\",\n        }.Generate();\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/HelpDbRazor_V20.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\n\n/// <summary>\n/// This should contain help for Razor which is used in all versions.\n/// </summary>\npartial class HelpDbRazor\n{\n    [field: AllowNull, MaybeNull]\n    private static List<CodeHelp> RemovedV20 => field ??=\n    [\n\n        // New v20 - detect usage of `PrimaryValue(name, languages, resolveHyperlinks: bool)` which does not exist anymore\n        new CodeHelp\n        {\n            Name = \"Detect use of old PrimaryValue / PrimaryValue<T>\",\n            // Full error is something like: \"error CS1061: 'IEntity' does not contain a definition for 'PrimaryValue' and no accessible extension method 'PrimaryValue' accepting a first argument of type 'IEntity' could be found (are you missing a using directive or an assembly reference?) at System.Web.Compilation.AssemblyBuilder.Compile()\"\n            // But it can also come from a non IEntity object, like from a 'ToSic.Eav.Data.EntityDecorators.Sys.EntityWithDecorator<ToSic.Sxc.Data.Internal.Decorators.EntityInBlockDecorator>'\n            Detect = @\"does not contain a definition for 'PrimaryValue'\",\n            UiMessage =\n                \"Your code seems to use an old 'PrimaryValue(...) method to get values. This has is removed in v20. Please use 'Get(...)' instead.\",\n        },\n\n        new CodeHelp\n        {\n            Name = \"Detect use of old Value / Value<T>\",\n            // Full error is something like: Error: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'ToSic.Eav.Data.EntityDecorators.Sys.EntityWithDecorator<ToSic.Sxc.Data.Internal.Decorators.EntityInBlockDecorator>' does not contain a definition for 'Value' at CallSite.Target(Closure , CallSite , Object , String ) at\n            // note that \"at\" has a few spaces in front of it\n            Detect = @\"does not contain a definition for 'Value'\",\n            UiMessage =\n                \"Your code seems to use an old 'Value(...) method to get values. This has is removed in v20. Please use 'Get(...)' instead.\",\n        },\n\n        new CodeHelp\n        {\n            Name = \"Detect use of old GetBestValue - any which stopped existing\",\n            // Full error is something like: \"ToSic.Eav.Data.EntityDecorators.Sys.EntityWithDecorator<ToSic.Sxc.Data.Sys.Decorators.CmsEditDecorator>' does not contain a definition for 'GetBestValue' at CallSite\"\n            Detect = @\"does not contain a definition for 'GetBestValue'\",\n            UiMessage =\n                \"Your code seems to use an old 'GetBestValue() overload to get with/without converting to links. Please use Get(...) instead.\",\n            LinkCode = \"brc-20-getbestvalue\",\n        },\n\n        // New v20 - detect use of using ToSic.Eav.Interfaces\n        new CodeHelp\n        {\n            Name = \"Using-ToSic.Eav.Interfaces\",\n            Detect =\n                @\"error CS0234: The type or namespace name 'Interfaces' does not exist in the namespace 'ToSic.Eav' (are you missing an assembly reference?)\",\n            UiMessage =\n                \"You are probably using the old namespace ToSic.Eav.Interfaces, which is not supported since v20. Replace \\\"ToSic.Eav.Interfaces\\\" with \\\"ToSic.Eav.Data\\\" in your code.\",\n            LinkCode = \"ErrIEntity\",\n        },\n        new CodeHelp\n        {\n            Name = \"Using-ToSic.SexyContent.Interfaces\",\n            Detect =\n                @\"error CS0234: The type or namespace name 'Interfaces' does not exist in the namespace 'ToSic.SexyContent' (are you missing an assembly reference?)\",\n            UiMessage =\n                \"You are probably using the old namespace ToSic.SexyContent.Interfaces, which is not supported since v20. Please remove/replace according to upgrade guide TODO!.\",\n        },\n\n        // New v20 - detect usage of `IEntity` without the namespace \n        new CodeHelp\n        {\n            Name = \"IEntity-Without-Namespace\",\n            Detect =\n                @\"error CS0246: The type or namespace name 'IEntity' could not be found (are you missing a using directive or an assembly reference?)\",\n            UiMessage = \"You are probably using IEntity in your code, but missing the @using ToSic.Eav.Data\",\n        },\n\n        // New v20 - detect usage of `IEntityLight` - but not clear why it could think it exists, since it shouldn't - but in my tests it tried...\n        new CodeHelp\n        {\n            Name = \"Detect Convert to IEntityLight\",\n            // Full error is something like \"Unable to cast object of type 'ToSic.Eav.Data.Entity' to type 'ToSic.Eav.Data.IEntityLight'.\"\n            Detect = @\"to type 'ToSic.Eav.Data.IEntityLight'\",\n            UiMessage =\n                \"Your code seems to use an old interface IEntityLight. Best just use 'ToSic.Eav.Data.IEntity' or see if the conversion is even necessary.\",\n        },\n\n        // New v20 - detect usage of `IEntityLight` which should not exist in any DLLs any more\n        new CodeHelp\n        {\n            Name = \"Detect missing IEntityLight\",\n            // Full error is something like: \"error CS0246: The type or namespace name 'IEntityLight' could not be found (are you missing a using directive or an assembly reference?)\"\n            Detect = @\"error CS0246: The type or namespace name 'IEntityLight' could not be found\",\n            UiMessage =\n                \"Your code seems to use an old interface IEntityLight. Best just use 'ToSic.Eav.Data.IEntity' or see if the conversion is even necessary\",\n        },\n\n        // New v20 - detect usage of `GetBestValue(name, languages, bool)` which does not exist anymore\n        new CodeHelp\n        {\n            Name = \"Detect use of old GetBestValue - without the parameter name\",\n            // Full error is something like: \"error CS1501: No overload for method 'GetBestValue' takes 3 arguments at System.Web.Compilation.AssemblyBuilder.Compile()\"\n            Detect = @\"error CS1501: No overload for method 'GetBestValue' takes 3 arguments\",\n            UiMessage =\n                \"Your code seems to use an old 'GetBestValue() overload to get with/without converting to links. This has been inactive for a long time and is removed in v20. Please see guide TODO!\",\n        },\n\n        // New v20 - detect usage of `GetBestValue(name, languages, resolveHyperlinks: bool)` which does not exist anymore\n        new CodeHelp\n        {\n            Name = \"Detect use of old GetBestValue - with the parameter name\",\n            // Full error is something like: \"error CS1739: The best overload for 'GetBestValue' does not have a parameter named 'resolveHyperlinks' at System.Web.Compilation.AssemblyBuilder.Compile()\"\n            Detect =\n                @\"error CS1739: The best overload for 'GetBestValue' does not have a parameter named 'resolveHyperlinks'\",\n            UiMessage =\n                \"Your code seems to use an old 'GetBestValue() overload to get with/without converting to links. This has been inactive for a long time and is removed in v20. Please see guide TODO!\",\n        },\n\n\n        new CodeHelp\n        {\n            Name = \"Detect use of Get<T> without using\",\n            // Full error is something like: \"error CS0308: The non-generic method 'IEntity.Get(string)' cannot be used with type arguments\"\n            Detect = @\"error CS0308: The non-generic method 'IEntity.Get(string)' cannot be used with type arguments\",\n            UiMessage =\n                \"Your code seems to use a generic 'Get...(...). This is an extension method as of v20. Make sure you add '@using ToSic.Eav.Data' to your razor file.\",\n        },\n\n        // Added in v20, but for everything - detect calls to APIs without using parameter names\n        new CodeHelp\n        {\n            Name = \"Detect missing parameter names\",\n            // Full error is something like: \"error CS1503: Argument 2: cannot convert from 'string' to 'ToSic.Lib.Coding.NoParamOrder' at System.Web.Compilation.AssemblyBuilder.Compile()\"\n            // It seems that the ' may be escaped, so we're really trying to just detect the bare minimum\n            Detect = @\"ToSic.Lib.Coding.NoParamOrder\",\n            UiMessage =\n                \"Your code seems to call an API which expects named parameters, and you didn't name them. See help.\",\n            LinkCode = \"https://go.2sxc.org/named-params\",\n        },\n\n        \n\n        // New v20 - removal of #RemovedV20 #Element\n        new()\n        {\n            Name = \"The Blocks.IRenderService was removed\",\n            Detect = \"error CS0234: The type or namespace name 'IRenderService' does not exist in the namespace 'ToSic.Sxc.Blocks'\",\n            LinkCode = \"brc-20-blocks-irenderservice\",\n            UiMessage = \"The old List ToSic.Sxc.Blocks.IRenderService has been replaced/renamed with ToSic.Sxc.Services.IRenderService.\"\n        },\n\n        // New v21 - removal of the mock: parameter\n        new CodeHelp\n        {\n            Name = \"Detect use of old GetBestValue - with the parameter name\",\n            // Full error is something like: \"error CS1739: The best overload for 'GetBestValue' does not have a parameter named 'resolveHyperlinks' at System.Web.Compilation.AssemblyBuilder.Compile()\"\n            //Detect = @\"error CS1739: The best overload for 'AsItem' does not have a parameter named 'mock'\",\n            Detect = @\"does not have a parameter named 'mock'\",\n            UiMessage =\n                \"Your code seems to use an old 'AsItem' or 'As' overload to create mock data. This was a bad design choice, please use Convert.ToMock(...) instead.\",\n        },\n\n\n    ];\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeErrorHelp/RazorExceptions.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.CodeErrorHelp;\npublic class RazorExceptions\n{\n\n    #region Exceptions to throw in various not-supported cases\n\n    public static dynamic ExAsDynamicForList()\n        => throw new(\"AsDynamic for lists isn't supported in RazorComponent. Please use AsList instead.\");\n\n    internal static dynamic ExCreateSourceString()\n        => throw new($\"CreateSource(string, ...) {HelpDbRazor.IsNotSupportedIn12Plus}. Please use CreateSource<DataSourceTypeName>(...) instead.\");\n\n    private static dynamic ExNotYetSupported(string original, string recommended)\n        => throw new($\"{original} {HelpDbRazor.IsNotSupportedIn12Plus}. Use {recommended}.\");\n\n    public static object ExAsDynamicKvp() => ExNotYetSupported(\"AsDynamic(KeyValuePair<int, IEntity>\", \"AsDynamic(IEnumerable<IEntity>...)\");\n\n    public static object ExPresentation() => ExNotYetSupported(\"Presentation\", \"Content.Presentation\");\n    public static object ExListPresentation() => ExNotYetSupported(\"ListPresentation\", \"Header.Presentation\");\n    public static object ExListContent() => ExNotYetSupported(\"ListContent\", \"Header\");\n    public static IEnumerable<object> ExList() => ExNotYetSupported(\"List\", \"Data[\\\"Default\\\"].List\");\n\n    public static object ExAsDynamicInterfacesIEntity()\n        =>\n            ExNotYetSupported($\"AsDynamic(Eav.Interfaces.IEntity)\", \"Please cast your data to ToSic.Eav.Data.IEntity.\");\n\n    public static object AsDynamicKvpInterfacesIEntity()\n        =>\n            ExNotYetSupported(\"AsDynamic(KeyValuePair<int, Eav.Interfaces.IEntity>)\",\n                \"Please cast your data to ToSic.Eav.Data.IEntity.\");\n\n    public static IEnumerable<object> AsDynamicIEnumInterfacesIEntity()\n        =>\n            ExNotYetSupported(\"AsDynamic(IEnumerable<Eav.Interfaces.IEntity> entities)\",\n                \"Please cast your data to ToSic.Eav.Data.IEntity.\");\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeRunHelpers/CodeHelperBase.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeHelperBase : ServiceWithContext\n{\n    protected CodeHelperBase(string logName) : base(logName)\n    { }\n\n    public override void ConnectToRoot(IExecutionContext exCtx)\n    {\n        base.ConnectToRoot(exCtx);\n        // Make sure the Code-Log is reset, in case it was used before this call\n        _codeLog.Reset();\n    }\n\n\n    #region CodeLog / Html Helper\n\n    public ICodeLog CodeLog => _codeLog.Get(() => new CodeLog(Log))!;\n    private readonly GetOnce<ICodeLog> _codeLog = new();\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeRunHelpers/CodeHelperTypedData.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.DataSources;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n/// <summary>\n/// Code Helper for typed code v16+\n/// </summary>\n/// <param name=\"helperSpecs\"></param>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeHelperTypedData(CompileCodeHelperSpecs helperSpecs, string? logName = null)\n    : CodeHelperV00Base(helperSpecs, SxcLogName + (logName ?? \".TC16HL\"))\n{\n    public bool DefaultStrict = true;\n\n    [field: AllowNull, MaybeNull] internal ContextData Data => field ??= ExCtx.GetContextData();\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= ExCtx.GetCdf();\n\n    public ITypedItem MyItem => _myItem.Get(() => Cdf.AsItem(Data.MyItems.FirstOrDefault(), new() { ItemIsStrict = DefaultStrict })!)!;\n    private readonly GetOnce<ITypedItem> _myItem = new();\n\n    public IEnumerable<ITypedItem> MyItems => _myItems.Get(() =>\n        Cdf.EntitiesToItems(Data.MyItems, new() { ItemIsStrict = DefaultStrict, DropNullItems = true }))!;\n    private readonly GetOnce<IEnumerable<ITypedItem>> _myItems = new();\n\n    public ITypedItem MyHeader => _myHeader.Get(() => Cdf.AsItem(Data.MyHeaders.FirstOrDefault(), new() { ItemIsStrict = DefaultStrict })!)!;\n    private readonly GetOnce<ITypedItem> _myHeader = new();\n\n    [field: AllowNull, MaybeNull]\n    private ICodeTypedApiHelper TypedApiHelper => field ??= ExCtx.GetTypedApi();\n\n    public ITypedStack AllResources => TypedApiHelper.AllResources;\n\n    public ITypedStack AllSettings => TypedApiHelper.AllSettings;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeRunHelpers/CodeHelperV00Base.cs",
    "content": "﻿using ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n/// <summary>\n/// Base class for version-specific code helpers.\n/// </summary>\n/// <param name=\"helperSpecs\"></param>\n/// <param name=\"logName\"></param>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class CodeHelperV00Base(CompileCodeHelperSpecs helperSpecs, string logName)\n    : HelperBase(helperSpecs.ExCtx.Log, logName)\n{\n    protected IExecutionContext ExCtx => Specs.ExCtx;\n\n    public CompileCodeHelperSpecs Specs { get; } = helperSpecs;\n\n\n    public IDevTools DevTools => _devTools.Get(() => new DevTools(Specs, Log))!;\n    private readonly GetOnce<IDevTools> _devTools = new();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.CodeRunHelpers/CompileCodeHelperSpecs.cs",
    "content": "﻿using ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n/// <summary>\n/// Helper information for all code helpers, which is often passed around from one helper to another.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record CompileCodeHelperSpecs(\n    IExecutionContext ExCtx,\n    bool IsRazor,\n    string CodeFileName\n);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.HotBuild/HotBuildConstants.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n// TODO: MAKE class INTERNAL AGAIN AFTER MOVING TO ToSic.Sxc.Custom\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HotBuildConstants\n{\n    /// <summary>\n    /// Check if an object is from the AppCode-xxx.dll\n    /// </summary>\n    /// <param name=\"obj\"></param>\n    /// <returns></returns>\n    public static bool ObjectIsFromAppCode(object? obj)\n    {\n        if (obj == null)\n            return false;\n        var ownType = obj.GetType();\n        return (ownType.Namespace ?? \"\").StartsWith(FolderConstants.AppCodeFolder)\n               || ownType.Assembly.FullName!.Contains(FolderConstants.AppCodeFolder);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.SourceCode/CodeFileInfo.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sys;\nusing ToSic.Sys.Code.Help;\n\nnamespace ToSic.Sxc.Code.Sys.SourceCode;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeFileInfo\n{\n    private CodeFileInfo(string inherits, CodeFileTypes type, List<CodeHelp> help, bool useAppCode = false, string? sourceCode = default, string? relativePath = default, string? fullPath = default)\n    {\n        Inherits = inherits;\n        Type = type;\n        Help = help ?? [];\n        AppCode = useAppCode;\n        SourceCode = sourceCode;\n        RelativePath = relativePath;\n        FullPath = fullPath;\n    }\n\n    internal CodeFileInfo(CodeFileInfo original, string? sourceCode, string? relativePath = default, string? fullPath = default, bool? useAppCode = default)\n    {\n        Inherits = original.Inherits;\n        Type = original.Type;\n        Help = original.Help;\n        AppCode = useAppCode ?? original.AppCode;\n        SourceCode = sourceCode;\n        RelativePath = relativePath ?? original.RelativePath;\n        FullPath = fullPath ?? original.FullPath;\n    }\n\n    public string Inherits { get; }\n    public string? SourceCode { get; }\n    public string? RelativePath { get; }\n    public string? FullPath { get; }\n    public CodeFileTypes Type { get; }\n    public List<CodeHelp> Help { get; }\n    public bool AppCode { get; }\n\n    // without base class\n    public static CodeFileInfo TemplateUnknown = new(SysConstants.Unknown, CodeFileTypes.Unknown, HelpDbRazor.CompileVersionUnknown);\n\n    // with some other base class\n    public static CodeFileInfo TemplateOther = new(\"other\", CodeFileTypes.Other, HelpDbRazor.CompileVersionUnknown);\n\n    public static CodeFileInfo CodeFileNotFound = new(\"\", CodeFileTypes.FileNotFound, []);\n\n    public static CodeFileInfo CodeFileInheritsAppCode = new(\"AppCode.*\", CodeFileTypes.V16, HelpDbRazor.Compile16, sourceCode: null);\n    /// <summary>\n    /// Template CodeFile objects for different types of files.\n    /// They don't contain the source code, which would be added later if needed.\n    /// </summary>\n    internal static List<CodeFileInfo> CodeFileInfoTemplates =\n    [\n        TemplateUnknown,\n        TemplateOther,\n        // cshtml\n        new(\"Custom.Hybrid.Razor12\", CodeFileTypes.V12, HelpDbRazor.CompileRazorOrCode12, sourceCode: null),\n        new(\"Custom.Hybrid.Razor14\", CodeFileTypes.V14, HelpDbRazor.CompileRazorOrCode14, sourceCode: null),\n        new(\"Custom.Hybrid.RazorTyped\", CodeFileTypes.V16, HelpDbRazor.Compile16, sourceCode: null),\n\n        // c#\n        new(\"Custom.Hybrid.Code12\", CodeFileTypes.V12, HelpDbRazor.CompileRazorOrCode12, sourceCode: null),\n        new(\"Custom.Hybrid.Code14\", CodeFileTypes.V14, HelpDbRazor.CompileRazorOrCode14, sourceCode: null),\n        new(\"Custom.Hybrid.CodeTyped\", CodeFileTypes.V16, HelpDbRazor.Compile16, sourceCode: null),\n    ];\n\n    /// <summary>\n    /// Override ToString for better debugging\n    /// </summary>\n    public override string ToString() => _toString ??= $\"{nameof(CodeFileInfo)} - {nameof(RelativePath)}: '{RelativePath}'; {nameof(FullPath)}: '{FullPath}'; {nameof(SourceCode)}: {SourceCode?.Length}; {nameof(Inherits)}: '{Inherits}'; {nameof(Type)}: '{Type}'; {nameof(AppCode)}: '{AppCode}'\";\n    private string? _toString;\n\n    /// <summary>\n    /// Create a dictionary of the specs for logging\n    /// </summary>\n    public IDictionary<string, string?> ToDictionary() => new Dictionary<string, string?>\n    {\n        { \"RelativePath\", RelativePath },\n        { \"FullPath\", FullPath },\n        { \"SourceCode\", SourceCode?.Length.ToString() },\n        { \"Inherits\", Inherits },\n        { \"Type\", Type.ToString() },\n        { \"AppCode\", AppCode.ToString() },\n    };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.SourceCode/CodeFileInfoExtensions.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.SourceCode;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class CodeFileInfoExtensions\n{\n    /// <summary>\n    /// AppCode is supported in RazorTyped and newer, and\n    /// enabled when \"using AppCode\" is used\n    /// </summary>\n    /// <param name=\"razorType\"></param>\n    /// <returns></returns>\n    public static bool IsHotBuildSupported(this CodeFileInfo razorType)\n        => razorType.AppCode\n           && razorType.Type == CodeFileTypes.V16;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.SourceCode/CodeFileTypes.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.SourceCode;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic enum CodeFileTypes\n{\n    Unknown,\n    FileNotFound,\n    V12,\n    V14,\n    V16,\n    Other\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/Sys.SourceCode/SourceAnalyzer.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\n\nnamespace ToSic.Sxc.Code.Sys.SourceCode;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SourceAnalyzer(IServerPaths serverPaths) : ServiceBase(\"Sxc.RzrSrc\", connect: [serverPaths])\n{\n    public CodeFileInfo TypeOfVirtualPath(string virtualPath)\n    {\n        var l = Log.Fn<CodeFileInfo>($\"{nameof(virtualPath)}: '{virtualPath}'\");\n        string? fullPath = default, sourceCode = default;\n        try\n        {\n            (_, fullPath, sourceCode) = GetFileContentsOfVirtualPath(virtualPath);\n            return sourceCode == null\n                ? l.ReturnAndLog(CodeFileInfo.CodeFileNotFound)\n                : l.ReturnAndLog(AnalyzeContent(virtualPath, fullPath, sourceCode));\n        }\n        catch\n        {\n            return l.ReturnAndLog(new(CodeFileInfo.TemplateUnknown, sourceCode: sourceCode, relativePath: virtualPath, fullPath: fullPath), \"error trying to find type\");\n        }\n    }\n\n    private (string relativePath, string? fullPath, string? sourceCode) GetFileContentsOfVirtualPath(string relativePath)\n    {\n        var l = Log.Fn<(string, string?, string?)>($\"{nameof(relativePath)}: '{relativePath}'\");\n\n        if (relativePath.IsEmptyOrWs())\n            return l.Return((relativePath, null, null), \"no relativePath\");\n\n        var fullPath = serverPaths.FullContentPath(relativePath);\n        if (fullPath == null || fullPath.IsEmptyOrWs())\n            return l.Return((relativePath, fullPath, null), \"no relativePath\");\n\n        if (!File.Exists(fullPath))\n            return l.Return((relativePath, fullPath, null), \"file not found\");\n\n        var sourceCode = File.ReadAllText(fullPath);\n        return l.Return((relativePath, fullPath, sourceCode), $\"found, {sourceCode.Length} bytes\");\n    }\n\n    private CodeFileInfo AnalyzeContent(string relativePath, string? fullPath, string sourceCode)\n    {\n        var l = Log.Fn<CodeFileInfo>($\"{nameof(relativePath)}:{relativePath}\");\n        if (sourceCode.Length < 10)\n            return l.Return(new(CodeFileInfo.TemplateUnknown, sourceCode: sourceCode), \"file too short\");\n\n        var isCs = relativePath.ToLowerInvariant().EndsWith(SourceCodeConstants.CsFileExtension, StringComparison.InvariantCultureIgnoreCase);\n        l.A($\"isCs: {isCs}\");\n\n        if (isCs)\n        {\n            var csUseAppCode = IsAppCodeUsedInCs(sourceCode);\n            l.A($\"cs, appCode: {csUseAppCode}\");\n\n            var className = Path.GetFileNameWithoutExtension(relativePath);\n            l.A($\"cs, className: {className}\");\n\n            var baseClass = ExtractBaseClass(sourceCode, className);\n            l.A($\"cs, baseClass: {baseClass}\");\n\n            if (baseClass.IsEmptyOrWs())\n                return l.Return(\n                    BuildCfi(CodeFileInfo.TemplateUnknown, csUseAppCode),\n                    \"Ok, cs file without base class\");\n\n            var csBaseClassMatch = CodeFileInfo.CodeFileInfoTemplates\n                .FirstOrDefault(cf => cf.Inherits == baseClass); // && cf.AppCode == csHasAppCode);\n\n            return csBaseClassMatch != null\n                ? l.ReturnAndLog(new(csBaseClassMatch, sourceCode: sourceCode, relativePath: relativePath, fullPath: fullPath, useAppCode: csUseAppCode))\n                : l.Return(\n                    BuildCfi(CodeFileInfo.TemplateOther, csUseAppCode),\n                    \"Ok, cs file with other base class\");\n        }\n\n        // Cshtml part\n        var inheritsMatch = Regex.Match(sourceCode, @\"@inherits\\s+(?<BaseName>[\\w\\.]+)\", RegexOptions.Multiline);\n\n        if (!inheritsMatch.Success)\n            return l.Return(\n                BuildCfi(CodeFileInfo.TemplateUnknown, false),\n                \"no @inherits found\");\n\n        var ns = inheritsMatch.Groups[\"BaseName\"].Value;\n        if (ns.IsEmptyOrWs())\n            return l.Return(\n                BuildCfi(CodeFileInfo.TemplateUnknown, false),\n                \"@inherits empty string\"\n                );\n\n        // check @inherits AppCode.Something\n        if (ns.StartsWith(\"AppCode.\"))\n            return l.Return(BuildCfi(CodeFileInfo.CodeFileInheritsAppCode, true));\n\n        var razorUseAppCode = IsAppCodeUsedInCshtml(sourceCode);\n\n        var findMatch = CodeFileInfo.CodeFileInfoTemplates\n            .FirstOrDefault(cf => cf.Inherits == ns); // && cf.AppCode == cshtmlHasAppCode);\n\n        return findMatch != null\n            ? l.ReturnAndLog(BuildCfi(findMatch, razorUseAppCode))\n            : l.Return(\n                BuildCfi(CodeFileInfo.TemplateOther, razorUseAppCode),\n                $\"namespace '{ns}' can't be found\");\n\n        // Helper to build the CodeFileInfo based on a template and all the specs provided originally\n        CodeFileInfo BuildCfi(CodeFileInfo original, bool useAppCode)\n            => new(original, sourceCode: sourceCode, relativePath: relativePath, fullPath: fullPath, useAppCode: useAppCode);\n    }\n\n    private static bool IsAppCodeUsedInCshtml(string sourceCode)\n    {\n        // TODO: stv, update code because this code is not robust enough\n        // it does not correctly handle all edge cases\n\n        // Pattern to match '@using AppCode' not commented out\n        const string pattern = @\"\n            # Ignore leading whitespaces\n            (?<=^\\s*)\n\n            # Match the @using statement\n            @using\\s+AppCode\n\n            # Ensure that it's not part of a comment\n            (?<!@(/\\*)[\\s\\S]*?@using\\s+AppCode) # Not in Razor comment\";\n\n        var options = RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace;\n        var appCodeMatch = Regex.Match(sourceCode, pattern, options);\n\n        return appCodeMatch.Success;\n    }\n\n    private static bool IsAppCodeUsedInCs(string sourceCode)\n    {\n        // Pattern to match 'using AppCode;' with optional additional namespace segments\n        // or inheritance code ': AppCode' with additional namespace segments followed\n        // by optional whitespace and either a comma or opening curly brace\n        // not in single-line or multi-line comments\n        const string pattern = @\"\n        # Ignore leading whitespaces\n        (?<=^\\s*)\n\n        # Match either 'using AppCode;' or ': AppCode' with additional namespace segments\n        (using\\s+AppCode(?:\\.\\w+)*\\s*;|(?:.*):\\s*AppCode(?:\\.\\w+)+\\s*(?={|,|\\s))\n\n        # Ensure that it's not part of a single-line comment\n        (?<!//.*(?:using\\s+AppCode(?:\\.\\w+)*\\s*;|(?:.*):\\s*AppCode(?:\\.\\w+)+\\s*(?={|,|\\s)))\n\n        # Ensure that it's not part of a multi-line comment\n        (?<!/\\*[\\s\\S]*?(?:using\\s+AppCode(?:\\.\\w+)*\\s*;|(?:.*):\\s*AppCode(?:\\.\\w+)+\\s*(?={|,|\\s)))\";\n\n        var options = RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace;\n        var appCodeMatch = Regex.Match(sourceCode, pattern, options);\n\n        return appCodeMatch.Success;\n    }\n\n\n\n    /// <summary>\n    /// Extract 'className' base class from source code\n    /// </summary>\n    /// <param name=\"sourceCode\"></param>\n    /// <param name=\"className\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Code Complexity: This regex won't work well if the class declaration spans multiple lines or if there are comments between the class name and its base class.\n    /// Generic Classes: If the base class uses generics, the regex needs to be adjusted to handle such cases.\n    /// Multiple Inheritance: C# doesn't support multiple inheritance for classes. However, if interfaces are involved, this regex will only capture the first inherited type (which is usually the base class).\n    /// Formatting: The regex assumes standard formatting.If there are unusual spacings or line breaks, it might not work correctly.\n    /// Nested Classes: If the class is nested within another class, the regex will not match it.\n    /// Comments and Strings: If the class declaration is commented out or appears within a string, the regex will still match it, which might not be desired.\n    /// More robust solution can be done with Roslyn source pars, but additional packages can be needed.\n    /// </remarks>\n    public static string? ExtractBaseClass(string sourceCode, string className)\n    {\n        if (sourceCode.IsEmptyOrWs() || className.IsEmptyOrWs())\n            return null;\n        var pattern = $@\"class\\s+{className}\\s*:\\s*([^\\s{{,]+)\";\n        var match = Regex.Match(sourceCode, pattern, RegexOptions.IgnoreCase);\n        return match.Success && match.Groups.Count > 1\n            ? match.Groups[1].Value\n            : null;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/TypedCode/ITypedApi.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// This API describes objects with a TypedApi.\n/// </summary>\n/// <remarks>\n/// This is usually only relevant when using the `ITypedApiService` which will get you a standalone object with this API.\n/// </remarks>\n[WorkInProgressApi(\"Still WIP v20\")]\npublic interface ITypedApi\n{\n    #region App, Resources, Settings\n\n    /// <summary>\n    /// The current App object (with strictly typed Settings/Resources).\n    /// Use it to access App properties such as `Path` or any data in the App.\n    /// </summary>\n    public IAppTyped App { get; }\n\n    /// <summary>\n    /// Stack of all Resources in the System, merging Resources of View, App, Site, Global etc.\n    /// Will retrieve values by priority, with View-Resources being top priority and Preset-Resources being the lowest.\n    ///\n    /// > [!TIP]\n    /// > If you know that Resources come from the App, you should prefer `App.Resources` instead.\n    /// > That is faster and helps people reading your code figure out where to change a value.\n    /// </summary>\n    ITypedStack AllResources { get; }\n\n    /// <summary>\n    /// Stack of all Settings in the System, merging Settings of View, App, Site, Global etc.\n    /// Will retrieve values by priority, with View-Settings being top priority and Preset-Settings being the lowest.\n    ///\n    /// > [!TIP]\n    /// > If you know that Settings come from the App, you should prefer `App.Settings` instead.\n    /// > That is faster and helps people reading your code figure out where to change a value.\n    /// </summary>\n    ITypedStack AllSettings { get; }\n\n    /// <summary>\n    /// The main Item belonging to this Template/Module.\n    /// This data is edited by the user directly on this specific module.\n    /// In some cases it can also be a pre-set item configured in the View to be used if the user has not added any data himself.\n    ///\n    /// If this view can have a list of items (more than one) then this contains the first item.\n    /// To get all the items, see <see cref=\"MyItems\"/>\n    /// </summary>\n    ITypedItem MyItem { get; }\n\n    /// <summary>\n    /// List of all Items belonging to this Template/Module.\n    /// This data is edited by the user directly on this specific module.\n    /// In some cases it can also be a pre-set item configured in the View to be used if the user has not added any data himself.\n    ///\n    /// If this view is configured to only have one item, then this list will only contain one item.\n    /// Otherwise, it will have as many items as the editor added.\n    /// </summary>\n    IEnumerable<ITypedItem> MyItems { get; }\n\n    /// <summary>\n    /// The Header-Item belonging to this Template/Module.\n    /// This data is edited by the user directly on this specific module.\n    /// In some cases it can also be a pre-set item configured in the View to be used if the user has not added any data himself.\n    /// </summary>\n    ITypedItem MyHeader { get; }\n\n    /// <summary>\n    /// All the data which the current Template received, based on the View configuration.\n    /// There are a few common scenarios:\n    ///\n    /// 1. If it's a simple view, then this will just contain streams with the main Item(s) and Header\n    /// 1. If the view expects no data, it will just contain a `Default` stream containing no items\n    /// 1. If the view has a Query behind it, then MyData will have all the streams provided by the Query\n    /// </summary>\n    IDataSource MyData { get; }\n\n    /// <inheritdoc cref=\"IHasKit{TServiceKit}\"/>\n    ServiceKit16 Kit { get; }\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\"/>\n    ILinkService Link { get; }\n\n    #endregion\n\n    #region MyContext / UniqueKey\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    ICmsContext MyContext { get; }\n\n    /// <inheritdoc cref=\"ICmsContext.Page\" />\n    ICmsPage MyPage { get; }\n\n    /// <inheritdoc cref=\"ICmsContext.User\" />\n    ICmsUser MyUser { get; }\n\n    /// <inheritdoc cref=\"ICmsContext.View\" />\n    ICmsView MyView { get; }\n\n    /// <inheritdoc cref=\"IKeyService.UniqueKey\"/>\n    string UniqueKey { get; }\n\n    #endregion\n\n    /// <summary>\n    /// Convert something to a <see cref=\"ITypedItem\"/>.\n    /// This works for all kinds of <see cref=\"IEntity\"/>s,\n    /// <see cref=\"IDynamicEntity\"/>s as well as Lists/Enumerables of those.\n    /// \n    /// Will always return a single item.\n    /// If a list is provided, it will return the first item in the list.\n    /// If null was provided, it will return null.\n    /// </summary>\n    /// <param name=\"data\">An original object which can be converted to a TypedItem, such as a <see cref=\"IEntity\"/> .</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"propsRequired\">make the resulting object [strict](xref:NetCode.Conventions.PropertiesRequired), default `true`</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New in v16.02\n    /// Parameter `mock` removed in v21 (breaking, but probably never used in the wild); use `Convert.ToMock()` instead\n    /// </remarks>\n    ITypedItem? AsItem(\n        object data,\n        NoParamOrder npo = default,\n        bool? propsRequired = default\n    );\n\n    /// <summary>\n    /// Convert an object containing a list of Entities or similar to a list of <see cref=\"ITypedItem\"/>s.\n    /// </summary>\n    /// <param name=\"list\">The original list which is usually a list of <see cref=\"IEntity\"/> objects.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"propsRequired\">make the resulting object [strict](xref:NetCode.Conventions.PropertiesRequired), default `true`</param>\n    /// <returns></returns>\n    /// <remarks>New in v16.01</remarks>\n    IEnumerable<ITypedItem> AsItems(\n        object list,\n        NoParamOrder npo = default,\n        bool? propsRequired = default\n    );\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    IEntity AsEntity(ICanBeEntity thing);\n\n    /// <summary>\n    /// Creates a typed object to read the original passed into this function.\n    /// This is usually used to process objects which the compiler can't know, such as anonymous objects returned from helper code etc.\n    /// \n    /// If you have an array of such objects, use <see cref=\"AsTypedList\"/>.\n    /// </summary>\n    /// <param name=\"data\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"propsRequired\">make the resulting object [strict](xref:NetCode.Conventions.PropertiesRequired), default `true`</param>\n    /// <returns></returns>\n    ITyped AsTyped(object data, NoParamOrder npo = default, bool? propsRequired = default);\n\n    /// <summary>\n    /// Create a list\n    /// </summary>\n    /// <param name=\"list\">List/Enumerable object containing a bunch of items to make typed</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"propsRequired\">make the resulting object [strict](xref:NetCode.Conventions.PropertiesRequired), default `true`</param>\n    /// <returns></returns>\n    IEnumerable<ITyped> AsTypedList(object list, NoParamOrder npo = default, bool? propsRequired = default);\n\n    /// <summary>\n    /// Create a typed object which will provide all the properties of the things wrapped inside it.\n    /// The priority is first-object first, so if multiple items have the property, the first in the list will be returned.\n    /// </summary>\n    /// <param name=\"items\">objects to stack together</param>\n    /// <returns></returns>\n    ITypedStack AsStack(params object[] items);\n\n    /// <summary>\n    /// Create a custom-typed object which will provide all the properties of the things wrapped inside it.\n    /// The priority is first-object first, so if multiple items have the property, the first in the list will be returned.\n    /// </summary>\n    /// <param name=\"items\">objects to stack together</param>\n    /// <returns>Item of the custom type</returns>\n    /// <remarks>New in 17.07</remarks>\n    T AsStack<T>(params object[] items)\n        where T : class, IModelFromData, new();\n\n    /// <summary>\n    /// Convert an Entity or TypedItem into a strongly typed object.\n    /// Typically, the type will be from your `AppCode.Data`.\n    /// </summary>\n    /// <typeparam name=\"T\">the target type</typeparam>\n    /// <param name=\"source\">the source object - an `IEntity` or `ITypedItem`</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Released v17.05\n    /// Parameter `mock` removed in v21 (breaking, but probably never used in the wild); use `Convert.ToMock()` instead\n    /// </remarks>\n    T As<T>(object source, NoParamOrder npo = default)\n        where T : class, IModelFromData;\n\n    /// <summary>\n    /// Convert a list of Entities or TypedItems into a strongly typed list.\n    /// Typically, the type will be from your `AppCode.Data`.\n    /// </summary>\n    /// <typeparam name=\"T\">the target type</typeparam>\n    /// <param name=\"source\">the source object - a List/Enumerable of `IEntity` or `ITypedItem`</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"nullIfNull\">if `true` will return null when `source` is `null` - otherwise a wrapper item with empty-contents</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Release in v17.05\n    /// </remarks>\n    IEnumerable<T> AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    TService GetService<TService>() where TService : class;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/TypedCode/TypedApiStandalone.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// Standalone object with the typical typed APIs - for use in the `ITypedApiService`\n/// </summary>\n/// <param name=\"exCtx\"></param>\n/// <param name=\"apiHelper\"></param>\ninternal class TypedApiStandalone(IExecutionContext exCtx, ICodeTypedApiHelper apiHelper) : ITypedApi, IHasLog\n{\n    public ILog Log => exCtx.Log!;\n\n    public IAppTyped App => apiHelper.AppTyped;\n\n    public ITypedStack AllResources => apiHelper.AllResources;\n\n    public ITypedStack AllSettings => apiHelper.AllSettings;\n\n\n    #region Services\n\n    /// <inheritdoc/>\n    public TService GetService<TService>() where TService : class\n        => exCtx.GetService<TService>();\n\n    [field: AllowNull, MaybeNull]\n    public ServiceKit16 Kit => field ??= apiHelper.ServiceKit16;\n\n    public ILinkService Link => apiHelper.Link;\n\n    #endregion\n\n    #region My Data Stuff\n\n    [field: AllowNull, MaybeNull]\n    private CodeHelperTypedData CodeHelper => field ??= new(helperSpecs: new(exCtx, false, \"error no code file\"));\n\n    /// <inheritdoc />\n    public ITypedItem MyItem => CodeHelper.MyItem;\n\n    /// <inheritdoc />\n    public IEnumerable<ITypedItem> MyItems => CodeHelper.MyItems;\n\n    /// <inheritdoc />\n    public ITypedItem MyHeader => CodeHelper.MyHeader;\n\n    /// <inheritdoc />\n    public IDataSource MyData => CodeHelper.Data;\n\n    #endregion\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= exCtx.GetCdf();\n\n    public ITypedItem? AsItem(object data, NoParamOrder npo = default, bool? propsRequired = default)\n        => Cdf.AsItem(data, new() { ItemIsStrict = propsRequired ?? true });\n\n    public IEnumerable<ITypedItem> AsItems(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => Cdf.AsItems(list, new() { ItemIsStrict = propsRequired ?? true });\n\n    public IEntity AsEntity(ICanBeEntity thing)\n        => Cdf.AsEntity(thing);\n\n    public ITyped AsTyped(object original, NoParamOrder npo = default, bool? propsRequired = default)\n        => Cdf.AsTyped(original, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true });\n\n    public IEnumerable<ITyped> AsTypedList(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => Cdf.AsTypedList(list, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true })!;\n\n    public ITypedStack AsStack(params object[] items)\n        => Cdf.AsStack(items);\n\n    public T AsStack<T>(params object[] items)\n        where T : class, IModelFromData, new()\n        => Cdf.AsStack<T>(items);\n\n    #region As / AsList WIP v17\n\n    /// <inheritdoc />\n    public T As<T>(object source, NoParamOrder npo = default)\n        where T : class, IModelFromData\n        => Cdf.AsCustom<T>(source: source, npo: npo);\n\n    /// <inheritdoc />\n    public IEnumerable<T> AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData\n        => Cdf.AsCustomList<T>(source: source, npo: npo, nullIfNull: nullIfNull);\n\n    #endregion\n\n    #region MyContext & UniqueKey\n\n    /// <inheritdoc cref=\"ITypedApi.MyContext\" />\n    public ICmsContext MyContext => apiHelper.CmsContext;\n\n    /// <inheritdoc cref=\"ITypedApi.MyPage\" />\n    public ICmsPage MyPage => apiHelper.CmsContext.Page;\n\n    /// <inheritdoc cref=\"ITypedApi.MyUser\" />\n    public ICmsUser MyUser => apiHelper.CmsContext.User;\n\n    /// <inheritdoc cref=\"ITypedApi.MyView\" />\n    public ICmsView MyView => apiHelper.CmsContext.View;\n\n    /// <inheritdoc cref=\"ITypedApi.UniqueKey\" />\n    public string UniqueKey => Kit.Key.UniqueKey;\n\n    #endregion\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/TypedRazorModel/ITypedRazorModel.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Edit.Toolbar;\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// Object in partial Razor files to access parameters handed in.\n/// Example caller:\n///\n/// ```c#\n/// @Html.Partial(someFile, new { blogPost, file = mainFile, title = \"hello\" }\n/// ```\n///\n/// Example partial:\n///\n/// ```c#\n/// var blogPost = MyModel.Item(\"BlogPost\");\n/// var file = MyModel.File(\"File\");\n/// var title = MyModel.String(\"Title\");\n/// ```\n///\n/// > [!TIP]\n/// > The common data types such as `string` or <see cref=\"ITypedItem\"/> have methods to quickly get them in the desired type.\n/// > This allows things such as `var message = MyModel.String(\"Message\");`\n/// > For less common types you'll need to use <see cref=\"Get\"/> and cast it as needed, like this:\n/// > `string message = MyModel.Get(\"Message\");`.\n/// </summary>\n/// <remarks>Introduced in v16.02</remarks>\n[PublicApi]\npublic interface ITypedRazorModel: IHasKeys\n{\n    #region Check if parameters were supplied\n\n    /// <inheritdoc cref=\"IHasKeys.ContainsKey\"/>\n    new bool ContainsKey(string name);\n\n\n    /// <inheritdoc cref=\"IHasKeys.Keys\"/>\n    new IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default);\n        \n    #endregion\n\n    #region Get\n\n    /// <summary>\n    /// Will get the value and return as object, since the type isn't known. \n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>Object if found, `null` if not found.</returns>\n    object? Get(string name, NoParamOrder npo = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value and return as type T as specified.\n    /// </summary>\n    /// <typeparam name=\"T\">The returned type</typeparam>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The fallback value. If provided, the type is automatically determined.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is provided which is not the `default`.\n    /// So like `Get&lt;string&gt;(..., fallback: false)` can't be detected, but `..., fallback: \"hello\"` can.\n    /// </param>\n    /// <returns>Object of type T if found, `null` if not found.</returns>\n    T? Get<T>(string name, NoParamOrder npo = default, T? fallback = default, bool? required = default);\n\n    #endregion\n\n    #region Code (new 16.05)\n\n    /// <summary>\n    /// Get code forwarded to the current razor.\n    /// Code was usually created in the caller using `GetCode(...)` and may need to be passed around.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">A fallback to use if not found - not commonly used here.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns>The resulting object is `dynamic` which is necessary for making calls to methods etc.</returns>\n    /// <remarks>New in 16.05</remarks>\n    dynamic? Code(string name, NoParamOrder npo = default, object? fallback = default, bool? required = default);\n\n    #endregion\n\n    #region Simple Values: String / Bool / Guid / DateTime\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns>typed result if found, `null` if not found.</returns>\n    string? String(string name, NoParamOrder npo = default, string? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, false if not found.</returns>\n    bool Bool(string name, NoParamOrder npo = default, bool? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, empty-guid if not found.</returns>\n    Guid Guid(string name, NoParamOrder npo = default, Guid? fallback = default, bool? required = default);\n\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, default-date if not found.</returns>\n    DateTime DateTime(string name, NoParamOrder npo = default, DateTime? fallback = default, bool? required = default);\n\n    #endregion\n\n    #region Numbers\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns>int result if found, `0` if not found/convertible.</returns>\n    /// <exception cref=\"ArgumentException\">if the name is not found and no fallback provided and required not false</exception>\n    int Int(string name, NoParamOrder npo = default, int? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns>int result if found, `0` if not found/convertible.</returns>\n    /// <exception cref=\"ArgumentException\">if the name is not found and no fallback provided and required not false</exception>\n    float Float(string name, NoParamOrder npo = default, float? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns>int result if found, `0` if not found/convertible.</returns>\n    /// <exception cref=\"ArgumentException\">if the name is not found and no fallback provided and required not false</exception>\n    double Double(string name, NoParamOrder npo = default, double? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns>int result if found, `0` if not found/convertible.</returns>\n    /// <exception cref=\"ArgumentException\">if the name is not found and no fallback provided and required not false</exception>\n    decimal Decimal(string name, NoParamOrder npo = default, decimal? fallback = default, bool? required = default);\n\n    #endregion\n\n    #region ADAM: File/Files, Folder/Folders\n\n    /// <summary>\n    /// Will get the value if specified.\n    /// If the value is a list of files, then this will only return the first one.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, `null` if not found.</returns>\n    IFile? File(string name, NoParamOrder npo = default, IFile? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value if specified.\n    /// If the value is a single file, will return a list containing that file.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, empty-list if not found.</returns>\n    IEnumerable<IFile>? Files(string name, NoParamOrder npo = default, IEnumerable<IFile>? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value if specified.\n    /// If the value is a list of folders, then this will only return the first one.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, `null` if not found.</returns>\n    IFolder? Folder(string name, NoParamOrder npo = default, IFolder? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value if specified.\n    /// If the value is a single folder, will return a list containing that folder.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, empty-list if not found.</returns>\n    IEnumerable<IFolder>? Folders(string name, NoParamOrder npo = default, IEnumerable<IFolder>? fallback = default, bool? required = default);\n\n    #endregion\n\n    #region Complex Data like Gps\n\n    /// <summary>\n    /// Will get the value and return in the desired type.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns><see cref=\"GpsCoordinates\"/> if found, null if not found/convertible.</returns>\n    /// <exception cref=\"ArgumentException\">if the name is not found and no fallback provided and required not false</exception>\n    /// <remarks>\n    /// Added in 17.08\n    /// </remarks>\n    GpsCoordinates? Gps(string name, NoParamOrder npo = default, GpsCoordinates? fallback = default, bool? required = default);\n\n    #endregion\n\n    //#region Stacks\n\n    ///// <summary>\n    ///// Get a stack which was passed to this\n    ///// </summary>\n    ///// <param name=\"name\"></param>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    ///// <param name=\"fallback\"></param>\n    ///// <param name=\"required\"></param>\n    ///// <returns></returns>\n    //ITypedStack Stack(string name, NoParamOrder npo = default, ITypedStack fallback = default, bool? required = default);\n\n    //#endregion\n\n    #region Item / Entity\n\n    /// <summary>\n    /// Will get the value if specified.\n    /// If the value is a list of items, then this will only return the first one.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, `null` if not found.</returns>\n    ITypedItem? Item(string name, NoParamOrder npo = default, ITypedItem? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value if specified.\n    /// If the value is a single item, will return a list containing that item.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, empty-list if not found.</returns>\n    IEnumerable<ITypedItem>? Items(string name, NoParamOrder npo = default, IEnumerable<ITypedItem>? fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Will get the value being a toolbar as specified.\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is set / not `null`.\n    /// </param>\n    /// <returns>typed result if found, `null` if not found</returns>\n    IToolbarBuilder? Toolbar(string name, NoParamOrder npo = default, IToolbarBuilder? fallback = default, bool? required = default);\n\n    #endregion\n\n    #region HtmlTags\n\n    /// <summary>\n    /// Will get the value being an `IHtmlTag` as specified (RazorBlade objects)\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns>typed result if found, `null` if not found</returns>\n    IHtmlTag? HtmlTag(string name, NoParamOrder npo = default, IHtmlTag? fallback = default,\n        bool? required = default);\n\n    /// <summary>\n    /// Will get the value being an list (IEnumerable) of `IHtmlTag` as specified (RazorBlade objects)\n    /// </summary>\n    /// <param name=\"name\">Property name on the passed in data object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The optional fallback value.</param>\n    /// <param name=\"required\">\n    /// Throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired).\n    /// It is automatically `false` if a `fallback` is not `null`.\n    /// </param>\n    /// <returns>typed result if found, `null` if not found</returns>\n    IEnumerable<IHtmlTag>? HtmlTags(string name, NoParamOrder npo = default,\n        IEnumerable<IHtmlTag>? fallback = default, bool? required = default);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/TypedRazorModel/TypedConverter.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Edit.Toolbar;\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// Helper to convert some unknown object into the possible result.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class TypedConverter(ICodeDataFactory cdf)\n{\n    public ICodeDataFactory Cdf { get; } = cdf;\n\n    private static (T? typed, object? untyped, bool ok) EvalInterface<T>(object? maybe, T? fallback = default)\n        where T: class\n        => maybe switch\n        {\n            null => (fallback, null, true),\n            T typed => (typed, maybe, true),\n            _ => (null, maybe, false)\n        };\n\n    public IEntity? Entity(object maybe, IEntity fallback)\n    {\n        var (typed, untyped, ok) = EvalInterface(maybe, fallback);\n        // Try to convert, in case it's an IEntity or something; could also result in error\n        return ok\n            ? typed\n            : untyped == null\n                ? null\n                : Cdf.AsEntity(untyped);\n    }\n\n    public ITypedItem? Item(object? data, NoParamOrder npo, ITypedItem? fallback)\n    {\n        var (typed, untyped, ok) = EvalInterface(data, fallback);\n        // Try to convert, in case it's an IEntity or something; could also result in error\n        // TODO: #ConvertItemSettings\n        return ok\n            ? typed\n            : untyped == null\n                ? null\n                : Cdf.AsItem(untyped, new() { ItemIsStrict = false });\n    }\n\n    public IEnumerable<ITypedItem>? Items(object? maybe, NoParamOrder npo, IEnumerable<ITypedItem>? fallback)\n    {\n        var (typed, untyped, ok) = EvalInterface(maybe, fallback);\n        // Try to convert, in case it's an IEntity or something; could also result in error\n        return ok\n            ? typed\n            : untyped == null\n                ? null\n                : Cdf.AsItems(untyped, new() { ItemIsStrict = false });\n    }\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public IToolbarBuilder? Toolbar(object? maybe, IToolbarBuilder? fallback)\n    {\n        var (typed, _, ok) = EvalInterface(maybe, fallback);\n        // Try to convert, in case it's an IEntity or something; could also result in error\n        return ok\n            ? typed\n            : fallback;\n    }\n\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public IFile? File(object? maybe, IFile? fallback)\n    {\n        var (typed, untyped, ok) = EvalInterface(maybe, fallback);\n        if (ok)\n            return typed;\n\n        // Flatten list if necessary\n        return untyped is IEnumerable<IFile> list\n            ? list.First()\n            : fallback;\n    }\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public IEnumerable<IFile>? Files(object? maybe, IEnumerable<IFile>? fallback)\n    {\n        // ReSharper disable PossibleMultipleEnumeration\n        var (typed, untyped, ok) = EvalInterface(maybe, fallback);\n        if (ok)\n            return typed;\n\n        // Wrap into list if necessary\n        return untyped is IFile item\n            ? new List<IFile> { item }\n            : fallback;\n        // ReSharper restore PossibleMultipleEnumeration\n    }\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public IFolder? Folder(object? maybe, IFolder? fallback)\n    {\n        var (typed, untyped, ok) = EvalInterface(maybe, fallback);\n        if (ok)\n            return typed;\n\n        // Flatten list if necessary\n        return untyped is IEnumerable<IFolder> list ? list.First() : fallback;\n    }\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public IEnumerable<IFolder>? Folders(object? maybe, IEnumerable<IFolder>? fallback)\n    {\n        // ReSharper disable PossibleMultipleEnumeration\n        var (typed, untyped, ok) = EvalInterface(maybe, fallback);\n        if (ok) return typed;\n\n        // Wrap into list if necessary\n        return untyped is IFolder item ? new List<IFolder> { item } : fallback;\n        // ReSharper restore PossibleMultipleEnumeration\n    }\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public ITypedStack? Stack(object? maybe, ITypedStack? fallback)\n    {\n        var (typed, _, ok) = EvalInterface(maybe, fallback);\n        return ok ? typed : null;\n    }\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public ITyped? Typed(object? maybe, NoParamOrder npo, ITyped? fallback)\n    {\n        var (typed, untyped, ok) = EvalInterface(maybe, fallback);\n        // Try to convert, in case it's an IEntity or something; could also result in error\n        // TODO: #ConvertItemSettings\n        return ok ? typed : Cdf.AsItem(untyped, new() { ItemIsStrict = false });\n    }\n\n    #region Tags\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public IHtmlTag? HtmlTag(object? maybe, IHtmlTag? fallback)\n    {\n        var (typed, _, ok) = EvalInterface(maybe, fallback);\n        return ok ? typed : null;\n    }\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public IEnumerable<IHtmlTag>? HtmlTags(object? maybe, IEnumerable<IHtmlTag>? fallback)\n    {\n        var (typed, _, ok) = EvalInterface(maybe, fallback);\n        return ok ? typed : null;\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Code/TypedRazorModel/TypedRazorModel.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// Implementation of the MyModel which has .Get() .String() etc. methods to get parameters from the Razor model.\n/// </summary>\n/// <param name=\"helperSpecs\"></param>\n/// <param name=\"paramsDictionary\"></param>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class TypedRazorModel(CompileCodeHelperSpecs helperSpecs, IDictionary<string, object> paramsDictionary) : ITypedRazorModel\n{\n    private readonly IDictionary<string, object> _paramsDictionary = paramsDictionary?.ToInvariant() ?? new Dictionary<string, object>();\n    private readonly TypedConverter _converter = new(helperSpecs.ExCtx.GetCdf());\n\n    #region Check if parameters were supplied\n\n    public bool ContainsKey(string name) => !name.IsEmptyOrWs() && _paramsDictionary.ContainsKey(name);\n\n    [PrivateApi]\n    public bool IsEmpty(string name, NoParamOrder npo = default, string? language = default /* ignore */)\n        => HasKeysHelper.IsEmpty(Get(name, required: false), blankIsEmpty: default);\n\n    [PrivateApi]\n    public bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default /* ignore */)\n        => HasKeysHelper.IsNotEmpty(Get(name, required: false), blankIsEmpty: default);\n\n    public IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default) \n        => TypedHelpers.FilterKeysIfPossible(npo, only, _paramsDictionary.Keys);\n\n    #endregion\n\n    #region Get and GetInternal\n\n    public object? Get(string name, NoParamOrder npo = default, bool? required = default) \n        => GetInternalObj(name, required);\n\n    public T? Get<T>(string name, NoParamOrder npo = default, T? fallback = default, bool? required = default) \n        => GetInternal(name, fallback, fallbackAsObj: fallback, required: required);\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"name\"></param>\n    /// <param name=\"fallback\"></param>\n    /// <param name=\"fallbackAsObj\">Untyped fallback, for special null-checks</param>\n    /// <param name=\"required\"></param>\n    /// <param name=\"method\"></param>\n    /// <returns></returns>\n    private T GetInternal<T>(string name, T fallback, object? fallbackAsObj, bool? required, [CallerMemberName] string? method = default)\n    {\n        // If we have a clear fallback, don't make it required\n        if (fallbackAsObj is not null || (fallback != null && fallback.IsNotDefault()))\n            required = false;\n\n        var found = GetInternalObj(name, required, method: method);\n\n        return found switch\n        {\n            null => fallback,\n            // Already matching type OR Interface (because ConvertOrFallback can't handle interface)\n            T typed => typed,\n            _ => typeof(T).IsInterface\n                ? fallback\n                : found.ConvertOrFallback(fallback)\n        };\n    }\n\n    private object? GetInternalObj(string name, bool? required, [CallerMemberName] string? method = default)\n    {\n        if (_paramsDictionary.TryGetValue(name, out var result))\n            return result;\n        if (required == false)\n            return null;\n\n        var call = $\"{nameof(TypedRazorModel)}.{method}(\\\"{name}\\\")\";\n        var callReqFalse = call.Replace(\")\", \", required: false)\");\n        throw new ArgumentException($@\"Tried to get parameter with {call} but parameter '{name}' not provided. \nEither change the calling Html.Partial(\"\"{helperSpecs.CodeFileName}\"\", {{ {name} = ... }} ) or use {callReqFalse} to make it optional.\", nameof(name));\n    }\n\n    #endregion\n\n    public dynamic? Code(string name, NoParamOrder npo = default, object? fallback = default, bool? required = default)\n        => GetInternal(name: name, fallback: fallback, fallbackAsObj: fallback, required: required);\n\n    #region Numbers\n\n    public int Int(string name, NoParamOrder npo = default, int? fallback = default, bool? required = default) \n        => GetInternal(name, fallback ?? default, fallbackAsObj: fallback, required: required);\n\n    public float Float(string name, NoParamOrder npo = default, float? fallback = default, bool? required = default) \n        => GetInternal(name, fallback ?? default, fallbackAsObj: fallback, required: required);\n\n    public double Double(string name, NoParamOrder npo = default, double? fallback = default, bool? required = default) \n        => GetInternal(name, fallback ?? default, fallbackAsObj: fallback, required: required);\n\n    public decimal Decimal(string name, NoParamOrder npo = default, decimal? fallback = default, bool? required = default) \n        => GetInternal(name, fallback ?? default, fallbackAsObj: fallback, required: required);\n\n    #endregion\n\n    #region Standard value types\n\n    public string? String(string name, NoParamOrder npo = default, string? fallback = default, bool? required = default) \n        => GetInternal(name, fallback, fallbackAsObj: fallback, required: required);\n\n    public Guid Guid(string name, NoParamOrder npo = default, Guid? fallback = default, bool? required = default) \n        => GetInternal(name, fallback ?? default, fallbackAsObj: fallback, required: required);\n\n    public bool Bool(string name, NoParamOrder npo = default, bool? fallback = default, bool? required = default) \n        => GetInternal(name, fallback ?? default, fallbackAsObj: fallback, required: required);\n\n    public DateTime DateTime(string name, NoParamOrder npo = default, DateTime? fallback = default, bool? required = default) \n        => GetInternal(name, fallback ?? default, fallbackAsObj: fallback, required: required);\n\n    #endregion\n\n\n    //#region Stacks\n\n    //public ITypedStack Stack(string name, NoParamOrder npo = default, ITypedStack fallback = default, bool? required = default) \n    //    => _converter.Stack(GetInternal(name, required, noParamOrder), fallback);\n\n    //#endregion\n\n    #region Adam\n\n    public IFile? File(string name, NoParamOrder npo = default, IFile? fallback = default, bool? required = default) \n        => _converter.File(GetInternalObj(name, required), fallback);\n\n    public IEnumerable<IFile>? Files(string name, NoParamOrder npo = default, IEnumerable<IFile>? fallback = default, bool? required = default) \n        => _converter.Files(GetInternalObj(name, required), fallback);\n\n    public IFolder? Folder(string name, NoParamOrder npo = default, IFolder? fallback = default, bool? required = default)\n        => _converter.Folder(GetInternalObj(name, required), fallback);\n\n    public IEnumerable<IFolder>? Folders(string name, NoParamOrder npo = default, IEnumerable<IFolder>? fallback = default, bool? required = default)\n        => _converter.Folders(GetInternalObj(name, required), fallback);\n\n    public GpsCoordinates? Gps(string name, NoParamOrder npo = default, GpsCoordinates? fallback = default, bool? required = default)\n        => GetInternal(name: name, fallback: fallback, fallbackAsObj: fallback, required: required);\n\n    #endregion\n\n    #region Entity and Item(s)\n\n    public ITypedItem? Item(string name, NoParamOrder npo = default, ITypedItem? fallback = default, bool? required = default)\n        => _converter.Item(GetInternalObj(name, required), npo, fallback);\n\n    public IEnumerable<ITypedItem>? Items(string name, NoParamOrder npo = default, IEnumerable<ITypedItem>? fallback = default, bool? required = default)\n        => _converter.Items(GetInternalObj(name, required), npo, fallback);\n\n    #endregion\n\n    #region HtmlTags\n\n    public IHtmlTag? HtmlTag(string name, NoParamOrder npo = default, IHtmlTag? fallback = default, bool? required = default)\n        => _converter.HtmlTag(GetInternalObj(name, required), fallback);\n\n    public IEnumerable<IHtmlTag>? HtmlTags(string name, NoParamOrder npo = default, IEnumerable<IHtmlTag>? fallback = default, bool? required = default)\n        => _converter.HtmlTags(GetInternalObj(name, required), fallback);\n\n\n    #endregion\n\n    #region Toolbar\n\n    public IToolbarBuilder? Toolbar(string name, NoParamOrder npo = default, IToolbarBuilder? fallback = default, bool? required = default)\n        => _converter.Toolbar(GetInternalObj(name, required), fallback);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Compatibility/Internal/IDynamicCodeBeforeV10.cs",
    "content": "﻿// #RemovedV20 #IAppAndDataHelpers\n\n//#if NETFRAMEWORK\n\n//using ToSic.Eav.DataSource;\n//using ToSic.Eav.LookUp.Sys.Engines;\n\n//namespace ToSic.Sxc.Compatibility.Internal\n//{\n//\t/// <summary>\n//    /// Old interface for the SexyContent Web Page\n//    /// </summary>\n//    [ShowApiWhenReleased(ShowApiMode.Never)]\n//    public interface IDynamicCodeBeforeV10 // Most of it removed in v20\n//    {\n\n//        ///// <summary>\n//        ///// this is for compatibility with old systems, to ensure that things cast to IEntity in a razor can still be cast back\n//        ///// </summary>\n//        //[PrivateApi]\n//        //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n//        //dynamic AsDynamic(IEntity entity);\n\n//        ///// <summary>\n//        ///// Returns the value of a KeyValuePair as DynamicEntity\n//        ///// </summary>\n//        ///// <param name=\"entityKeyValuePair\"></param>\n//        ///// <returns></returns>\n//        //dynamic AsDynamic(KeyValuePair<int, IEntity> entityKeyValuePair);\n\n//        ///// <summary>\n//        ///// this is for compatibility with old systems, to ensure that things cast to IEntity in a razor can still be cast back\n//        ///// </summary>\n//        //[PrivateApi]\n//        //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n//        //dynamic AsDynamic(KeyValuePair<int, Eav.Interfaces.IEntity> entityKeyValuePair);\n\n//        ///// <summary>\n//        ///// this is for compatibility with old systems, to ensure that things cast to IEntity in a razor can still be cast back\n//        ///// </summary>\n//        //[PrivateApi]\n//        //[Obsolete(\"for compatibility only, avoid using this and cast your entities to ToSic.Eav.Data.IEntity\")]\n//        //IEnumerable<dynamic> AsDynamic(IEnumerable<Eav.Interfaces.IEntity> entities);\n\n//        /// <summary>\n//        /// Create a <see cref=\"IDataSource\"/> which will process data from the given stream.\n//        /// </summary>\n//        /// <returns>A typed DataSource object</returns>\n//        [Obsolete(\"Please use the CreateSource<T> overload instead.\")]\n//        [PrivateApi]\n//        IDataSource CreateSource(string typeName = \"\", IDataSource? inSource = null, ILookUpEngine? configurationProvider = null);\n\n//    }\n//}\n//#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Compatibility/RemoveInV10/ToSic.SexyContent.Element.cs",
    "content": "﻿// #RemovedV20 #Element\n//#if NETFRAMEWORK\n\n//// ReSharper disable once CheckNamespace\n//namespace ToSic.SexyContent;\n\n//[Obsolete(\"This is an old way used to loop things - shouldn't be used any more - will be removed in 2sxc v11 or v12\")]\n//[ShowApiWhenReleased(ShowApiMode.Never)]\n//public class Element\n//{\n//    /// <summary>\n//    /// The DynamicContent object, as dynamic\n//    /// </summary>\n//    public dynamic? Content { get; set; }\n\n//    /// <summary>\n//    /// The Presentation object, as dynamic\n//    /// </summary>\n//    public dynamic? Presentation { get; set; }\n    \n//    /// <summary>\n//    /// The EntityID of the ContentGroupItem\n//    /// </summary>\n//    public int? EntityId { get; set; }\n\n//    /// <summary>\n//    /// The SortOrder of the ContentGroupItem\n//    /// </summary>\n//    public int SortOrder { get; set; }\n\n//    /// <summary>\n//    /// The ContentGroupID of the ContentGroupItem\n//    /// </summary>\n//    public Guid GroupId { get; set; }\n\n//}\n\n//#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/ICmsView_TSettings_TResources.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// Special Views for strongly typed code.\n/// It supplies the Settings and Resources as strongly typed objects.\n/// </summary>\n/// <typeparam name=\"TSettings\">Custom class for Settings</typeparam>\n/// <typeparam name=\"TResources\">Custom class for Resources</typeparam>\n/// <remarks>\n/// New v17.03\n/// </remarks>\n[PublicApi]\npublic interface ICmsView<out TSettings, out TResources> : ICmsView\n    where TSettings : class, IModelFromData, new()\n    where TResources : class, IModelFromData, new()\n{\n    /// <summary>\n    /// All the app settings which are custom for each app.\n    /// These are typed - typically to AppCode.Data.AppSettings\n    /// </summary>\n    new TSettings? Settings { get; }\n\n    /// <summary>\n    /// All the app resources (usually used for multi-language labels etc.).\n    /// /// These are typed - typically to AppCode.Data.AppResources\n    /// </summary>\n    new TResources? Resources { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsBlock.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\ninternal class CmsBlock(IBlock? block) : ICmsBlock\n{\n    /// <inheritdoc />\n    public int Id => block?.ConfigurationIsReady == true\n        ? block.Configuration.Id\n        : 0;\n\n    /// <inheritdoc />\n    public Guid Guid => block?.ConfigurationIsReady == true\n        ? block.Configuration.Guid\n        : Guid.Empty;\n\n    /// <inheritdoc />\n    public bool IsRoot => block is { ParentBlockOrNull: null };\n\n    /// <inheritdoc />\n    public IMetadata Metadata => (block?.Configuration as ICanBeEntity)?.Entity?.Metadata!;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsContext.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context.Sys.Module;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n/// <summary>\n/// Runtime context information, used in dynamic code. Help the code to detect what environment it's in, what page etc.\n/// This lets the code be platform-agnostic, so that it works across implementations (Dnn, Oqtane, NopCommerce)\n/// </summary>\n[PrivateApi(\"we only show the interface in the docs\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CmsContext(\n    IPlatform platform,\n    IContextOfSite siteCtxFallback,\n    LazySvc<IPage> pageLazy,\n    //LazySvc<IModule> moduleFallback,\n    IAppReaderFactory appReaders)\n    : ServiceWithContext(SxcLogName + \".CmsCtx\",\n        connect: [siteCtxFallback, pageLazy, /*moduleFallback,*/ appReaders, platform]), ICmsContext\n{\n    #region Internal context\n\n    /// <summary>\n    /// Provide the Execution Context to the parts\n    /// </summary>\n    internal new IExecutionContext ExCtx => base.ExCtx;\n\n    // Note: Internal so it can be used for View<T, T>\n    internal IBlock BlockInternal => _realBlock.Get(() => ExCtx.GetBlock())!;\n    private readonly GetOnce<IBlock?> _realBlock = new();\n\n    internal IContextOfBlock? CtxBlockOrNull => _ctxBlock.Get(() => BlockInternal?.Context);\n    private readonly GetOnce<IContextOfBlock?> _ctxBlock = new();\n\n    internal IContextOfSite CtxSite => CtxBlockOrNull ?? siteCtxFallback;\n\n    [field: AllowNull, MaybeNull]\n    private IAppReader SiteAppReader => field ??= appReaders.GetZonePrimary(CtxSite.Site.ZoneId);\n\n    #endregion\n\n    public ICmsPlatform Platform { get; } = platform;\n\n    [field: AllowNull, MaybeNull]\n    public ICmsSite Site => field\n        ??= new CmsSite(this, SiteAppReader);\n\n    [field: AllowNull, MaybeNull]\n    public ICmsPage Page => field\n        ??= new CmsPage(this, pageLazy, SiteAppReader.Metadata);\n\n    [field: AllowNull, MaybeNull]\n    public ICmsCulture Culture => field\n        ??= new CmsCulture(this);\n\n    [field: AllowNull, MaybeNull]\n    public ICmsModule Module => field\n        ??= new CmsModule(this,\n            // First try to get the module from the block\n            module: BlockInternal?.Context?.Module\n                    // If that's unknown, try to see if the execution context has an alternate module\n                    // like when used on a container which is not a 2sxc module\n                    ?? (ExCtx as ExecutionContext)?.ModuleIfBlockUnknown\n                    // Fallback: just make sure don't have errors\n                    ?? new ModuleUnknown(null!),\n            rootBlock: BlockInternal?.RootBlock,\n            appMetadata: SiteAppReader.Metadata\n        );\n\n    [field: AllowNull, MaybeNull]\n    public ICmsUser User => field\n        ??= CreateCurrentUser();\n\n    private ICmsUser CreateCurrentUser()\n    {\n        var userSvc = ExCtx.GetService<IUserService>(reuse: true);\n        var userModel = userSvc.GetCurrentUser();\n        return new CmsUser(this, userModel, SiteAppReader.Metadata);\n    }\n\n    [field: AllowNull, MaybeNull]\n    public ICmsView View => field\n        ??= new CmsView(this, BlockInternal);\n\n    [field: AllowNull, MaybeNull]\n    public ICmsBlock Block => field\n        ??= new CmsBlock(BlockInternal);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsContextPartBase.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class CmsContextPartBase<T>(CmsContext cmsContext, T contents) : Wrapper<T>(contents), IHasMetadata\n    where T : class\n{\n    protected CmsContext CmsContext = cmsContext;\n\n    /// <summary>\n    /// Typed IMetadata accessor to all the metadata of this object.\n    /// </summary>\n    public ITypedMetadata Metadata => field ??= CmsContext.ExCtx.GetCdf().MetadataTyped(MetadataRaw);\n\n    [JsonIgnore] // ignore, as it's published through the Metadata property which is better typed.\n    IMetadata IHasMetadata.Metadata => MetadataRaw;\n\n    private IMetadata MetadataRaw => field ??= GetMetadataOf();\n\n    protected abstract IMetadata GetMetadataOf();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsContextPartHelpers.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Eav.Metadata.Sys;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\nstatic class CmsContextPartHelpers\n{\n    /// <summary>\n    /// Enhance the MetadataOf with recommendations,\n    /// so that other systems can review this object and determine what additional metadata to suggest adding.\n    /// </summary>\n    /// <returns></returns>\n    [return: NotNullIfNotNull(nameof(md))]\n    internal static IMetadata? AddRecommendations(this IMetadata? md, string[]? recommendations = default)\n    {\n        if (md == null)\n            return null;\n        md.Target.Recommendations = recommendations ?? [KnownDecorators.NoteDecoratorName];\n        return md;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsCulture.cs",
    "content": "﻿using ToSic.Eav.Context.Sys.ZoneCulture;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CmsCulture(CmsContext parent) : ICmsCulture\n{\n    public string DefaultCode => parent.CtxSite.Site.DefaultCultureCode;\n\n    public string CurrentCode => parent.CtxSite.Site.SafeCurrentCultureCode();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsModule.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Eav.Metadata.Sys;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\ninternal class CmsModule(CmsContext parent, IModule module, IBlock? rootBlock, IMetadataOfSource appMetadata)\n    : CmsContextPartBase<IModule>(parent, module), ICmsModule\n{\n    public int Id => GetContents()?.Id ?? 0;\n\n    [field: AllowNull, MaybeNull]\n    public ICmsBlock Block => field ??= new CmsBlock(rootBlock); // note: will return a dummy info if rootBlock is null\n\n    protected override IMetadata GetMetadataOf() \n        => appMetadata.GetMetadataOf(TargetTypes.Module, Id, title: \"Module \" + Id)\n            .AddRecommendations();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsPage.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Eav.Metadata.Sys;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CmsPage(CmsContext parent, LazySvc<IPage> fallbackPage, IMetadataOfSource appMetadata)\n    : CmsContextPartBase<IPage>(parent, parent.CtxBlockOrNull?.Page ?? fallbackPage.Value), ICmsPage\n{\n    public int Id => GetContents()?.Id ?? 0;\n\n    // note: made it non-nullable v20 2025-06-20 2dm, not sure if it's even relevant...\n    [field: AllowNull, MaybeNull] public IParameters Parameters => field ??= GetContents()!.Parameters;\n\n    public string Url => GetContents()!.Url ?? string.Empty;\n\n    protected override IMetadata GetMetadataOf() =>\n        appMetadata.GetMetadataOf(TargetTypes.Page, Id, title: Url)\n            .AddRecommendations([KnownDecorators.NoteDecoratorName, KnownDecorators.OpenGraphName]);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsSite.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Metadata;\nusing ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CmsSite(CmsContext parent, IAppReader appReader)\n    : CmsContextPartBase<ISite>(parent, parent.CtxSite.Site), ICmsSite\n{\n    public int Id => GetContents()?.Id ?? EavConstants.NullId;\n    public string Url => GetContents()?.Url ?? string.Empty;\n    public string UrlRoot => GetContents()?.UrlRoot ?? string.Empty;\n\n    protected override IMetadata GetMetadataOf() \n        => appReader.Metadata.GetMetadataOf(TargetTypes.Site, Id, title: Url)\n            .AddRecommendations();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsUser.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Eav.Metadata.Sys;\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CmsUser(CmsContext parent, IUserModel userModel, IMetadataOfSource appReader)\n    : CmsContextPartBase<IUser>(parent, parent.CtxSite.User), ICmsUser\n{\n    public string Email => userModel.Email ?? \"\"; // TODO: not sure if defaulting to empty string is good, as it's probably different from the IUserModel\n\n\n    public int Id => userModel.Id;\n    public string NameId => userModel.NameId!;\n    public Guid Guid => userModel.Guid;\n\n    public string Name => IsAnonymous ? \"\" : userModel.Name!;\n    public string Username => IsAnonymous ? \"\" : userModel.Username!;\n\n    public DateTime Created => userModel.Created;\n    public DateTime Modified => userModel.Modified;\n\n\n    public bool IsAnonymous => userModel.IsAnonymous;\n    public bool IsContentEditor => userModel.IsContentEditor; \n    public bool IsContentAdmin => userModel.IsContentAdmin;\n    public bool IsSiteAdmin => userModel.IsSiteAdmin;\n    public bool IsSystemAdmin => userModel.IsSystemAdmin;\n    public bool IsSiteDeveloper => userModel.IsSiteDeveloper;\n\n\n    protected override IMetadata GetMetadataOf() \n        => appReader.GetMetadataOf(TargetTypes.User, Id, title: \"User (\" + Id + \")\")\n            .AddRecommendations();\n\n    public IEnumerable<IUserRoleModel> Roles => userModel.Roles;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsView.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps.Sys.Assets;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CmsView(CmsContext cmsContext, IBlock block) : CmsContextPartBase<IView>(cmsContext, block.View!), ICmsView\n{\n    private readonly IView _view = block.View!;\n\n    /// <inheritdoc />\n    public int Id => _view?.Id ?? 0;\n\n    /// <inheritdoc />\n    public string Name => _view?.Name ?? \"\";\n\n    /// <inheritdoc />\n    public string Identifier => _view?.Identifier ?? \"\";\n\n    /// <inheritdoc />\n    public string Edition => _view?.Edition ?? \"\";\n\n    protected override IMetadata GetMetadataOf()\n        => _view?.Metadata.AddRecommendations()!;\n\n    [field: AllowNull, MaybeNull]\n    public IFolder Folder => field ??= FolderAdvanced();\n\n    [PrivateApi]\n    private IFolder FolderAdvanced(NoParamOrder npo = default, string? location = default)\n        => new CmsViewFolder(this, block.App, AppAssetsHelpers.DetermineShared(location) ?? _view.IsShared);\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= CmsContext.ExCtx.GetCdf();\n\n    /// <summary>\n    /// Note: this is an explicit implementation, so in Dynamic Razor it won't work. This is by design.\n    /// </summary>\n    ITypedItem? ICmsView.Settings => _settings.Get(() => Cdf.AsItem(_view.Settings, new() { ItemIsStrict = true }));\n    private readonly GetOnce<ITypedItem?> _settings = new();\n\n    /// <summary>\n    /// Note: this is an explicit implementation, so in Dynamic Razor it won't work. This is by design.\n    /// </summary>\n    ITypedItem? ICmsView.Resources => _resources.Get(() => Cdf.AsItem(_view.Resources, new() { ItemIsStrict = true }));\n    private readonly GetOnce<ITypedItem?> _resources = new();\n\n    /// <inheritdoc />\n    [PrivateApi(\"Hidden in 16.04, because we want people to use the Folder. Can't remove it though, because there are many apps that already published this.\")]\n    public string Path => _path.Get(() => FigureOutPath(block.App.Path))!;\n    private readonly GetOnce<string> _path = new();\n\n    /// <summary>\n    /// Figure out the path to the view based on a root path.\n    /// </summary>\n    /// <returns></returns>\n    private string FigureOutPath(string root)\n    {\n        // Get addition, but must ensure it doesn't have a leading slash (otherwise Path.Combine treats it as a root)\n        var addition = (_view.EditionPath ?? \"\").TrimPrefixSlash();\n        var pathWithFile = System.IO.Path.Combine(root ?? \"\", addition).ForwardSlash();\n        return pathWithFile.BeforeLast(\"/\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsViewFolder.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Apps.Sys.Assets;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CmsViewFolder(CmsView cmsView, IApp app, bool shared) : AppAssetFolder\n{\n    [field: AllowNull, MaybeNull]\n    public override string Path => field ??= FigureOutPath(shared ? app.RelativePathShared : app.RelativePath).Backslash();\n\n    [field: AllowNull, MaybeNull]\n    public override string Url => field ??= FigureOutPath(shared ? app.PathShared : app.Path);\n\n    [field: AllowNull, MaybeNull]\n    public override string PhysicalPath => field ??= FigureOutPath(shared ? app.PhysicalPathShared : app.PhysicalPath).Backslash();\n\n    [field: AllowNull, MaybeNull]\n    public override string Name => field ??= new DirectoryInfo(Path).Name;\n\n    /// <summary>\n    /// Figure out the path to the view based on a root path.\n    /// </summary>\n    /// <returns></returns>\n    private string FigureOutPath(string root)\n    {\n        // Get addition, but must ensure it doesn't have a leading slash (otherwise Path.Combine treats it as a root)\n        var addition = (cmsView.GetContents()?.EditionPath ?? \"\").TrimPrefixSlash();\n        var pathWithFile = System.IO.Path.Combine(root ?? \"\", addition).ForwardSlash();\n        return pathWithFile.BeforeLast(\"/\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.CmsContext/CmsView_TSettings_TResources.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Context.Sys.CmsContext;\n\n/// <summary>\n/// \n/// </summary>\n/// <typeparam name=\"TSettings\"></typeparam>\n/// <typeparam name=\"TResources\"></typeparam>\n/// <param name=\"cmsContext\"></param>\n/// <param name=\"block\"></param>\n/// <param name=\"settingsPropsRequired\">\n/// Problem: in v16/17 we forgot to make propsRequired for Setting be true.\n/// So they were `false` - and the Content App used such settings which didn't exist! :(\n/// So for now we need to keep this as `true` - but we should change it back to `false` in\n/// the next base class update, probably v18.\n/// </param>\ninternal class CmsView<TSettings, TResources>(CmsContext cmsContext, IBlock block, bool settingsPropsRequired = true)\n    : CmsView(cmsContext, block), ICmsView<TSettings, TResources>\n    where TSettings : class, IModelFromData, new()\n    where TResources : class, IModelFromData, new()\n{\n    private readonly IView _view = block.View!;\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= CmsContext.ExCtx.GetCdf();\n\n    public TSettings? Settings => _settings.Get(() => Cdf.AsCustom<TSettings>(Cdf.AsItem(_view.Settings, new() { ItemIsStrict = settingsPropsRequired })));\n    private readonly GetOnce<TSettings?> _settings = new();\n\n    public TResources? Resources => _resources.Get(() => Cdf.AsCustom<TResources>(_view.Resources));\n    private readonly GetOnce<TResources?> _resources = new();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.Module/ModuleUnknown.cs",
    "content": "﻿using ToSic.Eav.Sys;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Context.Sys.Module;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ModuleUnknown: IModule, IIsUnknown\n{\n    // ReSharper disable once UnusedParameter.Local\n    public ModuleUnknown(WarnUseOfUnknown<ModuleUnknown> _) { }\n\n    /// <summary>\n    /// Dummy init, don't do anything\n    /// </summary>\n    /// <param name=\"id\"></param>\n    /// <returns></returns>\n    public IModule Init(int id) => this;\n\n    public int Id => EavConstants.NullId;\n    public bool IsContent => true;\n\n    public IBlockIdentifier BlockIdentifier =>\n        new BlockIdentifier(EavConstants.NullId, EavConstants.NullId, EavConstants.NullNameId, Guid.Empty, Guid.Empty);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.Module/Module_T.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Context.Sys.Module;\n\n/// <summary>\n/// A base implementation of the block information wrapping the CMS specific object along with it.\n/// </summary>\n/// <typeparam name=\"T\"></typeparam>\n[PrivateApi(\"this is just fyi\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class Module<T>(string logName, object[]? connect = null) : ServiceBase(logName, connect: connect), IModule, IWrapper<T>\n    where T : class\n{\n    #region Constructors and DI\n\n    public T GetContents() => UnwrappedModule;\n    [PrivateApi] protected T UnwrappedModule = null!;\n\n    public IModule Init(T item)\n    {\n        UnwrappedModule = item;\n        return this;\n    }\n\n    public abstract IModule Init(int id);\n    #endregion\n\n    /// <inheritdoc />\n    public abstract int Id { get; }\n\n    /// <inheritdoc />\n    public abstract bool IsContent { get; }\n\n    /// <inheritdoc />\n    public abstract IBlockIdentifier BlockIdentifier { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.Page/Page.cs",
    "content": "﻿using ToSic.Eav.Sys;\nusing ToSic.Sxc.Web.Sys.Http;\nusing ToSic.Sxc.Web.Sys.Parameters;\n\nnamespace ToSic.Sxc.Context.Sys.Page;\n\n/// <summary>\n/// Constructor for DI\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class Page(LazySvc<IHttp> httpLazy) : IPage\n{\n    public IPage Init(int id)\n    {\n        Id = id;\n        return this;\n    }\n\n    public int Id { get; private set; } = EavConstants.NullId;\n\n    [field: AllowNull, MaybeNull]\n    public virtual IParameters Parameters => field ??= new Parameters { Nvc = OriginalParameters.GetOverrideParams(httpLazy.Value?.QueryStringParams!) };\n\n\n    public string Url { get; set; } = EavConstants.UrlNotInitialized;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.Page/PageUnknown.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Context.Sys.Page;\n\ninternal class PageUnknown(WarnUseOfUnknown<PageUnknown> _) : IPage, IIsUnknown\n{\n    public IPage Init(int id)\n    {\n        Id = id;\n        return this;\n    }\n        \n    public int Id { get; private set; } = EavConstants.NullId;\n\n    public string Url => EavConstants.UrlNotInitialized;\n\n    public IParameters Parameters => new Parameters();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.Platform/Platform.cs",
    "content": "﻿namespace ToSic.Sxc.Context.Sys.Platform;\n\n/// <summary>\n/// General platform information\n/// </summary>\n/// <remarks>\n/// This must be provided through Dependency Injection, Singleton, as it cannot change at runtime.\n/// </remarks>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class Platform: IPlatform\n{\n\n    /// <summary>\n    /// The platform type Id from the enumerator - so stored as an int.\n    /// </summary>\n    public abstract PlatformType Type { get; }\n\n    /// <summary>\n    /// A nice name ID, like \"Dnn\" or \"Oqtane\"\n    /// </summary>\n    public string Name => Type.ToString();\n\n    public abstract Version Version { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Context/Sys.Platform/PlatformUnknown.cs",
    "content": "﻿namespace ToSic.Sxc.Context.Sys.Platform;\n\ninternal class PlatformUnknown: Platform, IIsUnknown\n{\n    public PlatformUnknown(WarnUseOfUnknown<PlatformUnknown> _) { }\n    public override PlatformType Type => PlatformType.Unknown;\n\n    public override Version Version => new(0, 0, 0);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Build.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Context.Sys.CmsContext;\nusing ToSic.Sxc.Data.Sys.DynamicJacket;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.InfoSystem;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\n// todo: make internal once we have an interface\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class CodeDataFactory(\n    IServiceProvider serviceProvider,\n    LazySvc<CodeDataServices> codeDataServices,\n    LazySvc<AdamManager> adamManager,\n    LazySvc<IContextOfApp> contextOfAppLazy,\n    LazySvc<DataAssembler> dataBuilderLazy,\n    LazySvc<ContentTypeTypeAssembler> contentTypeAssembler,\n    LazySvc<ICodeDataPoCoWrapperService> codeDataWrapper,\n    Generator<CodeJsonWrapper> wrapJsonGenerator,\n    LazySvc<CodeInfoService> codeInfoSvc,\n    LazySvc<IZoneMapper> zoneMapper)\n    : ServiceWithContext(\"Sxc.AsConv\",\n        connect: [/* never: serviceProvider */codeDataServices, adamManager, contextOfAppLazy, dataBuilderLazy, contentTypeAssembler, codeDataWrapper, wrapJsonGenerator, codeInfoSvc, zoneMapper]),\n        ICodeDataFactory\n{\n    public CodeInfoService CodeInfo => codeInfoSvc.Value;\n\n    public void SetFallbacks(ISite site, int? compatibility = default, object? adamManagerPrepared = default)\n    {\n        _siteOrNull = site;\n        _compatibilityLevel = compatibility ?? _compatibilityLevel;\n\n        // Handle Adam Manager - passed in as an object so that the Type doesn't have to exist at top level definition\n        // but if we get it, we must really make sure it's the correct type\n        if (adamManagerPrepared is null)\n            return;\n        if (adamManagerPrepared is AdamManager adamManagerTyped)\n            AdamManager = adamManagerTyped;\n        else\n            throw new($\"The {nameof(adamManager)} must be of type {nameof(AdamManager)}\");\n    }\n    private ISite? _siteOrNull;\n\n    [field: AllowNull, MaybeNull]\n    private ISite SiteFromContextOrFallback => field \n        ??= (ExCtxOrNull?.GetCmsContext() as CmsContext)?.CtxSite.Site\n            ?? _siteOrNull\n            ?? throw new(\"Tried getting site from context or fallback, neither returned anything useful. \");\n\n    #region Compatibility Level\n\n    public void SetCompatibilityLevel(int compatibilityLevel)\n        => _compatibilityLevelOverride = compatibilityLevel;\n\n    public int CompatibilityLevel => _compatibilityLevelOverride ?? _compatibilityLevel;\n    private int? _compatibilityLevelOverride;\n    private int _compatibilityLevel = CompatibilityLevels.CompatibilityLevel10;\n\n    #endregion\n\n    #region CodeDataServices\n\n    public CodeDataServices Services => _services.Get(() => \n    {\n        var cds = codeDataServices.Value;\n        // if the render service is ever needed, it should be connected to the root\n        //cds.RenderServiceGenerator.SetInit(nowRs => (nowRs as INeedsCodeApiService)?.ConnectToRoot(_CodeApiSvc));\n        return cds;\n    })!;\n    private readonly GetOnce<CodeDataServices> _services = new();\n\n    /// <summary>\n    /// List of dimensions for value lookup, incl. priorities etc. and null-trailing.\n    /// lower case safe guaranteed. \n    /// </summary>\n    // If we don't have a DynCodeRoot, try to generate the language codes and compatibility\n    // There are cases where these were supplied using SetFallbacks, but in some cases none of this is known\n    [field: AllowNull, MaybeNull]\n    public string?[] Dimensions => field ??=\n        // note: can't use SiteFromContextOrFallback.SafeLanguagePriorityCodes() because it will error during testing\n        (ExCtxOrNull?.GetCmsContext() as CmsContext)?.CtxSite.Site.SafeLanguagePriorityCodes()\n        ?? _siteOrNull.SafeLanguagePriorityCodes();\n\n\n    public IBlock? BlockOrNull => ExCtxOrNull?.GetBlock();\n\n    #endregion\n\n    public object? Json2Jacket(string? json, string? fallback = default)\n        => wrapJsonGenerator.New().Setup(WrapperSettings.Dyn(true, true))\n            .Json2Jacket(json, fallback: fallback);\n\n    /// <summary>\n    /// WIP, we need this in the GetAndConvertHelper, and want to make sure it's not executed on every entity used,\n    /// so for now we're doing this once only here.\n    /// </summary>\n    /// <remarks>\n    /// IMPORTANT: LOWER-CASE guaranteed.\n    /// </remarks>\n    [field: AllowNull, MaybeNull]\n    public List<string> SiteCultures => field\n        ??= zoneMapper.Value\n                .CulturesEnabledWithState(SiteFromContextOrFallback)?\n                .Select(c => c.Code.ToLowerInvariant())\n                .ToList()\n            ?? [];\n\n    /// <summary>\n    /// Special service provider for Data objects. Use with caution and as little as possible!\n    ///\n    /// Important: this will auto-attach to the root CodeApiSvc and get the context as well, which is important for render services etc.!\n    /// </summary>\n    /// <typeparam name=\"TService\"></typeparam>\n    /// <returns></returns>\n    public TService GetService<TService>() where TService : class\n        => ExCtxOrNull?.GetService<TService>() ?? serviceProvider.Build<TService>();\n    \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_Adam.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys.Cms;\nusing ToSic.Sxc.Services.Tweaks;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory\n{\n    [field: AllowNull, MaybeNull]\n    public AdamManager AdamManager\n    {\n        get => field ??= GetAdamManager();\n        private set;\n    }\n\n    /// <summary>\n    /// Special helper - if the DynamicCode is generated by the service or used in a WebApi there is no block, but we can figure out the context.\n    /// </summary>\n    /// <returns></returns>\n    /// <exception cref=\"Exception\"></exception>\n    private AdamManager GetAdamManager()\n    {\n        // If we don't even have a _DynCodeRoot (like when exporting from a neutral WebAPI)\n        if (ExCtxOrNull is null)\n            throw new($\"Can't create App Context for {nameof(AdamManager)} in {nameof(ICodeDataFactory)} - no block, no App\");\n\n        IContextOfApp contextOfApp = ExCtx.GetContextOfBlock();\n        // TODO: @2dm - find out / document why this could even be null\n        if (contextOfApp == null)\n        {\n            var app = ExCtx.GetApp();\n            if (app == null)\n                throw new(\"Can't create App Context for ADAM - no block, no App\");\n            contextOfApp = contextOfAppLazy.Value;\n            contextOfApp.ResetApp(app);\n        }\n\n        return adamManager.Value.Init(contextOfApp, CompatibilityLevel, this);\n    }\n    #region ADAM / Folder\n\n    public IFile File(int id)\n        => AdamManager.AdamFs.GetFile(AdamAssetIdentifier.Create(id));\n\n    private ExecutionContext ExCtxReal => (ExCtxOrNull as ExecutionContext)!;\n\n    [field: AllowNull, MaybeNull]\n    private ServiceKit16 ServiceKit16 => field ??= ExCtxReal.GetKit<ServiceKit16>();\n\n    // TODO: MUST FINISH THIS, NOT WORKING YET\n    public IFile? File(IField field)\n        => ServiceKit16.Adam.File(field);\n\n    public IFolder Folder(int id)\n        => AdamManager.AdamFs.GetFolder(AdamAssetIdentifier.Create(id));\n\n    public IFolder Folder(ICanBeEntity item, string name, IField? field)\n        => AdamManager.FolderOfField(item.Entity.EntityGuid, name, field);\n\n    public IFolder Folder(Guid entityGuid, string fieldName, IField? field = default)\n        => AdamManager.FolderOfField(entityGuid, fieldName, field);\n\n    [field: AllowNull, MaybeNull]\n    private ICmsService CmsSvc => field ??= ExCtxReal.GetService<ICmsService>(reuse: true);\n\n    // TODO: MUST FINISH THIS, NOT WORKING YET\n    public IHtmlTag Html(\n        object thing,\n        NoParamOrder npo = default,\n        object? container = default,\n        string? classes = default,\n        bool debug = default,\n        object? imageSettings = default,\n        bool? toolbar = default,\n        Func<ITweakInput<string>, ITweakInput<string>>? tweak = default)\n        => CmsSvc.Html(\n            thing,\n            npo: npo,\n            container: container,\n            classes: classes,\n            debug: debug,\n            imageSettings: imageSettings,\n            toolbar: toolbar,\n            tweak: tweak\n        );\n\n    [field: AllowNull, MaybeNull]\n    private IImageService ImgSvc => field ??= ExCtxReal.GetService<IImageService>(reuse: true);\n\n\n    public IResponsivePicture Picture(\n        object? link = null,\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        string? pictureClass = default,\n        object? pictureAttributes = default,\n        object? toolbar = default,\n        object? recipe = default\n    ) => ImgSvc.Picture(link, settings, npo, tweak, factor, width, imgAlt, imgAltFallback, imgClass,\n        imgAttributes, pictureClass, pictureAttributes, toolbar, recipe);\n\n    public IResponsiveImage Img(\n        object? link = null,\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        object? toolbar = default,\n        object? recipe = default\n    )\n        => ImgSvc.Img(link, settings, npo, tweak, factor, width, imgAlt, imgAltFallback, imgClass,\n            imgAttributes, toolbar, recipe);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_AsCustom.cs",
    "content": "﻿using System.Collections;\nusing Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Models;\nusing ToSic.Eav.Models.Factory;\nusing ToSic.Eav.Models.Sys;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory: IModelFactory\n{\n    public TModel? Create<TSource, TModel>(TSource? source)\n        where TModel : IModelFromEntity\n    {\n        var wrapper = serviceProvider.Build<TModel>();\n        var ok = (wrapper as IModelSetup<TSource>)?.SetupModel(source) ?? false;\n        return ok ? wrapper : default;\n    }\n\n    /// <summary>\n    /// Convert an object to a custom type, if possible.\n    /// If the object is an entity-like thing, that will be converted.\n    /// If it's a list of entity-like things, the first one will be converted.\n    /// </summary>\n    [return: NotNullIfNotNull(nameof(source))]\n    public TCustom? AsCustom<TCustom>(object? source, NoParamOrder npo = default, bool mock = false)\n        where TCustom : class, IModelFromData\n    {\n        var settings = new ModelSettings { ItemIsStrict = true, UseMock = mock };\n        return source switch\n        {\n            null when !mock => null,\n            TCustom alreadyT => alreadyT,\n            IEntity entity => AsCustomFrom<TCustom, ITypedItem>(AsItem(entity, settings), settings),\n            _ => AsCustomFrom<TCustom, ITypedItem>(source as ITypedItem ?? AsItem(source, settings), settings)\n        };\n    }\n\n    [return: NotNullIfNotNull(\"item\")]\n    public TCustom? AsCustomFrom<TCustom, TData>(TData? item, ModelSettings? settings)\n        where TCustom : class, IModelFromData\n    {\n        if (item == null)\n            return null;\n        if (item is TCustom t)\n            return t;\n\n        var bestType = ModelAnalyseUse.GetTargetType<TCustom>();\n        var newT = ActivatorUtilities.CreateInstance(serviceProvider, bestType) as TCustom;\n\n        switch (newT)\n        {\n            // 1. Direct setup from the data type specified, no further conversions\n            // Should be an ITypedItemWrapper, but not enforced in the signature\n            case IModelSetupWithFactory<TData> withMatchingSetup:\n                withMatchingSetup.Setup(item, this);\n                return newT;\n\n            // 2. Setup from Item, a more complex object which already has more features\n            // In some cases the type of the data is already a model, so we need to unwrap it\n            case IModelSetupWithFactory<ITypedItem> forItem when item is ICanBeItem canBeItem:\n                forItem.Setup(canBeItem.Item, this);\n                return newT;\n\n            // 3. Setup from Entity, the most basic object\n            // DataModelOfEntity can also be filled from Typed (but ATM not the other way around)\n            case IModelSetupWithFactory<IEntity> forEntity when item is ICanBeEntity canBeEntity:\n                forEntity.Setup(canBeEntity.Entity, this);\n                return newT;\n\n            // 4. Setup from item, when starting with an entity\n            // In some cases we can only wrap an item, but the data is an entity-based model\n            case IModelSetupWithFactory<ITypedItem> forTypedItem when item is ICanBeEntity canBeEntity:\n                settings ??= new() { ItemIsStrict = true };\n                var asItem = AsItem(canBeEntity.Entity, settings);\n                // TODO: #ConvertItemSettings\n                forTypedItem.Setup(asItem, this);\n                return newT;\n\n            case IModelSetup<IEntity> forEntitySetup when item is ICanBeEntity canBeEntity:\n                forEntitySetup.Setup(canBeEntity.Entity);\n                return newT;\n\n            default:\n                throw new($\"The custom type {typeof(TCustom).Name} does not implement 'ICanWrap<TData>'. This is probably a mistake.\");\n        }\n    }\n\n    public TCustom? GetOne<TCustom>(Func<IEntity?> getItem, object id, bool skipTypeCheck)\n        where TCustom : class, IModelFromData\n    {\n        var item = getItem();\n        if (item == null)\n            return null;\n\n        // Skip Type-Name check\n        if (skipTypeCheck)\n            return AsCustom<TCustom>(item);\n\n        // Check all type names if they are `*` or match the data ContentType\n        DataModelAnalyzer.IsTypeNameAllowedOrThrow(typeof(TCustom), item, id, skipTypeCheck);\n        return AsCustom<TCustom>(item);\n    }\n\n    /// <summary>\n    /// Create list of custom-typed ITypedItems\n    /// </summary>\n    public IEnumerable<TCustom> AsCustomList<TCustom>(object? source, NoParamOrder npo, bool nullIfNull)\n        where TCustom : class, IModelFromData\n    {\n        return source switch\n        {\n            // Note: for simplicity, the interface always claims to be non-null, since it will only ever be null if clearly demanded\n            null => nullIfNull\n                ? null!\n                : new List<TCustom>(),\n            IEnumerable<TCustom> alreadyListT => alreadyListT,\n            // special case: empty list, with hidden info about where it's from so the toolbar can adjust and provide new-buttons\n            ListTypedItems<ITypedItem> { Count: 0, Entity: not null } list => new ListTypedItems<TCustom>(new List<TCustom>(), list.Entity),\n            _ => new ListTypedItems<TCustom>(SafeItems()\n                    .Select(item => AsCustomFrom<TCustom, ITypedItem>(item, new() { ItemIsStrict = true })),\n                null\n            )\n        };\n\n        // Helper function to be called from above to ensure that\n        // the source is a list of ITypedItems\n        IEnumerable<ITypedItem> SafeItems()\n            => source switch\n            {\n                null => [],\n                IEnumerable enumerable when !enumerable.Cast<object>().Any() => [],\n                IEnumerable<ITypedItem> alreadyOk => alreadyOk,\n                // TODO: #ConvertItemSettings - NOT SURE IF THIS DEFAULT IS CORRECT\n                _ => AsItems(source, new() { ItemIsStrict = false })\n            };\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_AsTypedPure.cs",
    "content": "﻿using System.Collections;\nusing ToSic.Eav.Models.Sys;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory\n{\n    private const string NameOfAsTyped = /*nameof(IDynamicCode16.AsTyped)*/ \"AsTyped\" + \"(...)\";\n\n    public ITyped? AsTyped(object data, ModelSettings settings, string? detailsMessage = default)\n    {\n        var l = Log.Fn<ITyped>();\n\n        if (AsTypedPreflightReturnNull(data, NameOfAsTyped, settings.EntryPropIsRequired, detailsMessage))\n            return l.ReturnNull();\n\n        if (data is ITyped alreadyTyped)\n            return l.Return(alreadyTyped, \"already typed\");\n\n        var result = codeDataWrapper.Value.ChildNonJsonWrapIfPossible(data: data, wrapNonAnon: true,\n            WrapperSettings.Typed(children: true, realObjectsToo: false, propsRequired: settings.ItemIsStrict));\n        if (result is ITyped resTyped)\n            return l.Return(resTyped, \"converted to dyn-read\");\n\n        throw l.Done(new ArgumentException($\"Can't wrap/convert the original '{data.GetType()}'\"));\n    }\n\n    private const string NameOfAsTypedList = /*nameof(IDynamicCode16.AsTypedList)*/ \"AsTypedList\" + \"(...)\";\n    public IEnumerable<ITyped>? AsTypedList(object list, ModelSettings settings)\n    {\n        var l = Log.Fn<IEnumerable<ITyped>>();\n\n        if (AsTypedPreflightReturnNull(list, NameOfAsTypedList, settings.EntryPropIsRequired))\n            return l.ReturnNull();\n\n        if (list is IEnumerable<ITyped> alreadyTyped)\n            return l.Return(alreadyTyped, \"already typed\");\n\n        if (list is not IEnumerable enumerable)\n            throw new ArgumentException($\"The object provided to {NameOfAsTypedList} is not enumerable/array so it can't be converted.\", nameof(list));\n\n        //var subSettings = new ConvertItemSettings { FirstIsRequired = required, ItemIsStrict = propsRequired ?? true };\n        var result = enumerable\n            .Cast<object>()\n            .Select((o, i) => AsTyped(o, settings, $\"index: {i}\")!)\n            .Where(o => o != null) // filter out nulls, as this is the default behavior\n            .ToList();\n\n        return result;\n    }\n\n    private bool AsTypedPreflightReturnNull(object original, string methodName, bool required, string? detailsMessage = default)\n    {\n        var l = Log.Fn<bool>();\n        switch (original)\n        {\n            case null:\n                return required \n                    ? throw l.Done(new ArgumentException($\"Tried to convert using {methodName} but got null, with {nameof(required)} = {required}. {detailsMessage}\"))\n                    : l.ReturnTrue();\n            case string _:\n                throw l.Done(new ArgumentException($\"Tried to convert using {methodName} but got a string.\" +\n                                                   $\"If you want to convert a string JSON to an easier-to-use object, use Kit.Json.ToTyped(...) instead. {detailsMessage}\"));\n            case ICanBeEntity _:\n                throw l.Done(new ArgumentException(\n                    $\"Tried to convert using {methodName} but got an entity-like object.\" +\n                    $\"If you want to convert an Entity-Like object, use AsItem(...) instead. {detailsMessage}\"));\n            default:\n                // Check value types - note that it won't catch strings, but these were handled above\n                if (original.GetType().IsValueType)\n                    throw l.Done(new ArgumentException(\n                        $\"Tried to convert using {methodName} but got value type: '{original.GetType()}'. This can't be converted. {detailsMessage}\"));\n\n                return l.ReturnFalse();\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_Dynamic.cs",
    "content": "﻿using System.Dynamic;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.Models.Sys;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory: ICodeDataFactoryDeepWip\n{\n\n    #region Dynamic\n\n    /// <summary>\n    /// Implement AsDynamic for DynamicCode - not to be used in internal APIs.\n    /// Always assumes Strict is false\n    /// </summary>\n    /// <param name=\"entity\"></param>\n    /// <returns></returns>\n    public IDynamicEntity CodeAsDyn(IEntity entity)\n        => new DynamicEntity(entity, this, propsRequired: false);\n\n    public IDynamicEntity AsDynamic(IEntity entity, ModelSettings settings)\n        => new DynamicEntity(entity, this, propsRequired: settings.ItemIsStrict);\n\n    /// <summary>\n    /// Convert a list of Entities into a DynamicEntity.\n    /// Only used in DynamicCodeRoot.\n    /// </summary>\n    public IDynamicEntity AsDynamicFromEntities(IEnumerable<IEntity> list, ModelSettings settings, NoParamOrder npo = default, IEntity? parent = default, string? field = default) \n        => new DynamicEntity(list: list, parent: parent, field: field, appIdOrNull: null, propsRequired: settings.ItemIsStrict, cdf: this);\n\n    /// <summary>\n    /// Convert any object into a dynamic list.\n    /// Only used in Dynamic Code for the public API.\n    /// </summary>\n    public IEnumerable<dynamic> CodeAsDynList(object list) //, bool propsRequired = false)\n    {\n        var settings = new ModelSettings() { ItemIsStrict = false };\n        return list switch\n        {\n            null => new List<dynamic>(),\n            IDataSource dsEntities => CodeAsDynList(dsEntities.List),\n            IEnumerable<IEntity> iEntities =>\n                iEntities.Select(e => AsDynamic(e, settings)),\n            IEnumerable<IDynamicEntity> dynIDynEnt => dynIDynEnt,\n            IEnumerable<dynamic> dynEntities => dynEntities,\n            _ => throw new($\"Error trying to convert object into a dynamic list; object type unknown\"),\n        };\n    }\n\n\n    /// <summary>\n    /// Convert any object into a dynamic object.\n    /// Only used in Dynamic Code for the public API.\n    /// </summary>\n    public object? AsDynamicFromObject(object dynObject)\n    {\n        var l = Log.Fn<object?>();\n        //var typed = AsTypedInternal(dynObject);\n        //if (typed != null) return l.Return(typed, nameof(ITypedRead));\n\n        switch (dynObject)\n        {\n            case null:\n                return l.Return(Json2Jacket(null), \"null\");\n            case string strObject:\n                return l.Return(Json2Jacket(strObject), \"string\");\n            case IDynamicEntity dynEnt:\n                return l.Return(dynEnt, \"DynamicEntity\");\n            // New case - should avoid re-converting dynamic json, DynamicStack etc.\n            case ISxcDynamicObject sxcDyn:\n                return l.Return(sxcDyn, \"Dynamic Something\");\n            case IEntity entity:\n                return l.Return(new DynamicEntity(entity, this, propsRequired: false), \"IEntity\");\n            case DynamicObject typedDynObject:\n                return l.Return(typedDynObject, \"DynamicObject\");\n            default:\n                // Check value types - note that it won't catch strings, but these were handled above\n                if (dynObject.GetType().IsValueType) return l.Return(dynObject, \"bad call - value type\");\n\n                // 2021-09-14 new - just convert to a DynamicReadObject\n                var result = codeDataWrapper.Value.ChildNonJsonWrapIfPossible(data: dynObject,\n                    // 2023-08-08 2dm - changed `wrapNonAnon` to true, I'm not sure why it was false, but I'm certain that's wrong\n                    wrapNonAnon: true /* false, */,\n                    WrapperSettings.Dyn(children: true, realObjectsToo: false));\n                if (result is not null) return l.Return(result, \"converted to dyn-read\");\n\n                // Note 2dm 2021-09-14 returning the original object was actually the default till now.\n                // Unknown conversion, just return the original and see what happens/breaks\n                // probably not a good solution\n                return l.Return(dynObject, \"unknown, return original\");\n        }\n    }\n\n    #endregion\n\n\n    #region Merge Dynamic\n\n    public dynamic? MergeDynamic(object[]? entities) =>\n        entities == null || !entities.Any()\n            ? null\n            : AsStack(null, entities, strictTypes: false, AsDynStack);\n\n    #endregion\n\n    // 2026-05-13 2dm - not sure if AppReaderRequired is correct, but I assume that if we do have a context,\n    // then it must have an AppReader, so we can use it.\n    public IAppReader? AppReaderOrNull => BlockOrNull?.Context?.AppReaderRequired;\n\n    int ICodeDataFactoryDeepWip.AppIdOrZero => BlockOrNull?.AppId ?? 0;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_Entity.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Data.Build.Sys;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory\n{\n    public IEntity AsEntity(object thingToConvert)\n        => thingToConvert == null\n            ? throw new ArgumentNullException(nameof(thingToConvert))\n            : thingToConvert as IEntity\n              ?? (thingToConvert as ICanBeEntity)?.Entity\n              ?? throw new ArgumentException($\"Tried to convert an object to {nameof(IEntity)} but cannot convert a {thingToConvert.GetType()}\");\n\n    public IEntity FakeEntity(int appId) => dataBuilderLazy.Value.FakeEntity(contentTypeAssembler.Value, appId);\n\n    public IEntity PlaceHolderInBlock(int? appIdOrNull, IEntity? parent, string? fieldName)\n    {\n        var dummyEntity = FakeEntity(appIdOrNull ?? parent?.AppId ?? 0);\n        return parent == null\n            ? dummyEntity\n            : EntityInBlockDecorator.Wrap(entity: dummyEntity, fieldName: fieldName, parent: parent);\n    }\n\n    /// <summary>\n    /// Creates an empty list of a specific type, with hidden information to remember what field this is etc.\n    /// </summary>\n    /// <typeparam name=\"TTypedItem\"></typeparam>\n    /// <param name=\"parent\"></param>\n    /// <param name=\"field\"></param>\n    /// <returns></returns>\n    public IEnumerable<TTypedItem> CreateEmptyChildList<TTypedItem>(IEntity parent, string field) where TTypedItem : class, ITypedItem\n    {\n        // Generate a marker/placeholder to remember what field this is etc.\n        var fakeEntity = PlaceHolderInBlock(parent.AppId, parent, field);\n        return new ListTypedItems<TTypedItem>(new List<TTypedItem>(), fakeEntity);\n    }\n\n\n    #region Publishing\n    private IAppReader AppReader => field ??= ExCtx.GetState<IAppReader>();\n\n    public IEntity? GetDraft(IEntity entity) => AppReader.GetDraft(entity);\n\n    public IEntity? GetPublished(IEntity entity) => AppReader.GetPublished(entity);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_Field.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Eav.Models.Sys;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Data.Sys.Fields;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory\n{\n    public IField? Field(ITypedItem parent, bool supportOldMetadata, string? name, ModelSettings settings)\n    {\n        if (name.IsEmptyOrWs())\n        {\n            if (!settings.EntryPropIsRequired)\n                return null; // name is optional, so no error\n            throw new ArgumentNullException(nameof(name), @\"Field name must not be null or empty.\");\n        }\n\n        // Make sure that if we use a path, the field is from the correct parent\n        var dot = PropertyStack.PathSeparator.ToString();\n        if (name.Contains(dot))\n        {\n            var parentPath = name.BeforeLast(dot);\n            var field = name.AfterLast(dot);\n            var newParent = parent.Child(parentPath);\n            if (newParent == null)\n                throw new NullReferenceException(\n                    $\"Tried to get the child object the path '{name}' (would be '{parentPath}') but got null.\" +\n                    $\" Can't return the field '{field}' of this null object.\");\n            return newParent.Field(field, required: settings.ItemIsStrict);\n        }\n\n        return IsErrStrictNameRequired(parent, name, settings.EntryPropIsRequired, settings.ItemIsStrict)\n            ? throw ErrStrictForTyped(parent, name)\n            : supportOldMetadata\n                ? new FieldForDynamic(parent, name, this)\n                : new Fields.Field(parent, name, this);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_Metadata.cs",
    "content": "﻿using ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory\n{\n    public object MetadataDynamic(IMetadata mdOf)\n        => new Metadata.MetadataDynamic(mdOf, this);\n\n    public ITypedMetadata MetadataTyped(IMetadata mdOf)\n        => new Metadata.Metadata(mdOf, this);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_Stack.cs",
    "content": "﻿using System.Collections;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Models;\nusing ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory\n{\n    [PrivateApi]\n    public ITypedStack AsStack(object[] parts)\n        => AsStack(null, parts, strictTypes: true, AsTypedStack);\n\n    [PrivateApi]\n    public T AsStack<T>(object[] parts)\n        where T : class, IModelFromData, new() \n        => AsCustom<T>(AsStack(parts));\n\n    private TStackType AsStack<TStackType>(string? name, object[] parts, bool strictTypes, Func<string, List<KeyValuePair<string, IPropertyLookup>>, TStackType> generate)\n    {\n        name ??= EavConstants.NullNameId;\n        var l = Log.Fn<TStackType>($\"'{name}', {parts?.Length}\");\n\n        // Error if nothing\n        if (parts == null || !parts.SafeAny())\n            throw l.Ex(new ArgumentNullException(nameof(parts)));\n\n        // Return if already correct (this is just to type-cast the object from dynamic code)\n        if (parts.Length == 1 && parts[0] is TStackType alreadyStack)\n            return alreadyStack;\n            \n        // Filter out unexpected\n        var cleaned = parts\n            .Select((original, index) =>\n            {\n                var lookup = GetPropertyLookupOrNull(original)\n                             // This should cover the case where it's a list<ITypedItem> or similar\n                             ?? (original is IEnumerable maybePlEnum\n                                 ? GetPropertyLookupOrNull(maybePlEnum\n                                     .Cast<object>()\n                                     .FirstOrDefault(mpl => mpl is IHasPropLookup or IPropertyLookup)\n                                 )\n                                 : null);\n                return new { index, original, lookup };\n            })\n            .Where(s => s.original is not null)\n            .ToList();\n\n        // If strict (new implementation for typed) throw error if unexpected data arrived\n        if (strictTypes)\n        {\n            var unexpected = cleaned\n                .Where(s => s.lookup is null)\n                .ToList();\n            if (unexpected.Any())\n            {\n                var names = string.Join(\", \", unexpected.Select(s => s.index + \":\" + s.original.GetType()));\n                throw l.Ex(new ArgumentException($\"Tried to do {nameof(AsStack)} but got some objects are not {nameof(IPropertyLookup)}/{nameof(IHasPropLookup)}. Index/Type: {names}\"));\n            }\n        }\n\n        // Must create a stack\n        var sources = cleaned\n            .Where(s => s.lookup != null)\n            .Select(s => new KeyValuePair<string, IPropertyLookup>($\"lookup-{s.index}\", s.lookup!))\n            .ToList();\n        return l.ReturnAsOk(generate(name, sources));\n    }\n\n    private static IPropertyLookup? GetPropertyLookupOrNull(object? original)\n        => original switch\n        {\n            IPropertyLookup pl => pl,\n            IHasPropLookup hasPl => hasPl.PropertyLookup,\n            _ => null\n        };\n\n    public IDynamicStack AsDynStack(string name, List<KeyValuePair<string, IPropertyLookup>> sources)\n        => new DynamicStack.DynamicStack(name, this, sources);\n\n    public ITypedStack AsTypedStack(string name, List<KeyValuePair<string, IPropertyLookup>> sources)\n        => new TypedStack.TypedStack(name, this, sources);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/CodeDataFactory_TypedItem.cs",
    "content": "﻿using System.Collections;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.Models.Sys;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.CodeDataFactory;\n\npartial class CodeDataFactory\n{\n    public const int MaxRecursions = 3;\n\n    #region AsTyped Implementations\n\n    [return: NotNullIfNotNull(nameof(data)), NotNullIfNotNull(nameof(fallback))]\n    public ITypedItem? AsItem(object? data, ModelSettings settings, NoParamOrder npo = default, ITypedItem? fallback = default)\n    {\n        // If we need mock data, return a fake object\n        if (settings.UseMock)\n            return codeDataWrapper.Value.TypedItemFromObject(data,\n                WrapperSettings.Typed(true, true, settings.ItemIsStrict),\n                new LazyLike<ICodeDataFactory>(this));\n\n        return AsItemInternal(data, settings, MaxRecursions)\n               ?? fallback;\n    }\n\n    /// <summary>\n    /// Quick convert an entity to item - if not null, otherwise return null.\n    /// </summary>\n    /// <returns></returns>\n    [return: NotNullIfNotNull(nameof(entity))]\n    public ITypedItem? AsItem(IEntity? entity, ModelSettings settings)\n        => entity == null\n            ? null\n            : new TypedItemOfEntity(entity, this, propsRequired: settings.ItemIsStrict);\n\n    [field: AllowNull, MaybeNull]\n    private LogFilter AsItemLogFilter\n        => field ??= new(Log, logFirstMax: 25, reLogIteration: 100);\n\n    [return: NotNullIfNotNull(nameof(data))]\n    internal ITypedItem? AsItemInternal(object? data, ModelSettings settings, int recursions)\n    {\n        // Only log the first 25 calls to this method, then stop logging\n        var l = AsItemLogFilter.FnOrNull<ITypedItem?>();\n\n        if (recursions <= 0)\n            throw l.Done(new Exception($\"Conversion with {nameof(AsItem)} failed, max recursions reached\"));\n\n        switch (data)\n        {\n            case null:\n                return l.ReturnNull(\"null\");\n            case string:\n                throw l.Done(new ArgumentException($\"Type '{data.GetType()}' cannot be converted to {nameof(ITypedItem)}\"));\n            case ITypedItem alreadyItem:\n                return ToItemOrNullAndLog(alreadyItem.Entity, nameof(ITypedItem));\n            case IEntity entity:\n                return ToItemOrNullAndLog(entity, nameof(IEntity));\n            // Dynamic Entity is also an ICanBeEntity\n            //case IDynamicEntity dynEnt:\n            //    return l.Return(new TypedItem(dynEnt), nameof(IDynamicEntity));\n            case ICanBeEntity canBeEntity:\n                return ToItemOrNullAndLog(canBeEntity.Entity, nameof(ICanBeEntity));\n            case IDataSource ds:\n                return ToItemOrNullAndLog(ds.List.FirstOrDefault(), nameof(IDataSource))!;\n            case IDataStream ds:\n                return ToItemOrNullAndLog(ds.List.FirstOrDefault(), nameof(IDataStream))!;\n            case IEnumerable<IEntity> entList:\n                return ToItemOrNullAndLog(entList.FirstOrDefault(), \"IEnumerable<IEntity>\")!;\n            case IEnumerable enumerable:\n                var enumFirst = enumerable.Cast<object>().FirstOrDefault();\n                if (enumFirst is null)\n                    return l.ReturnNull($\"{nameof(IEnumerable)} with null object\")!;\n                // retry conversion\n                return l.Return(AsItemInternal(enumFirst, settings, recursions - 1));\n            default:\n                throw l.Done(new ArgumentException($\"Type '{data.GetType()}' cannot be converted to {nameof(ITypedItem)}. \" +\n                                                   $\"If you are trying to create mock/fake/fallback data, try using \\\", mock: true\\\"\"));\n        }\n\n        [return: NotNullIfNotNull(nameof(e))]\n        ITypedItem? ToItemOrNullAndLog(IEntity? e, string typeName)\n            => e == null\n                ? l.ReturnNull($\"empty {typeName}\")\n                : l.Return(new TypedItemOfEntity(e, this, propsRequired: settings.ItemIsStrict), typeName);\n    }\n\n    public IEnumerable<ITypedItem> EntitiesToItems(IEnumerable<IEntity>? entities, ModelSettings settings)\n    {\n        if (entities == null)\n            return [];\n        var result = entities\n            .Select(e => AsItem(e, settings))\n            .ToList();\n\n        if (settings.DropNullItems)\n            result = result\n                .Where(e => e != null! /* rare cases do have null */)\n                .ToList();\n\n        // Ignore that some items could contain null, since the default behavior is no-nulls\n        return result;\n    }\n\n    public IEnumerable<ITypedItem> AsItems(object list, ModelSettings settings, NoParamOrder npo = default, IEnumerable<ITypedItem>? fallback = null) \n        => AsItemList(list, fallback, MaxRecursions, settings);\n\n    private IEnumerable<ITypedItem> AsItemList(object list, IEnumerable<ITypedItem>? fallback, int recursions, ModelSettings settings)\n    {\n        var l = Log.Fn<IEnumerable<ITypedItem>>($\"{nameof(list)}: '{list}'; Settings: {settings}\");\n\n        if (recursions <= 0)\n            return FallbackOrErrorAndLog(\"max recursions\", $\"Max recursions {MaxRecursions} reached.\");\n\n        switch (list)\n        {\n            case null:\n                return FallbackOrErrorAndLog(\"null\", \"Got null.\");\n            // String check must come early because strings are enumerable\n            case string:\n                return FallbackOrErrorAndLog(\"string\", \"Got a string.\");\n            // List of ITypedItem\n            case IEnumerable<ITypedItem> alreadyOk:\n                return l.Return(alreadyOk.Select(e => AsItem(e.Entity, settings)), nameof(IEnumerable<ITypedItem>));\n            //return l.Return(alreadyOk, \"already matches type\");\n            //case IEnumerable<IDynamicEntity> dynIDynEnt:\n            //    return l.Return(dynIDynEnt.Select(e => AsTyped(e, services, MaxRecursions, log)), \"IEnum<DynEnt>\");\n            case IDataSource source:\n                return l.Return(EntitiesToItems(source.List, settings), \"DataSource - convert list\");\n            case IDataStream stream:\n                return l.Return(EntitiesToItems(stream.List, settings), \"DataStream - convert list\");\n            case IEnumerable<IEntity> entList:\n                return l.Return(EntitiesToItems(entList, settings), \"IEnumerable<IEntity>\");\n            case IEnumerable<dynamic> dynList:\n                var fromDynList = dynList.Select(e => AsItemInternal(e as object, settings, MaxRecursions));\n                if (settings.DropNullItems)\n                    fromDynList = fromDynList.Where(e => e != null!).ToListOpt();\n                return l.Return(fromDynList, \"IEnumerable<dynamic>\");\n            // Variations of single items - should be converted to list\n            // All of the commented out variants are ICanBeEntity\n            //case IEntity ent:\n            //    return l.Return(AsItemFromEntity(ent, propsRequired).ToListOfOneOrNone(), nameof(IEntity));\n            //case IDynamicEntity dynEnt:\n            //    return l.Return(AsItemFromEntity(dynEnt.Entity, propsRequired).ToListOfOneOrNone(), nameof(IDynamicEntity));\n            //case ITypedItem oneTyped:\n            //    return l.Return(AsItemFromEntity(oneTyped.Entity, propsRequired).ToListOfOneOrNone(), \"already typed\");\n            case ICanBeEntity canBeEntity:\n                var converted = AsItem(canBeEntity.Entity, settings);\n                return l.Return(converted.ToListOfOneOrNone(), nameof(ICanBeEntity) + (converted == null ? \" - null\" : \"\"));\n            // Check for IEnumerable but make sure it's not a string (so that should come before)\n            // Should come fairly late, because some things like DynamicEntities can also be enumerated\n            case IEnumerable asEnumerable:\n                return l.Return(asEnumerable.Cast<object>().Select(e => AsItemInternal(e, settings, MaxRecursions)), \"IEnumerable\");\n            default:\n                return FallbackOrErrorAndLog($\"can't convert '{list.GetType()}'\", $\"Type '{list.GetType()}' cannot be converted.\");\n\n\n        }\n\n        // Inner call to complete scenarios where the data couldn't be created\n        IEnumerable<ITypedItem> FallbackOrErrorAndLog(string fallbackMsg, string exMsg)\n            => fallback != null\n                ? l.Return(fallback, fallbackMsg + \", fallback\")\n                : settings.EntryPropIsRequired\n                    ? throw l.Done(new ArgumentException($@\"Conversion with {nameof(AsItems)} failed, {nameof(settings.EntryPropIsRequired)}=true. {exMsg}\", nameof(list)))\n                    : l.Return([], \"no fallback, not required, empty list\");\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Data.Sys.CodeDataFactory/ConvertItemSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.CodeDataFactory;\npublic record ConvertItemSettings\n{\n    public required bool ItemIsStrict { get; init; }\n    public required bool DropNullItems { get; init; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Engines.Sys.Token/LookUpForTokenTemplate.cs",
    "content": "﻿using System.Globalization;\nusing System.Text.RegularExpressions;\nusing ToSic.Eav.LookUp;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Engines.Sys.Token;\n\n/// <summary>\n/// LookUp for creating token based templates. In addition to retrieving values, it also resolves special tokens like\n/// - repeater:index\n/// - repeater:isfirst\n/// - etc.\n/// </summary>\n/// <remarks>\n/// Only use this for Token templates, do not use for normal lookups which end up in data-sources.\n/// The reason is that this tries to respect culture formatting, which will cause trouble (numbers with comma etc.) when trying to\n/// use in other systems.\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"this is just fyi\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[method: PrivateApi]\ninternal partial class LookUpForTokenTemplate(\n    string name,\n    IDynamicEntity dynEntity,\n    CultureInfo cultureInfo,\n    int repeaterIndex = -1,\n    int repeaterTotal = -1)\n    : ILookUp\n{\n    public string Name { get; } = name ?? throw new NullReferenceException(\"LookUp must have a Name\");\n\n    public string Description => \"LookUp for creating token based templates. In addition to retrieving values, it also resolves special tokens like repeater:index, repeater:isfirst, etc.\";\n\n    /// <summary>\n    /// Get Property out of NameValueCollection\n    /// </summary>\n    /// <param name=\"key\"></param>\n    /// <param name=\"strFormat\"></param>\n    /// <returns></returns>\n    private string? GetProperty(string key, string strFormat)\n    {\n\n        // As of 2025-05-13 v20 (2dm) the toolbar will only work in DNN\n        // and not in Oqtane, since the DynamicEntity.Toolbar doesn't exist there\n        // since we don't really plan to support token templates in future\n        // this is acceptable for now.\n#if NETFRAMEWORK\n        // Create Toolbar if requested, even if dynEntity is null\n        if (key == ViewConstants.FieldToolbar)\n#pragma warning disable CS0618 // Type or member is obsolete\n            return (dynEntity as ToSic.Sxc.Data.Sys.DynamicEntity)?.Toolbar.ToString();\n#pragma warning restore CS0618 // Type or member is obsolete\n        // old till 2025-05-13, changed to not depend on the ItemToolbar object\n        // return new Edit.Toolbar.ItemToolbar(dynEntity?.Entity).ToolbarAsTag;\n\n#endif\n        // Return empty string if Entity is null\n        if (dynEntity == null! || key.IsEmptyOrWs())\n            return \"\";\n\n        // If we have a delimiter in the key, then we must check for sub-properties\n        if (key.Contains(':'))\n            return TryGetSubProperty(key);\n\n        // If it's a repeater token for list index or something, get that first (or null)\n        // Otherwise just get the normal value\n        var valueObject = ResolveRepeaterTokens(key) \n                          ?? dynEntity.Get(key);\n\n        return valueObject switch\n        {\n            null => string.Empty,\n            string str => LookUpHelpers.FormatString(str, strFormat),\n            bool b => LookUpHelpers.Format(b),\n            DateTime or double or float or short or int or long or decimal =>\n                ((IFormattable)valueObject).ToString(strFormat.NullIfNoValue() ?? \"g\", cultureInfo),\n            _ => LookUpHelpers.FormatString(valueObject.ToString(), strFormat),\n        };\n    }\n\n    private string TryGetSubProperty(string strPropertyName)\n    {\n        // dynamic valueObject;\n        var propertyMatch = Regex.Match(strPropertyName, \"([a-z]+):([a-z]+)\", RegexOptions.IgnoreCase);\n        if (!propertyMatch.Success)\n            return \"\";\n\n        var subSource = propertyMatch.Groups[1].Value;\n        var subProp = propertyMatch.Groups[2].Value;\n\n        // Find the sub-object on the Presentation item\n        var subEntity = subSource.EqualsInsensitive(ViewParts.Presentation)\n            ? dynEntity.Presentation as IDynamicEntity\n            : dynEntity.Get(subSource) as IDynamicEntity;\n\n        if (subEntity == null)\n            return \"\";\n\n        var subLookup = new LookUpForTokenTemplate(\"NoName\", subEntity, cultureInfo);\n\n        return subLookup.GetProperty(subProp, \"\") ?? \"\";\n    }\n\n    public string Get(string key, string strFormat)\n        => GetProperty(key, strFormat) ?? \"\";\n\n    /// <inheritdoc/>\n    public virtual string Get(string key)\n        => Get(key, \"\") ?? \"\";\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Engines.Sys.Token/LookUpForTokenTemplate_ListIndexes.cs",
    "content": "﻿using static System.StringComparison;\n\nnamespace ToSic.Sxc.Engines.Sys.Token;\n\npartial class LookUpForTokenTemplate\n{\n    public const string TokenRepeater = \"Repeater\";\n\n    public const string KeyIndex = \"index\";\n    public const string KeyIndex1 = \"index1\";\n    public const string KeyAlternator2 = \"alternator2\";\n    public const string KeyAlternator3 = \"alternator3\";\n    public const string KeyAlternator4 = \"alternator4\";\n    public const string KeyAlternator5 = \"alternator5\";\n    public const string KeyIsFirst = \"isfirst\";\n    public const string KeyIsLast = \"islast\";\n    public const string KeyCount = \"count\";\n\n    private string? ResolveRepeaterTokens(string strPropertyName)\n    {\n        if (repeaterIndex <= -1 || !strPropertyName.StartsWith(TokenRepeater + \":\", OrdinalIgnoreCase))\n            return null;\n\n        return strPropertyName.Substring(TokenRepeater.Length + 1).ToLowerInvariant() switch\n        {\n            KeyIndex => (repeaterIndex).ToString(),\n            KeyIndex1 => (repeaterIndex + 1).ToString(),\n            KeyAlternator2 => (repeaterIndex % 2).ToString(),\n            KeyAlternator3 => (repeaterIndex % 3).ToString(),\n            KeyAlternator4 => (repeaterIndex % 4).ToString(),\n            KeyAlternator5 => (repeaterIndex % 5).ToString(),\n            KeyIsFirst => repeaterIndex == 0 ? \"First\" : \"\",\n            KeyIsLast => repeaterIndex == repeaterTotal - 1 ? \"Last\" : \"\",\n            KeyCount => repeaterTotal.ToString(),\n            _ => null\n        };\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Engines.Sys.Token/TokenEngine.cs",
    "content": "﻿using System.Globalization;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Eav.LookUp;\nusing ToSic.Eav.LookUp.Sys;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Engines.Sys.Token;\nusing ToSic.Sxc.LookUp.Sys;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Utils.Culture;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Engines;\n\n/// <summary>\n/// Rendering Engine for Token based templates (html using [Content:Title] kind of placeholders. \n/// </summary>\n[PrivateApi(\"used to be InternalApi_DoNotUse_MayChangeWithoutNotice, hidden in 17.08\")]\n[EngineDefinition(Name = \"Token\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class TokenEngine(\n    EngineSpecsService engineSpecsService,\n    IBlockResourceExtractor blockResourceExtractor,\n    EngineAppRequirements engineAppRequirements,\n    IServerPaths serverPaths,\n    LazySvc<IExecutionContextFactory> exCtxFactory,\n    Generator<IAppDataConfigProvider> tokenEngineWithContext)\n    : ServiceBase(\"Sxc.TokEng\", connect: [engineSpecsService, blockResourceExtractor, engineAppRequirements, exCtxFactory, tokenEngineWithContext]),\n        ITokenEngine\n{\n    #region Replacement List to still support old Tokens\n\n    /// <summary>\n    /// Token translation table - to auto-convert tokens as they were written\n    /// pre v7 to be treated as they should in the new convention\n    /// </summary>\n    private readonly Dictionary<string, string> _upgrade6To7Dict = new()\n    {\n        { \"[Presentation:\", \"[Content:Presentation:\" },\n        { \"[ListPresentation:\", \"[ListContent:Presentation:\" },\n        { \"[AppSettings:\", \"[App:Settings:\" },\n        { \"[AppResources:\", \"[App:Resources:\" },\n        { \"<repeat>\", \"<repeat repeat=\\\"Content in Data:Default\\\">\" },\n        { \"[List:\", \"[Content:Repeater:\" }\n    };\n\n    #endregion\n\n    #region Regular Expressions / String Constants\n\n    private static readonly dynamic RegexToken = new {\n        SourceName = \"sourceName\",\n        StreamName = \"streamName\",\n        Template   = \"template\"\n    };\n\n    private static readonly string RepeatPlaceholder = \"<repeat_placeholder>\";\n\n    private static readonly string RepeatPattern = @\"\n                # Begins with <repeat\n                <repeat\\s\n                    # Must contain the attribute repeat='...' according to the schema with 'in Data:...'\n                    repeat=['|\"\"](?<sourceName>[a-zA-Z0-9$_]+)\\sin\\sData\\:(?<streamName>[a-zA-Z0-9$_]+)['|\"\"]\n                    >\n                    (?<template>.*?)\n                </repeat>\";\n\n    private static readonly Regex RepeatRegex = new(RepeatPattern, \n        RegexOptions.IgnoreCase \n        | RegexOptions.Multiline \n        | RegexOptions.Singleline \n        | RegexOptions.Compiled \n        | RegexOptions.IgnorePatternWhitespace);\n    #endregion\n\n    /// <inheritdoc />\n    public RenderEngineResult Render(IBlock block, RenderSpecs specs)\n    {\n        var l = Log.Fn<RenderEngineResult>(timer: true);\n\n        // Prepare #1: Specs\n        var engineSpecs = engineSpecsService.GetSpecs(block);\n\n        // Preflight: check if rendering is possible, or throw exceptions...\n        var preFlightResult = engineAppRequirements.CheckExpectedNoRenderConditions(engineSpecs);\n        if (preFlightResult != null)\n            return l.ReturnAsError(preFlightResult);\n\n        // Prepare #2: Helpers etc.\n        var exCtx = exCtxFactory.Value.New(new()\n        {\n            OwnerOrNull = null,\n            BlockOrNull = engineSpecs.Block,\n            ParentLog = Log,\n            CompatibilityFallback = CompatibilityLevels.CompatibilityLevel9Old,\n        });\n        var cdf = exCtx.GetCdf();\n        var cultureInfo = CultureHelpers.SafeCultureInfo(cdf.Dimensions);\n        var rootLookups = InitTokenReplace(exCtx.GetDynamicApi(), engineSpecs, cultureInfo);\n\n        // Render and process / return\n        var renderedTemplate = RenderTokenTemplate(engineSpecs, specs, cdf, cultureInfo, rootLookups);\n        var result = blockResourceExtractor.Process(renderedTemplate);\n        return l.ReturnAsOk(result);\n    }\n\n\n    private LookUpEngine InitTokenReplace(ICodeDynamicApiHelper codeApiHelper, EngineSpecs engineSpecs, CultureInfo cultureInfo)\n    {\n        var specs = new SxcAppDataConfigSpecs { BlockForLookupOrNull = engineSpecs.Block };\n        var appDataConfig = tokenEngineWithContext.New().GetDataConfiguration((engineSpecs.App as SxcAppBase)!, specs);\n\n        return new(appDataConfig.LookUpEngine, Log, sources: [\n            new LookUpForTokenTemplate(ViewParts.ListContentLower, codeApiHelper.Header, cultureInfo),\n            new LookUpForTokenTemplate(ViewParts.ContentLower, codeApiHelper.Content, cultureInfo),\n        ]);\n    }\n\n\n    [PrivateApi]\n    protected RenderEngineResultRaw RenderTokenTemplate(EngineSpecs engineSpecs, RenderSpecs specs, ICodeDataFactory cdf, CultureInfo cultureInfo, LookUpEngine rootLookups)\n    {\n        var l = Log.Fn<RenderEngineResultRaw>();\n        var templateSource = File.ReadAllText(serverPaths.FullAppPath(engineSpecs.TemplatePath));\n        // Convert old <repeat> elements to the new ones\n        templateSource = _upgrade6To7Dict.Aggregate(templateSource,\n            (current, var) => current.Replace(var.Key, var.Value)\n        );\n\n        // Render all <repeat>s\n        var repeatsMatches = RepeatRegex.Matches(templateSource);       \n        var repeatsRendered = new List<string>();\n        foreach (Match match in repeatsMatches)\n            repeatsRendered.Add(RenderRepeat(\n                engineSpecs,\n                cdf,\n                cultureInfo,\n                rootLookups,\n                match.Groups[RegexToken.SourceName].Value.ToLowerInvariant(),\n                match.Groups[RegexToken.StreamName].Value,\n                match.Groups[RegexToken.Template].Value));\n\n        // Render sections between the <repeat>s (but before replace the <repeat>s and \n        // the templates contained with placeholders, so the templates in the <repeat>s \n        // are not rendered twice)\n        var template = RepeatRegex.Replace(templateSource, RepeatPlaceholder);\n        var rendered = RenderSection(template, rootLookups, new Dictionary<string, ILookUp>());\n\n        // Insert <repeat>s rendered to the template target\n        var repeatsIndexes = FindAllIndexesOfString(rendered, RepeatPlaceholder);\n        var renderedBuilder = new StringBuilder(rendered);\n\n        // Replace the parts in reversed order, so the indexes don't shift\n        for (var i = repeatsIndexes.Count - 1; i >= 0; i--)\n            renderedBuilder\n                .Remove(repeatsIndexes[i], RepeatPlaceholder.Length)\n                .Insert(repeatsIndexes[i], repeatsRendered[i]);\n\n        return l.Return(new() { Html = renderedBuilder.ToString(), ExceptionsOrNull = null });\n    }\n\n\n    private string RenderRepeat(EngineSpecs engineSpecs, ICodeDataFactory cdf, CultureInfo cultureInfo, LookUpEngine rootLookups, string sourceName, string streamName, string template)\n    {\n        if (string.IsNullOrEmpty(template))\n            return \"\";\n\n        var builder = new StringBuilder();\n\n        var stream = engineSpecs.DataSource.GetStream(streamName, nullIfNotFound: true)\n            ?? throw new ArgumentException(\"Was not able to implement REPEAT because I could not find Data:\" + streamName + \". Please check spelling the pipeline delivering data to this template.\");\n\n        var dataItems = stream.List.ToImmutableOpt();\n        var itemsCount = dataItems.Count;\n        for (var i = 0; i < itemsCount; i++)\n        {\n            // Create property sources for the current data item (for the current data item and its list information)\n            var dynEntity = cdf.AsDynamic(dataItems.ElementAt(i), new() { ItemIsStrict = false });\n            var propertySources = new Dictionary<string, ILookUp>\n            {\n                { sourceName, new LookUpForTokenTemplate(sourceName, dynEntity, cultureInfo, i, itemsCount) }\n            };\n            builder.Append(RenderSection(template, rootLookups, propertySources));\n        }\n\n        return builder.ToString();\n    }\n\n    private string RenderSection(string template, LookUpEngine rootLookups, IDictionary<string, ILookUp> valuesForThisInstanceOnly)\n    {\n        var l = Log.Fn<string>($\"{nameof(valuesForThisInstanceOnly)}: {valuesForThisInstanceOnly.Count}\");\n        if (string.IsNullOrEmpty(template))\n            return l.Return(\"\", \"empty\");\n\n        // Get the existing sources and remove the ones which would be duplicate\n        var sources = rootLookups.Sources.ToList();\n        foreach (var src in valuesForThisInstanceOnly)\n        {\n            var lookup = sources.GetSource(src.Key);\n            if (lookup != null)\n                sources.Remove(lookup);\n        }\n\n        // Create a new lookup engine with the new sources; but skip the original sources; only use the downstream\n        var newEngine = new LookUpEngine(rootLookups, Log, sources: [..valuesForThisInstanceOnly.Values, ..sources], skipOriginalSource: true);\n        var tokenReplace = new TokenReplace(newEngine);\n\n        // Render\n        var section = tokenReplace.ReplaceTokens(template);\n        return l.Return(section, \"new render\");\n\n    }\n\n    // Find all indexes of a string in a source string\n    private static List<int> FindAllIndexesOfString(string source, string value)\n    {\n        var indexes = new List<int>();\n        for (var index = 0; ; index += value.Length)\n        {\n            index = source.IndexOf(value, index, StringComparison.Ordinal);\n            if (index == -1) // No more found\n                return indexes;\n            indexes.Add(index);\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Engines.Sys.Token/readme.md",
    "content": "# Engines.Token\n\nThis is not the correct place for this,\nbut it uses some APIs which the code provides, and we didn't want to create an own DLL just for this file, so ATM it's here.\n\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Wrappers;\nglobal using ToSic.Sys.Performance;\nglobal using ToSic.Sys.Utils;\nglobal using static ToSic.Sxc.Sys.SxcLogging;\nglobal using ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Properties/SxcCodeInternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Custom\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Core\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Razor\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.SystemTests\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Services/IDynamicCodeService.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Code;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// This is a service to give you DynamicCode outside 2sxc.\n/// </summary>\n/// <remarks>\n/// Use this to access 2sxc data from a Theme, a `.ascx` WebControl or anywhere else. \n/// \n/// History\n/// \n/// * New in v13.02 - this is meant to replace the `ToSic.Sxc.Dnn.Factory`. Please use this from now on.\n/// * In v21 it's superseded by <see cref=\"ITypedApiService\"/> - please use that instead\n/// </remarks>\n[PublicApi]\n[Obsolete($\"Superseded by ITypedApi\")]\npublic interface IDynamicCodeService\n{\n    /// <summary>\n    /// Get a <see cref=\"IDynamicCode12\"/> object for a specific Module on a page\n    /// </summary>\n    /// <param name=\"pageId\"></param>\n    /// <param name=\"moduleId\"></param>\n    /// <returns></returns>\n    IDynamicCode12 OfModule(int pageId, int moduleId);\n\n    /// <summary>\n    /// Get a <see cref=\"IDynamicCode12\"/> object for the primary App of the current Site/Portal.\n    /// </summary>\n    /// <returns></returns>\n    IDynamicCode12 OfSite();\n\n    /// <summary>\n    /// Get a <see cref=\"IDynamicCode12\"/> object for a specific Site/Portal.\n    /// </summary>\n    /// <returns></returns>\n    IDynamicCode12 OfSite(int siteId);\n\n\n    /// <summary>\n    /// Get a <see cref=\"IDynamicCode12\"/> object for a specific App.\n    /// This is the simplest way to work with Dynamic Code for this App.\n    ///\n    /// Note that this is without Page/Module context, so there will be no useful `Content` object on the dynamic code.\n    /// </summary>\n    /// <param name=\"appId\">The AppId</param>\n    /// <returns>The dynamic code object for this App</returns>\n    IDynamicCode12 OfApp(int appId);\n\n    /// <summary>\n    /// Get a <see cref=\"IDynamicCode12\"/> object for a specific App.\n    /// This is the simplest way to work with Dynamic Code for this App.\n    /// \n    /// Note that this is without Page/Module context, so there will be no useful `Content` object on the dynamic code.\n    /// </summary>\n    /// <param name=\"zoneId\">The ZoneId of the App</param>\n    /// <param name=\"appId\">The AppId</param>\n    /// <returns>The dynamic code object for this App</returns>\n    IDynamicCode12 OfApp(int zoneId, int appId);\n\n    /// <summary>\n    /// Get a <see cref=\"IDynamicCode12\"/> object for a specific App.\n    /// This is the simplest way to work with Dynamic Code for this App.\n    /// \n    /// Note that this is without Page/Module context, so there will be no useful `Content` object on the dynamic code.\n    /// </summary>\n    /// <param name=\"appIdentity\">The App Identifier</param>\n    /// <returns>The dynamic code object for this App</returns>\n    IDynamicCode12 OfApp(IAppIdentity appIdentity);\n\n    /// <summary>\n    /// Get a rich <see cref=\"Apps.IApp\"/> object for a specific App.\n    /// This is the simplest way to work with data of this App, but won't give you commands like `AsDynamic(...)`\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"zoneId\">The ZoneId of the App (optional)</param>\n    /// <param name=\"appId\">The AppId - REQUIRED</param>\n    /// <param name=\"site\">Site information for further context (optional) </param>\n    /// <param name=\"withUnpublished\">Determines if the App.Data gives you unpublished data (like in admin-mode) or just published data. If not set, will default to user permissions.</param>\n    /// <returns>An initialized App object which you can use to access App.Data</returns>\n    IApp App(\n        NoParamOrder npo = default,\n        int? zoneId = null,\n        int? appId = null,\n        ISite? site = null,\n        bool? withUnpublished = null);\n\n    /// <summary>\n    /// Get a rich <see cref=\"Apps.IApp\"/> object for the primary (aka Site) App of the _current_ Site/Portal and using permissions of the current user.\n    /// This is the simplest way to work with data of this App, but won't give you commands like `AsDynamic(...)`.\n    /// For more control, use the `AppOfSite` with parameters. \n    /// </summary>\n    IApp AppOfSite();\n    \n    /// <summary>\n    /// Get a rich <see cref=\"Apps.IApp\"/> object for the primary (aka Site) App. \n    /// This is the simplest way to work with data of this App, but won't give you commands like `AsDynamic(...)`\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"siteId\">The SiteId which is the PortalId in DNN. Optional - without it, the current Site / Portal is used. </param>\n    /// <param name=\"overrideSite\">Site information for further context (optional) </param>\n    /// <param name=\"withUnpublished\">Determines if the App.Data gives you unpublished data (like in admin-mode) or just published data. If not set, will default to user permissions.</param>\n    /// <returns>An initialized App object which you can use to access App.Data</returns>\n    IApp AppOfSite(\n        // ReSharper disable once MethodOverloadWithOptionalParameter\n        NoParamOrder npo = default,\n        int? siteId = null,\n        ISite? overrideSite = null,\n        bool? withUnpublished = null);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Services/ITypedApiService.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// This is a service to give you Typed Code outside 2sxc.\n/// </summary>\n/// <remarks>\n/// Use this to access 2sxc data from a Theme, a `.ascx` WebControl or anywhere else. \n/// \n/// History\n/// \n/// * New in v20\n/// </remarks>\n[PublicApi]\npublic interface ITypedApiService\n{\n    ///// <summary>\n    ///// Get a <see cref=\"IDynamicCode12\"/> object for a specific Module on a page\n    ///// </summary>\n    ///// <param name=\"pageId\"></param>\n    ///// <param name=\"moduleId\"></param>\n    ///// <returns></returns>\n    //IDynamicCode12 OfModule(int pageId, int moduleId);\n\n    ///// <summary>\n    ///// Get a <see cref=\"IDynamicCode12\"/> object for the primary App of the current Site/Portal.\n    ///// </summary>\n    ///// <returns></returns>\n    //IDynamicCode12 OfSite();\n\n    ///// <summary>\n    ///// Get a <see cref=\"IDynamicCode12\"/> object for a specific Site/Portal.\n    ///// </summary>\n    ///// <returns></returns>\n    //IDynamicCode12 OfSite(int siteId);\n\n\n    ///// <summary>\n    ///// Get a <see cref=\"IDynamicCode12\"/> object for a specific App.\n    ///// This is the simplest way to work with Dynamic Code for this App.\n    /////\n    ///// Note that this is without Page/Module context, so there will be no useful `Content` object on the dynamic code.\n    ///// </summary>\n    ///// <param name=\"appId\">The AppId</param>\n    ///// <returns>The dynamic code object for this App</returns>\n    //IDynamicCode12 OfApp(int appId);\n\n    ///// <summary>\n    ///// Get a <see cref=\"IDynamicCode12\"/> object for a specific App.\n    ///// This is the simplest way to work with Dynamic Code for this App.\n    ///// \n    ///// Note that this is without Page/Module context, so there will be no useful `Content` object on the dynamic code.\n    ///// </summary>\n    ///// <param name=\"zoneId\">The ZoneId of the App</param>\n    ///// <param name=\"appId\">The AppId</param>\n    ///// <returns>The dynamic code object for this App</returns>\n    //IDynamicCode12 OfApp(int zoneId, int appId);\n\n    ///// <summary>\n    ///// Get a <see cref=\"IDynamicCode12\"/> object for a specific App.\n    ///// This is the simplest way to work with Dynamic Code for this App.\n    ///// \n    ///// Note that this is without Page/Module context, so there will be no useful `Content` object on the dynamic code.\n    ///// </summary>\n    ///// <param name=\"appIdentity\">The App Identifier</param>\n    ///// <returns>The dynamic code object for this App</returns>\n    //IDynamicCode12 OfApp(IAppIdentity appIdentity);\n\n    ///// <summary>\n    ///// Get a rich <see cref=\"Apps.IApp\"/> object for a specific App.\n    ///// This is the simplest way to work with data of this App, but won't give you commands like `AsDynamic(...)`\n    ///// </summary>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    ///// <param name=\"zoneId\">The ZoneId of the App (optional)</param>\n    ///// <param name=\"appId\">The AppId - REQUIRED</param>\n    ///// <param name=\"site\">Site information for further context (optional) </param>\n    ///// <param name=\"withUnpublished\">Determines if the App.Data gives you unpublished data (like in admin-mode) or just published data. If not set, will default to user permissions.</param>\n    ///// <returns>An initialized App object which you can use to access App.Data</returns>\n    //IApp App(\n    //    NoParamOrder npo = default,\n    //    int? zoneId = null,\n    //    int? appId = null,\n    //    ISite? site = null,\n    //    bool? withUnpublished = null);\n\n    ///// <summary>\n    ///// Get a rich <see cref=\"Apps.IApp\"/> object for the primary (aka Site) App of the _current_ Site/Portal and using permissions of the current user.\n    ///// This is the simplest way to work with data of this App, but won't give you commands like `AsDynamic(...)`.\n    ///// For more control, use the `AppOfSite` with parameters. \n    ///// </summary>\n    //IApp AppOfSite();\n\n    ///// <summary>\n    ///// Get a rich <see cref=\"Apps.IApp\"/> object for the primary (aka Site) App. \n    ///// This is the simplest way to work with data of this App, but won't give you commands like `AsDynamic(...)`\n    ///// </summary>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    ///// <param name=\"siteId\">The SiteId which is the PortalId in DNN. Optional - without it, the current Site / Portal is used. </param>\n    ///// <param name=\"overrideSite\">Site information for further context (optional) </param>\n    ///// <param name=\"withUnpublished\">Determines if the App.Data gives you unpublished data (like in admin-mode) or just published data. If not set, will default to user permissions.</param>\n    ///// <returns>An initialized App object which you can use to access App.Data</returns>\n    //IApp AppOfSite(\n    //    // ReSharper disable once MethodOverloadWithOptionalParameter\n    //    NoParamOrder npo = default,\n    //    int? siteId = null,\n    //    ISite? overrideSite = null,\n    //    bool? withUnpublished = null);\n\n    /// <summary>\n    /// Get the Typed App object for a specific App, which is the most convenient way to work with the content of this App.\n    /// </summary>\n    /// <returns></returns>\n    IAppTyped App(NoParamOrder npo = default, int? zoneId = null, int? appId = null, ISite? site = null, bool? withUnpublished = null);\n\n    /// <summary>\n    /// Get the Typed App object for the site-wide App, which contains shared data.\n    /// </summary>\n    /// <returns></returns>\n    IAppTyped AppOfSite();\n\n    /// <summary>\n    /// Get an API object for a specific App.\n    /// </summary>\n    /// <returns></returns>\n    ITypedApi ApiOfApp(int appId);\n\n    /// <summary>\n    /// Get an API object for a specific App.\n    /// </summary>\n    /// <returns></returns>\n    ITypedApi ApiOfApp(int zoneId, int appId);\n\n    /// <summary>\n    /// Get an API object for a specific Module - the Module must have a 2sxc App or Content on it for this to work.\n    /// </summary>\n    /// <remarks>\n    /// This is to work with the content, data or app on this specific module.\n    /// It is *not* meant for module-level metadata, which should be on the ApiOfSite.\n    /// </remarks>\n    /// <returns></returns>\n    ITypedApi ApiOfModule(int pageId, int moduleId);\n\n\n    /// <summary>\n    /// Get an API object for a current Site/Portal.\n    /// </summary>\n    /// <returns></returns>\n    ITypedApi ApiOfSite();\n\n    /// <summary>\n    /// Get an API object for a specified Site/Portal.\n    /// </summary>\n    /// <returns></returns>\n    ITypedApi ApiOfSite(int siteId);\n\n    /// <summary>\n    /// Get an API object for a specific Site/Portal including proper context of a specific Module on a page.\n    /// </summary>\n    /// <remarks>\n    /// This is the most complex way to get an API, but it will give you the most complete context for your code, which you need for ModuleMetadata.\n    /// </remarks>\n    /// <returns></returns>\n    ITypedApi ApiOfSite(int siteId, int pageId, int moduleId);\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Services/Sys.CodeApiServiceHelpers/CodeApiServiceBase.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Services.Sys.CodeApiServiceHelpers;\npublic abstract class CodeApiServiceBase(CodeApiServiceBase.Dependencies services, string logName)\n    : ServiceBase<CodeApiServiceBase.Dependencies>(services, logName),\n        ILogWasConnected\n{\n    public record Dependencies(\n        IServiceProvider ServiceProvider,\n        LazySvc<ILogStore> LogStore,\n        LazySvc<IUser> User,\n        // Dependencies to get primary app\n        LazySvc<ISite> Site,\n        LazySvc<IZoneMapper> ZoneMapper,\n        LazySvc<IAppsCatalog> AppsCatalog)\n        : DependenciesRecord(connect: [/* never! serviceProvider */ LogStore, User, Site, ZoneMapper, AppsCatalog]);\n\n    public record ScopedDependencies(\n        Generator<IExecutionContextFactory> ExCtxGenerator,\n        Generator<App> AppGenerator,\n        LazySvc<IModuleAndBlockBuilder> ModAndBlockBuilder)\n        : DependenciesRecord(connect: [ExCtxGenerator, AppGenerator, ModAndBlockBuilder]);\n\n    protected IApp GetApp(Generator<App> appGenerator, NoParamOrder npo = default, int? zoneId = null, int? appId = null, ISite? site = null, bool? withUnpublished = null)\n    {\n        MakeSureLogIsInHistory();\n\n        // Ensure AppId is provided\n        var realAppId = appId ?? throw new ArgumentException($@\"At least the {nameof(appId)} is required and must be a valid AppId\", nameof(appId));\n\n        // lookup zoneId if not provided\n        var realZoneId = zoneId ?? Services.AppsCatalog.Value.AppIdentity(realAppId).ZoneId;\n        return GetAndInitApp(appGenerator.New(), new AppIdentityPure(realZoneId, realAppId), site, showDrafts: withUnpublished);\n    }\n\n\n    protected IAppIdentityPure GetPrimaryAppIdentity(int? siteId, ISite? site = default)\n    {\n        siteId ??= site?.Id ?? Services.Site.Value.Id;\n        var zoneId = Services.ZoneMapper.Value.GetZoneId(siteId.Value);\n        var primaryApp = Services.AppsCatalog.Value.PrimaryAppIdentity(zoneId);\n        return primaryApp;\n    }\n\n    protected IApp GetAndInitApp(App app, IAppIdentityPure appIdentity, ISite? overrideSite, bool? showDrafts = null)\n    {\n        var l = Log.Fn<IApp>($\"{appIdentity.Show()}, site:{overrideSite != null}, showDrafts: {showDrafts}\");\n        app.Init(overrideSite, appIdentity, new() { ShowDrafts = showDrafts });\n        return l.Return(app);\n    }\n\n\n    public void LogWasConnected() => _logInitDone = true; // if we link it to a parent, we don't need to add own entry in log history\n    private bool _logInitDone;\n\n    protected void MakeSureLogIsInHistory()\n    {\n        if (_logInitDone) return;\n        _logInitDone = true;\n        Services.LogStore.Value.Add(\"dynamic-code-service\", Log);\n    }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Services/Sys.DynamicCodeService/DynamicCodeService.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Services.Sys.CodeApiServiceHelpers;\n\nnamespace ToSic.Sxc.Services.Sys.DynamicCodeService;\n\n/// <summary>\n/// WIP - goal is to have a DI factory which creates DynamicCode objects for use in Skins and other external controls\n/// Not sure how to get this to work, since normally we always start with a code-file, and here we don't have one!\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class DynamicCodeService(CodeApiServiceBase.Dependencies services, string? logName = null /* must be nullable for DI */)\n    : CodeApiServiceBase(services, logName ?? $\"{SxcLogName}.DCS\"),\n#pragma warning disable CS0618 // Type or member is obsolete\n        IDynamicCodeService\n#pragma warning restore CS0618 // Type or member is obsolete\n{\n    #region Constructor and Init\n\n    /// <summary>\n    /// This is for all the services used here, or also for services needed in inherited classes which will need the same scoped objects.\n    /// It's important to understand that everything in here will use the scoped service provider.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    protected IServiceProvider ScopedServiceProvider => field ??= Services.ServiceProvider.CreateScope().ServiceProvider;\n\n    [field: AllowNull, MaybeNull]\n    private ScopedDependencies ServicesScoped => field ??= ScopedServiceProvider.Build<ScopedDependencies>().ConnectServices(Log);\n\n\n    protected void ActivateEditUi() => EditUiRequired = true;\n\n    protected bool EditUiRequired;\n\n    #endregion\n\n    #region App\n\n    /// <inheritdoc />\n    public IApp App(NoParamOrder npo = default, int? zoneId = null, int? appId = null, ISite? site = null, bool? withUnpublished = null)\n        => GetApp(ServicesScoped.AppGenerator, npo, zoneId, appId, site, withUnpublished);\n\n    /// <inheritdoc />\n    public IApp AppOfSite()\n        => GetAndInitApp(ServicesScoped.AppGenerator.New(), GetPrimaryAppIdentity(null), null);\n\n    /// <inheritdoc />\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public IApp AppOfSite(NoParamOrder npo = default, int? siteId = null, ISite? overrideSite = null, bool? withUnpublished = null)\n        => GetAndInitApp(ServicesScoped.AppGenerator.New(), GetPrimaryAppIdentity(siteId, overrideSite), overrideSite, withUnpublished);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Services/Sys.DynamicCodeService/DynamicCodeService_Of.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApiService;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Services.Sys.DynamicCodeService;\n\npartial class DynamicCodeService\n{\n    /// <inheritdoc />\n    public IDynamicCode12 OfApp(int appId) => OfAppInternal(appId: appId);\n\n    /// <inheritdoc />\n    public IDynamicCode12 OfApp(int zoneId, int appId) => OfAppInternal(zoneId: zoneId, appId: appId);\n\n    /// <inheritdoc />\n    public IDynamicCode12 OfApp(IAppIdentity appIdentity) => OfAppInternal(zoneId: appIdentity.ZoneId, appId: appIdentity.AppId);\n\n    /// <inheritdoc />\n    public IDynamicCode12 OfModule(int pageId, int moduleId)\n    {\n        var l = Log.Fn<IDynamicCode12>($\"{pageId}, {moduleId}\");\n        MakeSureLogIsInHistory();\n        ActivateEditUi();\n        var cmsBlock = ServicesScoped.ModAndBlockBuilder.Value.BuildBlock(pageId, moduleId);\n        var exCtx = ServicesScoped.ExCtxGenerator.New().New(new()\n        {\n            OwnerOrNull = null,\n            BlockOrNull = cmsBlock,\n            ParentLog = Log,\n            CompatibilityFallback = CompatibilityLevels.CompatibilityLevel12,\n        });\n\n        var code12 = new DynamicCodeStandalone(exCtx, ((ExecutionContext)exCtx).DynamicApi);\n        return l.ReturnAsOk(code12);\n    }\n\n    /// <inheritdoc />\n    public IDynamicCode12 OfSite() => OfApp(GetPrimaryAppIdentity(null));\n\n    /// <inheritdoc />\n    public IDynamicCode12 OfSite(int siteId) => OfApp(GetPrimaryAppIdentity(siteId));\n\n    private IDynamicCode12 OfAppInternal(int? zoneId = null, int? appId = null)\n    {\n        var l = Log.Fn<IDynamicCode12>();\n        MakeSureLogIsInHistory();\n        ActivateEditUi();\n        var exCtx = ServicesScoped.ExCtxGenerator.New().New(new()\n        {\n            OwnerOrNull = null,\n            BlockOrNull = null,\n            ParentLog = Log,\n            CompatibilityFallback = CompatibilityLevels.CompatibilityLevel12,\n        });\n        var app = App(zoneId: zoneId, appId: appId);\n        ((IExCtxAttachApp)exCtx).AttachApp(app);\n        var code12 = new DynamicCodeStandalone(exCtx, ((ExecutionContext)exCtx).DynamicApi);\n        return l.ReturnAsOk(code12);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Services/Sys.TypedApiService/TypedApiService.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Services.Sys.CodeApiServiceHelpers;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Services.Sys.TypedApiService;\n\n/// <summary>\n/// WIP - goal is to have a DI factory which creates DynamicCode objects for use in Skins and other external controls\n/// Not sure how to get this to work, since normally we always start with a code-file, and here we don't have one!\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class TypedApiService(CodeApiServiceBase.Dependencies services, string? logName = null /* must be nullable for DI */)\n    : CodeApiServiceBase(services, logName ?? $\"{SxcLogName}.TypeCS\"),\n        ITypedApiService\n{\n    /// <summary>\n    /// This is for all the services used here, or also for services needed in inherited classes which will need the same scoped objects.\n    /// It's important to understand that everything in here will use the scoped service provider.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    protected IServiceProvider ScopedServiceProvider => field\n        ??= Services.ServiceProvider.CreateScope().ServiceProvider;\n\n    [field: AllowNull, MaybeNull]\n    private ScopedDependencies ServicesScoped => field\n        ??= ScopedServiceProvider.Build<ScopedDependencies>().ConnectServices(Log);\n\n\n    protected void ActivateEditUi() => EditUiRequired = true;\n\n    protected bool EditUiRequired;\n\n    #region App\n\n    public IAppTyped App(NoParamOrder npo = default, int? zoneId = null, int? appId = null, ISite? site = null, bool? withUnpublished = null)\n    {\n        var l = Log.Fn<IAppTyped>();\n        MakeSureLogIsInHistory();\n\n        var app = GetApp(ServicesScoped.AppGenerator, zoneId: zoneId, appId: appId, site: site, withUnpublished: withUnpublished);\n        return l.ReturnAsOk(GetNewCodeRoot(app).GetState<IAppTyped>());\n    }\n\n    /// <inheritdoc />\n    public IAppTyped AppOfSite()\n    {\n        var l = Log.Fn<IAppTyped>();\n\n        MakeSureLogIsInHistory();\n        var app = GetAndInitApp(ServicesScoped.AppGenerator.New(), GetPrimaryAppIdentity(null), null);\n        return l.ReturnAsOk(GetNewCodeRoot(app).GetState<IAppTyped>());\n    }\n\n    #endregion\n\n\n    #region Of App / Site / Module etc.\n\n    /// <inheritdoc />\n    public ITypedApi ApiOfApp(int appId) => OfAppOrSiteInternal(appId: appId);\n\n    /// <inheritdoc />\n    public ITypedApi ApiOfApp(int zoneId, int appId) => OfAppOrSiteInternal(zoneId: zoneId, appId: appId);\n\n    /// <inheritdoc />\n    public ITypedApi ApiOfModule(int pageId, int moduleId)\n    {\n        var l = Log.Fn<ITypedApi>($\"{pageId}, {moduleId}\");\n        MakeSureLogIsInHistory();\n        ActivateEditUi();\n        var cmsBlock = ServicesScoped.ModAndBlockBuilder.Value.BuildBlock(pageId, moduleId);\n\n        var exCtx = ServicesScoped.ExCtxGenerator.New().New(new()\n        {\n            OwnerOrNull = null,\n            BlockOrNull = cmsBlock,\n            ParentLog = Log,\n            CompatibilityFallback = CompatibilityLevels.CompatibilityLevel16,\n        });\n\n        var code12 = new TypedApiStandalone(exCtx, exCtx.GetTypedApi());\n        return l.ReturnAsOk(code12);\n    }\n\n    /// <inheritdoc />\n    public ITypedApi ApiOfSite() =>\n        ApiOfAppOrSite(GetPrimaryAppIdentity(null));\n\n    /// <inheritdoc />\n    public ITypedApi ApiOfSite(int siteId) =>\n        ApiOfAppOrSite(GetPrimaryAppIdentity(siteId));\n\n\n    public ITypedApi ApiOfSite(int siteId, int pageId, int moduleId)\n    {\n        var moduleFallback = ServicesScoped.ModAndBlockBuilder.Value.GetModule(pageId, moduleId);\n        var appIdentity = GetPrimaryAppIdentity(siteId);\n        return OfAppOrSiteInternal(zoneId: appIdentity.ZoneId, appId: appIdentity.AppId, moduleFallback);\n    }\n\n    private ITypedApi ApiOfAppOrSite(IAppIdentity appIdentity) =>\n        OfAppOrSiteInternal(zoneId: appIdentity.ZoneId, appId: appIdentity.AppId);\n\n\n    private ITypedApi OfAppOrSiteInternal(int? zoneId = null, int? appId = null, IModule? moduleIfBlockUnknown = default)\n    {\n        var l = Log.Fn<ITypedApi>();\n        MakeSureLogIsInHistory();\n        ActivateEditUi();\n        var app = GetApp(ServicesScoped.AppGenerator, zoneId: zoneId, appId: appId);\n        var exCtx = GetNewCodeRoot(app, moduleIfBlockUnknown);\n        var code12 = new TypedApiStandalone(exCtx, exCtx.GetTypedApi());\n        return l.ReturnAsOk(code12);\n    }\n\n    private IExecutionContext GetNewCodeRoot(IApp? appToAttach = default, IModule? moduleIfBlockUnknown = default)\n    {\n        var exCtx = ServicesScoped.ExCtxGenerator.New().New(new()\n        {\n            OwnerOrNull = null,\n            BlockOrNull = null,\n            ParentLog = Log,\n            CompatibilityFallback = CompatibilityLevels.CompatibilityLevel16,\n            ModuleIfBlockUnknown = moduleIfBlockUnknown,\n        });\n        if (appToAttach != null)\n            ((IExCtxAttachApp)exCtx).AttachApp(appToAttach);\n        return exCtx;\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/StartupSxcCode.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Customizer;\nusing ToSic.Sxc.Code.Sys.CodeApiService;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys.CmsContext;\nusing ToSic.Sxc.Context.Sys.Module;\nusing ToSic.Sxc.Context.Sys.Page;\nusing ToSic.Sxc.Context.Sys.Platform;\nusing ToSic.Sxc.Data.Sys.CodeDataFactory;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys.CodeApiServiceHelpers;\nusing ToSic.Sxc.Services.Sys.DynamicCodeService;\nusing ToSic.Sxc.Services.Sys.TypedApiService;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcCode\n{\n    public static IServiceCollection AddSxcCode(this IServiceCollection services)\n    {\n        services.TryAddTransient<CodeErrorHelpService>();\n        services.TryAddTransient<SourceAnalyzer>();\n\n        services.TryAddTransient<ICodeCustomizer, Customizer>();\n\n        services.TryAddTransient<IExecutionContextFactory, ExecutionContextFactory>();\n\n        // Code / Dynamic Code\n        services.TryAddTransient<ExecutionContext.Dependencies>();\n\n        // Code Fallbacks if not registered by the platform\n        services.TryAddTransient<ExecutionContext, ExecutionContextUnknown>();\n        services.TryAddTransient(typeof(ExecutionContext<,>), typeof(ExecutionContextUnknown<,>));\n\n        // v13 DynamicCodeService\n        services.TryAddTransient<CodeApiServiceBase.Dependencies>();\n        services.TryAddTransient<CodeApiServiceBase.ScopedDependencies>();  // new v15\n#pragma warning disable CS0618 // Type or member is obsolete\n        services.TryAddTransient<IDynamicCodeService, DynamicCodeService>();\n#pragma warning restore CS0618 // Type or member is obsolete\n\n        // v20 TypedCodeService\n        services.TryAddTransient<ITypedApiService, TypedApiService>();\n\n\n        //services.TryAddTransient<CodeDataFactory>();\n        services.TryAddTransient<ICodeDataFactory, CodeDataFactory>();\n        services.TryAddTransient<CodeDataServices>();\n\n        // Temporary solution for the TokenEngine\n        services.TryAddTransient<ITokenEngine, TokenEngine>();\n\n        // CmsContext / MyContext\n        services.TryAddTransient<ICmsContext, CmsContext>();\n        // Module fallback context\n        services.TryAddTransient<IModule, ModuleUnknown>();\n        services.TryAddTransient<IPage, Page>();\n        services.TryAddTransient<Page>();\n        services.TryAddSingleton<IPlatform, PlatformUnknown>();\n\n        // v15\n        services.TryAddTransient<CodeCreateDataSourceSvc>();\n\n        return services;\n    }\n\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/ExecutionContextExtensions.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Sxc.DataSources;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\ninternal static class ExecutionContextExtensions\n{\n    public static ContextData GetContextData(this IExecutionContext exCtx)\n    {\n        return (ContextData)exCtx.GetState<IDataSource>();\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/ExecutionContextOptions.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// Options necessary to initialize a fresh execution context.\n/// </summary>\npublic record ExecutionContextOptions\n{\n    /// <summary>\n    /// The owning object - usually a razor file or a WebApi - providing version information for compatibility\n    /// </summary>\n    public object? OwnerOrNull { get; init; }\n\n    /// <summary>\n    /// The block for this execution context, if available.\n    /// </summary>\n    public IBlock? BlockOrNull { get; init; }\n\n    /// <summary>\n    /// The module we're on, in case the block is not known.\n    /// </summary>\n    public IModule? ModuleIfBlockUnknown { get; init; }\n\n    /// <summary>\n    /// The parent log to attach to. Required.\n    /// </summary>\n    public required ILog ParentLog { get; init; }\n\n    /// <summary>\n    /// Fallback compatibility to use if the Owner is unknown/null or if it does not implement <see cref=\"ICompatibilityLevel\"/>.\n    /// </summary>\n    public int CompatibilityFallback { get; init; }\n\n    /// <summary>\n    /// The true compatibility to apply.\n    /// </summary>\n    public int Compatibility => _compatibility\n        ??= (OwnerOrNull as ICompatibilityLevel)?.CompatibilityLevel ?? CompatibilityFallback;\n\n    private int? _compatibility;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/ICompatibilityLevel.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// Carries information about what compatibility level to use. Important for components that have an older and newer API.\n/// </summary>\n[PrivateApi(\"this is just fyi, was published as internal till v14\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ICompatibilityLevel\n{\n    /// <summary>\n    /// The compatibility level to use.\n    /// Will affect what features Razor etc. will provide.\n    /// </summary>\n    int CompatibilityLevel { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/IExCtxAttachApp.cs",
    "content": "﻿using ToSic.Sxc.Apps;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IExCtxAttachApp\n{\n    void AttachApp(IApp app);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/IExecutionContextFactory.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic interface IExecutionContextFactory\n{\n    /// <summary>\n    /// Creates a CodeApiService - if possible based on the parent class requesting it.\n    /// </summary>\n    /// <returns></returns>\n    IExecutionContext New(ExecutionContextOptions options);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/IExecutionContext_TModel_TKit.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IExecutionContext<out TModel, out TServiceKit>: IExecutionContext, IHasKit<TServiceKit>\n    where TModel : class\n    where TServiceKit : ServiceKit;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeApiService;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing ToSic.Sys.Caching.PiggyBack;\nusing IApp = ToSic.Sxc.Apps.IApp;\n// ReSharper disable InheritdocInvalidUsage\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// Base class for any dynamic code root objects. <br/>\n/// Root objects are the ones compiled by 2sxc - like the RazorComponent or ApiController. <br/>\n/// If you create code for dynamic compilation, you'll always inherit from ToSic.Sxc.Dnn.DynamicCode.\n/// Note that other DynamicCode objects like RazorComponent or ApiController reference this object for all the interface methods of <see cref=\"IDynamicCode\"/>.\n/// </summary>\n/// <remarks>\n/// It can usually not be created directly, but through the <see cref=\"ExecutionContextUnknown\"/> which would return a <see cref=\"IExecutionContextFactory\"/>.\n/// </remarks>\n[PrivateApi(\"Was public till v17, and previously called DynamicCodeRoot\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract partial class ExecutionContext : ServiceBase<ExecutionContext.Dependencies>, IExecutionContext, IGetCodePath, IHasPiggyBack, IServiceWithSetup<ExecutionContextOptions>\n{\n    #region Constructor\n\n    /// <summary>\n    /// Helper class to ensure if dependencies change, inheriting objects don't need to change their signature\n    /// </summary>\n    [PrivateApi]\n    public record Dependencies(\n        IServiceProvider ServiceProvider,\n        LazySvc<IClassCompiler> CodeCompilerLazy,\n        AppDataStackService DataStackService,\n        LazySvc<IConvertService> ConvertService,\n        LazySvc<CodeCreateDataSourceSvc> DataSources,\n        ICodeDataFactory Cdf,\n        PolymorphConfigReader Polymorphism)\n        : DependenciesRecord(connect:\n            [/* never! serviceProvider */ CodeCompilerLazy, DataStackService, ConvertService, DataSources, Cdf, Polymorphism]);\n\n    [PrivateApi]\n    protected internal ExecutionContext(Dependencies services, string logPrefix) : base(services, logPrefix + \".DynCdR\")\n    {\n        // Prepare services which need to be attached to this dynamic code root\n        CmsContext = GetService<ICmsContext>();\n\n        // Make sure we get and initialize (auto-connect) the app-level CSP if that exists or is enabled\n        GetService<CspOfApp>();\n    }\n\n    [PrivateApi]\n    internal ICmsContext CmsContext { get; }\n\n    internal IModule? ModuleIfBlockUnknown { get; private set; }\n\n    #endregion\n\n\n    PiggyBack IHasPiggyBack.PiggyBack { get; } = new();\n\n    [PrivateApi]\n    void IServiceWithSetup<ExecutionContextOptions>.Setup(ExecutionContextOptions options)\n    {\n        Setup(options);\n    }\n\n    public virtual IExecutionContext Setup(ExecutionContextOptions options)\n    {\n        this.LinkLog(options.ParentLog);\n        var cLog = Log.Fn<IExecutionContext>();\n\n        Cdf.SetCompatibilityLevel(options.Compatibility);\n        ModuleIfBlockUnknown = options.ModuleIfBlockUnknown;\n\n        if (options.BlockOrNull == null)\n            return cLog.Return(this, \"no block\");\n\n        var block = options.BlockOrNull;\n        Block = block;\n\n        // Only attach App if it exists\n        // For example when using the Execution Context in a module container, which doesn't have initialized data yet\n        if (block.AppIsReady)\n            AttachApp(block.App);\n\n        return cLog.Return(this, $\"AppId: {App?.AppId}, Block: {(block.ConfigurationIsReady ? block.Configuration?.BlockIdentifierOrNull?.Guid : null)}\");\n    }\n\n    /// <inheritdoc />\n    internal IApp App { get; private set; } = null!;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    [field: AllowNull, MaybeNull]\n    internal ILinkService Link => field ??= GetService<ILinkService>(reuse: true);\n\n\n    #region Edit\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    internal IEditService Edit => field ??= GetService<IEditService>(reuse: true);\n\n    #endregion\n\n    [PrivateApi(\"Not yet ready\")]\n    internal IDevTools DevTools => throw new NotImplementedException(\"This is a future feature, we're just reserving the object name\");\n\n    /// <summary>\n    /// WIP!\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    internal ICodeDynamicApiHelper DynamicApi => field ??= new CodeDynamicApiHelper(this);\n\n    [field: AllowNull, MaybeNull]\n    internal ICodeTypedApiHelper TypedApi => field ??= new CodeTypedApiHelper(this);\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContextUnknown.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\ninternal class ExecutionContextUnknown(ExecutionContext.Dependencies services, WarnUseOfUnknown<ExecutionContextUnknown> _)\n    : ExecutionContext<object, ServiceKit>(services, LogScopes.Base);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_As.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Data.Sys.CodeDataFactory;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services;\nusing IFolder = ToSic.Sxc.Adam.IFolder;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic partial class ExecutionContext\n{\n    [PrivateApi]\n    internal ICodeDataFactory Cdf => _cdf.Get(() =>\n    {\n        ((CodeDataFactory)Services.Cdf).ConnectToRoot(this);\n        return Services.Cdf;\n    })!;\n    private readonly GetOnce<ICodeDataFactory> _cdf = new();\n\n    #region AsDynamic Implementations\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic? AsDynamic(string json, string? fallback = default) => Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic? AsDynamic(IEntity entity) => Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic? AsDynamic(object dynamicEntity) => Cdf.AsDynamicFromObject(dynamicEntity);\n\n    // 2025-05-11 2dm disabled since we're not supporting DynamicCode12 any more...\n    ///// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    //public dynamic AsDynamic(params object[] entities) => Cdf.MergeDynamic(entities);\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic>? AsList(object list) => Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region Convert\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public IConvertService Convert => field ??= Services.ConvertService.Value;\n\n    #endregion\n\n    #region Adam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) \n        => Cdf.Folder(item, fieldName, null);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_Compiler.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Code.Sys.HotBuild;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic partial class ExecutionContext\n{\n    #region SharedCode Compiler\n\n    /// <inheritdoc />\n    public object? CreateInstance(string virtualPath,\n        NoParamOrder npo = default,\n        string? name = null,\n        string? relativePath = null,\n        bool throwOnError = true)\n    {\n        var l = Log.Fn<object>($\"{virtualPath}, {name}, {relativePath}, {throwOnError}\");\n\n        // Compile\n        var compiler = Services.CodeCompilerLazy.Value;\n        var runtimeKey = (App as IAppWithInternal)?.AppReader.Specs.RuntimeKey;\n        var spec = new HotBuildSpec(App.AppId, _editionForHotBuild, App.Name, runtimeKey);\n        var instance = compiler.InstantiateClass(virtualPath, spec, className: name, relativePath: relativePath, throwOnError: throwOnError);\n\n        if (instance == null)\n            return l.ReturnNull(\"null / not found / error\");\n\n        var typeName = instance.GetType().FullName;\n\n        // if it supports all our known context properties, attach them\n        if (instance is INeedsExecutionContext needsRoot)\n        {\n            l.A($\"will attach root / Kit to {typeName}\");\n            needsRoot.ConnectToRoot(this);\n        }\n        else\n            l.A($\"no root / Kit for {typeName}\");\n\n        return l.Return(instance, instance.ToString());\n    }\n\n    /// <inheritdoc />\n    public string CreateInstancePath { get; set; } = null!; // must be set as the context becomes clear\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_Content.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys;\nusing static ToSic.Eav.DataSource.DataSourceConstants;\nusing static ToSic.Sxc.Blocks.Sys.Views.ViewParts;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic partial class ExecutionContext\n{\n    #region basic properties like Content, Header\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public object? Content => _contentGo.Get(() => TryToBuildFirstOfStream(StreamDefaultName));\n    private readonly GetOnce<object?> _contentGo = new();\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public object? Header => _header.Get(GetHeaderOrNull);\n    private readonly GetOnce<object?> _header = new();\n\n    private object? GetHeaderOrNull()\n    {\n        var l = Log.Fn<object?>();\n        if (TryToBuildFirstOfStream(StreamHeader) is { } header)\n            return l.Return(header, \"found\");\n        // If header isn't found, it could be that an old query is used which attached the stream to the old name\n        l.A($\"Header not yet found in {StreamHeader}, will try {StreamHeaderOld}\");\n        return l.Return(TryToBuildFirstOfStream(StreamHeaderOld), \"old query\");\n\n    }\n\n    /// <summary>\n    /// Note: can be null\n    /// </summary>\n    /// <param name=\"sourceStream\"></param>\n    /// <returns></returns>\n    private object? TryToBuildFirstOfStream(string sourceStream)\n    {\n        var l = Log.Fn<object>(sourceStream);\n        if (Block is not { DataIsReady: true })\n            return l.ReturnNull(\"no data/view\");\n        var data = Block.Data;\n\n        var stream = data.GetStream(sourceStream, nullIfNotFound: true);\n        if (stream == null)\n            return l.ReturnNull(\"stream not found\");\n\n        var list = stream.List.ToList();\n        return !list.Any()\n            ? l.ReturnNull(\"first is null\") \n            : l.Return(Cdf.AsDynamicFromEntities(list, new() { ItemIsStrict = false }), \"found\");\n    }\n        \n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_DataSources.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApiService;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic partial class ExecutionContext: IExCtxLookUpEngine\n{\n    #region DataSource and ConfigurationProvider (for DS) section\n\n    [PrivateApi]\n    public ILookUpEngine LookUpForDataSources => _lookupEngine.Get(() =>\n        // check if we have a block-context, in which case the lookups also know about the module\n        Block?.Data?.Configuration?.LookUpEngine\n        // otherwise try to fall back to the App configuration provider, which has a lot, but not the module-context\n#pragma warning disable CS0618 // Type or member is obsolete\n        ?? App.TryGetAppLookUpEngineOrNull()\n#pragma warning restore CS0618 // Type or member is obsolete\n        // show explanation what went wrong\n        ?? throw new(\"Tried to get Lookups for creating data-sources; neither module-context nor app is known.\")\n    )!;\n    private readonly GetOnce<ILookUpEngine> _lookupEngine = new();\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    public CodeCreateDataSourceSvc DataSources => field\n        ??= Services.DataSources.Value.Setup(App, () => LookUpForDataSources);\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource \n        => DataSources.CreateDataSource<T>(false, attach: inSource, options: configurationProvider);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n    {\n        // if it has a source, then use this, otherwise it's null and then it uses the App-Default\n        // Reason: some sources like DataTable or SQL won't have an upstream source\n        var src = CreateSource<T>(source.Source);\n        src.Attach(DataSourceConstants.StreamDefaultName, source);\n        return src;\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_Internal.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic partial class ExecutionContext\n    : IWrapper<ICodeDataFactory>,\n        IExCtxAttachApp\n{\n    [PrivateApi]\n    public void AttachApp(IApp app)\n    {\n        if (app is App appClassic)\n            appClassic.SetupCodeDataFactory(Cdf);\n\n        App = app;\n\n        _editionForHotBuild = Block == null\n            ? null\n            : Services.Polymorphism.UseViewEditionOrGet(Block.View, ((IAppWithInternal)App).AppReader);\n    }\n\n    private string? _editionForHotBuild;\n\n    //[PrivateApi]\n    //[Obsolete(\"Warning - avoid using this on the DynamicCode Root - always use the one on the AsC\")]\n    //public int CompatibilityLevel => Cdf.CompatibilityLevel;\n\n    /// <summary>\n    /// The current block - can be null if the context only knows about the App, but not about the block.\n    /// </summary>\n    [PrivateApi] public IBlock? Block { get; private set; } = null!;\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal IAppTyped AppTyped => field ??= GetService<IAppTyped>(reuse: true);\n\n\n    public TState GetState<TState>() where TState : class\n    {\n        if (typeof(TState) == typeof(ICmsContext))\n            return (TState)CmsContext;\n\n        if (typeof(TState) == typeof(IApp))\n            return (TState)App;\n\n        if (typeof(TState) == typeof(IAppReader))\n            return (TState)((IAppWithInternal)App)?.AppReader!;\n\n        if (typeof(TState) == typeof(IDataSource))\n            return (TState)(Block?.Data ?? throw new NullReferenceException($\"{nameof(Block)} isn't available\"));\n\n        if (typeof(TState) == typeof(IBlock))\n            return (TState)Block!;\n\n        if (typeof(TState) == typeof(IContextOfBlock))\n            return (TState)Block?.Context!;\n\n        if (typeof(TState) == typeof(IAppTyped))\n            return (TState)AppTyped;\n\n        throw new InvalidOperationException(\n            $\"Can't get state of type {typeof(TState).Name} - only {nameof(IApp)}, {nameof(IDataSource)}, {nameof(IBlock)} and {nameof(IAppTyped)} are supported\");\n    }\n\n    public TState GetDataStack<TState>(string name) where TState : class\n    {\n        if (typeof(TState) == typeof(IDynamicStack) && name == ExecutionContextStateNames.Settings)\n            return (TState)Settings;\n\n        if (typeof(TState) == typeof(ITypedStack) && name == ExecutionContextStateNames.AllSettings)\n            return (TState)AllSettings;\n\n        if (typeof(TState) == typeof(ITypedStack) && name == ExecutionContextStateNames.AllResources)\n            return (TState)AllResources;\n\n        throw new InvalidOperationException(\"Can only retrieve 'Settings', 'AllSettings', 'AllResources'\");\n    }\n\n    ICodeDataFactory IWrapper<ICodeDataFactory>.GetContents()\n        => Cdf;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_Kit.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Data.Sys.CodeDataFactory;\nusing ToSic.Sxc.Services.Sys;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic partial class ExecutionContext: ICanGetService\n{\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class\n    {\n        var newService = Services.ServiceProvider.Build<TService>(Log);\n        if (newService is INeedsExecutionContext newWithNeeds)\n            newWithNeeds.ConnectToRoot(this);\n        return newService;\n    }\n\n\n    #region Kit Handling\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TService GetService<TService>(NoParamOrder npo = default, bool reuse = false, Type? type = default) where TService : class\n    {\n        // No reuse - just build and return, but optionally with the type specified\n        if (!reuse)\n            return BuildWithOptionalType();\n\n        // Reuse - check if we already have it, if not, build it and store it\n        var typeInCache = type ?? typeof(TService);\n        if (_reusableServices.TryGetValue(typeInCache, out var service))\n            return (TService)service;\n\n        // Not found, so build it and store it\n        var generated = BuildWithOptionalType();\n        _reusableServices[typeInCache] = generated;\n        return generated;\n\n        TService BuildWithOptionalType()\n        {\n            var newService = type == null \n                ? Services.ServiceProvider.Build<TService>(Log)\n                : Services.ServiceProvider.Build<TService>(type, Log);\n\n            if (newService is INeedsExecutionContext newWithNeeds)\n                newWithNeeds.ConnectToRoot(this);\n            return newService;\n        }\n    }\n\n    public TService GetServiceForData<TService>() where TService : class\n    {\n        if (typeof(TService) == typeof(AdamManager))\n            return ((CodeDataFactory)Cdf).AdamManager as TService\n                ?? throw new InvalidOperationException(\"Can't get AdamManager from ExecutionContext - it is not initialized.\");\n\n        throw new NotImplementedException();\n    }\n\n    /// <summary>\n    /// A kind of cache for:\n    /// - all kinds of kits by version, like Kit14, Kit16\n    /// - all services used inside these kits, as they should share the state (like the Edit kit)\n    /// ...so we don't have to create them over and over again.\n    /// This allows us to just get an object, kit, and if it's already created, we get the same instance.\n    /// </summary>\n    private readonly Dictionary<Type, object> _reusableServices = [];\n\n    /// <summary>\n    /// WIP 19.03.xx - replace a service in the cache, mainly for unit testing\n    /// </summary>\n    /// <typeparam name=\"TService\"></typeparam>\n    /// <param name=\"service\"></param>\n    internal void ReplaceServiceInCache<TService>(TService service)\n        => _reusableServices[typeof(TService)] = service!;\n\n    /// <summary>\n    /// Get or Create a Kit by type\n    /// </summary>\n    /// <typeparam name=\"TKit\"></typeparam>\n    /// <returns></returns>\n    public TKit GetKit<TKit>() where TKit : ServiceKit\n        => GetService<TKit>(reuse: true);\n\n    ///// <summary>\n    ///// Special workaround so this can provide the data without\n    ///// having to support an interface.\n    ///// To call this, you must explicitly cast it to IWrapper&lt;IServiceKitForTypedData&gt;\n    ///// </summary>\n    ///// <returns></returns>\n    //IExCtxServicesForTypedData IWrapper<IExCtxServicesForTypedData>.GetContents()\n    //    => GetKit<ServiceKit16>();\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_SettingsResources.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Data;\nusing static ToSic.Eav.Apps.Sys.AppStack.AppStackConstants;\nusing SettingsSources = System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, ToSic.Eav.Data.Sys.PropertyLookup.IPropertyLookup>>;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\npublic partial class ExecutionContext\n{\n    /// <inheritdoc />\n    [PublicApi]\n    public IDynamicStack Resources => _resources.Get(() => Cdf.AsDynStack(RootNameResources, ResSrc))!;\n    private readonly GetOnce<IDynamicStack> _resources = new();\n\n    [PrivateApi]\n    public ITypedStack AllResources => _allRes.Get(() => Cdf.AsTypedStack(RootNameResources, ResSrc))!;\n    private readonly GetOnce<ITypedStack> _allRes= new();\n\n    [field: AllowNull, MaybeNull]\n    private AppDataStackService AppDss => field ??= Services.DataStackService.Init(((IAppWithInternal)App).AppReader);\n\n    private SettingsSources ResSrc => _resSrc.Get(() => AppDss.GetStack(AppStackConstants.Resources, Block?.View?.Resources))!;\n    private readonly GetOnce<SettingsSources> _resSrc = new();\n\n\n    private SettingsSources SetSrc => _setSrc.Get(() => AppDss.GetStack(AppStackConstants.Settings, Block?.View?.Settings))!;\n    private readonly GetOnce<SettingsSources> _setSrc = new();\n\n    /// <inheritdoc />\n    [PublicApi]\n    public IDynamicStack Settings => _settings.Get(() => Cdf.AsDynStack(RootNameSettings, SetSrc))!;\n    private readonly GetOnce<IDynamicStack> _settings = new();\n\n    public ITypedStack AllSettings => _allSettings.Get(() => Cdf.AsTypedStack(RootNameSettings, SetSrc))!;\n    private readonly GetOnce<ITypedStack> _allSettings = new();\n\n    // TODO: 2025-05-11 2dm WIP\n    //dynamic IDynamicCode12.Resources => Resources;\n    //dynamic IDynamicCode12.Settings => Settings;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_TModel_TKit.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// \n/// </summary>\n/// <typeparam name=\"TModel\"></typeparam>\n/// <typeparam name=\"TServiceKit\"></typeparam>\n/// <param name=\"services\"></param>\n/// <param name=\"logPrefix\"></param>\n/// <remarks>\n/// Note that it used to be abstract, but we changed that so it can be used in unit tests.\n///\n/// Both Dnn and Oqtane have their own version of this class, but the changes are minimal.\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExecutionContext<TModel, TServiceKit>(ExecutionContext.Dependencies services, string logPrefix)\n    : ExecutionContext(services, logPrefix), IExecutionContext<TModel, TServiceKit>\n    where TModel : class\n    where TServiceKit : ServiceKit\n{\n    // Model not in use ATM, may never be. \n    //public TModel Model => default;\n\n    /// <summary>\n    /// The primary kit for this service.\n    /// Other kit versions can be accessed using `GetKit{TKit}`\n    /// </summary>\n    public TServiceKit Kit => _kit.Get(GetKit<TServiceKit>)!;\n    private readonly GetOnce<TServiceKit> _kit = new();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/Sys.ExecutionContext/Implementation/ExecutionContext_TTUnknown.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\ninternal class ExecutionContextUnknown<TModel, TServiceKit>(ExecutionContext.Dependencies services, WarnUseOfUnknown<ExecutionContextUnknown> _)\n    : ExecutionContext<object, ServiceKit>(services, LogScopes.Base);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/ToSic.Sxc.Code.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Code</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code/ToSic.Sxc.Code.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_005Cdevtools/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_005Cdynamiccode/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_005Cinternal_005Ckits/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_005Ctypedcode/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_005Ctypedrazormodel/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sys_002Eexecutioncontext_005Cimplementation/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/CSharpCustomModelGenerator.cs",
    "content": "using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\n/// <summary>\n/// Generator for individual CustomModel classes\n/// Creates lightweight model classes that inherit from CustomModel\n/// </summary>\ninternal class CSharpCustomModelGenerator(CSharpCustomModelsGenerator generator, IContentType type, string baseName) \n    : CSharpModelGeneratorBase(generator, type, baseName, generator.Log, \"Gen.CstMdl\")\n{\n    #region Overrides\n\n    protected override string ClassSuffix => Specs.Suffix ?? \"\"; // Specs.BaseClassSuffix; // \"Model\"\n\n    protected override string GenerateFileIntroComment(string userName) =>\n        $$\"\"\"\n          // DO NOT MODIFY THIS FILE - IT IS AUTO-GENERATED\n          // See also: https://go.2sxc.org/copilot-data\n          // To extend it, create a \"{{ClassName}}.cs\" with this contents:\n          /*\n          namespace {{Generator.Specs.DataNamespace}}\n          {\n            public partial class {{ClassName}}\n            {\n              // Add your own properties and methods here\n            }\n          }\n          */\n\n          {{CSharpGeneratorHelper.GeneratorHeader(Generator, Specs, userName)}}\n          \n          \"\"\";\n\n    protected override string GenerateMainClassComment(string? firstPropertyName)\n    {\n        var remarks = GenerateCommonScopeRemarks();\n        return CodeGenHelper.CodeComment(Specs.TabsClass,\n                   $\"\"\"\n                    This is a generated custom model class for {ClassName} {GetScopeDescription()}\n                    To extend/modify it, see instructions above.\n                    \"\"\")\n               + CodeGenHelper.XmlComment(Specs.TabsClass, summary:\n                   $\"\"\"\n                    {ClassName} custom model. <br/>\n                    Re-generate whenever you change the ContentType. <br/>\n                    <br/>\n                    This is a lightweight model that inherits from CustomModel. <br/>\n                    For properties, use the strongly-typed access such as `.{firstPropertyName}`. <br/>\n                    For advanced features, consider using the full CustomItem instead.\n                    \"\"\",\n                   remarks: remarks);\n    }\n\n    protected override string GenerateAutoGenClassComment() =>\n        CodeGenHelper.XmlComment(Specs.TabsClass,\n            summary: $\"Auto-Generated *base* class for '{ClassName}' in data scope '{Type.Scope}'. \" +\n                     $\"It uses special names to avoid accidental use.\");\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/CSharpCustomModelsGenerator.cs",
    "content": "using ToSic.Eav.Apps;\nusing ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\n/// <summary>\n/// Experimental\n/// Generator for C# Custom Model classes that inherit from CustomModel instead of CustomItem.\n/// These are lightweight models without the full ITypedItem API surface.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CSharpCustomModelsGenerator(IUser user, IAppReaderFactory appReadFac)\n    : CSharpModelsGeneratorBase(user, appReadFac, SxcLogName + \".CMdGen\") // IFileGenerator is inherited from base\n{\n    #region Information for the interface\n\n    public override string Description => \"Generates light-weight C# Custom Model Classes for the AppCode/Data folder\";\n\n    public override string DescriptionHtml => $\"The {Name} will generate <code>[TypeName]Model.Generated.cs</code> files in the <code>AppCode/Data</code> folder.\";\n\n    protected override string GeneratedSetName => \"C# Custom Model Classes\";\n\n    #endregion\n\n    protected internal override CSharpCodeSpecs BuildDerivedSpecs(IFileGeneratorSpecs parameters)\n        => BuildCustomModelSpecs(parameters);\n\n    /// <summary>\n    /// Build CustomModel-specific specs with CustomModel inheritance and naming conventions\n    /// </summary>\n    private CSharpCodeSpecs BuildCustomModelSpecs(IFileGeneratorSpecs parameters)\n    {\n        var codeSpecs = base.BuildSpecs(parameters);\n\n        codeSpecs = codeSpecs with\n        {\n            //DataClassGeneratedSuffix = modelSuffix, // Custom suffix for model classes\n            DataInherits = \"Custom.Data.CustomModel\", // Inherit from CustomModel instead of CustomItem\n            FileGeneratedSuffix = \".Generated\" // Suffix is handled in class name\n        };\n        return codeSpecs;\n    }\n\n    protected override IGeneratedFile? CreateFileGenerator(IContentType type, string baseName)\n    {\n        // Empty the list of override methods and property names\n        // since the model-generator doesn't add any overrides\n        // because the base class doesn't have any own methods or properties.\n        CodeGenHelper.OverrideMethods = [];\n        CodeGenHelper.OverridePropertyNames = [];\n        return new CSharpCustomModelGenerator(this, type, baseName).PrepareFile();\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/CSharpModelGeneratorBase.cs",
    "content": "using System.Text;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\n/// <summary>\n/// Abstract base class for C# model generators (both DataModel and CustomModel)\n/// Contains common logic for generating model classes with properties\n/// </summary>\ninternal abstract class CSharpModelGeneratorBase(CSharpModelsGeneratorBase generator, IContentType type, string baseName, ILog parentLog, string logName) \n    : HelperBase(parentLog, logName)\n{\n    protected readonly CSharpModelsGeneratorBase Generator = generator;\n    protected readonly IContentType Type = type;\n\n    /// <summary>\n    /// The \"true\" name such as \"Tag\" without prefix/suffix\n    /// </summary>\n    protected readonly string BaseName = baseName;\n\n    ///// <summary>\n    ///// Prefix to use for the class name\n    ///// </summary>\n    //protected string Prefix => Specs.Prefix ?? \"\";\n\n    ///// <summary>\n    ///// Gets the suffix associated with the class.\n    ///// </summary>\n    //protected string Suffix => ClassSuffix;\n\n    protected string ClassName => $\"{Specs.Prefix}{BaseName}{ClassSuffix}\";\n\n    internal CSharpCodeSpecs Specs => Generator.Specs;\n    protected CSharpGeneratorHelper CodeGenHelper => Generator.CodeGenHelper;\n\n    #region Abstract Members\n\n    /// <summary>\n    /// Gets the username for file generation\n    /// </summary>\n    protected string UserName => Generator.User.Name;\n\n    /// <summary>\n    /// Gets the class suffix to append to the main class name (e.g., \"Model\" for CustomModel)\n    /// </summary>\n    protected abstract string ClassSuffix { get; }\n\n    /// <summary>\n    /// Generates the file introduction comment with extension instructions\n    /// </summary>\n    /// <param name=\"userName\">The name of the user generating the file</param>\n    /// <returns>The file introduction comment</returns>\n    protected abstract string GenerateFileIntroComment(string userName);\n\n    /// <summary>\n    /// Generates the main class XML documentation comment\n    /// </summary>\n    /// <param name=\"firstPropertyName\">The name of the first property for examples</param>\n    /// <returns>The main class comment</returns>\n    protected abstract string GenerateMainClassComment(string? firstPropertyName);\n\n    /// <summary>\n    /// Generates the auto-generated base class XML documentation comment\n    /// </summary>\n    /// <returns>The auto-generated class comment</returns>\n    protected abstract string GenerateAutoGenClassComment();\n\n    #endregion\n\n    #region Common Implementation\n\n    internal GeneratedDataModel? PrepareFile()\n    {\n        var finalClassName = ClassName;\n        var l = Log.Fn<GeneratedDataModel>($\"ClassName: {finalClassName}; {nameof(Type)}: {Type?.Name} ({Type?.NameId})\");\n\n        if (Type == null)\n            return l.ReturnNull(\"No content type provided\");\n\n        // Generate main partial class with optional suffix\n        // TODO: WHY are we using 2 prefixes here?\n        var autoGenClassName = $\"{Specs.BaseClassPrefix}{ClassName}{Specs.BaseClassSuffix}\";\n        var mainClass = CodeGenHelper.ClassWrapper(finalClassName, false, true, Specs.NamespaceAutoGen + \".\" + autoGenClassName);\n\n        // Generate AutoGen class with properties\n        var classAutoGen = CodeGenHelper.ClassWrapper(autoGenClassName, true, false, Specs.DataInherits);\n        var (_, propsSb, usings, firstProperty) = ClassProperties(Type.Attributes.ToList());\n        var classCode = classAutoGen.ToString(propsSb);\n\n        var autoGenClass =\n            GenerateAutoGenClassComment()\n            + classCode;\n\n        var fullBody =\n            GenerateMainClassComment(firstProperty)\n            + mainClass;\n\n        var fileContents =\n            CodeGenHelper.GenerateUsings(usings)\n            + CodeGenHelper.NamespaceWrapper(Specs.DataNamespace)\n                .ToString(fullBody)\n            + \"\\n\\n\"\n            + CodeGenHelper.NamespaceWrapper(Specs.BaseClassNamespace)\n                .ToString(autoGenClass);\n\n        return l.Return(new($\"{finalClassName}{Specs.FileGeneratedSuffix}\", fileContents, GenerateFileIntroComment(UserName)), $\"File size: {fileContents.Length}\");\n    }\n\n    private (bool HasProps, string? Code, List<string>? Usings, string? FirstProperty) ClassProperties(List<IContentTypeAttribute> attributes)\n    {\n        var l = Log.Fn<(bool, string?, List<string>?, string?)>($\"{nameof(attributes)}: {attributes.Count}\");\n\n        // Generate all properties with the helpers\n        var propsSnippets = attributes\n            .Select(a => new\n            {\n                Attribute = a,\n                Generators = GenDataProperties.Generators(CodeGenHelper)\n                    .Where(p => p.ForDataType == a.Type)\n                    .ToList()\n            })\n            .Where(a => a.Generators.Any())\n            .SelectMany(set =>\n            {\n                return set.Generators\n                    .SelectMany(p => p.Generate(set.Attribute, Specs.TabsProperty));\n            })\n            .ToList();\n\n        if (!propsSnippets.Any())\n            return l.Return((false, null, null, null), \"no snippets found\");\n\n        // Detect duplicate names as this would fail\n        // If we have duplicates, keep the first with a real priority\n        var deduplicated = propsSnippets\n            .GroupBy(ps => ps.NameId)\n            .SelectMany(g => g.OrderBy(ps => ps.Priority ? 0 : 1).Take(1))\n            .OrderBy(ps => ps.NameId)\n            .ToList();\n\n        var sb = new StringBuilder();\n        foreach (var genCode in deduplicated)\n            sb.AppendLine(genCode.ToString());\n\n        var usings = deduplicated\n            .SelectMany(ps => ps.Usings)\n            .Distinct()\n            .OrderBy(u => u)\n            .ToList();\n\n        l.A($\"Snippets: {propsSnippets.Count}; Deduplicated: {deduplicated.Count}; Usings: {usings.Count}\");\n        var properties = sb.ToString();\n\n        return l.Return((true, properties, usings, deduplicated.First().NameId), $\"props string len: {properties.Length}\");\n    }\n\n    #endregion\n\n    #region Helper Methods for Derived Classes\n\n    protected string? GenerateCommonScopeRemarks()\n    {\n        var scope = Type.Scope;\n        var scopeIsSpecial = scope != ScopeConstants.Default;\n        return scopeIsSpecial ? $\"This Content-Type is NOT in the default scope, so you may not see it in the Admin UI. It's in the scope {scope}.\" : null;\n    }\n\n    protected string GetScopeDescription()\n    {\n        var scope = Type.Scope;\n        var scopeIsSpecial = scope != ScopeConstants.Default;\n        return scopeIsSpecial ? $\"(scope: {scope})\" : \"\";\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/CSharpModelsGeneratorBase.cs",
    "content": "using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.Ancestors;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sys.Performance;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\n/// <summary>\n/// Base class for C# models (data/custom) generators.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class CSharpModelsGeneratorBase(IUser user, IAppReaderFactory appReadFac, string logName)\n    : CSharpGeneratorBase(user, appReadFac, logName), IFileGenerator\n{\n    protected internal CSharpCodeSpecs Specs { get; protected set; } = new();\n    protected internal CSharpGeneratorHelper CodeGenHelper { get; protected set; } = null!;\n\n    // Abstract properties to be implemented by derived classes\n    public abstract string Description { get; }\n    public abstract string DescriptionHtml { get; }\n    protected abstract string GeneratedSetName { get; }\n\n    // OutputType is common\n    public string OutputType => \"DataModel\";\n\n    protected internal abstract CSharpCodeSpecs BuildDerivedSpecs(IFileGeneratorSpecs parameters);\n\n    protected virtual void Setup(IFileGeneratorSpecs parameters)\n    {\n        Specs = BuildDerivedSpecs(parameters);\n\n        var selected = GetSelectedContentTypeNameIds();\n\n        var types = selected == null\n            ? GetContentTypesInDefaultScope()\n            : GetSelectedContentTypes(selected);\n\n        Specs = Specs with { ExportedContentContentTypes = types };\n\n        CodeGenHelper = new(Specs, Log);\n    }\n\n    private List<IContentType> GetContentTypesInDefaultScope()\n    {\n        var appContentTypes = Specs.AppContentTypes;\n\n        // Prepare Content Types and add to Specs, so the generators know what is available\n        // Generate classes for all types in scope Default\n        var types = appContentTypes.ContentTypes\n            .OfScope(ScopeConstants.Default)\n            .ToList();\n\n        appContentTypes.TryGetContentType(AppLoadConstants.TypeAppResources).DoIfNotNull(types.Add);\n        appContentTypes.TryGetContentType(AppLoadConstants.TypeAppSettings).DoIfNotNull(types.Add);\n\n        var appConfigTypes = appContentTypes.ContentTypes\n            .OfScope(ScopeConstants.SystemConfiguration)\n            .Where(ct => !ct.HasAncestor())\n            .ToList();\n\n        // Fix Bug introduced in v19.03.01 or so\n        // In that UI it accidentally created new content-types called AppResources or AppSettings\n        // In the SystemConfiguration scope. These must really be ignored.\n        // In addition, to avoid any other naming conflicts, we'll just skip all the names that were already used.\n        var typeNames = types\n            .Select(t => t.Name)\n            .ToList();\n        appConfigTypes = appConfigTypes\n            .Where(ct => !typeNames.Contains(ct.Name))\n            .ToList();\n\n        types.AddRange(appConfigTypes);\n        return types;\n    }\n\n    private HashSet<string>? GetSelectedContentTypeNameIds()\n    {\n        var selected = Specs.ContentTypes?\n            .Where(name => !string.IsNullOrWhiteSpace(name))\n            .Select(name => name.Trim())\n            .Distinct(StringComparer.OrdinalIgnoreCase)\n            .ToHashSet(StringComparer.OrdinalIgnoreCase);\n\n        return selected?.Any() == true\n            ? selected\n            : null;\n    }\n\n    private List<IContentType> GetSelectedContentTypes(HashSet<string> selected)\n    {\n        var appContentTypes = Specs.AppContentTypes;\n\n        var filtered = appContentTypes.ContentTypes\n            .Where(ct => selected.Contains(ct.NameId))\n            .ToList();\n\n        return filtered.Any()\n            ? filtered\n            : []; // No content types matched selection\n    }\n\n    protected abstract IGeneratedFile? CreateFileGenerator(IContentType type, string baseName);\n    \n    public IGeneratedFileSet[] Generate(IFileGeneratorSpecs specs)\n    {\n        Setup(specs);\n\n        var classFiles = Specs.ExportedContentContentTypes\n            .Select(t =>\n            {\n                var baseName = (t.Name ?? \"\").Replace(\"-\", \"\");\n                return CreateFileGenerator(t, baseName);\n            })\n            .Where(f => f != null) // Ensure no null files are added\n            .ToListOpt();\n\n        var result = new GeneratedFileSet\n        {\n            Name = GeneratedSetName,\n            Description = Description, // This will call the derived implementation\n            Generator = $\"{Name} v{Version}\", // Name and Version from CSharpGeneratorBase\n            Path = GenerateConstants.PathToAppCode,\n            Files = classFiles.Cast<IGeneratedFile>().ToList()\n        };\n        return [result];\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/CSharpTypedDataModelGenerator.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class CSharpTypedDataModelGenerator(CSharpTypedDataModelsGenerator generator, IContentType type, string baseName) \n    : CSharpModelGeneratorBase(generator, type, baseName, generator.Log, \"Gen.DtaCls\")\n{\n    #region Overrides\n\n    protected override string ClassSuffix => Specs.Suffix ?? \"\";\n\n    protected override string GenerateFileIntroComment(string userName) =>\n        $$\"\"\"\n          // DO NOT MODIFY THIS FILE - IT IS AUTO-GENERATED\n          // See also: https://go.2sxc.org/copilot-data\n          // To extend it, create a \"{{ClassName}}.cs\" with this contents:\n          /*\n          namespace {{Generator.Specs.DataNamespace}}\n          {\n            public partial class {{ClassName}}\n            {\n              // Add your own properties and methods here\n            }\n          }\n          */\n\n          {{CSharpGeneratorHelper.GeneratorHeader(Generator, Specs, userName)}}\n          \n          \"\"\";\n\n    protected override string GenerateMainClassComment(string? firstPropertyName)\n    {\n        var remarks = GenerateCommonScopeRemarks();\n        return CodeGenHelper.CodeComment(Specs.TabsClass,\n                   $\"\"\"\n                    This is a generated class for {ClassName} {GetScopeDescription()}\n                    To extend/modify it, see instructions above.\n                    \"\"\")\n               + CodeGenHelper.XmlComment(Specs.TabsClass, summary:\n                   $\"\"\"\n                    {ClassName} data. <br/>\n                    Re-generate whenever you change the ContentType. <br/>\n                    <br/>\n                    Default properties such as `.Title` or `.Id` are provided in the base class. <br/>\n                    Most properties have a simple access, such as `.{firstPropertyName}`. <br/>\n                    For other properties or uses, use methods such as\n                    .IsNotEmpty(\"FieldName\"), .String(\"FieldName\"), .Children(...), .Picture(...), .Html(...).\n                    \"\"\",\n                   remarks: remarks);\n    }\n\n    protected override string GenerateAutoGenClassComment() =>\n        CodeGenHelper.XmlComment(Specs.TabsClass,\n            summary:\n            $\"Auto-Generated *base* class for '{ClassName}' in scope '{Type.Scope}'. \" +\n            $\"It uses special names to avoid accidental use.\");\n\n    #endregion\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/CSharpTypedDataModelsGenerator.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\n/// <summary>\n/// Experimental\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CSharpTypedDataModelsGenerator(IUser user, IAppReaderFactory appReadFac)\n    : CSharpModelsGeneratorBase(user, appReadFac, SxcLogName + \".DMoGen\") // IFileGenerator is inherited from base\n{\n    #region Information for the interface\n\n    public override string Description => \"Generates C# Data Classes for the AppCode/Data folder\";\n\n    public override string DescriptionHtml => $\"The {Name} will generate <code>[TypeName].Generated.cs</code> files in the <code>AppCode/Data</code> folder.\";\n\n    protected override string GeneratedSetName => \"C# Data Classes\";\n\n    #endregion\n\n    protected internal override CSharpCodeSpecs BuildDerivedSpecs(IFileGeneratorSpecs parameters) => BuildSpecs(parameters);\n\n    protected override IGeneratedFile? CreateFileGenerator(IContentType type, string baseName) \n        => new CSharpTypedDataModelGenerator(this, type, baseName).PrepareFile();\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyBase.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal abstract class GeneratePropertyBase(CSharpGeneratorHelper helper)\n{\n    protected CSharpCodeSpecs Specs = helper.Specs;\n\n    public abstract ValueTypes ForDataType { get; }\n\n    public abstract List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs);\n\n    protected CodeFragment GenPropSnip(int tabs, string returnType, string name, string method,\n        NoParamOrder npo = default,\n        string? sourceName = default,\n        string[]? summary = default,\n        string[]? remarks = default,\n        string[]? returns = default,\n        string? parameters = default,\n        bool priority = true,\n        List<string>? usings = default,\n        bool cache = false,\n        bool jsonIgnore = false)\n    {\n        var overrideProp = helper.OverridePropertyNames.Contains(name);\n        var overrideMeth = helper.OverrideMethods.Contains(method);\n        var isOverride = overrideProp || overrideMeth;\n        if (isOverride)\n        {\n            var originalName = overrideProp ? $\"property {name}\" : $\"method {name}(...)\";\n            remarks =\n            [\n                ..remarks ?? [],\n                $\"This hides base {originalName}.\",\n                \"To access original, convert using AsItem(...) or cast to ITypedItem.\",\n                \"Consider renaming this field in the underlying content-type.\"\n            ];\n        }\n\n        var comment = helper.XmlComment(tabs, summary: summary, remarks: remarks, returns: returns);\n        return new(\n            name,\n            comment\n            + GenAttribute(jsonIgnore, tabs)\n            + GenProp(tabs, returnType, name, sourceName ?? name, method, parameters: parameters, cache, isOverride),\n            priority: priority,\n            usings: GenUsings(usings ?? [], jsonIgnore)\n        );\n    }\n\n    private string GenAttribute(bool jsonIgnore, int tabs) \n        => jsonIgnore ? $\"\\n{helper.Indent(tabs)}[JsonIgnore]\\n\" : \"\";\n\n    private string GenProp(int tabs, string returnType, string name, string sourceName, string method, string? parameters, bool cache, bool isOverride)\n    {\n        if (parameters.HasValue())\n            parameters = \", \" + parameters;\n\n        var indent = helper.Indent(tabs);\n\n        var cacheVarName = $\"_{char.ToLower(name[0])}{name.Substring(1)}\";\n        var cacheResult = cache ? $\"{cacheVarName} ??= \" : \"\";\n\n        var newPrefix = isOverride ? \"new \" : \"\";\n\n        var mainCode = $\"{indent}public {newPrefix}{returnType} {name} => {cacheResult}{method}(\\\"{sourceName}\\\"{parameters});\";\n\n        var cacheCode = cache\n            ? $\"\\n{indent}private {returnType} {cacheVarName};\"\n            : null;\n\n        return mainCode + cacheCode;\n    }\n\n    private static List<string> GenUsings(List<string> usings, bool jsonIgnore) \n        => jsonIgnore \n            ? [\"System.Text.Json.Serialization\", .. usings] \n            : usings;\n\n\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyBool.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GeneratePropertyBool(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.Boolean;\n\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n    {\n        var name = attribute.Name;\n\n        return [GenPropSnip(tabs, \"bool\", name, $\"{Specs.ItemAccessor}.Bool\", summary:\n        [\n            $\"{name} as bool. <br/>\",\n            $\"To get nullable use .Get(\\\"{name}\\\") as bool?;\"\n        ])];\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyCustom.cs",
    "content": "﻿using ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GeneratePropertyCustom(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.Custom;\n\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n    {\n        if (attribute.InputType != \"custom-gps\")\n            return [];\n\n        var name = attribute.Name;\n\n        return\n        [\n            GenPropSnip(tabs, \"GpsCoordinates\", name, $\"{Specs.ItemAccessor}.Gps\", usings: UsingCustomData, summary:\n            [\n                $\"{name} as GPS Coordinates object with {nameof(GpsCoordinates.Latitude)} and {nameof(GpsCoordinates.Longitude)}.\",\n            ]),\n        ];\n    }\n\n    private List<string> UsingCustomData { get; } =\n    [\n        typeof(GpsCoordinates).Namespace!,\n    ];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyDateTime.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GeneratePropertyDateTime(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.DateTime;\n\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n    {\n        var name = attribute.Name;\n\n        return\n        [\n            GenPropSnip(tabs, \"DateTime\", name, $\"{Specs.ItemAccessor}.DateTime\", usings: UsingDateTime, summary:\n            [\n                $\"{name} as DateTime.\",\n            ]),\n        ];\n    }\n\n    private List<string> UsingDateTime { get; } = [\"System\"];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyEmpty.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GeneratePropertyEmpty(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.Empty;\n\n    /// <summary>\n    /// Empty is - empty - so we don't generate anything\n    /// </summary>\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n        => [];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyEntity.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GeneratePropertyEntity(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.Entity;\n\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n    {\n        var name = attribute.Name;\n\n        var entityType = attribute.Metadata.Get<string>(\"EntityType\");\n        var allowMulti = attribute.Metadata.Get<bool>(\"AllowMultiValue\");\n\n        var msgPrefix = $\"{name} as \" + (allowMulti ? \"list\" : \"single item\") + \" of\";\n        // var msgSuffix = \"Use methods such as .Children(\\\"{name}\\\") or .Child(\\\"{name}\\\") to get the actual items.\";\n        var method = allowMulti ? \"Children\" : \"Child\";\n        var result = allowMulti ? \"IEnumerable<{0}>\" : \"{0}\";\n        var resultType = nameof(ITypedItem);\n        var usings = UsingTypedItems;\n\n        // TODO: CONSIDER GOING TO lIST - REQUIRES A ToList at the end.\n\n        var msgReturns = allowMulti\n            ? \"An IEnumerable of specified type, but can be empty.\"\n            : \"A single item OR null if nothing found, so you can use ?? to provide alternate objects.\";\n\n        var msgRemarks = allowMulti\n            ? \"Generated to return child-list child because field settings had Multi-Value=true. \"\n            : \"Generated to only return 1 child because field settings had Multi-Value=false. \";\n\n        // If we know the entity type, we can use the actual type instead of ITypedItem\n        if (entityType.HasValue())\n            Specs.ExportedContentContentTypes\n                .FirstOrDefault(t => entityType.EqualsInsensitive(t.Name))\n                .DoIfNotNull(ct =>\n                {\n                    // Switch the result type\n                    resultType = ct.Name;\n                    // Make the method generic returning the expected type\n                    method += $\"<{resultType}>\";\n                    // No usings needed, as the type is already in the namespace\n                    usings = allowMulti ? UsingList : [];\n                    msgRemarks += $\"The type {resultType} was specified in the field settings.\";\n                });\n\n        return\n        [\n            GenPropSnip(tabs, string.Format(result, resultType), name, $\"{Specs.ItemAccessor}.\" + method, cache: true, usings: usings,\n                summary: [$\"{msgPrefix} {resultType}.\"],\n                remarks: [msgRemarks],\n                returns: [msgReturns]\n            ),\n        ];\n    }\n\n    private List<string> UsingList { get; } =\n    [\n        \"System.Collections.Generic\",\n    ];\n\n    private List<string> UsingTypedItems { get; } =\n    [\n        \"System.Collections.Generic\",\n        \"ToSic.Sxc.Data\"\n    ];\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyHyperlink.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GeneratePropertyHyperlink(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.Hyperlink;\n\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n    {\n        var name = attribute.Name;\n\n        return\n        [\n            GenPropSnip(tabs, \"string\", name, $\"{Specs.ItemAccessor}.Url\", summary:\n            [\n                $\"{name} as link (url). <br/>\",\n                $\"To get the underlying value like 'file:72' use String(\\\"{name}\\\")\"\n            ]),\n            GenPropSnip(tabs, \"IFile\", name + \"File\", $\"{Specs.ItemAccessor}.File\", sourceName: name, priority: false, usings: UsingAdam, jsonIgnore: true ,summary:\n            [\n                $\"Get the file object for {name} - or null if it's empty or not referencing a file.\"\n            ]),\n            GenPropSnip(tabs, \"IFolder\", name + \"Folder\", $\"{Specs.ItemAccessor}.Folder\", sourceName: name, priority: false, usings: UsingAdam, jsonIgnore: true ,summary:\n            [\n                $\"Get the folder object for {name}.\"\n            ]),\n        ];\n    }\n\n    private List<string> UsingAdam { get; } = [\"ToSic.Sxc.Adam\"];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyNumber.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GeneratePropertyNumber(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.Number;\n\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n    {\n        var name = attribute.Name;\n\n        var decimals = attribute.Metadata.Get<int>(\"Decimals\");\n\n        return decimals == 0\n            ?\n            [\n                GenPropSnip(tabs, \"int\", name, $\"{Specs.ItemAccessor}.Int\", summary:\n                [\n                    $\"{name} as int. <br/>\",\n                    $\"To get other types use methods such as .Decimal(\\\"{name}\\\")\"\n                ]),\n            ]\n            :\n            [\n                GenPropSnip(tabs, \"decimal\", name, $\"{Specs.ItemAccessor}.Decimal\", summary:\n                [\n                    $\"{name} as decimal. <br/>\",\n                    $\"To get other types use methods such as .Int(\\\"{name}\\\")\"\n                ]),\n            ];\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/GeneratePropertyString.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GeneratePropertyString(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.String;\n\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n    {\n        var name = attribute.Name;\n\n        // If we're generating a \"Title\" for a property that is already the title, don't generate it again\n        // Don't do this. Reason is that it will confuse people why it's missing, and serialization might also miss it.\n        // if (name == Attributes.TitleNiceName && attribute.IsTitle) return [];\n\n        return\n        [\n            GenPropSnip(tabs: tabs, returnType: \"string\", name: name, method: $\"{Specs.ItemAccessor}.String\",\n                parameters: \"fallback: \\\"\\\"\",\n                summary:\n                [\n                    $\"{name} as string. <br/>\",\n                    $\"For advanced manipulation like scrubHtml, use .String(\\\"{name}\\\", scrubHtml: true) etc.\"\n                ]),\n        ];\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/ModelGeneratorConstants.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\ninternal class ModelGeneratorConstants\n{\n    /// <summary>\n    /// These names exist in the base class, so we need to override them with `new`.\n    /// It would work without this override, but would add warnings that can confuse users.\n    /// </summary>\n    public static readonly string[] OverridePropertyNames =\n    [\n        nameof(ITypedItem.Id),\n        nameof(ITypedItem.Guid),\n        nameof(ITypedItem.Title),\n        nameof(ITypedItem.Type),\n        nameof(ITypedItem.Metadata),\n        nameof(ITypedItem.Presentation),\n        nameof(ITypedItem.IsPublished),\n        nameof(ITypedItem.Publishing),\n        nameof(ITypedItem.IsDemoItem),\n        nameof(ITypedItem.Entity),\n        nameof(ITypedItem.Type),\n        nameof(ITypedItem.Field),\n        // Using name directly for Html because otherwise we would need to reference RazorBlade assembly which we want to avoid just for this one property\n        /*nameof(ITypedItem.Html)*/ \"Html\",\n        nameof(ITypedItem.Picture),\n        nameof(ITypedItem.Url),\n        nameof(ITypedItem.Img),\n        nameof(ITypedItem.File),\n        nameof(ITypedItem.Folder),\n        nameof(ITypedItem.Gps),\n        // Using name directly for Attribute because otherwise we would need to reference RazorBlade assembly which we want to avoid just for this one property\n        /*nameof(ITypedItem.Attribute)*/ \"Attribute\",\n\n        nameof(ITypedItem.IsEmpty),\n        nameof(ITypedItem.IsNotEmpty),\n        nameof(ITypedItem.Keys),\n        nameof(ITypedItem.ContainsKey),\n        nameof(ITypedItem.Get),\n\n        nameof(ITypedItem.Bool),\n        nameof(ITypedItem.DateTime),\n        nameof(ITypedItem.String),\n        nameof(ITypedItem.Int),\n        nameof(ITypedItem.Double),\n        nameof(ITypedItem.Decimal),\n        nameof(ITypedItem.Long),\n        nameof(ITypedItem.Float),\n\n        nameof(ITypedItem.Child),\n        nameof(ITypedItem.Children),\n        nameof(ITypedItem.Parent),\n        nameof(ITypedItem.Parents),\n\n    ];\n\n    public static readonly string[] OverrideMethods =\n    [\n        nameof(ITypedItem.Field),\n\n        nameof(ITypedItem.Get),\n        nameof(ITypedItem.Bool),\n        nameof(ITypedItem.DateTime),\n        nameof(ITypedItem.String),\n        nameof(ITypedItem.Int),\n        nameof(ITypedItem.Double),\n        nameof(ITypedItem.Decimal),\n        nameof(ITypedItem.Long),\n        nameof(ITypedItem.Float),\n\n        nameof(ITypedItem.Child),\n        nameof(ITypedItem.Children),\n        nameof(ITypedItem.Parent),\n        nameof(ITypedItem.Parents),\n\n        nameof(ITypedItem.Attribute),\n        nameof(ITypedItem.Url),\n        nameof(ITypedItem.Img),\n        nameof(ITypedItem.Picture),\n        nameof(ITypedItem.Html),\n\n        nameof(ITypedItem.File),\n        nameof(ITypedItem.Folder),\n        nameof(ITypedItem.Gps),\n\n        // Key / value handling methods\n        nameof(ITypedItem.ContainsKey),\n        nameof(ITypedItem.IsEmpty),\n        nameof(ITypedItem.IsNotEmpty),\n        nameof(ITypedItem.Keys),\n    ];\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Data/PropertyGenerators.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Data;\n\ninternal class GenDataProperties\n{\n    internal static List<GeneratePropertyBase> Generators(CSharpGeneratorHelper helper)\n    {\n        return\n        [\n            new GeneratePropertyBool(helper),\n            new GeneratePropertyString(helper),\n            new GeneratePropertyEmpty(helper),\n            new GeneratePropertyHyperlink(helper),\n            new GeneratePropertyNumber(helper),\n            new GeneratePropertyDateTime(helper),\n            new GeneratePropertyCustom(helper),\n            new GeneratePropertyEntity(helper),\n        ];\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CSharp/CSharpCodeSpecs.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal record CSharpCodeSpecs: FileGeneratorSpecs\n{\n    private const string ItemAccessorDefault = \"_item\"; // TODO: nameof(CustomItem._item);\n    private const string DefAutoGenNamespace = \"AutoGenerated\";\n\n    public string AppName { get; init; } = \"App\";\n\n    internal IAppReadContentTypes AppContentTypes { get; init; } = null!; // not sure where this is set, nullability should be improved\n\n    public List<IContentType> ExportedContentContentTypes { get; init; } = null!; // not sure where this is set, nullability should be improved\n\n    /// <summary>\n    /// Namespace for the data classes\n    /// TODO: UNCLEAR IF THIS IS NEEDED, OR IF WE SHOULD NOT JUST USE Namespace FROM BASE CLASS\n    /// </summary>\n    public string DataNamespace { get; init; } = $\"{FolderConstants.AppCodeFolder}.Data\";\n\n    public string NamespaceAutoGen { get; init; } = DefAutoGenNamespace;\n\n    /// <summary>\n    /// Namespace for the data classes\n    /// </summary>\n    public string BaseClassNamespace => $\"{DataNamespace}.{NamespaceAutoGen}\";\n\n    /// <summary>\n    /// This is added to the end of the class name to indicate that it was auto-generated.\n    /// It's quite verbose, to ensure that it's unlikely to clash with a real class name.\n    /// </summary>\n    public string BaseClassSuffix { get; init; } = \"\";\n\n    public string BaseClassPrefix { get; init; } = \"ZAutoGen\";\n\n    /// <summary>\n    /// Default class to inherit from - ATM CustomItem only\n    /// </summary>\n    public string DataInherits { get; init; } = \"Custom.Data.CustomItem\";\n\n    public string ItemAccessor { get; init; } = ItemAccessorDefault;\n\n\n    /// <summary>\n    /// This is added to the end of a file name to indicate that it was auto-generated.\n    /// It's shorter for practical reasons, and should start with a dot and a letter > \"c\"\n    /// so that in the list of files it will be after the \".cs\" file which may be created.\n    /// </summary>\n    public string FileGeneratedSuffix { get; init; } = \".Generated\";\n\n    /// <summary>\n    /// Tab size for the generated code\n    /// </summary>\n    public int TabSize { get; init; } = 2;\n\n    /// <summary>\n    /// Tabs in front of namespace code\n    /// </summary>\n    public int TabsNamespace { get; init; } = 0;\n\n    /// <summary>\n    /// Tabs in front of class code\n    /// </summary>\n    public int TabsClass { get; init; } = 1;\n\n    /// <summary>\n    /// Tabs in front of property code\n    /// </summary>\n    public int TabsProperty { get; init; } = 2;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CSharp/CSharpGeneratorBase.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Sxc.Sys;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Experimental\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class CSharpGeneratorBase(IUser user, IAppReaderFactory appReadFac, string? logName)\n    : ServiceBase(logName ?? (SxcLogName + \".DMoGen\"))\n{\n\n    internal IUser User = user;\n\n    #region Information for the interface\n\n    public string NameId => GetType().FullName!;\n\n    public string Name => GetType().Name;\n\n    public string Version => SxcSharedAssemblyInfo.AssemblyVersion;\n\n    public string OutputLanguage => \"CSharp\";\n\n    #endregion\n\n    internal CSharpCodeSpecs BuildSpecs(IFileGeneratorSpecs parameters)\n    {\n        // Prepare App State and add to Specs\n        var appReader = appReadFac.Get(parameters.AppId);\n\n        var specs = new CSharpCodeSpecs\n        {\n            AppId = parameters.AppId,\n            Edition = parameters.Edition ?? \"\",\n            DateTime = parameters.DateTime,\n            Namespace = parameters.Namespace,\n            TargetPath = parameters.TargetPath,\n            ContentTypes = parameters.ContentTypes,\n            Prefix = parameters.Prefix,\n            Suffix = parameters.Suffix,\n            AppContentTypes = appReader,\n            AppName = appReader.Specs.Name,\n        };\n        if (!string.IsNullOrWhiteSpace(parameters.Namespace))\n            specs = specs with { DataNamespace = parameters.Namespace! };\n        //if (parameters.Suffix != null)\n            //specs = specs with { DataClassGeneratedSuffix = parameters.Suffix };\n\n        return specs;\n    }\n    \n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CSharp/CSharpGeneratorHelper.cs",
    "content": "﻿using System.Text;\nusing ToSic.Sxc.Code.Generate.Data;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\ninternal class CSharpGeneratorHelper(CSharpCodeSpecs specs, ILog parentLog): HelperBase(parentLog, \"Cde.GenHlp\")\n{\n    public CSharpCodeSpecs Specs => specs;\n\n    public string[] OverridePropertyNames { get; set; } = ModelGeneratorConstants.OverridePropertyNames;\n    public string[] OverrideMethods { get; set; } = ModelGeneratorConstants.OverrideMethods;\n\n    public string Indent(int depth) => new(' ', specs.TabSize * depth);\n\n    public void AddLines(StringBuilder sb, int lines)\n    {\n        for (var i = 0; i < lines; i++)\n            sb.AppendLine();\n    }\n\n    public string CodeComment(int tabs, string comment, int padBefore = 1, int padAfter = default, int altGap = 1)\n        => CodeComment(tabs, comment.SplitNewLine(), padBefore, padAfter, altGap);\n\n    public string CodeComment(int tabs, string[] comment, int padBefore = 1, int padAfter = default, int altGap = 1)\n    {\n        var l = Log.Fn<string>();\n        // If nothing, return empty lines as much as altGap\n        if (!comment.SafeAny())\n            return new('\\n', altGap);\n\n        // Summary\n        var sb = new StringBuilder();\n        AddLines(sb, padBefore);\n        var indent = Indent(tabs);\n        foreach (var c in comment)\n            sb.AppendLine($\"{indent}// {c}\");\n        AddLines(sb, padAfter);\n\n        return l.Return(sb.ToString());\n    }\n\n    public string XmlComment(int tabs, string? summary = default, string? remarks = default, string? returns = default, int padBefore = 1, int padAfter = default,\n        int altGap = 1)\n        => XmlComment(tabs, summary: summary.SplitNewLine(), remarks: remarks.SplitNewLine(), returns: returns.SplitNewLine(), padBefore: padBefore, padAfter: padAfter, altGap: altGap);\n\n    public string XmlComment(int tabs, string[]? summary = default, string[]? remarks = default, string[]? returns = default, int padBefore = 1, int padAfter = default, int altGap = 1)\n    {\n        var l = Log.Fn<string>();\n        // 1. If nothing, return empty lines as much as altGap\n        // first merge all the comments to see if we have any\n        var merged = (summary ?? []).Concat(returns ?? []).ToList();\n        if (!merged.Any() || merged.All(s => s.IsEmptyOrWs()))\n            return new('\\n', altGap);\n\n        var sb = new StringBuilder();\n        AddLines(sb, padBefore);\n        var indent = Indent(tabs);\n\n        // Summary\n        var summaryComment = XmlCommentOne(indent, \"summary\", summary);\n        if (summaryComment.HasValue())\n            sb.Append(summaryComment);\n\n        // Remarks\n        var remarksComment = XmlCommentOne(indent, \"remarks\", remarks);\n        if (remarksComment.HasValue())\n            sb.Append(remarksComment);\n\n        // Returns\n        var returnsComment = XmlCommentOne(indent, \"returns\", returns);\n        if (returnsComment.HasValue())\n            sb.Append(returnsComment);\n\n        AddLines(sb, padAfter);\n\n        return l.Return(sb.ToString());\n    }\n\n    private static string? XmlCommentOne(string indent, string tagName, string[]? comments = default)\n    {\n        // If nothing, return empty lines as much as altGap\n        if (comments == null || comments.All(s => s.IsEmptyOrWs()))\n            return null;\n\n        // Single liner\n        // 2024-02-16 2dm disabled for now, seems like an optimization but the code is harder to read\n        //if (comments.Length == 1)\n        //    return $\"{indent}/// <{tagName}>{comments[0]}</{tagName}>\";\n\n        // Multi-liner\n        var sb = new StringBuilder();\n        sb.AppendLine($\"{indent}/// <{tagName}>\");\n        foreach (var l in comments) sb.AppendLine($\"{indent}/// {l}\");\n        sb.AppendLine($\"{indent}/// </{tagName}>\");\n\n        return sb.ToString();\n    }\n\n    public string? GenerateUsings(List<string>? usings)\n    {\n        if (usings == null || !usings.Any())\n            return null;\n        var sb = new StringBuilder();\n        foreach (var u in usings) sb.AppendLine($\"using {u};\");\n        sb.AppendLine();\n        return sb.ToString();\n    }\n\n    internal CodeFragment NamespaceWrapper(string @namespace)\n    {\n        var l = Log.Fn<CodeFragment>($\"{nameof(@namespace)}: {@namespace}\");\n        return l.Return(new(\"namespace\", $\"{Indent(specs.TabsNamespace)}namespace {@namespace}\" + \"\\n{\", closing: \"}\"));\n    }\n\n    internal CodeFragment ClassWrapper(string className, bool isAbstract, bool isPartial, string? inherits)\n    {\n        var l = Log.Fn<CodeFragment>($\"{nameof(className)}: {className}; {nameof(isAbstract)}: {isAbstract}; {nameof(isPartial)}: {isPartial}; {nameof(inherits)}: {inherits}\");\n        var indent = Indent(specs.TabsClass);\n        var specifiers = (isAbstract ? \"abstract \" : \"\") + (isPartial ? \"partial \" : \"\");\n        inherits = inherits.NullOrGetWith(i => $\": {i}\");\n\n        var start = $$\"\"\"\n                      {{indent}}public {{specifiers}}class {{className}}{{inherits}}\n                      {{indent}}{\n                      \"\"\";\n        return l.Return(new(\"class\", start, closing: $\"{indent}}}\\n\"));\n    }\n\n    public static string GeneratorHeader(IFileGenerator generator, CSharpCodeSpecs specs, string userName) =>\n        $\"\"\"\n         // Generator:   {generator.Name}\n         // App/Edition: {specs.AppName}/{specs.Edition}\n         // User:        {userName}\n         \"\"\";\n\n    public static string DoNotModifyMessage = \"\"\"\n                                              // DO NOT MODIFY THIS FILE - IT IS AUTO-GENERATED\n                                              // All the classes are partial, so you can extend them in a separate file.\n                                              \"\"\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CSharp/GeneratePropertyApp.cs",
    "content": "﻿using ToSic.Sxc.Code.Generate.Data;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\ninternal class GeneratePropertyApp(CSharpGeneratorHelper helper) : GeneratePropertyBase(helper)\n{\n    public override ValueTypes ForDataType => ValueTypes.Undefined;\n\n    public override List<CodeFragment> Generate(IContentTypeAttribute attribute, int tabs)\n    {\n\n\n\n\n        var name = attribute.Name;\n\n        var entityType = attribute.Metadata.Get<string>(\"EntityType\");\n        var allowMulti = attribute.Metadata.Get<bool>(\"AllowMultiValue\");\n\n        var msgPrefix = $\"{name} as \" + (allowMulti ? \"list\" : \"single item\") + \" of\";\n        // var msgSuffix = \"Use methods such as .Children(\\\"{name}\\\") or .Child(\\\"{name}\\\") to get the actual items.\";\n        var method = allowMulti ? \"Children\" : \"Child\";\n        var result = allowMulti ? \"IEnumerable<{0}>\" : \"{0}\";\n        var resultType = nameof(ITypedItem);\n        var usings = UsingTypedItems;\n\n        // TODO: CONSIDER GOING TO lIST - REQUIRES A ToList at the end.\n\n        var msgReturns = allowMulti\n            ? \"An IEnumerable of specified type, but can be empty.\"\n            : \"A single item OR null if nothing found, so you can use ?? to provide alternate objects.\";\n\n        var msgRemarks = allowMulti\n            ? \"Generated to return child-list child because field settings had Multi-Value=true. \"\n            : \"Generated to only return 1 child because field settings had Multi-Value=false. \";\n\n        // If we know the entity type, we can use the actual type instead of ITypedItem\n        if (entityType.HasValue())\n            Specs.ExportedContentContentTypes\n                ?.FirstOrDefault(t => entityType.EqualsInsensitive(t.Name))\n                .DoIfNotNull(ct =>\n                {\n                    // Switch the result type\n                    resultType = ct.Name;\n                    // Make the method generic returning the expected type\n                    method += $\"<{resultType}>\";\n                    // No usings needed, as the type is already in the namespace\n                    usings = allowMulti ? UsingList : [];\n                    msgRemarks += $\"The type {resultType} was specified in the field settings.\";\n                });\n\n        return\n        [\n            GenPropSnip(tabs, string.Format(result, resultType), name, $\"{Specs.ItemAccessor}.\" + method, cache: true, usings: usings,\n                summary: [\"Typed App with typed Settings & Resources\"]\n            ),\n        ];\n    }\n\n    private List<string> UsingList { get; } =\n    [\n        \"System.Collections.Generic\",\n    ];\n\n    private List<string> UsingTypedItems { get; } =\n    [\n        \"System.Collections.Generic\",\n        \"ToSic.Sxc.Data\"\n    ];\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CSharpBaseClasses/BaseClassHelper.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys.CSharpBaseClasses;\n\ninternal class BaseClassHelper\n{\n    internal static (CSharpGeneratorHelper CSharpGenHelper, CodeFragment AppSnip, List<string> Usings) BaseClassTools(CSharpCodeSpecs cSharpSpecs, ILog parentLog)\n    {\n        var l = parentLog.Fn();\n        var codeGenHelper = new CSharpGeneratorHelper(cSharpSpecs, parentLog);\n\n        var snipApp = AppPropertyCodeFragment(codeGenHelper, parentLog);\n\n        var allUsings = snipApp.Usings\n            .Distinct()\n            .OrderBy(u => u)\n            .Select(u => $\"using {u};\")\n            .ToList();\n\n        l.Done();\n        return (codeGenHelper, snipApp, allUsings);\n    }\n\n    private static CodeFragment AppPropertyCodeFragment(CSharpGeneratorHelper codeGenHelper, ILog parentLog)\n    {\n        var l = parentLog.Fn<CodeFragment>();\n        var tabs = codeGenHelper.Specs.TabsProperty;\n        var indent = codeGenHelper.Indent(tabs);\n        var summary = codeGenHelper.XmlComment(tabs, [\"Typed App with typed Settings & Resources\"]);\n        var snipApp = new CodeFragment(\n            \"App\",\n            summary +\n            $\"\"\"\n             {indent}public new IAppTyped<AppSettings, AppResources> App => _app ??= Customize.App<AppSettings, AppResources>();\n             {indent}private IAppTyped<AppSettings, AppResources> _app;\n             \"\"\",\n            true,\n            [\"AppCode.Data\", \"ToSic.Sxc.Apps\"]\n        );\n\n        return l.Return(snipApp);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CSharpBaseClasses/CSharpServicesGenerator.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Code.Generate.Sys.CSharpBaseClasses;\n\n/// <summary>\n/// Experimental\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CSharpServicesGenerator(IUser user, IAppReaderFactory appReadFac)\n    : CSharpGeneratorBase(user, appReadFac, SxcLogName + \".SvcGen\"), IFileGenerator\n{\n    #region Information for the interface\n\n    public string Description => \"Generates CSharp Service Base Classes in the AppCode/Services folder\";\n\n    public string DescriptionHtml => $\"The {Name} will generate <code>[Prefix]ServiceBase[Suffix].Generated.cs</code> files in the <code>AppCode/Services</code> folder. <br> IMPORTANT: Requires that Content-Types were generated.\";\n\n    public string OutputType => \"RazorView\";// \"CSharpService\";\n\n    #endregion\n\n\n    public IGeneratedFileSet[] Generate(IFileGeneratorSpecs specs)\n    {\n        var cSharpSpecs = BuildSpecs(specs);\n\n        var file = CSharpServiceBase(cSharpSpecs, \"ServiceBase\", \"Custom.Hybrid.CodeTyped\", \"Services\");\n\n        var result = new GeneratedFileSet\n        {\n            Name = \"C# Services\",\n            Description = Description,\n            Generator = $\"{Name} v{Version}\",\n            Path = GenerateConstants.PathToAppCode,\n            Files = [file],\n        };\n        return [result];\n    }\n\n    internal GeneratedFile CSharpServiceBase(CSharpCodeSpecs cSharpSpecs, string baseName, string baseClass, string nsAndPath)\n    {\n        var className = $\"{cSharpSpecs.Prefix}{baseName}{cSharpSpecs.Suffix}\";\n        var (_, appSnip, allUsings) = BaseClassHelper.BaseClassTools(cSharpSpecs, Log);\n\n        var file = new GeneratedFile\n        {\n            FileName = $\"{className}.Generated.cs\",\n            Path = nsAndPath,\n            Body = $$\"\"\"\n                     {{CSharpGeneratorHelper.DoNotModifyMessage}}\n                     \n                     {{CSharpGeneratorHelper.GeneratorHeader(this, cSharpSpecs, User.Name)}}\n                     \n                     {{string.Join(\"\\n\", allUsings)}}\n                     \n                     namespace AppCode.{{nsAndPath}}\n                     {\n                       /// <summary>\n                       /// Base Class for Services which have a typed App.\n                       /// </summary>\n                       public abstract partial class {{className}}: {{baseClass}}\n                       {\n                     {{appSnip}}\n                       }\n                     }\n\n                     \"\"\",\n            Dependencies = [],\n        };\n        return file;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CSharpBaseClasses/RazorViewsGenerator.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Code.Generate.Sys.CSharpBaseClasses;\n\n/// <summary>\n/// Experimental\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class RazorViewsGenerator(IUser user, IAppReaderFactory appReadFac)\n    : CSharpGeneratorBase(user, appReadFac, SxcLogName + \".RzrVGn\"), IFileGenerator\n{\n    #region Information for the interface\n\n    public string Description => \"Generates Razor Views in the AppCode/Razor folder\";\n\n    public string DescriptionHtml => $\"The {Name} will generate <code>[Prefix]AppRazor[Suffix].Generated.cs</code> files in the <code>AppCode/Razor</code> folder. <br> IMPORTANT: Requires that Content-Types were generated.\";\n\n    public string OutputType => \"RazorView\";\n\n    #endregion\n\n\n    public IGeneratedFileSet[] Generate(IFileGeneratorSpecs specs)\n    {\n        var cSharpSpecs = BuildSpecs(specs);\n        var file = AppRazors(cSharpSpecs, \"AppRazor\");\n\n        var result = new GeneratedFileSet\n        {\n            Name = \"C# Razor Views\",\n            Description = Description,\n            Generator = $\"{Name} v{Version}\",\n            Path = GenerateConstants.PathToAppCode,\n            Files = [file],\n        };\n        return [result];\n    }\n\n    private GeneratedFile AppRazors(CSharpCodeSpecs cSharpSpecs, string baseName)\n    {\n        var className = $\"{cSharpSpecs.Prefix}{baseName}{cSharpSpecs.Suffix}\";\n        var (_, appSnip, allUsings) = BaseClassHelper.BaseClassTools(cSharpSpecs, Log);\n\n        var file = new GeneratedFile\n        {\n            FileName = $\"{className}.Generated.cs\",\n            Path = \"Razor\",\n            Body = $$\"\"\"\n                     {{CSharpGeneratorHelper.DoNotModifyMessage}}\n\n                     {{CSharpGeneratorHelper.GeneratorHeader(this, cSharpSpecs, User.Name)}}\n\n                     {{string.Join(\"\\n\", allUsings)}}\n\n                     namespace AppCode.Razor\n                     {\n                       /// <summary>\n                       /// Base Class for Razor Views which have a typed App but don't use the Model or use the typed MyModel.\n                       /// </summary>\n                       public abstract partial class {{className}}: {{className}}<object>\n                       {\n                       }\n                     \n                       /// <summary>\n                       /// Base Class for Razor Views which have a typed App and a typed Model\n                       /// </summary>\n                       public abstract partial class {{className}}<TModel>: Custom.Hybrid.RazorTyped<TModel>\n                       {\n                     {{appSnip}}\n                       }\n                     }\n\n                     \"\"\",\n            Dependencies = [],\n        };\n        return file;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CSharpBaseClasses/WebApiGenerator.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Code.Generate.Sys.CSharpBaseClasses;\n\n/// <summary>\n/// Experimental\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WebApiGenerator(IUser user, IAppReaderFactory appReadFac)\n    : CSharpServicesGenerator(user, appReadFac), IFileGenerator\n{\n    #region Information for the interface\n\n    public new string Description => \"Generates CSharp WebApi Base Controller in the AppCode/Api folder (WIP)\";\n\n    public new string DescriptionHtml => $\"The {Name} will generate <code>[Prefix]ControllerBase[Suffix].Generated.cs</code> files in the <code>AppCode/Api</code> folder. <br> IMPORTANT: Requires that Content-Types were generated.\";\n\n    public new string OutputType => \"WebApi\";\n\n    #endregion\n\n\n    public new IGeneratedFileSet[] Generate(IFileGeneratorSpecs specs)\n    {\n        var cSharpSpecs = BuildSpecs(specs);\n\n        var file = CSharpServiceBase(cSharpSpecs, \"ControllerBase\", \"Custom.Hybrid.ApiTyped\", \"Api\");\n\n        var result = new GeneratedFileSet\n        {\n            Name = \"C# Services\",\n            Description = Description,\n            Generator = $\"{Name} v{Version}\",\n            Path = GenerateConstants.PathToAppCode,\n            Files = [file],\n        };\n        return [result];\n    }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CodeFragment.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Temporary object to hold the generated code and usings,\n/// so that the caller can later merge all required usings.\n/// </summary>\n/// <param name=\"code\"></param>\n/// <param name=\"usings\"></param>\n/// <param name=\"closing\">special closing string if the code wraps something else</param>\ninternal class CodeFragment(string nameId, string code, bool priority = true, List<string>? usings = default, string? closing = default)\n{\n    /// <summary>\n    /// Distinct property name to deduplicate, in case multiple fragments would generate the same property.\n    ///\n    /// like if we had a string property `ImageFile` and a file property `Image` which would both generate a property `ImageFile`,\n    /// </summary>\n    public string NameId { get; } = nameId;\n\n    /// <summary>\n    /// Priority to respect when deduplicating properties.\n    /// </summary>\n    public bool Priority { get; } = priority;\n\n    /// <summary>\n    /// List of additional usings when generating, which would end up on top.\n    /// </summary>\n    public List<string> Usings { get; } = usings ?? [];\n\n    /// <summary>\n    /// ToString should basically create the code - without contents.\n    /// </summary>\n    /// <returns></returns>\n    public override string ToString() => ToString(null);\n\n    /// <summary>\n    /// Convert to string, wrapping the contents with the code and closing.\n    /// </summary>\n    /// <param name=\"contents\"></param>\n    /// <returns></returns>\n    public string ToString(string? contents) => code + contents + closing;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CopilotContentTypeAutoGenerateService.cs",
    "content": "using ToSic.Eav.Apps;\nusing ToSic.Sys.DI;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CopilotContentTypeAutoGenerateService(\n    FileSaver fileSaver,\n    LazySvc<IEnumerable<IFileGenerator>> generators,\n    IAppReaderFactory appReaders)\n    : ServiceBase(SxcLogName + \".AutoGen.Run\", connect: [fileSaver, generators, appReaders])\n{\n    private const string DataCopilotConfigurationContentType = \"DataCopilotConfiguration\";\n    private const string FieldAutoGenerate = \"AutoGenerate\";\n    private const string FieldCodeGenerator = \"CodeGenerator\";\n    private const string FieldNamespace = \"Namespace\";\n    private const string FieldTargetFolder = \"TargetFolder\";\n    private const string FieldContentTypes = \"ContentTypes\";\n    private const string FieldPrefix = \"Prefix\";\n    private const string FieldSuffix = \"Suffix\";\n    private const string FieldEdition = \"Edition\";\n\n    public List<Exception> Generate(int appId, string changedTypeNameId, string origin)\n    {\n        var l = Log.Fn<List<Exception>>($\"origin:{origin}, app:{appId}, type:{changedTypeNameId}\");\n        var errors = new List<Exception>();\n\n        if (changedTypeNameId.IsEmptyOrWs())\n        {\n            Log.A(\"Copilot auto-generate skipped: content-type name-id is empty.\");\n            return l.Return(errors, \"missing content-type name-id\");\n        }\n\n        var appReader = appReaders.Get(appId);\n        var changedType = appReader.TryGetContentType(changedTypeNameId);\n        if (changedType == null)\n        {\n            errors.Add(new ArgumentException(\n                $\"Content-Type '{changedTypeNameId}' not found in app '{appId}'.\"));\n            Log.A($\"Copilot auto-generate skipped: content-type '{changedTypeNameId}' not found in app '{appId}'.\");\n            return l.Return(errors, \"content-type not found\");\n        }\n\n        var matchingConfigurations = appReader.List\n            .GetAll(DataCopilotConfigurationContentType)\n            .Where(configuration => configuration.Get<bool>(FieldAutoGenerate))\n            .Select(configuration => BuildRunConfiguration(configuration, changedType))\n            .Where(configuration => configuration != null)\n            .Cast<RunConfiguration>()\n            .ToList();\n\n        if (!matchingConfigurations.Any())\n        {\n            Log.A($\"Copilot auto-generate: no matching configurations for content-type '{changedType.NameId}' ({origin}).\");\n            return l.Return(errors, \"no matching auto-generate configurations\");\n        }\n\n        foreach (var configuration in matchingConfigurations)\n        {\n            try\n            {\n                var generator = generators.Value.FirstOrDefault(g => g.Name.EqualsInsensitive(configuration.GeneratorName));\n                if (generator == null)\n                {\n                    Log.A($\"Copilot auto-generate: generator '{configuration.GeneratorName}' not found.\");\n                    errors.Add(new InvalidOperationException(\n                        $\"Generator '{configuration.GeneratorName}' not found for configuration '{configuration.ConfigurationId}'.\"));\n                    continue;\n                }\n\n                (generator as IHasLog)?.LinkLog(Log);\n                fileSaver.GenerateAndSaveFiles(generator, configuration.Specs);\n            }\n            catch (Exception ex)\n            {\n                errors.Add(ex);\n                Log.Ex(ex);\n            }\n        }\n\n        return l.Return(errors, $\"processed {matchingConfigurations.Count} configuration(s)\");\n    }\n\n    private static RunConfiguration? BuildRunConfiguration(IEntity configuration, IContentType changedType)\n    {\n        var generatorName = Sanitize(configuration.Get<string>(FieldCodeGenerator));\n        if (generatorName.IsEmptyOrWs())\n            return null;\n\n        var selectedTypes = Normalize(configuration.Get<string>(FieldContentTypes));\n        if (selectedTypes != null && !selectedTypes.Any(selection =>\n                selection.EqualsInsensitive(changedType.NameId) || selection.EqualsInsensitive(changedType.Name)))\n            return null;\n\n        var specs = new FileGeneratorSpecs\n        {\n            AppId = changedType.AppId,\n            Configuration = $\"{configuration.EntityId} {configuration.GetBestTitle()}\",\n            Namespace = Sanitize(configuration.Get<string>(FieldNamespace)),\n            TargetPath = Sanitize(configuration.Get<string>(FieldTargetFolder)),\n            ContentTypes = selectedTypes,\n            Prefix = Sanitize(configuration.Get<string>(FieldPrefix)),\n            Suffix = Sanitize(configuration.Get<string>(FieldSuffix)),\n            Edition = Sanitize(configuration.Get<string>(FieldEdition)),\n        };\n\n        return new(configuration.EntityId, generatorName, specs);\n    }\n\n    private static string? Sanitize(string? value)\n        => value.HasValue() ? value.Trim() : null;\n\n    private static ICollection<string>? Normalize(string? raw)\n    {\n        var cleaned = Sanitize(raw);\n        return cleaned == null\n            ? null\n            : Normalize([cleaned]);\n    }\n\n    private static ICollection<string>? Normalize(IEnumerable<string>? raw)\n    {\n        if (raw == null)\n            return null;\n\n        var cleaned = raw\n            .SelectMany(item => item?\n                .Split([',', ';', '\\n', '\\r'], StringSplitOptions.RemoveEmptyEntries)\n                ?? [])\n            .Where(item => !string.IsNullOrWhiteSpace(item))\n            .Select(item => item.Trim())\n            .Distinct(StringComparer.OrdinalIgnoreCase)\n            .ToList();\n\n        return cleaned.Any()\n            ? cleaned\n            : null;\n    }\n\n    private record RunConfiguration(\n        int ConfigurationId,\n        string GeneratorName,\n        FileGeneratorSpecs Specs);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/CopilotContentTypeDataProcessor.cs",
    "content": "using ToSic.Eav.Data.Processing;\nusing static ToSic.Eav.Data.Processing.DataProcessingEvents;\nusing static ToSic.Eav.Data.Processing.DataProcessingContextSources;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Runs copilot code generation after content-type schema saves.\n/// Uses the shared <see cref=\"PostSave\"/> action plus schema context and expects an\n/// <see cref=\"IEntity\"/> payload carrying the app id and changed content-type.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CopilotContentTypeDataProcessor(\n    CopilotContentTypeAutoGenerateService autoGenerate)\n    : ServiceBase(SxcLogName + \".AutoGen.CT\", connect: [autoGenerate]), IDataProcessor\n{\n    /// <summary>\n    /// Handle post-save processing for a changed content-type and run matching auto-generate configurations.\n    /// </summary>\n    /// <param name=\"action\">Expected to be <see cref=\"PostSave\"/> for schema triggers.</param>\n    /// <param name=\"data\">Processor payload containing the trigger entity context.</param>\n    /// <returns>Original or enriched processor result with collected exceptions.</returns>\n    public Task<DataProcessorResult<IEntity?>> Process(string action, DataProcessorResult<IEntity?> data)\n    {\n        var l = Log.Fn<DataProcessorResult<IEntity?>>($\"action:{action}\");\n\n        var context = data.Context;\n        if (!IsContentTypeSchemaPostSave(action, context))\n            return Task.FromResult(l.Return(data, \"unsupported action/context\"));\n\n        var errors = data.Exceptions.ToList();\n        var triggerEntity = data.Data;\n        if (triggerEntity == null)\n        {\n            Log.A(\"Copilot auto-generate skipped: missing IEntity context for content-type post-save.\");\n            return Task.FromResult(l.Return(data, \"missing entity context\"));\n        }\n\n        var appId = triggerEntity.AppId;\n        var changedTypeNameId = triggerEntity.Type.NameId;\n        if (changedTypeNameId.IsEmptyOrWs())\n        {\n            Log.A(\"Copilot auto-generate skipped: entity content-type name-id is empty.\");\n            return Task.FromResult(l.Return(data, \"missing content-type name-id\"));\n        }\n\n        var source = context!.Source ?? \"\";\n        Log.A($\"Copilot auto-generate: source '{source}' for content-type '{changedTypeNameId}'.\");\n        errors.AddRange(autoGenerate.Generate(appId, changedTypeNameId, origin: source));\n\n        var result = ResultWithErrors(data, errors);\n        return Task.FromResult(l.Return(result, $\"errors: {result.Exceptions.Count}\"));\n    }\n\n    private static DataProcessorResult<IEntity?> ResultWithErrors(DataProcessorResult<IEntity?> original, List<Exception> errors)\n        => errors.Count == original.Exceptions.Count\n            ? original\n            : original with { Exceptions = errors };\n\n    private static bool IsContentTypeSchemaPostSave(string action, DataProcessingContext? context)\n        => action.EqualsInsensitive(PostSave)\n           && context?.Source is { } source\n           && (source.EqualsInsensitive(ContentType) || source.EqualsInsensitive(ContentTypeField));\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/FileGeneratorSpecs.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// WIP Parameters to give the code generator\n/// </summary>\ninternal record FileGeneratorSpecs : IFileGeneratorSpecs\n{\n    /// <inheritdoc />\n    public string? Configuration { get; init; }\n\n    /// <inheritdoc />\n    public int AppId { get; init; }\n\n    /// <inheritdoc />\n    public string? Edition { get; init; }\n\n    /// <inheritdoc />\n    public DateTime DateTime { get; init; } = DateTime.Now;\n\n    /// <inheritdoc />\n    public string? Namespace { get; init; }\n\n    /// <inheritdoc />\n    public string? TargetPath { get; init; }\n\n    /// <inheritdoc />\n    public ICollection<string>? ContentTypes { get; init; }\n\n    /// <inheritdoc />\n    public string? Prefix { get; init; }\n\n    /// <inheritdoc />\n    public string? Suffix { get; init; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/FileSaver.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Service to take generated files and save them to the file system\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class FileSaver(ISite site, IAppReaderFactory appReadFac, IAppPathsMicroSvc appPaths)\n    : ServiceBase(SxcLogName + \".GenFSv\", connect: [site, appReadFac, appPaths])\n{\n    public void GenerateAndSaveFiles(IFileGenerator generator, IFileGeneratorSpecs specs)\n    {\n        var l = Log.Fn();\n\n        var bundle = generator.Generate(specs).First();\n        var physicalPath = GetAppCodeDataPhysicalPath(bundle.Path, specs);\n        l.A($\"{nameof(physicalPath)}: '{physicalPath}'\");\n\n        var classFiles = bundle.Files;\n        foreach (var classSb in classFiles)\n        {\n            l.A($\"Writing {classSb.FileName}; Path: {classSb.Path}; Content: {classSb.Body.Length}\");\n\n            var addPath = classSb.Path ?? \"\";\n            if (addPath.StartsWith(\"/\") || addPath.StartsWith(\"\\\\\") || addPath.EndsWith(\"/\") || addPath.EndsWith(\"\\\\\") || addPath.Contains(\"..\"))\n                throw new($\"Invalid path '{addPath}' in class '{classSb.FileName}' - contains invalid path like '..' or starts/ends with a slash.\");\n\n            var basePath = Path.Combine(physicalPath, addPath);\n\n            if (specs.TargetPath.HasValue())\n            {\n                var target = specs.TargetPath!;\n                l.A($\"custom TargetPath: '{target}'\");\n\n                if (target.ContainsPathTraversal())\n                    throw new($\"Invalid target path '{target}' - {PathFixer.PathTraversalMayNotContainMessage}\");\n\n                var find = $\"{FolderConstants.AppCodeFolder}\\\\{addPath}\";\n                if (basePath.EndsWith(find))\n                {\n                    basePath = (basePath.Substring(0, basePath.Length - find.Length) + \"\\\\\" + target.TrimPrefixSlash())\n                        .FlattenSlashes();\n\n                    l.A($\"custom BasePath: '{basePath}'\");\n                }\n            }\n\n            // normalized\n            basePath = new DirectoryInfo(basePath).FullName;\n\n            // ensure the folder for the file exists - it could be different for each file\n            Directory.CreateDirectory(basePath);\n\n            var fileFullPath = new FileInfo(Path.Combine(basePath, classSb.FileName)).FullName;\n            l.A($\"filePath: '{fileFullPath}'\");\n\n            File.WriteAllText(fileFullPath, classSb.Body);\n        }\n\n        // Update the code-generator.log file\n        if (classFiles.Any())\n            File.AppendAllText(\n                Path.Combine(physicalPath, \"code-generator.log\"),\n                $\"{DateTime.Now:u}: Code generated. Generator: {generator.Name} v{generator.Version} {specs}\\n\"\n            );\n\n        l.Done();\n    }\n\n    private string GetAppFullPath(int appId)\n    {\n        var appReader = appReadFac.Get(appId);\n        return appPaths.Get(appReader, site).PhysicalPath;\n    }\n\n    private string GetAppCodeDataPhysicalPath(string mask, IFileGeneratorSpecs specs)\n    {\n        // Do basic mask tests\n        if (mask.IsEmpty()) throw new(\"Mask must not be empty\");\n        if (mask.ContainsPathTraversal()) throw new($\"Mask {PathFixer.PathTraversalMayNotContainMessage}\");\n        if (!mask.StartsWith(GenerateConstants.PathPlaceholderAppRoot)) throw new($\"Mask must start with '{GenerateConstants.PathPlaceholderAppRoot}'\");\n\n\n        // Get the full path to the app\n        var path = mask.Replace(GenerateConstants.PathPlaceholderAppRoot, GetAppFullPath(specs.AppId).TrimLastSlash());\n\n        // Optionally add / replace the edition\n        if (path.IndexOf(GenerateConstants.PathPlaceholderEdition, StringComparison.OrdinalIgnoreCase) > -1)\n        {\n            // sanitize path because 'edition' is user provided\n            if (specs.Edition.ContainsPathTraversal())\n                throw new($\"Invalid edition '{specs.Edition}' - {PathFixer.PathTraversalMayNotContainMessage}\");\n\n            path = path.Replace(GenerateConstants.PathPlaceholderEdition, specs.Edition).TrimLastSlash();\n        }\n\n        path = path.FlattenSlashes().Backslash();\n\n        var appWithEditionNormalized = new DirectoryInfo(path).FullName;\n\n        return appWithEditionNormalized;\n    }\n\n    //public string Dump()\n    //{\n    //    var sb = new StringBuilder();\n\n    //    var classFiles = Generate().First().Files;\n    //    foreach (var classSb in classFiles)\n    //    {\n    //        sb.AppendLine($\"// ----------------------- file: {classSb.FileName} ----------------------- \");\n    //        sb.AppendLine(classSb.Body);\n    //        sb.AppendLine();\n    //        sb.AppendLine();\n    //    }\n\n    //    return sb.ToString();\n    //}\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/GenerateConstants.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Constants used in the code generation process.\n/// </summary>\n/// <remarks>\n/// WIP v17.04\n/// </remarks>\n[WorkInProgressApi(\"still being standardized\")]\npublic class GenerateConstants\n{\n    /// <summary>\n    /// Placeholder for the root of the app, which will be replaced with the actual path.\n    ///\n    /// It's usually used to prefix the target path of a generated file.\n    /// </summary>\n    public const string PathPlaceholderAppRoot = \"[app:root]\";\n\n    /// <summary>\n    /// Placeholder for the edition of the app, which will be replaced with the actual edition.\n    ///\n    /// It's usually used in the path of the generated file, to create edition-specific files.\n    /// </summary>\n    public const string PathPlaceholderEdition = \"[target:edition]\";\n\n    public const string PathToAppCode = $\"{PathPlaceholderAppRoot}/{PathPlaceholderEdition}/{FolderConstants.AppCodeFolder}\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/GeneratedDataModel.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Object which contains the info to generate the class code file.\n/// </summary>\ninternal class GeneratedDataModel(string typeName, string body, string introComment) : IGeneratedFile\n{\n    /// <inheritdoc />\n    public string FileName => typeName + \".cs\";\n\n    /// <inheritdoc />\n    public string Path => \"Data\";\n\n    /// <summary>\n    /// The main code body of the class.\n    /// It's separate from the intro, to allow optional check if the file changed.\n    /// </summary>\n    private string BodyWithoutIntro => body;\n\n    /// <summary>\n    /// Intro comment to add to the top of the file.\n    /// It always changes a bit, as it has a time stamp and version number.\n    /// </summary>\n    private string IntroComment => introComment;\n\n    /// <inheritdoc />\n    public string Body => IntroComment + BodyWithoutIntro;\n\n    /// <inheritdoc />\n    public IReadOnlyCollection<IGeneratedFileInfo> Dependencies => [];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/GeneratedFile.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Represents a generated file.\n/// It's usually provided in a <see cref=\"IGeneratedFileSet\"/>, which contains additional specs.\n/// </summary>\n[WorkInProgressApi(\"still being standardized\")]\npublic class GeneratedFile: IGeneratedFile\n{\n    /// <inheritdoc />\n    public required string FileName { get; init; }\n\n    /// <inheritdoc />\n    public required string Path { get; init; }\n\n    /// <inheritdoc />\n    public required string Body { get; init; }\n\n    /// <inheritdoc />\n    public IReadOnlyCollection<IGeneratedFileInfo> Dependencies { get; init; } = [];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/GeneratedFileSet.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// WIP - should contain a list of code-files and additional specs\n/// </summary>\n[WorkInProgressApi(\"still being standardized\")]\npublic class GeneratedFileSet : IGeneratedFileSet\n{\n    /// <inheritdoc />\n    public required string Name { get; init; }\n\n    /// <inheritdoc />\n    public required string Description { get; init; }\n\n    /// <inheritdoc />\n    public required string Generator { get; init; }\n\n    /// <inheritdoc />\n    public required string Path { get; init; }\n\n    /// <inheritdoc />\n    public required IReadOnlyCollection<IGeneratedFile> Files { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/IFileGenerator.cs",
    "content": "﻿using ToSic.Sys.Data;\n\nnamespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Describes a file generator which can generate (code) files.\n/// </summary>\n[WorkInProgressApi(\"still being standardized\")]\npublic interface IFileGenerator : IHasIdentityNameId\n{\n    /// <summary>\n    /// Generator name, to select it in a list of generators\n    /// </summary>\n    public string Name { get; }\n\n    /// <summary>\n    /// Generator version for additional info when selecting the generator.\n    /// </summary>\n    public string Version { get; }\n\n    /// <summary>\n    /// Generator description for selecting the generator.\n    /// </summary>\n    public string Description { get; }\n\n    public string DescriptionHtml { get; }\n\n    /// <summary>\n    /// Language this generator creates, e.g. \"CSharp\", \"TypeScript\", \"JavaScript\"\n    /// </summary>\n    public string OutputLanguage { get; }\n\n    /// <summary>\n    /// WIP, string name for what kind of output we'll generate.\n    /// Not final yet, should be used in dialogs to only provide generators with the correct output type.\n    /// </summary>\n    public string OutputType { get; }\n\n    /// <summary>\n    /// Call to run the generator and get the files\n    /// </summary>\n    public IGeneratedFileSet[] Generate(IFileGeneratorSpecs specs);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/IFileGeneratorSpecs.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Specs for a file generator.\n///\n/// An object containing these specs - and sometimes more - is passed to the file generator.\n/// </summary>\n/// <remarks>\n/// WIP v17.04\n/// </remarks>\n[WorkInProgressApi(\"still being standardized\")]\npublic interface IFileGeneratorSpecs\n{\n    /// <summary>\n    /// ID and name of the configuration used.\n    /// If null, configuration is not used.\n    /// </summary>\n    string? Configuration { get; init; }\n\n    /// <summary>\n    /// The AppId of the app for which the file is generated.\n    /// </summary>\n    int AppId { get; }\n\n    /// <summary>\n    /// The Edition for which we're generating the file.\n    /// </summary>\n    string? Edition { get; }\n\n    /// <summary>\n    /// The moment the generation was performed.\n    /// </summary>\n    DateTime DateTime { get; }\n\n    /// <summary>\n    /// Alternate namespace to use for the generated code files.\n    /// If null, just use automatic / default namespace.\n    /// </summary>\n    string? Namespace { get; init; }\n\n    /// <summary>\n    /// The target path for the generated code files.\n    /// If null, use default path.\n    /// </summary>\n    string? TargetPath { get; init; }\n\n    /// <summary>\n    /// The content types to generate files for.\n    /// If null, use all available content types in the \"Default\" scope + the app settings/resources.\n    /// </summary>\n    ICollection<string>? ContentTypes { get; init; }\n\n    /// <summary>\n    /// Prefix for generated class and file names.\n    /// If null, don't change the default naming.\n    /// </summary>\n    string? Prefix { get; init; }\n\n    /// <summary>\n    /// Suffix for generated class and file names.\n    /// If null, don't change the default naming.\n    /// </summary>\n    string? Suffix { get; init; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/IGeneratedFile.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Data which is meant to create a new file.\n/// The file will usually be saved directly to the file system of the App.\n///\n/// This is WIP - goal is to make it more standard so others could create generators too.\n/// </summary>\n/// <remarks>\n/// Introduced in v17.05\n/// </remarks>\n[WorkInProgressApi(\"still being standardized\")]\npublic interface IGeneratedFile : IGeneratedFileInfo\n{\n    /// <summary>\n    /// The body of the file, which will be written to the file.\n    /// </summary>\n    string Body { get; }\n\n    /// <summary>\n    /// List of dependencies which are required to create this file.\n    ///\n    /// For example, if we generate a PersonList.cshtml which will inherit the AppRazor, then the AppRazor should be in the list.\n    ///\n    /// Note: not implemented yet - this is for later when users may want to select which files to generate.\n    /// </summary>\n    IReadOnlyCollection<IGeneratedFileInfo> Dependencies { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/IGeneratedFileInfo.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Data which describes a code file which will be created or may already exist.\n///\n/// It's used as the foundation for <see cref=\"IGeneratedFile\"/>\n/// but also to reference dependencies to other files created or which should be created in tandem.\n/// </summary>\n[WorkInProgressApi(\"still being standardized\")]\npublic interface IGeneratedFileInfo\n{\n    /// <summary>\n    /// The file name of the final code file, with extension.\n    /// May not contain any slashes.\n    /// </summary>\n    string FileName { get; }\n\n    /// <summary>\n    /// The path to put the file in, relative to the root which is determined elsewhere.\n    /// May not begin or end with a slash.\n    ///\n    /// Example: if path is \"Data\" and the root is \"AppCode\", the file will be saved to \"AppCode\\Data\\FileName.cs\"\n    /// </summary>\n    string Path { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Code.Generate/Sys/IGeneratedFileSet.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Generate.Sys;\n\n/// <summary>\n/// Set of code files to generate, including some information about the generator.\n/// </summary>\n[WorkInProgressApi(\"still being standardized\")]\npublic interface IGeneratedFileSet\n{\n    /// <summary>\n    /// Name for easy identification.\n    /// </summary>\n    string Name { get; }\n\n    /// <summary>\n    /// Description to show in the UI\n    /// </summary>\n    string Description { get; }\n\n    /// <summary>\n    /// Name of the generator, possibly with version\n    /// </summary>\n    string Generator { get; }\n\n    /// <summary>\n    /// The path, but not sure yet how to do, especially if it will be relative or contain editions.\n    /// </summary>\n    string Path { get; }\n\n    /// <summary>\n    /// List of files to generate\n    /// </summary>\n    IReadOnlyCollection<IGeneratedFile> Files { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/DataSources/CodeGenerators.cs",
    "content": "﻿using ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sys.DI;\n\nnamespace ToSic.Sxc.DataSources;\n\n[PrivateApi]\n[VisualQuery(\n    NiceName = \"Code Generators\",\n    NameId = \"f512e44b-5b34-4a32-bfe3-d46d46800a7f\",\n    NameIds = [\"System.CodeGenerators\"], // Internal name for the system, used in some entity-pickers. Can change at any time.\n    Type = DataSourceType.System,\n    Audience = Audience.System,\n    DataConfidentiality = DataConfidentiality.System,\n    UiHint = \"Generators in this system\")]\n// ReSharper disable once UnusedMember.Global\npublic class CodeGenerators: CustomDataSource\n{\n    public CodeGenerators(Dependencies services, LazySvc<IEnumerable<IFileGenerator>> generators)\n        : base(services, logName: \"CDS.Generators\", connect: [generators])\n    {\n        ProvideOutRaw(\n            () => Generators(generators.Value),\n            options: () => new()\n            {\n                AutoId = true,\n                TitleField = \"Name\",\n                TypeName = \"Generator\",\n            });\n\n        ProvideOutRaw(\n            () => OutputTypes(generators.Value),\n            name: \"OutputType\",\n            options: () => new()\n            {\n                AutoId = true,\n                TitleField = \"Name\",\n                TypeName = \"OutputType\",\n            });\n\n    }\n\n    private IEnumerable<IRawEntity> Generators(IEnumerable<IFileGenerator> fileGenerators)\n    {\n        var l = Log.Fn<IEnumerable<IRawEntity>>();\n        var list = fileGenerators\n            .Select(g => new RawEntity(new()\n            {\n                //{ AttributeNames.NameIdNiceName, g.NameId },\n                { nameof(g.Name), g.Name },\n                { nameof(g.Version), g.Version },\n                { nameof(g.Description), g.Description },\n                { nameof(g.DescriptionHtml), g.DescriptionHtml },\n                { nameof(g.OutputLanguage), g.OutputLanguage },\n                { nameof(g.OutputType), g.OutputType },\n            }))\n            .ToList();\n\n        return l.Return(list, $\"{list.Count}\");\n    }\n\n    private IEnumerable<IRawEntity> OutputTypes(IEnumerable<IFileGenerator> fileGenerators)\n    {\n        var l = Log.Fn<IEnumerable<IRawEntity>>();\n        var list = fileGenerators\n            .GroupBy(g => g.OutputType)\n            .Select(g => new RawEntity(new()\n            {\n                { \"Name\", g.Key },\n            }))\n            .ToList();\n\n        return l.Return(list, $\"{list.Count}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Linq;\nglobal using ToSic.Sys.Utils;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.WebApi\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/StartupSxcCodeGenerate.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Sxc.Code.Generate.Data;\nusing ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sxc.Code.Generate.Sys.CSharpBaseClasses;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcCodeGenerate\n{\n    public static IServiceCollection AddSxcCodeGen(this IServiceCollection services)\n    {\n        // v17 Code Generators\n        services.TryAddTransient<CSharpTypedDataModelsGenerator>();  // direct registration\n        services.AddTransient<IFileGenerator, CSharpTypedDataModelsGenerator>(); // with interface and no try, so all can be listed in DI\n        services.AddTransient<IFileGenerator, RazorViewsGenerator>(); // with interface and no try, so all can be listed in DI\n        services.AddTransient<IFileGenerator, CSharpServicesGenerator>(); // with interface and no try, so all can be listed in DI\n        services.AddTransient<IFileGenerator, WebApiGenerator>(); // with interface and no try, so all can be listed in DI\n        services.TryAddTransient<FileSaver>();\n\n        // v20 Code Generators\n        services.TryAddTransient<CSharpCustomModelsGenerator>();  // direct registration\n        services.AddTransient<IFileGenerator, CSharpCustomModelsGenerator>(); // with interface and no try, so all can be listed in DI\n\n        // v21.04 Copilot auto-generate on schema changes\n        services.TryAddTransient<CopilotContentTypeAutoGenerateService>();\n        services.TryAddTransient<CopilotContentTypeDataProcessor>();\n        services.TryAddEnumerable(ServiceDescriptor.Transient(typeof(IDataProcessor), typeof(CopilotContentTypeDataProcessor)));\n\n        return services;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/ToSic.Sxc.Code.Generate.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Code.Generate</AssemblyName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.DataSource\\ToSic.Eav.DataSource.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.Generate/ToSic.Sxc.Code.Generate.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_002Egenerate_005Cinternal_005Ccsharp/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_002Egenerate_005Cinternal_005Ccsharpmodels/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_002Egenerate_005Csys_005Ccsharp/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_002Egenerate_005Csys_005Ccsharpmodels/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=code_002Egenerate_005Csys_005Cdatagenerators/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=internal_005Ccsharp/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=internal_005Ccsharpmodels/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/AppCodeCompiler.cs",
    "content": "﻿using System.Reflection;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sys.Configuration;\nusing ToSic.Sys.Locking;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class AppCodeCompiler(\n    IGlobalConfiguration globalConfiguration,\n    SourceCodeHasher sourceCodeHasher,\n    object[]? connect = default)\n    : ServiceBase(\"Sxc.MyApCd\", connect: connect)\n{\n    protected const string AppCodeDll = \"AppCode.dll\";\n\n    public abstract AssemblyResult GetAppCode(string relativePath, HotBuildSpecWithSharedSuffix spec);\n\n    protected string[] GetSourceFiles(string fullPath)\n    {\n        var l = Log.Fn<string[]>(timer: true);\n\n        if (!Directory.Exists(fullPath))\n            return l.ReturnAsOk([]);\n\n        // Build the AppCode folder with subfolders\n        var sourceFiles = sourceCodeHasher.GetSourceFilesInFolder(fullPath);\n\n        // Log all files\n        foreach (var sourceFile in sourceFiles) l.A(sourceFile);\n\n        return l.ReturnAsOk(sourceFiles);\n    }\n\n    /// <summary>\n    /// Generates a name with hash for a dll file.\n    /// </summary>\n    /// <returns>The generated random name.</returns>\n    private string GetAppCodeDllName(string sourceRootPath, HotBuildSpecWithSharedSuffix spec)\n    {\n        var l = Log.Fn<string>($\"{nameof(sourceRootPath)}: '{sourceRootPath}'; {spec}\", timer: true);\n        var appCodeHash = sourceCodeHasher.GetHashString(sourceRootPath);\n        var appCodeHashShort = appCodeHash.Length > 6\n            ? appCodeHash.Substring(0, 6)\n            : appCodeHash;\n        var assemblyName = $\"AppCode-{appCodeHashShort}\";\n        return l.ReturnAsOk(assemblyName);\n    }\n\n    /// <summary>\n    /// Generates a random name for a dll file and ensures it does not already exist in the \"2sxc.bin\" folder.\n    /// </summary>\n    /// <returns>The generated random name.</returns>\n    private string GetDependencyDllName(string folderPath, HotBuildSpecWithSharedSuffix spec, string dependency)\n    {\n        var l = Log.Fn<string>($\"{nameof(dependency)}: '{dependency}'; {nameof(folderPath)}: '{folderPath}'; {spec}\", timer: true);\n        var dependencyFileName = Path.GetFileNameWithoutExtension(dependency);\n        var assemblyName = $\"dep-{dependencyFileName}\";\n        return l.ReturnAsOk(RandomNameWithoutExtension(folderPath, assemblyName));\n    }\n\n    private static string RandomNameWithoutExtension(string folderPath, string assemblyName)\n    {\n        Directory.CreateDirectory(folderPath);\n        string randomNameWithoutExtension;\n        do\n        {\n            var randomSuffix = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());\n            randomNameWithoutExtension = $\"{assemblyName}-{randomSuffix}\";\n        }\n        while (File.Exists(Path.Combine(folderPath, $\"{randomNameWithoutExtension}.dll\")));\n\n        return randomNameWithoutExtension;\n    }\n    \n    /// <summary>\n    /// Normalize full file or folder path, so it is without redirections like \"../\" in \"dir1/dir2/../file.cs\"\n    /// </summary>\n    /// <param name=\"fullPath\"></param>\n    /// <returns></returns>\n    protected static string NormalizeFullPath(string fullPath)\n        => new FileInfo(fullPath).FullName;\n\n\n    protected void LogAllTypes(Assembly? assembly)\n    {\n        var l = Log.Fn<bool>(assembly?.FullName);\n\n        if (assembly == null)\n        {\n            l.Done(\"Assembly is null, nothing to log\");\n            return;\n        }\n\n        var list = AssemblyAnalyzer.TypeInformation(assembly);\n        foreach (var item in list)\n            l.A(item);\n\n        l.Done();\n    }\n\n    protected (string SymbolsPath, string AssemblyPath) GetAssemblyLocations(HotBuildSpecWithSharedSuffix spec, string sourceRootPath)\n    {\n        var l = Log.Fn<(string, string)>($\"{spec}\");\n        var cacheFolder = GetAppAssemblyFolder(spec);\n        l.A($\"App cache folder: '{cacheFolder}'\");\n\n        // need name \n        var assemblyName = GetAppCodeDllName(sourceRootPath, spec);\n        l.A($\"AssemblyName: '{assemblyName}'\");\n        var assemblyFilePath = Path.Combine(cacheFolder, $\"{assemblyName}.dll\");\n        l.A($\"AssemblyFilePath: '{assemblyFilePath}'\");\n        var symbolsFilePath = Path.Combine(cacheFolder, $\"{assemblyName}.pdb\");\n        l.A($\"SymbolsFilePath: '{symbolsFilePath}'\");\n        var assemblyLocations = (symbolsFilePath, assemblyFilePath);\n        return l.ReturnAsOk(assemblyLocations);\n    }\n\n    protected internal string GetDependencyAssemblyLocations(string dependency, HotBuildSpecWithSharedSuffix spec)\n    {\n        var l = Log.Fn<string>($\"{spec}\");\n        var cacheFolder = GetAppAssemblyFolder(spec);\n        l.A($\"TempAssemblyFolderPath: '{cacheFolder}'\");\n\n        // need random name, because assemblies has to be preserved on disk, and we can not replace them until AppDomain is unloaded \n        var assemblyName = GetDependencyDllName(cacheFolder, spec, dependency);\n        l.A($\"AssemblyName: '{assemblyName}'\");\n        var assemblyFilePath = Path.Combine(cacheFolder, $\"{assemblyName}.dll\");\n        l.A($\"AssemblyFilePath: '{assemblyFilePath}'\");\n\n        return l.ReturnAsOk(assemblyFilePath);\n    }\n\n    protected static readonly NamedLocks CompileAssemblyLocks = new();\n    protected readonly TryLockTryDo LockAppCodeAssemblyProvider = new();\n\n    protected bool ShouldGenerate(string assemblyPath)\n    {\n        var l = Log.Fn<bool>(assemblyPath);\n        if (!File.Exists(assemblyPath))\n            return l.ReturnTrue(\"should generate, file doesn't exist\");\n\n        var fileInfo = new FileInfo(assemblyPath);\n        if (fileInfo.Length == 0)\n            return l.ReturnTrue(\"should generate, file empty\");\n\n        var isLocked = IsFileLocked(fileInfo, assemblyPath);\n        return isLocked\n            //? l.ReturnTrue(\"exists and locked, should generate; - not sure why this would want to regenerate - ask STV\")\n            ? l.ReturnFalse(\"exists and locked, should MAYBE NOT generate; - not sure why this would want to regenerate - ask STV\")\n            : l.ReturnFalse(\"Just load existing. File exists and is not locked.\");\n    }\n\n    private bool IsFileLocked(FileInfo fileInfo, string filePath)\n    {\n        var l = Log.Fn<bool>($\"{filePath}\");\n        try\n        {\n            // Check if the file is read-only\n            if (fileInfo.IsReadOnly)\n                return l.ReturnTrue(\"read only\");\n\n            // Try to open the file with FileShare.None to check if it is locked\n            using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None);\n            var isLocked = !stream.CanRead;\n            // Experimental early close, because I'm not sure if automatic disposal happens fast enough\n            stream.Close();\n            return l.Return(isLocked, $\"{nameof(isLocked)}: {isLocked}\");\n        }\n        catch (IOException)\n        {\n            // If an IOException is thrown, the file is locked\n            return l.ReturnTrue(nameof(IOException));\n        }\n        catch (UnauthorizedAccessException)\n        {\n            // If an UnauthorizedAccessException is thrown, the file is locked\n            return l.ReturnTrue(nameof(UnauthorizedAccessException));\n        }\n        catch (Exception)\n        {\n            // Handle any other exceptions that might occur\n            return l.ReturnTrue($\"{nameof(Exception)} other\");\n        }\n    }\n\n    /// <summary>\n    /// Build the per-app cache folder path (app/edition/shared) and ensure it exists.\n    /// </summary>\n    protected string GetAppAssemblyFolder(HotBuildSpecWithSharedSuffix spec)\n    {\n        var root = spec.SharedSuffix.HasValue()\n            ? Path.Combine(globalConfiguration.TempAssemblyFolder(), spec.SharedSuffix)\n            : globalConfiguration.TempAssemblyFolder();\n        var edition = NormalizeForFolder(spec.Edition, \"root\");\n        var shorterAppKey = ShorterAppKey(spec); // t##-a##### or #####\n        var cacheFolder = Path.Combine(\n            root,\n            $\"{shorterAppKey}-{edition}\");\n\n        Directory.CreateDirectory(cacheFolder);\n        return cacheFolder;\n    }\n\n    private static string ShorterAppKey(HotBuildSpec spec)\n    {\n        var appKey = spec.RuntimeKey;\n        if (appKey == null)\n            return $\"{spec.AppId:D5}\";\n        \n        // Expected format: t##-z###-a#####\n        var parts = appKey.Split('-');\n\n        // Rebuild without the \"z###\" part\n        var shorterAppKey = string.Join(\"-\", parts.Where(p => !p.StartsWith(\"z\")));\n\n        // Remove \"a\" if start with\n        if (shorterAppKey.StartsWith(\"a\"))\n            shorterAppKey = shorterAppKey.Substring(1);\n\n        return shorterAppKey;\n    }\n\n    private static string NormalizeForFolder(string? value, string fallback)\n    {\n        if (string.IsNullOrWhiteSpace(value))\n            return fallback;\n        var invalid = Path.GetInvalidFileNameChars();\n        var cleaned = new string(value.Select(ch => invalid.Contains(ch) ? '-' : ch).ToArray());\n        return string.IsNullOrWhiteSpace(cleaned)\n            ? fallback\n            : cleaned;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/AppCodeExtensions.cs",
    "content": "﻿using System.Reflection;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n[PrivateApi(\"Internal stuff\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class AppCodeExtensions\n{\n    /// <summary>\n    /// Find ApiController Type by name in AppCode Assembly\n    /// </summary>\n    /// <param name=\"appCodeAssembly\"></param>\n    /// <param name=\"controllerTypeName\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// </remarks>\n    public static Type? FindControllerTypeByName(this Assembly appCodeAssembly, string controllerTypeName)\n    {\n        var type = appCodeAssembly.GetType(controllerTypeName, false, true)\n                   // Find in case it's in a namespace\n                   ?? appCodeAssembly.GetTypes().FirstOrDefault(t => t.Name.Equals(controllerTypeName, StringComparison.OrdinalIgnoreCase));\n        return type;\n    }\n\n    // 2024-05-02 2dm seems unused, maybe old\n    ///// <summary>\n    ///// Return list of types that are controllers\n    ///// </summary>\n    ///// <param name=\"appCodeAssembly\"></param>\n    ///// <returns>list of types that are controllers</returns>\n    //public static List<Type> GetAllControllerTypes(this Assembly appCodeAssembly) \n    //    => appCodeAssembly.GetTypes().Where(t => t.Name.EndsWith(Constants.ApiControllerSuffix, StringComparison.OrdinalIgnoreCase)).ToList();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/AppCodeLoader.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Services;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Locking;\nusing ISite = ToSic.Eav.Context.ISite;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppCodeLoader(\n    ILogStore logStore,\n    ISite site,\n    IAppReaderFactory appReadFac,\n    LazySvc<IAppPathsMicroSvc> appPathsLazy,\n    LazySvc<AppCodeCompiler> appCompilerLazy,\n    AssemblyCacheManager assemblyCacheManager,\n    LazySvc<IFeaturesService> features)\n    : ServiceBase(\"Sys.AppCodeLoad\",\n        connect: [logStore, site, appReadFac, appPathsLazy, appCompilerLazy, assemblyCacheManager, features])\n{\n    /// <summary>\n    /// Try to get the app code - first of the edition, then of the root.\n    /// </summary>\n    /// <param name=\"spec\"></param>\n    /// <returns></returns>\n    public (SourceCode.AssemblyResult? AssemblyResult, HotBuildSpec Specs) GetAppCode(HotBuildSpec spec)\n    {\n        var l = Log.Fn<(SourceCode.AssemblyResult?, HotBuildSpec)>(spec.ToString());\n        var firstRound = GetOrBuildAppCode(spec);\n        if (firstRound.AssemblyResult?.Assembly != null)\n            return l.Return(firstRound, $\"AppCode for '{spec.EditionToLog}'.\");\n\n        if (spec.Edition.IsEmpty())\n            return l.Return(firstRound, $\"No AppCode for '{spec.EditionToLog}', done.\");\n\n        // try get root edition\n        var rootSpec = spec.CloneWithoutEdition();\n        var root = GetOrBuildAppCode(rootSpec);\n        return l.Return(root, $\"AppCode in '{root.Specs.EditionToLog}'.\" + (root.AssemblyResult?.Assembly == null ? \", null.\" : \"\"));\n    }\n\n    /// <summary>\n    /// AppCode - get from cache or build - if there is any code to build.\n    /// Will throw exceptions if compile fails, but not if there is no code to compile.\n    /// </summary>\n    /// <param name=\"spec\"></param>\n    /// <returns></returns>\n    private (SourceCode.AssemblyResult? AssemblyResult, HotBuildSpec Specs) GetOrBuildAppCode(HotBuildSpec spec)\n    {\n        var l = Log.Fn<(AssemblyResult?, HotBuildSpec)>(spec.ToString());\n\n        // Check cache first\n        var assemblyResult = assemblyCacheManager.TryGetAppCode(spec).AssemblyResult;\n        if (assemblyResult?.Assembly != null)\n            return l.Return((assemblyResult, spec), $\"AppCode from cached for '{spec.EditionToLog}'.\");\n\n        // Try to compile\n        assemblyResult = TryBuildAppCodeAndLog(spec);\n        return l.Return((assemblyResult, spec), \"AppCode \" + (assemblyResult != null ? \"compiled\" : \"not compiled\") + $\" for '{spec.EditionToLog}'.\");\n    }\n\n    /// <summary>\n    /// Get the AppCode assembly, or throw an exception if it can't be found or compiled.\n    /// It can also return null, if there is no code to compile.\n    /// </summary>\n    /// <param name=\"spec\"></param>\n    /// <returns></returns>\n    private AssemblyResult? TryBuildAppCodeAndLog(HotBuildSpec spec)\n    {\n        // Add to global history and add specs\n        var logSummary = logStore.Add(SxcLogAppCodeLoader, Log)!;\n        logSummary.UpdateSpecs(spec.ToDictionary());\n\n        // Initial message for insights-overview\n        var l = Log.Fn<AssemblyResult?>($\"{spec}\", timer: true);\n\n        var assemblyResults = TryBuildAppCode(spec, logSummary);\n\n        // All OK (no errors) - return\n        if (string.IsNullOrEmpty(assemblyResults?.ErrorMessages))\n            return l.ReturnAsOk(assemblyResults);\n\n        // Problems - log and throw\n        l.ReturnAsError(null, assemblyResults!.ErrorMessages);\n        throw new(assemblyResults.ErrorMessages);\n    }\n\n    private static readonly NamedLocks CompileLocks = new();\n\n    private AssemblyResult? TryBuildAppCode(HotBuildSpec spec, LogStoreEntry logSummary)\n    {\n        var l = Log.Fn<AssemblyResult?>($\"{spec}\");\n\n        var (result, cacheKey) = assemblyCacheManager.TryGetAppCode(spec);\n        logSummary.AddSpec(\"Cached\", $\"{result != null!} on {cacheKey}\");\n\n        if (result != null)\n            return l.ReturnAsOk(result);\n\n        var lockObject = CompileLocks.Get(cacheKey);\n\n        lock (lockObject)\n        {\n            // Double check if another thread already built the app code\n            (result, cacheKey) = assemblyCacheManager.TryGetAppCode(spec);\n            if (result != null)\n                return l.Return(result, \"inside lock, start\");\n\n            // Get paths\n            var (physicalPath, relativePath, physicalPathShared, relativePathShared) = GetAppPaths(FolderConstants.AppCodeFolder, spec);\n            logSummary.AddSpec(\"PhysicalPath\", physicalPath);\n            logSummary.AddSpec(\"RelativePath\", relativePath);\n            logSummary.AddSpec(\"PhysicalPathShared\", physicalPathShared);\n            logSummary.AddSpec(\"RelativePathShared\", relativePathShared);\n\n            var appCodeInShared = false;\n            // First try app folder inside the site, as this has first priority\n            var assemblyResult = appCompilerLazy.Value.GetAppCode(relativePath, spec.WithoutSharedSuffix());\n            if (assemblyResult.HasValue)\n                l.A($\"local AppCode folder exists: {physicalPath}\");\n            // If not found, try the shared folder (if feature is activated)\n            else if (features.Value.IsEnabled(BuiltInFeatures.SharedAppCode.NameId))\n            {\n                assemblyResult = appCompilerLazy.Value.GetAppCode(relativePathShared, spec.WithSharedSuffix());\n                if (assemblyResult.HasValue)\n                {\n                    appCodeInShared = true;\n                    l.A($\"shared AppCode folder exists: {physicalPathShared}\");\n                }\n            }\n            else\n                l.A(\"local AppCode doesn't exist, and feature not enabled, shared location not checked.\");\n\n            logSummary.UpdateSpecs(assemblyResult.Infos);\n\n            if (assemblyResult.HasError)\n                return l.ReturnAsError(assemblyResult, assemblyResult.ErrorMessages);\n\n            #region WatchFolders\n            // for AppCode in local site path\n            assemblyResult.WatcherFolders = GetWatcherFolders(false, spec, physicalPath, Log);\n\n            // for AppCode in shared (global) path \n            if (appCodeInShared)\n                foreach (var w in GetWatcherFolders(assemblyResult.HasAssembly, spec, physicalPathShared, Log))\n                    assemblyResult.WatcherFolders.Add(w.Key, w.Value);\n\n            l.A(\"Folders to watch:\");\n            foreach (var watcherFolder in assemblyResult.WatcherFolders)\n                l.A($\"- '{watcherFolder}'\");\n            #endregion\n\n            assemblyResult.CacheDependencyId = cacheKey; // used to create cache dependency with CacheEntryChangeMonitor \n\n            // Triple check if another thread already built the app code\n            (result, cacheKey) = assemblyCacheManager.TryGetAppCode(spec);\n            if (result != null)\n                return l.Return(result, \"inside lock, end\");\n\n            // Add compiled assembly to cache\n            assemblyCacheManager.Add(\n                cacheKey,\n                assemblyResult,\n                slidingDuration: CacheConstants.DurationAppCode, // must be longer than the default used for Razor DLLs\n                folderPaths: assemblyResult.WatcherFolders\n            );\n\n            return l.ReturnAsOk(assemblyResult);\n        }\n    }\n\n    private static IDictionary<string, bool> GetWatcherFolders(bool editionHasAssembly, HotBuildSpec spec, string physicalPathAppCode, ILog log)\n    {\n        var l = log.Fn<IDictionary<string, bool>>($\"{nameof(physicalPathAppCode)}: {physicalPathAppCode}\");\n        var folders = new Dictionary<string, bool>();\n\n        // take AppCode folder (like ...\\edition\\AppCode)\n        IfExistsThenAdd(physicalPathAppCode, true);\n\n        // take parent folder (like ...\\edition)\n        var appCodeParentFolder = Path.GetDirectoryName(physicalPathAppCode);\n        if (appCodeParentFolder.IsEmpty())\n            return l.Return(folders, $\"{nameof(appCodeParentFolder)}.IsEmpty\");\n        IfExistsThenAdd(appCodeParentFolder, false);\n\n        // if no edition was used, then we were already in the root, and should stop now.\n        if (spec.Edition.IsEmpty())\n            return l.Return(folders, $\"{nameof(spec.Edition)}.IsEmpty\");\n\n        // If we have an edition, and it has an assembly, we don't need to watch the root folder\n        if (editionHasAssembly)\n            return l.Return(folders, $\"{nameof(editionHasAssembly)}\");\n\n        // If we had an edition and no assembly, then we need to watch the root folder\n        // we need to add more folders to watch for cache invalidation\n\n        // App Root folder (like ...\\)\n        var appRootFolder = Path.GetDirectoryName(appCodeParentFolder);\n        if (appRootFolder.IsEmpty())\n            return l.Return(folders, $\"{nameof(appRootFolder)}.IsEmpty\");\n\n        // Add to watcher list if it exists, otherwise exit, since we can't have subfolders\n        if (!IfExistsThenAdd(appRootFolder, false))\n            return l.Return(folders, $\"{nameof(appRootFolder)} doesn't exist\");\n\n        // \n        var appRootAppCode = Path.Combine(appRootFolder, FolderConstants.AppCodeFolder);\n        // Add to watcher list if it exists, otherwise exit, since we can't have subfolders\n        if (!IfExistsThenAdd(appRootAppCode, true))\n            return l.Return(folders, $\"{nameof(appRootAppCode)} doesn't exist\");\n\n        // all done\n        return l.ReturnAsOk(folders);\n\n        // Helper to add and return info if it exists\n        bool IfExistsThenAdd(string folder, bool watchSubfolders)\n        {\n            var l2 = log.Fn<bool>(folder);\n            if (!Directory.Exists(folder)) return l2.ReturnFalse();\n            folders.Add(folder, watchSubfolders);\n            return l2.ReturnTrue();\n        }\n    }\n\n    private (string physicalPath, string relativePath, string physicalPathShared, string relativePathShared) GetAppPaths(string folder, HotBuildSpec spec)\n    {\n        var l = Log.Fn<(string physicalPath, string relativePath, string physicalPathShared, string relativePathShared)>($\"{nameof(folder)}: '{folder}'; {spec}\");\n        l.A($\"site id: {site.Id}, ...: {site.AppsRootPhysicalFull}\");\n        var appPaths = appPathsLazy.Value.Get(appReadFac.Get(spec.AppId), site);\n        var folderWithEdition = folder.HasValue()\n            ? spec.Edition.HasValue() ? Path.Combine(spec.Edition, folder) : folder\n            : spec.Edition!;\n        var physicalPath = Path.Combine(appPaths.PhysicalPath, folderWithEdition);\n        //l.A($\"{nameof(physicalPath)}: '{physicalPath}'\");\n        var relativePath = Path.Combine(appPaths.RelativePath, folderWithEdition);\n        //l.A($\"{nameof(relativePath)}: '{relativePath}'\");\n        var physicalPathShared = Path.Combine(appPaths.PhysicalPathShared.Backslash(), folderWithEdition);\n        //l.A($\"{nameof(physicalPath)}: '{physicalPath}'\");\n        var relativePathShared = Path.Combine(appPaths.RelativePathShared.Backslash(), folderWithEdition);\n        return l.ReturnAsOk((physicalPath, relativePath, physicalPathShared, relativePathShared));\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/AssemblyAnalyzer.cs",
    "content": "﻿using System.Reflection;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\ninternal class AssemblyAnalyzer\n{\n    public static List<string> TypeInformation(Assembly assembly)\n    {\n        if (assembly == null)\n            return [\"no assembly\"];\n\n        var result = new List<string>();\n\n        foreach (var type in assembly.GetTypes().Where(t => t.FullName != null && !SkipTypeRoots.Any(prefix => t.FullName.StartsWith(prefix))))\n        {\n            // Get the name and all base classes\n            // Log all base classes\n            var typePath = type.FullName;\n            var baseType = type.BaseType;\n            while (baseType != null)\n            {\n                typePath = $\"{typePath} > {baseType.Name}\";\n                baseType = baseType.BaseType;\n            }\n            result.Add($\"Type: {typePath}\");\n\n\n            // Log all methods / properties\n            var x = type.GetMethods();\n            var y = type.GetMethods(BindingFlags.DeclaredOnly);\n            var z = type.GetMethods(BindingFlags.Instance);\n            var q = type.GetMethods(BindingFlags.Public);\n            var a = type.GetMethods(OwnPropsOnly);\n\n\n            result.AddRange(type.GetMethods(OwnPropsOnly).Where(m => !SkipMethods.Any(skip => m.Name.StartsWith(skip)))\n                .Select(m => $\"----- 🏃 Method: {m.Name}({GetParameterList(m.GetParameters())})\"));\n\n            result.AddRange(type.GetProperties(OwnPropsOnly)\n                .Select(p => $\"----- 🌈 Property: {p.Name} ({p.PropertyType})\"));\n\n            result.AddRange(type.GetFields(OwnPropsOnly)\n                .Select(f => $\"----- ⏹️ Field: {f.Name} ({f.FieldType})\"));\n\n            result.AddRange(type.GetEvents(OwnPropsOnly)\n                .Select(evt => $\"----- 🎉 Event: {evt.Name}\"));\n\n            result.AddRange(type.GetNestedTypes(OwnPropsOnly)\n                .Select(nt => $\"----- 🎯 Nested Type: {nt.FullName}\"));\n\n            result.AddRange(type.GetConstructors(OwnPropsOnly)\n                .Select(c => $\"----- 🚧 Constructor: {c.Name}({GetParameterList(c.GetParameters())})\"));\n\n            result.AddRange(type.GetInterfaces().Where(i => !(i.FullName ?? \"\").StartsWith(\"ToSic\"))\n                .Select(i => $\"----- 🔌 Interface: {i.FullName}\"));\n\n            result.AddRange(type.GetCustomAttributes()\n                .Select(a => $\"----- 🟫 Attribute: [{a.GetType().FullName}]\"));\n        }\n        return result;\n    }\n\n    private static string GetParameterList(IEnumerable<ParameterInfo> parameters) \n        => string.Join(\", \", parameters.Select(parameter => $\"{parameter.ParameterType} {parameter.Name}\"));\n\n    private const BindingFlags OwnPropsOnly = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;\n\n    private static readonly string[] SkipTypeRoots = []; // [\"Microsoft\", \"System\"];\n    private static readonly string[] SkipMethods = [\"get_\", \"set_\"];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/AssemblyCacheManager.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AssemblyCacheManager(MemoryCacheService memoryCacheService) : ServiceBase(SxcLogName + \".AssCMn\", connect: [memoryCacheService])\n{\n    private const string GlobalCacheRoot = \"Sxc-AssemblyCache.App.\";\n\n    #region Static Calls for **AppCode** - to use before requiring DI\n\n    public (AssemblyResult? AssemblyResult, string cacheKey) TryGetAppCode(HotBuildSpec spec)\n    {\n        var cacheKey = KeyAppCode(spec);\n        return (Get(cacheKey), cacheKey);\n    }\n\n    private static string KeyAppCode(HotBuildSpec spec) => $\"{GlobalCacheRoot}app:{spec.AppKeyForCache}.edition:{spec.Edition}.AppCode\";\n\n    #endregion\n\n    #region Static Calls for **Dependecies** - to use before requiring DI\n\n    public (List<AssemblyResult>? assemblyResults, string cacheKey) TryGetDependencies(HotBuildSpec spec)\n    {\n        var cacheKey = KeyDependency(spec);\n        return (memoryCacheService.Get<List<AssemblyResult>>(cacheKey), cacheKey);\n    }\n\n    private static string KeyDependency(HotBuildSpec spec) => $\"{GlobalCacheRoot}app:{spec.AppKeyForCache}.edition:{spec.Edition}.dep:{DependenciesLoader.DependenciesFolder}\";\n\n    #endregion\n\n    #region Static Calls Only - for use before the object is created using DI\n\n    internal static string KeyTemplate(string templateFullPath) => $\"{GlobalCacheRoot}view:{templateFullPath.ToLowerInvariant()}\";\n\n    private AssemblyResult? Get(string key)\n        => memoryCacheService.Get<AssemblyResult>(key);\n\n    public AssemblyResult? TryGetTemplate(string templateFullPath)\n        => Get(KeyTemplate(templateFullPath));\n\n    #endregion\n\n    public string Add(string cacheKey, object data, int slidingDuration, IList<string>? filePaths = null, IDictionary<string, bool>? folderPaths = null, IEnumerable<ICanBeCacheDependency>? dependencies = default)\n    {\n        var l = Log.Fn<string>($\"{nameof(cacheKey)}: {cacheKey}; {nameof(slidingDuration)}: {slidingDuration}\", timer: true);\n\n        // Never store 0, that's like never-expire\n        if (slidingDuration <= 0)\n            return l.ReturnAsError(\"slidingDuration must be greater than 0\");\n\n        // Try to add to cache - use try-catch to avoid exceptions\n        try\n        {\n            memoryCacheService.Set(cacheKey, data, p => p\n                .SetSlidingExpiration(slidingDuration)\n                .WatchFiles(filePaths)\n                .WatchFolders(folderPaths)\n                .WatchNotifyKeys(dependencies)\n            );\n\n            return l.ReturnAsOk(cacheKey);\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            /* ignore for now */\n            return l.ReturnAsError(\"error\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/AssemblyDiskCache.cs",
    "content": "using System.Reflection;\nusing System.Security.Cryptography;\nusing System.Text;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n/// <summary>\n/// Shared service for persisting and retrieving compiled assemblies from disk cache.\n/// Supports both Razor templates and AppCode assemblies across .NET Framework and .NET.\n/// Platform-neutral implementation with configurable assembly loading.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\n#pragma warning disable CS9113 // Parameter is unread.\npublic class AssemblyDiskCache(NoParamOrder npo = default, object[]? connect = default)\n#pragma warning restore CS9113 // Parameter is unread.\n    : ServiceBase(\"Sxc.AsmDskCch\", connect: connect)\n{\n    /// <summary>\n    /// Attempts to load a cached assembly from disk.\n    /// </summary>\n    /// <param name=\"cachePath\">Full path to the cached assembly file</param>\n    /// <param name=\"loadAssembly\">Platform-specific assembly loader function</param>\n    /// <param name=\"featureFlagCheck\">Optional feature flag check (null = always enabled)</param>\n    /// <returns>Assembly if found and valid; null if cache miss or error</returns>\n    /// <remarks>\n    /// Gracefully handles:\n    /// - File not found (cache miss)\n    /// - Corrupted assemblies (auto-deletes)\n    /// - I/O errors\n    /// - Feature flag disabled\n    /// </remarks>\n    public Assembly? TryLoadFromCache(\n        string cachePath,\n        Func<string, Assembly> loadAssembly,\n        Func<bool>? featureFlagCheck = null)\n    {\n        var l = Log.Fn<Assembly?>($\"path:{cachePath}\", timer: true);\n\n        // Check feature flag if provided\n        if (featureFlagCheck != null && !featureFlagCheck())\n        {\n            l.A(\"Disk cache disabled via feature flag\");\n            return l.ReturnNull();\n        }\n\n        try\n        {\n            var fileInfo = new FileInfo(cachePath);\n            if (!fileInfo.Exists)\n            {\n                l.A($\"Cache miss: file not found at {cachePath}\");\n                return l.ReturnNull();\n            }\n\n            l.A($\"Loading assembly from cache ({fileInfo.Length / 1024}KB)\");\n            var assembly = loadAssembly(cachePath);\n            l.A($\"Successfully loaded assembly: {assembly.FullName}\");\n\n            return l.Return(assembly, \"Cache hit\");\n        }\n        catch (BadImageFormatException ex)\n        {\n            l.Ex(ex);\n            HandleCorruptedCache(cachePath, l);\n            return l.ReturnNull();\n        }\n        catch (IOException ex)\n        {\n            l.Ex(ex);\n            l.A(\"I/O error loading from cache\");\n            return l.ReturnNull();\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnNull();\n        }\n    }\n\n    /// <summary>\n    /// Saves a compiled assembly to disk cache.\n    /// </summary>\n    /// <param name=\"sourceAssemblyPath\">Source assembly location</param>\n    /// <param name=\"cachePath\">Target cache path</param>\n    /// <param name=\"featureFlagCheck\">Optional feature flag check</param>\n    /// <returns>True if save successful; false otherwise</returns>\n    /// <remarks>\n    /// Gracefully handles:\n    /// - Directory creation\n    /// - Disk space exhaustion\n    /// - Permission errors\n    /// - Assembly already at target location (skip copy)\n    /// </remarks>\n    public bool TrySaveToCache(\n        string? sourceAssemblyPath,\n        string cachePath,\n        Func<bool>? featureFlagCheck = null)\n    {\n        var l = Log.Fn<bool>($\"source:{sourceAssemblyPath} -> cache:{cachePath}\", timer: true);\n\n        // Check feature flag if provided\n        if (featureFlagCheck != null && !featureFlagCheck())\n        {\n            l.A(\"Disk cache disabled via feature flag\");\n            return l.ReturnFalse(\"disabled\");\n        }\n\n        try\n        {\n            if (string.IsNullOrEmpty(sourceAssemblyPath))\n            {\n                l.A(\"Assembly has no location - cannot cache to disk\");\n                return l.ReturnFalse(\"no-location\");\n            }\n\n            // Ensure cache directory exists\n            var cacheDir = Path.GetDirectoryName(cachePath);\n            if (!string.IsNullOrEmpty(cacheDir) && !Directory.Exists(cacheDir))\n            {\n                Directory.CreateDirectory(cacheDir);\n                l.A($\"Created cache directory: {cacheDir}\");\n            }\n\n            // Skip if already at target location\n            if (string.Equals(Path.GetFullPath(sourceAssemblyPath), Path.GetFullPath(cachePath), StringComparison.OrdinalIgnoreCase))\n            {\n                l.A($\"Assembly already at cache location: {cachePath}\");\n                return l.ReturnTrue(\"already-in-cache\");\n            }\n\n            // Copy assembly to cache\n            File.Copy(sourceAssemblyPath, cachePath, overwrite: true);\n            var fileInfo = new FileInfo(cachePath);\n            l.A($\"Saved {fileInfo.Length / 1024}KB to disk cache: {cachePath}\");\n\n            return l.ReturnTrue(\"saved\");\n        }\n        catch (IOException ex)\n        {\n            l.Ex(ex);\n            l.A(\"I/O error saving to cache - will fallback to memory-only caching\");\n            return l.ReturnFalse(\"io-error\");\n        }\n        catch (UnauthorizedAccessException ex)\n        {\n            l.Ex(ex);\n            l.A(\"Permission error saving to cache - will fallback to memory-only caching\");\n            return l.ReturnFalse(\"permission-error\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnFalse(\"error\");\n        }\n    }\n\n    /// <summary>\n    /// Loads assembly from disk with retry logic for transient errors.\n    /// Useful for .NET Framework where antivirus/file locks are common.\n    /// </summary>\n    /// <param name=\"assemblyPath\">Path to the assembly file</param>\n    /// <param name=\"loadAssembly\">Platform-specific assembly loader function</param>\n    /// <param name=\"retryDelayMs\">Base delay between retry attempts in milliseconds</param>\n    /// <param name=\"timeoutMs\">Maximum time to retry in milliseconds</param>\n    /// <returns>Loaded assembly</returns>\n    /// <exception cref=\"IOException\">If assembly cannot be loaded after all retries</exception>\n    public Assembly LoadWithRetry(\n        string assemblyPath,\n        Func<string, Assembly> loadAssembly,\n        int retryDelayMs = 100,\n        int timeoutMs = 3000)\n    {\n        var l = Log.Fn<Assembly>($\"path:{assemblyPath}\", timer: true);\n        var stopwatch = System.Diagnostics.Stopwatch.StartNew();\n        var attempt = 0;\n        Exception? lastError = null;\n\n        while (stopwatch.ElapsedMilliseconds <= timeoutMs)\n        {\n            attempt++;\n            try\n            {\n                l.A($\"Attempt {attempt} to load cached assembly\");\n\n                // Test file accessibility\n                using (new FileStream(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))\n                {\n                    // Successfully opened; dispose immediately\n                }\n\n                var assembly = loadAssembly(assemblyPath);\n                return l.Return(assembly, $\"Loaded on attempt {attempt} after {stopwatch.ElapsedMilliseconds}ms\");\n            }\n            catch (Exception ex) when (IsTransientLoadException(ex))\n            {\n                lastError = ex;\n                var delay = retryDelayMs + new Random().Next(0, 100);\n                l.A($\"Attempt {attempt} failed ({ex.GetType().Name}). Retry in {delay}ms\");\n                Thread.Sleep(delay);\n            }\n            catch (Exception ex)\n            {\n                l.A($\"Non-transient error on attempt {attempt}, giving up\");\n                l.Ex(ex);\n                throw;\n            }\n        }\n\n        var message = $\"Failed to load after {attempt} attempts in {stopwatch.ElapsedMilliseconds}ms (last: {lastError?.GetType().Name}: {lastError?.Message})\";\n        l.E(message);\n        throw new IOException(message, lastError);\n    }\n\n    /// <summary>\n    /// Invalidates (deletes) cached assemblies matching a search pattern.\n    /// Safe to call even if directory doesn't exist.\n    /// </summary>\n    /// <param name=\"cacheDirectory\">Cache directory path</param>\n    /// <param name=\"searchPattern\">File search pattern (e.g., \"app-123-*.dll\")</param>\n    /// <param name=\"searchOption\">Search scope (TopDirectoryOnly by default)</param>\n    /// <returns>Number of files deleted</returns>\n    public int InvalidateCache(string cacheDirectory, string searchPattern, SearchOption searchOption = SearchOption.TopDirectoryOnly)\n    {\n        var l = Log.Fn<int>($\"dir:{cacheDirectory}, pattern:{searchPattern}\");\n\n        try\n        {\n            if (!Directory.Exists(cacheDirectory))\n            {\n                l.A(\"Cache directory does not exist - nothing to invalidate\");\n                return l.Return(0, \"no-directory\");\n            }\n\n            var matchingFiles = Directory.GetFiles(cacheDirectory, searchPattern, searchOption);\n            var deletedCount = 0;\n\n            foreach (var file in matchingFiles)\n            {\n                try\n                {\n                    File.Delete(file);\n                    l.A($\"Deleted: {file}\");\n                    deletedCount++;\n                }\n                catch (Exception ex)\n                {\n                    // Non-critical - log and continue\n                    l.Ex(ex);\n                }\n            }\n\n            return l.Return(deletedCount, $\"Invalidated {deletedCount} files\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return(0, \"error\");\n        }\n    }\n\n    /// <summary>\n    /// Computes SHA256 hash of content string.\n    /// </summary>\n    /// <param name=\"content\">Content to hash</param>\n    /// <returns>Lowercase hex string representing SHA256 hash; empty if content is null/empty</returns>\n    /// <remarks>\n    /// SHA256 is FIPS-compliant and performant for typical content sizes.\n    /// Used for cache key generation based on source code content.\n    /// </remarks>\n    public string ComputeContentHash(string content)\n    {\n        if (string.IsNullOrEmpty(content))\n            return string.Empty;\n\n        using var sha256 = SHA256.Create();\n        var bytes = Encoding.UTF8.GetBytes(content);\n        var hashBytes = sha256.ComputeHash(bytes);\n        return BitConverter.ToString(hashBytes).Replace(\"-\", \"\").ToLowerInvariant();\n    }\n\n    /// <summary>\n    /// Handles corrupted cache files by attempting deletion.\n    /// Called automatically when BadImageFormatException occurs during load.\n    /// </summary>\n    /// <param name=\"cachePath\">Path to corrupted cache file</param>\n    /// <param name=\"log\">Log for diagnostic output</param>\n    private void HandleCorruptedCache(string cachePath, ILog? log)\n    {\n        log.A(\"Corrupted cache file detected - will trigger recompilation\");\n        try\n        {\n            if (File.Exists(cachePath))\n            {\n                File.Delete(cachePath);\n                log.A($\"Deleted corrupted file: {cachePath}\");\n            }\n        }\n        catch (Exception ex)\n        {\n            log.Ex(ex);\n        }\n    }\n\n    /// <summary>\n    /// Determines if an exception is transient (worth retrying).\n    /// </summary>\n    /// <param name=\"ex\">Exception to check</param>\n    /// <returns>True if exception is likely transient (file lock, antivirus scan, etc.)</returns>\n    private static bool IsTransientLoadException(Exception ex)\n        => ex is FileNotFoundException\n            or IOException\n            or UnauthorizedAccessException\n            or BadImageFormatException;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/AssemblyResolver.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Reflection;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n/// <summary>\n/// Special SINGLETON service to resolve assemblies.\n/// The purpose is to ensure .net can access assemblies which are compiled at runtime.\n/// </summary>\n/// <remarks>\n/// This is a singleton!\n/// </remarks>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AssemblyResolver : ServiceBase, ILogShouldNeverConnect\n{\n    private static bool _isHandlerRegistered = false;\n    private readonly ConcurrentDictionary<string, Assembly> _assemblyCache = new();\n    private readonly ConcurrentDictionary<string, string> _assemblyPathPerApp = new(StringComparer.InvariantCultureIgnoreCase);\n\n#if DEBUG\n    private const bool Debug = true;\n#else\n    private const bool Debug = false;\n#endif\n\n    public AssemblyResolver(ILogStore logStore) : base($\"{SxcLogName}.AsmRsl\")\n    {\n        var l = Debug ? Log.Fn() : null;\n        \n        if (_isHandlerRegistered)\n        {\n            l.Done(\"already registered\");\n            return;\n        }\n\n        if (Debug)\n            logStore.Add(\"system-assemblyresolver\", Log);\n\n        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;\n        AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_AssemblyResolve;\n        _isHandlerRegistered = true;\n        l.Done(\"registered first time\");\n    }\n\n    private Assembly? CurrentDomain_AssemblyResolve(object? sender, ResolveEventArgs args)\n    {\n        var l = Debug ? Log.Fn<Assembly?>($\"{nameof(sender)}:'{sender}'; {nameof(args.Name)}:'{args.Name}'; {nameof(args.RequestingAssembly)}:'{args.RequestingAssembly}'\") : null;\n        var r = _assemblyCache.TryGetValue(args.Name, out var assembly)\n            ? assembly\n            : null;\n        return l.Return(r, r != null ? \"Ok\" : \"can't find\");\n    }\n\n    public void AddAssemblies(List<Assembly> assemblies, string? appRelativePath = null)\n    {\n        var l = Debug ? Log.Fn($\"{nameof(assemblies)}:'{assemblies?.Count}'; {nameof(appRelativePath)}:'{appRelativePath}'\") : null;\n        if (assemblies == null)\n        {\n            l.Done(\"assemblies is null\");\n            return;\n        }\n        foreach (var assembly in assemblies) \n            AddAssembly(assembly, appRelativePath);\n        l.Done(\"Ok\");\n    }\n\n    public void AddAssembly(Assembly? assembly, string? appRelativePath = null)\n    {\n        var l = Debug ? Log.Fn($\"{nameof(assembly)}:'{assembly}'; {nameof(appRelativePath)}:'{appRelativePath}'\") : null;\n        if (assembly == null)\n        {\n            l.Done(\"assembly is null\");\n            return;\n        }\n\n        l.A(_assemblyCache.TryAdd(assembly.GetName().FullName, assembly)\n            ? $\"added to cache: '{assembly.GetName().FullName}'\"\n            : $\"already in cache: '{assembly.GetName().FullName}'\");\n\n        if (appRelativePath != null && !string.IsNullOrEmpty(assembly.Location))\n        {\n            _assemblyPathPerApp[appRelativePath] = assembly.Location;\n            l.A($\"add or update {nameof(_assemblyPathPerApp)} {nameof(appRelativePath)}:'{appRelativePath}'; {nameof(assembly.Location)}:'{assembly.Location}'\");\n        }\n        l.Done(\"Ok\");\n    }\n\n    public string? GetAssemblyLocation(string? appRelativePath)\n    {\n        if (appRelativePath == null)\n            return null; // No app-relative path means no assembly location can be found\n\n        appRelativePath = appRelativePath.Backslash();\n        var l = Debug\n            ? Log.Fn<string?>($\"{nameof(appRelativePath)}:'{appRelativePath}'\")\n            : null; \n        var r = _assemblyPathPerApp.TryGetValue(appRelativePath, out var location)\n            ? location\n            : null;\n        return l.Return(r, r != null ? $\"Ok:'{r}'\" : \"can't find\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/DependenciesLoader.cs",
    "content": "﻿using System.Reflection;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DependenciesLoader(ILogStore logStore, IAppReaderFactory appReadFac, LazySvc<IAppPathsMicroSvc> appPathsLazy, AssemblyCacheManager assemblyCacheManager, LazySvc<AppCodeCompiler> appCodeCompilerLazy)\n    : ServiceBase(\"Sys.AppCodeLoad\", connect: [logStore, appReadFac, appPathsLazy, assemblyCacheManager, appCodeCompilerLazy])\n{\n    public const string DependenciesFolder = \"Dependencies\";\n\n    public (List<Assembly>? Assemblies, HotBuildSpec Specs) TryGetOrFallback(HotBuildSpec spec)\n    {\n        var l = Log.Fn<(List<Assembly>?, HotBuildSpec)>(spec.ToString());\n        var (assemblyResults, cacheKey) = TryGetAssemblyOfDependenciesFromCache(spec, Log);\n        if (assemblyResults != null)\n            return l.Return((assemblyResults.Select(r => r.Assembly!).ToList(), spec), \"Dependencies where cached.\");\n\n        var assemblies = LoadDependencyAssembliesOrNull(spec, cacheKey);\n        if (assemblies != null)\n            return l.Return((assemblies, spec), $\"Dependencies loaded from '/{spec.Edition}'\");\n\n        if (spec.Edition.IsEmpty())\n            return l.Return((null, spec), $\"Dependencies not found in '/', done.\");\n\n        // try get root edition\n        var rootSpec = spec.CloneWithoutEdition();\n        var pairFromRoot = TryGetOrFallback(rootSpec);\n        return l.Return(pairFromRoot, \"Dependencies found in '/'.\" + (pairFromRoot.Assemblies == null ? \", null.\" : \"\"));\n    }\n\n    private (List<AssemblyResult>? assemblyResults, string cacheKey) TryGetAssemblyOfDependenciesFromCache(HotBuildSpec spec, ILog callerLog)\n    {\n        var l = callerLog.Fn<(List<AssemblyResult>?, string)>($\"{spec}\");\n        var (assemblyResults, cacheKey) = assemblyCacheManager.TryGetDependencies(spec);\n        if (assemblyResults == null)\n            return l.Return((null, cacheKey), \"no dependencies in cache\");\n\n        l.A($\"dependencies from cache: {assemblyResults.Count}\");\n\n        foreach (var assemblyResult in assemblyResults)\n            l.A(assemblyResult.HasAssembly\n                ? $\"dependency from cache: {assemblyResult.Assembly!.FullName} location: {assemblyResult.Assembly.Location}\"\n                : $\"error in dependency from cache: {assemblyResult.ErrorMessages} \");\n\n        return l.ReturnAsOk((assemblyResults, cacheKey));\n    }\n\n    private List<Assembly>? LoadDependencyAssembliesOrNull(HotBuildSpec spec, string cacheKey)\n    {\n        // Add to global history and add specs\n        var logSummary = logStore.Add(SxcLogAppCodeLoader, Log);\n        logSummary?.UpdateSpecs(spec.ToDictionary());\n\n        // Initial message for insights-overview\n        var l = Log.Fn<List<Assembly>>($\"{spec}\", timer: true);\n\n        var assemblyResults = TryLoadDependencyAssemblies(spec, cacheKey, logSummary);\n\n        return assemblyResults != null\n            ? l.ReturnAsOk(assemblyResults.Select(r => r.Assembly!).ToList())\n            : l.ReturnNull(\"no dependencies\");\n    }\n\n    private List<AssemblyResult>? TryLoadDependencyAssemblies(HotBuildSpec spec, string cacheKey, LogStoreEntry? logSummary)\n    {\n        var l = Log.Fn<List<AssemblyResult>>($\"{spec}\");\n\n        // Get paths\n        var (physicalPath, relativePath, physicalPathShared, relativePathShared) = GetDependenciesPaths(DependenciesFolder, spec);\n        if (logSummary != null)\n        {\n            logSummary.AddSpec(\"Dependencies PhysicalPath\", physicalPath);\n            logSummary.AddSpec(\"Dependencies RelativePath\", relativePath);\n            logSummary.AddSpec(\"Dependencies PhysicalPathShared\", physicalPathShared);\n            logSummary.AddSpec(\"Dependencies RelativePathShared\", relativePathShared);\n        }\n\n        List<AssemblyResult> assemblyResults;\n        if (Directory.Exists(physicalPath))\n        {\n            l.A($\"local dependencies folder exists: {physicalPath}\");\n            assemblyResults = GetAssemblyResults(spec.WithoutSharedSuffix(), physicalPath);\n        }\n        else if (Directory.Exists(physicalPathShared))\n        {\n            l.A($\"shared dependencies folder exists: {physicalPathShared}\");\n            assemblyResults = GetAssemblyResults(spec.WithSharedSuffix(), physicalPathShared);\n        }\n        else\n        {\n            // missing dependencies folder\n            return l.ReturnNull($\"{DependenciesFolder} folder do not exists: '{physicalPath}', or '{physicalPathShared}'\");\n        }\n\n        l.A($\"dependencies loaded: {assemblyResults.Count}\");\n\n        // Add dependency assemblies to cache\n        assemblyCacheManager.Add(\n            cacheKey,\n            assemblyResults,\n            slidingDuration: CacheConstants.DurationAppDlls,\n            folderPaths: new Dictionary<string, bool> { [physicalPath] = true }\n        );\n        l.A($\"{assemblyResults.Count} dependencies added to cache: {cacheKey}\");\n\n        return l.ReturnAsOk(assemblyResults);\n    }\n\n    private List<AssemblyResult> GetAssemblyResults(HotBuildSpecWithSharedSuffix spec, string physicalPath)\n    {\n        var l = Log.Fn<List<AssemblyResult>>($\"{spec}; {nameof(physicalPath)}: '{physicalPath}'\");\n        var assemblyResults = new List<AssemblyResult>();\n        foreach (var dependency in Directory.GetFiles(physicalPath, \"*.dll\"))\n        {\n            try\n            {\n                var location = appCodeCompilerLazy.Value.GetDependencyAssemblyLocations(dependency, spec);\n                File.Copy(dependency, location, true);\n                var assembly = Assembly.LoadFrom(location);\n                assemblyResults.Add(new(assembly)\n                {\n                    AssemblyLocations = [dependency],\n                });\n                l.A($\"dependency loaded: {assembly.FullName} location: {location}\");\n            }\n            catch (Exception ex)\n            {\n                // sink\n                l.Ex(ex);\n            }\n        }\n\n        return assemblyResults;\n    }\n\n\n    //private static IDictionary<string, bool> GetWatcherFolders(AssemblyResult assemblyResult, HotBuildSpec spec, string physicalPath)\n    //{\n    //    var watcherFolders = new Dictionary<string, bool>();\n\n    //    // take AppCode folder (eg. ...\\edition\\AppCode)\n    //    var appCodeFolder = physicalPath;\n    //    IfExistsThenAdd(appCodeFolder, true);\n\n    //    // take parent folder (eg. ...\\edition)\n    //    var appCodeParentFolder = Path.GetDirectoryName(appCodeFolder);\n    //    if (appCodeParentFolder.IsEmpty()) return new Dictionary<string, bool>(watcherFolders);\n    //    IfExistsThenAdd(appCodeParentFolder, false);\n\n    //    // if no edition was used, then we were already in the root, and should stop now.\n    //    if (spec.Edition.IsEmpty()) return new Dictionary<string, bool>(watcherFolders);\n\n    //    // If we have an edition, and it has an assembly, we don't need to watch the root folder\n    //    if (assemblyResult.HasAssembly) return new Dictionary<string, bool>(watcherFolders);\n\n    //    // If we had an edition and no assembly, then we need to watch the root folder\n    //    // we need to add more folders to watch for cache invalidation\n\n    //    // App Root folder (eg. ...\\)\n    //    var appRootFolder = Path.GetDirectoryName(appCodeParentFolder);\n    //    if (appRootFolder.IsEmpty()) return new Dictionary<string, bool>(watcherFolders);\n    //    // Add to watcher list if it exists, otherwise exit, since we can't have subfolders\n    //    if (!IfExistsThenAdd(appRootFolder, false)) return new Dictionary<string, bool>(watcherFolders);\n\n    //    // \n    //    var appRootAppCode = Path.Combine(appRootFolder, DependenciesFolder);\n    //    // Add to watcher list if it exists, otherwise exit, since we can't have subfolders\n    //    if (!IfExistsThenAdd(appRootAppCode, true)) return new Dictionary<string, bool>(watcherFolders);\n\n    //    // all done\n    //    return new Dictionary<string, bool>(watcherFolders);\n\n    //    // Helper to add and return info if it exists\n    //    bool IfExistsThenAdd(string folder, bool watchSubfolders)\n    //    {\n    //        if (!Directory.Exists(folder)) return false;\n    //        watcherFolders.Add(folder, watchSubfolders);\n    //        return true;\n    //    }   \n    //}\n\n    // TODO: stv# candidate for refactoring, similar to AppCodeLoader.GetAppPaths\n    private (string physicalPath, string relativePath, string physicalPathShared, string relativePathShared) GetDependenciesPaths(string folder, HotBuildSpec spec)\n    {\n        var l = Log.Fn<(string physicalPath, string relativePath, string physicalPathShared, string relativePathShared)>($\"{spec}\");\n        var appPaths = appPathsLazy.Value.Get(appReadFac.Get(spec.AppId));\n        var folderWithEdition = folder.HasValue()\n            ? spec.Edition.HasValue()\n                ? Path.Combine(spec.Edition, folder)\n                : folder\n            : spec.Edition!;\n        var physicalPath = Path.Combine(appPaths.PhysicalPath, folderWithEdition);\n        // l.A($\"dependencies {nameof(physicalPath)}: '{physicalPath}'\");\n        var relativePath = Path.Combine(appPaths.RelativePath, folderWithEdition);\n        // l.A($\"dependencies {nameof(relativePath)}: '{relativePath}'\");\n        var physicalPathShared = Path.Combine(appPaths.PhysicalPathShared, folderWithEdition);\n        // l.A($\"dependencies {nameof(physicalPath)}: '{physicalPath}'\");\n        var relativePathShared = Path.Combine(appPaths.RelativePathShared, folderWithEdition);\n        // l.A($\"dependencies {nameof(relativePath)}: '{relativePath}'\");\n        return l.ReturnAsOk((physicalPath, relativePath, physicalPathShared, relativePathShared));\n    }\n\n    // Idea: put dll in the App/bin folder, for VS Intellisense - ATM not relevant\n    //private static void AssembliesDelete(IEnumerable<string> list)\n    //{\n    //    if (list == null) return;\n    //    foreach (var assembly in list)\n    //    {\n    //        try\n    //        {\n    //            File.Delete(assembly);\n    //        }\n    //        catch\n    //        {\n    //            // ignore\n    //        }\n    //    }\n    //}\n\n    // Idea: put dll in the App/bin folder, for VS Intellisense - ATM not relevant\n    //private static void CopyAssemblyForRefs(string source, string destination)\n    //{\n    //    if (!File.Exists(source)) return;\n    //    var destinationFolder = Path.GetDirectoryName(destination);\n    //    if (destinationFolder != null) Directory.CreateDirectory(destinationFolder);\n    //    File.Copy(source, destination, true);\n    //}\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/ExtensionCompileReferenceService.cs",
    "content": "using System.Reflection;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing ToSic.Eav.Sys;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n/// <summary>\n/// Helper that discovers compile-time references defined inside app extensions.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionCompileReferenceService(MemoryCacheService cache)\n    : ServiceBase(\"Sxc.ExtRefRd\", connect: [cache])\n{\n    private const string CompileConfigFileName = \"compile.json\";\n\n    private static readonly JsonSerializerOptions ConfigSerializerOptions = new()\n    {\n        AllowTrailingCommas = true,\n        ReadCommentHandling = JsonCommentHandling.Skip,\n    };\n\n    private const string CachePrefix = \"Sxc.ExtRefRdr\";\n    \n    /// <summary>\n    /// Load extension reference definitions underneath the AppCode/Extensions folder that contains <paramref name=\"startPath\"/>.\n    /// </summary>\n    public IReadOnlyList<ExtensionReference> GetReferences(string? startPath, bool netFramework)\n    {\n        var l = Log.Fn<List<ExtensionReference>>($\"start:{startPath}, net4:{netFramework}\");\n        var appCodeFolder = FindAppCodeFolder(startPath);\n        if (appCodeFolder.IsEmpty())\n            return l.Return([], \"no-appcode\");\n\n        var extensionsRoot = Path.Combine(appCodeFolder, FolderConstants.AppExtensionsFolder);\n        if (!Directory.Exists(extensionsRoot))\n            return l.Return([], \"no-extensions\");\n\n        var references = new List<ExtensionReference>();\n        foreach (var extensionDir in Directory.EnumerateDirectories(extensionsRoot))\n        {\n            var configPath = Path.Combine(extensionDir, CompileConfigFileName);\n            if (!File.Exists(configPath))\n                continue;\n\n            var config = LoadConfig(configPath);\n            var entries = netFramework ? config.NetFrameworkReferences : config.NetCoreReferences;\n            foreach (var entry in entries)\n            {\n                if (!entry.HasValue())\n                    continue;\n\n                references.Add(new(entry.Trim(), extensionDir));\n            }\n        }\n\n        return l.Return(references, $\"found:{references.Count}\");\n    }\n\n    public static bool IsAssemblyName(string referenceValue)\n    {\n        if (referenceValue.IsEmpty())\n            return false;\n\n        if (Path.IsPathRooted(referenceValue))\n            return false;\n\n        return !referenceValue.Contains(Path.DirectorySeparatorChar)\n               && !referenceValue.Contains(Path.AltDirectorySeparatorChar);\n    }\n\n    public static string NormalizeAssemblyName(string referenceValue)\n    {\n        if (referenceValue.IsEmpty())\n            return referenceValue;\n\n        return referenceValue.EndsWith(\".dll\", StringComparison.OrdinalIgnoreCase)\n            ? referenceValue.Substring(0, referenceValue.Length - 4)\n            : referenceValue;\n    }\n\n    public string? ResolveReferencePath(ExtensionReference reference)\n    {\n        var l = Log.Fn<string?>($\"value:{reference.Value}\");\n        if (reference.Value.IsEmpty())\n            return l.ReturnNull(\"empty\");\n\n        if (Path.IsPathRooted(reference.Value))\n            return l.Return(reference.Value, \"rooted\");\n\n        var combined = Path.Combine(reference.ExtensionFolder, reference.Value);\n        try\n        {\n            return l.ReturnAsOk(Path.GetFullPath(combined));\n        }\n        catch\n        {\n            return l.ReturnNull(\"invalid\");\n        }\n    }\n\n    public string? TryResolveAssemblyLocation(string assemblyName)\n    {\n        var l = Log.Fn<string?>($\"assembly:{assemblyName}\");\n        var normalized = ExtensionCompileReferenceService.NormalizeAssemblyName(assemblyName);\n        if (normalized.IsEmpty())\n            return l.ReturnNull(\"empty\");\n\n        try\n        {\n            var loaded = AppDomain.CurrentDomain\n                .GetAssemblies()\n                .FirstOrDefault(a => string.Equals(a.GetName().Name, normalized, StringComparison.OrdinalIgnoreCase));\n\n            loaded ??= Assembly.Load(new AssemblyName(normalized));\n\n            // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n            var location = loaded?.Location.HasValue() == true ? loaded.Location : null;\n            return location.HasValue()\n                ? l.ReturnAsOk(location)\n                : l.ReturnNull(\"no-location\");\n        }\n        catch\n        {\n            return l.ReturnNull(\"error\");\n        }\n    }\n\n    private string? FindAppCodeFolder(string? startPath)\n    {\n        var l = Log.Fn<string?>($\"start:{startPath}\");\n        if (startPath.IsEmpty())\n            return l.ReturnNull(\"empty\");\n\n        string? normalized;\n        try\n        {\n            normalized = Path.GetFullPath(startPath);\n        }\n        catch\n        {\n            return l.ReturnNull(\"invalid\");\n        }\n\n        var directory = Directory.Exists(normalized)\n            ? new DirectoryInfo(normalized)\n            : new FileInfo(normalized).Directory;\n\n        while (directory != null)\n        {\n            if (directory.Name.Equals(FolderConstants.AppCodeFolder, StringComparison.OrdinalIgnoreCase))\n                return directory.FullName;\n\n            var candidate = Path.Combine(directory.FullName, FolderConstants.AppCodeFolder);\n            if (Directory.Exists(candidate))\n                return l.ReturnAsOk(candidate);\n\n            directory = directory.Parent;\n        }\n\n        return l.ReturnNull(\"not-found\");\n    }\n\n    private CompileConfigCache LoadConfig(string configPath)\n    {\n        var cacheKey = $\"{CachePrefix}:{configPath}\";\n        if (cache.TryGet<CompileConfigCache>(cacheKey, out var cached) && cached is not null)\n            return cached;\n\n        var l = Log.Fn<CompileConfigCache>($\"config:{configPath}\");\n        var entry = ReadConfig(configPath);\n        cache.Set(cacheKey, entry, options =>\n        {\n            if (File.Exists(configPath))\n            {\n                options.WatchFiles([configPath]);\n            }\n            else\n            {\n                var parents = GetExistingParent(configPath);\n                if (parents.Count > 0)\n                    options.WatchFolders(parents.ToDictionary(p => p, _ => true));\n            }\n            return options;\n        });\n\n        return l.ReturnAsOk(entry);\n    }\n    private CompileConfigCache ReadConfig(string configPath)\n    {\n        var l = Log.Fn<CompileConfigCache>($\"config:{configPath}\");\n\n        if (!File.Exists(configPath))\n            return l.Return(new CompileConfigCache([], []), \"missing\");\n\n        try\n        {\n            var json = File.ReadAllText(configPath);\n            var config = JsonSerializer.Deserialize<CompileConfig>(json, ConfigSerializerOptions) ?? new CompileConfig();\n            var entry = new CompileConfigCache(config.NetCoreReferences,\n                config.NetFrameworkReferences);\n            return l.Return(entry, \"ok\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return(new CompileConfigCache([], []), \"error\");\n        }\n    }\n\n    private List<string> GetExistingParent(string filePath)\n    {\n        var l = Log.Fn<List<string>>($\"parent:{filePath}\");\n\n        var parentPath = Path.GetDirectoryName(filePath);\n        while (!parentPath.IsEmpty())\n        {\n            if (Directory.Exists(parentPath))\n                return l.Return([parentPath], \"found\");\n            parentPath = Path.GetDirectoryName(parentPath);\n        }\n\n        return l.Return([], \"not-found\");\n    }\n\n    public readonly struct ExtensionReference(string value, string extensionFolder)\n    {\n        public string Value { get; } = value;\n\n        public string ExtensionFolder { get; } = extensionFolder;\n    }\n\n    private sealed record CompileConfigCache(IReadOnlyList<string> NetCoreReferences, IReadOnlyList<string> NetFrameworkReferences);\n\n    private sealed class CompileConfig\n    {\n        [JsonPropertyName(\"References\")]\n        public List<string> NetCoreReferences { get; init; } = [];\n\n        [JsonPropertyName(\"References.net4\")]\n        public List<string> NetFrameworkReferences { get; init; } = [];\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/ImplicitUsings.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.HotBuild;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class ImplicitUsings\n{\n    /// <summary>\n    /// Usings which are implicitly added to all generated code files.\n    /// It's important that they are the same in Dnn and Oqtane, and that it's not too much,\n    /// because that ensures that the code created by others has to mention their usings explicitly.\n    ///\n    /// Otherwise, if we once shrink this list, then all code created by others could break.\n    /// </summary>\n    public static readonly List<string> ForRazor =\n    [\n        // 1. based on 'obj/*/*.GlobalUsings.g.cs' for Microsoft.NET.Sdk\n        \"System\",\n        \"System.Collections.Generic\",\n        //\"System.IO\", // not implicit using in Oqtane razor\n        \"System.Linq\",\n        //\"System.Net.Http\", // not referenced in DNN razor\n        //\"System.Threading\", // not implicit using in DNN razor\n        //\"System.Threading.Tasks\", // not implicit using in DNN razor\n\n        // 2. based on 'obj/*/*.GlobalUsings.g.cs' for Microsoft.NET.Sdk.Web\n        //\"System.Net.Http.Json\", // not referenced in DNN razor\n        //\"Microsoft.AspNetCore.Builder\", // not referenced in DNN razor\n        //\"Microsoft.AspNetCore.Hosting\", // not referenced in DNN razor\n        //\"Microsoft.AspNetCore.Http\", // not referenced in DNN razor\n        //\"Microsoft.AspNetCore.Routing\", // not referenced in DNN razor\n        //\"Microsoft.Extensions.Configuration\", // not implicit using in DNN razor\n        //\"Microsoft.Extensions.DependencyInjection\", // not implicit using in DNN razor\n        //\"Microsoft.Extensions.Hosting\", // not referenced in DNN razor\n        //\"Microsoft.Extensions.Logging\", // not implicit using in DNN razor\n\n        // 3. other usings\n        //\"System.Text\", // not implicit using in DNN razor\n        //\"System.Web\", // not implicit using in Oqtane razor\n        //\"System.Web.UI\", // not referenced in Oqtane razor\n        //\"System.Web.UI.WebControls\", // not referenced in Oqtane razor\n        //\"System.Web.WebPages\", // not referenced in Oqtane razor\n    ];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/RoslynConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.HotBuild;\n\n/// <summary>\n/// Contains constants and settings for Roslyn compilation.\n/// These settings define the language version and preprocessor symbols used during compilation.\n/// </summary>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic class RoslynConstants\n{\n    /// <summary>\n    /// Specifies the C# language version to use during Roslyn compilation.\n    /// The \"Preview\" version allows the use of the latest language features.\n    /// </summary>\n    public const string LanguageVersion = \"latest\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/SourceCodeHasher.cs",
    "content": "﻿using System.Reflection;\nusing System.Security.Cryptography;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Capabilities.Platform;\nusing ToSic.Sys.Locking;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild\n{\n    public class SourceCodeHasher(LazySvc<IPlatformInfo> platform, MemoryCacheService memoryCacheService) : ServiceBase(\"Sxc.ScCdHsh\", connect: [memoryCacheService])\n    {\n        private const string CsFiles = \".cs\";\n        private const bool UseSubfolders = true;\n        private const int BufferSize = 16 * 1024; // 16KB buffer\n        private const int CacheMinutes = 10;\n        private readonly TryLockTryDo _lockHashProvider = new();\n        private readonly TryLockTryDo _lockSourceFilesProvider = new();\n\n        public string GetHashString(string folderPath)\n        {\n            var l = Log.Fn<string>($\"{nameof(folderPath)}: '{folderPath}'\", timer: true);\n\n            // See if in memory cache\n            var cacheKey = FolderHashCacheKey(folderPath);\n            if (memoryCacheService.TryGet<string>(cacheKey, out var fromCache))\n                return l.Return(fromCache!, \"from cache\");\n\n            var result = _lockHashProvider.Call(\n                conditionToGenerate: () => !memoryCacheService.TryGet<string>(cacheKey, out _),\n                generator: () =>\n                {\n                    var files = GetSourceFilesInFolder(folderPath);\n                    l.A($\"{files.Length} files found\");\n\n                    var computeHashStringForFiles = BitConverter.ToString(ComputeHashForFiles(files)).Replace(\"-\", \"\").ToLower();\n                    l.A(\"hash string computed\");\n\n                    memoryCacheService.Set(cacheKey, computeHashStringForFiles, p => p\n                        .SetSlidingExpiration(CacheMinutes * 60)\n                        .WatchCacheKeys([SourceFilesInFolderCacheKey(folderPath)]));\n\n                    return computeHashStringForFiles;\n                },\n                cacheOrFallback: () => memoryCacheService.Get<string>(cacheKey)\n            );\n\n            return l.ReturnAsOk(result.Result!);\n        }\n\n        internal string[] GetSourceFilesInFolder(string fullPath)\n        {\n            var l = Log.Fn<string[]>($\"{nameof(fullPath)}: '{fullPath}'\", timer: true);\n\n            // See if in memory cache\n            var cacheKey = SourceFilesInFolderCacheKey(fullPath);\n            if (memoryCacheService.TryGet<string[]>(cacheKey, out var fromCache))\n                return l.Return(fromCache!, \"from cache\");\n\n            var result = _lockSourceFilesProvider.Call(\n                conditionToGenerate: () => !memoryCacheService.TryGet<string[]>(cacheKey, out _),\n                generator: () =>\n                {\n                    var files = Directory.GetFiles(fullPath, $\"*{CsFiles}\", UseSubfolders\n                        ? SearchOption.AllDirectories\n                        : SearchOption.TopDirectoryOnly\n                    );\n                    l.A($\"{files.Length} files found with {nameof(UseSubfolders)}: {UseSubfolders}\");\n                    Array.Sort(files, StringComparer.Ordinal); // sort the array of file paths before processing to ensure hashing deterministic behavior.\n                    l.A(\"sorted files\");\n\n                    memoryCacheService.Set(cacheKey, files, p => p\n                        .SetSlidingExpiration(CacheMinutes * 60)\n                        .WatchFolders(new Dictionary<string, bool> { { fullPath, UseSubfolders } }));\n\n                    return files;\n                },\n                cacheOrFallback: () => memoryCacheService.Get<string[]>(cacheKey)\n            );\n\n            return l.ReturnAsOk(result.Result!);\n        }\n\n\n        private string FolderHashCacheKey(string fullPath) => $\"Sxc-FolderHash-{fullPath}\";\n\n        private string SourceFilesInFolderCacheKey(string fullPath) => $\"Sxc-SourceFilesInFolder-{fullPath}\";\n\n        /// <summary>\n        /// Create a hash of all files which are relevant for the DLL.\n        /// </summary>\n        /// <param name=\"files\"></param>\n        /// <returns></returns>\n        private byte[] ComputeHashForFiles(string[] files)\n        {\n            var l = Log.Fn<byte[]>($\"{nameof(files)}: {files.Count()}\", timer: true);\n\n            using var hashAlgorithm = SHA256.Create(); // fips compatibility\n\n            HashRelevantKeys(hashAlgorithm);\n            l.A(\"relevant platform keys hashed\");\n\n            HashRelevantFiles(files, hashAlgorithm);\n            l.A(\"relevant files hashed\");\n\n            hashAlgorithm.TransformFinalBlock([], 0, 0); // Finalize the hash computation\n            l.A(\"finalized hash\");\n\n            return l.ReturnAsOk(hashAlgorithm.Hash ?? []);\n        }\n\n        /// <summary>\n        /// Hash relevant keys\n        /// </summary>\n        /// <param name=\"hashAlgorithm\"></param>\n        private void HashRelevantKeys(HashAlgorithm hashAlgorithm)\n            => hashAlgorithm.TransformBlock(PlatformBytes, 0, PlatformBytes.Length, PlatformBytes, 0);\n\n        // Cache platform bytes\n        private byte[] PlatformBytes => _platformBytes ??= GetPlatformBytes();\n        private static byte[]? _platformBytes;\n\n        // Combines relevant keys, incl. 2sxc and platform versions to hash.\n        private byte[] GetPlatformBytes()\n        {\n            var l = Log.Fn<byte[]>($\"\", timer: true);\n            var platformVersion = platform.Value.Version;\n            var sxcVersion = Assembly.GetExecutingAssembly().GetName().Version!;\n            var platformString = $\"{platform.Value.Name.ToLowerInvariant()}:{platformVersion.Major}.{platformVersion.Minor}.{platformVersion.Build}.{platformVersion.Revision}_2sxc:{sxcVersion.Major}.{sxcVersion.Minor}.{sxcVersion.Build}.{sxcVersion.Revision}\";\n            l.A($\"platform string: '{platformString}'\");\n            return l.ReturnAsOk(System.Text.Encoding.UTF8.GetBytes(platformString));\n        }\n\n        /// <summary>\n        /// Hash relevant files in the folder.\n        /// </summary>\n        /// <param name=\"files\"></param>\n        /// <param name=\"hashAlgorithm\"></param>\n        private static void HashRelevantFiles(string[] files, HashAlgorithm hashAlgorithm)\n        {\n            // Hash all files in the folder\n            foreach (var filePath in files)\n            {\n                // Read and hash the file content\n                using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);\n                var buffer = new byte[BufferSize];\n                int bytesRead;\n                while ((bytesRead = fs.Read(buffer, 0, BufferSize)) > 0)\n                    hashAlgorithm.TransformBlock(buffer, 0, bytesRead, buffer, 0);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.HotBuild/Util.cs",
    "content": "using ToSic.Sys.Configuration;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n/// <summary>\n/// On start need to clean the \"2sxc.bin\" (AppCode) and \"2sxc.bin.cshtml\" (Razor) folders,\n/// because they are used to temporarily save compiled assemblies.\n/// </summary>\npublic class Util(IGlobalConfiguration globalConfiguration)\n{\n    private const string Dll = \".dll\";\n    private const int RetentionDays = 28;\n    private static readonly TimeSpan RetentionPeriod = TimeSpan.FromDays(RetentionDays);\n    private static bool Cleaned { get; set; }\n    private static readonly object CleaningLock = new();\n    private static readonly HashSet<string> EphemeralExtensions = new(StringComparer.OrdinalIgnoreCase)\n    {\n        \".cmdline\", \".err\", \".out\", \".tmp\", \".cs\"\n    };\n\n    public void CleanTempAssemblyFolder()\n    {\n        // Ensure that cleaning is executed only once\n        if (Cleaned)\n            return;\n\n        lock (CleaningLock)\n        {\n            if (Cleaned)\n                return;\n\n            // Clean AppCode folder (2sxc.bin)\n            CleanAssemblyFolder(globalConfiguration.TempAssemblyFolder(), \"AppCode (2sxc.bin)\", AssemblyFolderType.AppCode);\n\n            // Clean Razor compiled templates folder (2sxc.bin.cshtml)\n            CleanAssemblyFolder(globalConfiguration.CshtmlAssemblyFolder(), \"Razor (2sxc.bin.cshtml)\", AssemblyFolderType.Cshtml);\n\n            // Clean ephemeral compiler artifacts from \"2sxc.bin.cshtml\\\\temp\" folder\n            CleanAssemblyFolder(Path.Combine(globalConfiguration.CshtmlAssemblyFolder(), \"temp\"), \"roslyn compiler temp Folder\", AssemblyFolderType.None);\n\n            Cleaned = true;\n        }\n    }\n\n    /// <summary>\n    /// Cleans a specific assembly folder by removing old/orphaned DLL files (including nested app/edition folders) and ephemeral compiler artifacts.\n    /// Keeps corresponding .pdb files for debugging.\n    /// </summary>\n    private void CleanAssemblyFolder(string folderPath, string folderDescription, AssemblyFolderType folderType)\n    {\n        _ = folderDescription;\n        if (string.IsNullOrEmpty(folderPath))\n            return;\n\n        if (!Directory.Exists(folderPath))\n        {\n            Directory.CreateDirectory(folderPath);\n            return; // nothing else to do first run\n        }\n\n        // Clean recursively because cache is now nested per app/edition/shared\n        var directories = Directory.GetDirectories(folderPath, \"*\", SearchOption.AllDirectories)\n            .Prepend(folderPath)\n            .Distinct(StringComparer.OrdinalIgnoreCase);\n\n        var now = DateTime.Now;\n\n        var enumerable = directories.ToList();\n        foreach (var dir in enumerable)\n        {\n            var isRoot = string.Equals(dir, folderPath, StringComparison.OrdinalIgnoreCase);\n\n            // Step 1: Remove ephemeral Roslyn temp files (*.cmdline, *.err, *.out, *.tmp, *.cs) but KEEP .pdb\n            foreach (var file in Directory.GetFiles(dir, \"*.*\", SearchOption.TopDirectoryOnly))\n            {\n                var ext = Path.GetExtension(file);\n\n                if (!EphemeralExtensions.Contains(ext))\n                    continue;\n\n                try\n                {\n                    File.Delete(file);\n                }\n                catch { /* ignore */ }\n            }\n\n            // Step 2a: legacy cleanup - delete any dll/pdb in the root folder (old flat layout, no longer used)\n            if (isRoot)\n            {\n                foreach (var legacy in Directory.GetFiles(dir, \"*.dll\", SearchOption.TopDirectoryOnly)\n                             .Concat(Directory.GetFiles(dir, \"*.pdb\", SearchOption.TopDirectoryOnly)))\n                {\n                    try\n                    {\n                        File.Delete(legacy);\n                    } catch { /* ignore */ }\n                }\n                // no retention logic needed on root after legacy cleanup\n                continue;\n            }\n\n            // Step 2b: keep only the newest assembly per prefix and purge younger duplicates\n            EnsureSingleNewestPerPrefix(dir, folderType, now);\n\n            // Step 3: delete old DLLs (and matching PDBs) past retention\n            foreach (var dll in Directory.GetFiles(dir, \"*\" + Dll, SearchOption.TopDirectoryOnly))\n            {\n                var fi = new FileInfo(dll);\n                if ((now - fi.LastWriteTime) < RetentionPeriod)\n                    continue;\n\n                DeleteAssemblyWithSymbols(dll);\n            }\n\n            // Step 4: remove orphaned pdbs without matching dll\n            foreach (var pdb in Directory.GetFiles(dir, \"*.pdb\", SearchOption.TopDirectoryOnly))\n            {\n                var dll = Path.ChangeExtension(pdb, \".dll\");\n                if (!File.Exists(dll))\n                    try\n                    {\n                        File.Delete(pdb);\n                    }\n                    catch { /* ignore */ }\n            }\n        }\n\n        // Step 5: remove empty subfolders (but leave the root)\n        foreach (var dir in enumerable\n                     .Where(d => !string.Equals(d, folderPath, StringComparison.OrdinalIgnoreCase))\n                     .OrderByDescending(d => d.Length))\n        {\n            try\n            {\n                if (Directory.Exists(dir) && !Directory.EnumerateFileSystemEntries(dir).Any())\n                    Directory.Delete(dir);\n            }\n            catch { /* ignore */ }\n        }\n    }\n\n    private void EnsureSingleNewestPerPrefix(string dir, AssemblyFolderType folderType, DateTime now)\n    {\n        if (folderType == AssemblyFolderType.None)\n            return;\n\n        var groupedFiles = Directory.GetFiles(dir, \"*\" + Dll, SearchOption.TopDirectoryOnly)\n            .Select(path => new FileInfo(path))\n            .Select(fileInfo => new\n            {\n                File = fileInfo,\n                Prefix = GetFilePrefix(fileInfo, folderType)\n            })\n            .Where(candidate => !string.IsNullOrEmpty(candidate.Prefix))\n            .GroupBy(candidate => candidate.Prefix!, StringComparer.OrdinalIgnoreCase);\n\n        foreach (var group in groupedFiles)\n        {\n            var ordered = group\n                .OrderByDescending(candidate => candidate.File.LastWriteTime)\n                .ToList();\n\n            var keep = ordered\n                .FirstOrDefault(candidate => (now - candidate.File.LastWriteTime) < RetentionPeriod);\n\n            foreach (var candidate in ordered)\n            {\n                if (keep != null && candidate.File.FullName.Equals(keep.File.FullName, StringComparison.OrdinalIgnoreCase))\n                    continue;\n\n                DeleteAssemblyWithSymbols(candidate.File.FullName);\n            }\n        }\n    }\n\n    private static string? GetFilePrefix(FileInfo fileInfo, AssemblyFolderType folderType)\n        => folderType switch\n        {\n            AssemblyFolderType.AppCode => GetAppCodePrefix(fileInfo) ?? GetDepPrefix(fileInfo),\n            AssemblyFolderType.Cshtml => GetCshtmlPrefix(fileInfo),\n            _ => null\n        };\n\n    private static string? GetAppCodePrefix(FileInfo fileInfo)\n    {\n        if (!string.Equals(fileInfo.Extension, Dll, StringComparison.OrdinalIgnoreCase))\n            return null;\n\n        var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.Name);\n        var lastDashIndex = fileNameWithoutExtension.LastIndexOf('-');\n        if (lastDashIndex <= 0 || lastDashIndex == fileNameWithoutExtension.Length - 1)\n            return null;\n\n        if (!fileNameWithoutExtension.StartsWith(\"AppCode-\", StringComparison.OrdinalIgnoreCase))\n            return null;\n\n        var hash = fileNameWithoutExtension.Substring(lastDashIndex + 1);\n        if (!IsHex(hash, minLength: 6, maxLength: 64))\n            return null;\n\n        return fileNameWithoutExtension.Substring(0, lastDashIndex);\n    }\n\n    private static string? GetDepPrefix(FileInfo fileInfo)\n    {\n        if (!string.Equals(fileInfo.Extension, Dll, StringComparison.OrdinalIgnoreCase))\n            return null;\n\n        var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.Name);\n        var lastDashIndex = fileNameWithoutExtension.LastIndexOf('-');\n        if (lastDashIndex <= 0 || lastDashIndex == fileNameWithoutExtension.Length - 1)\n            return null;\n\n        if (!fileNameWithoutExtension.StartsWith(\"dep-\", StringComparison.OrdinalIgnoreCase))\n            return null;\n\n        var hash = fileNameWithoutExtension.Substring(lastDashIndex + 1);\n        if (!IsHex(hash, minLength: 8, maxLength: 64))\n            return null;\n\n        return fileNameWithoutExtension.Substring(0, lastDashIndex);\n    }\n    private static string? GetCshtmlPrefix(FileInfo fileInfo)\n    {\n        if (!string.Equals(fileInfo.Extension, Dll, StringComparison.OrdinalIgnoreCase))\n            return null;\n\n        var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.Name);\n        var segments = fileNameWithoutExtension.Split('-');\n        if (segments.Length < 3)\n            return null;\n\n        var contentHash = segments[segments.Length - 2];\n        var appCodeHash = segments[segments.Length - 1];\n\n        if (!IsHex(contentHash, minLength: 6, maxLength: 64)\n            || !IsHex(appCodeHash, minLength: 6, maxLength: 64))\n            return null;\n\n        return string.Join(\"-\", segments.Take(segments.Length - 2));\n    }\n\n    private static bool IsHex(string value, int minLength, int maxLength)\n    {\n        if (string.IsNullOrEmpty(value)\n            || value.Length < minLength\n            || value.Length > maxLength)\n            return false;\n\n        foreach (var c in value)\n        {\n            var isHex = c is >= '0' and <= '9'\n                or (>= 'a' and <= 'f')\n                or (>= 'A' and <= 'F');\n\n            if (!isHex)\n                return false;\n        }\n\n        return true;\n    }\n\n    private static void DeleteAssemblyWithSymbols(string dllPath)\n    {\n        try\n        {\n            File.Delete(dllPath);\n        }\n        catch { /* ignore */ }\n\n        var pdb = Path.ChangeExtension(dllPath, \".pdb\");\n        if (string.IsNullOrEmpty(pdb) || !File.Exists(pdb))\n            return;\n\n        try\n        {\n            File.Delete(pdb);\n        }\n        catch { /* ignore */ }\n    }\n\n    private enum AssemblyFolderType\n    {\n        None,\n        AppCode,\n        Cshtml\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.SourceCode/AssemblyResult.cs",
    "content": "﻿using System.Reflection;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Code.Sys.SourceCode;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AssemblyResult(Assembly? assembly = null): ICanBeCacheDependency, ITimestamped\n{\n    public Assembly? Assembly { get; } = assembly;\n    public string? ErrorMessages { get; init; }\n    public string[] AssemblyLocations { get; init; } = []; // TODO: refactor this to not use array\n    public string? SafeClassName { get; init; }\n\n    /// <summary>\n    /// The main type of this assembly - typically for Razor files which usually just publish a single type.\n    /// This is to speed up performance, so the user of it doesn't need to find it again. \n    /// </summary>\n    public Type? MainType { get; set; }\n\n    /// <summary>\n    /// The list of folders which must be watched for changes when using this assembly.\n    /// ATM just used for AppCode assemblies, should maybe be in an inheriting class...\n    /// </summary>\n    // TODO: WIP - should be more functional, this get/set is still hacky\n    public IDictionary<string, bool>? WatcherFolders { get; internal set; }\n\n    public Dictionary<string, string> Infos { get; init; } = [];\n\n    /// <summary>\n    /// True if an assembly was created without compile errors.\n    /// </summary>\n    public bool HasAssembly => Assembly != null;\n\n    /// <summary>\n    /// True if an assembly was not created and we get compile errors.\n    /// </summary>\n    public bool HasError => !HasAssembly && ErrorMessages.HasValue();\n\n    /// <summary>\n    /// True if there is a value, either an assembly or an error.\n    /// </summary>\n    public bool HasValue => HasAssembly || HasError;\n\n    #region CacheDependency\n\n    public bool CacheIsNotifyOnly => false;\n\n    /// <summary>\n    /// Used to create cache dependency with CacheEntryChangeMonitor\n    /// </summary>\n    /// <remarks>\n    /// This cache item with Assembly usually has cache dependency on WatchFolders.\n    /// Other cache items can depend on this cache item, instead of creating additional file monitors on same WatchFolders.\n    ///\n    /// WARNING: AS OF 2024-06-01 it uses the same name as the ICanBeCacheDependency, but ATM it's used without the prefix\n    /// </remarks>\n    public string CacheDependencyId { get; set; } = null!; // not sure when this is actually used; null! may be wrong.\n\n    public long CacheTimestamp { get; } = DateTime.Now.Ticks;\n\n    #endregion\n\n    /// <summary>\n    /// Optional cache dependency to attach when this assembly is reused (e.g., AppCode dependency for Razor cache).\n    /// </summary>\n    public ICanBeCacheDependency? AppCodeDependency { get; init; }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Code.Sys.SourceCode/CodeCompiler.cs",
    "content": "﻿using ToSic.Eav.Sys;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Code.Sys.SourceCode;\n\n/// <summary>\n/// Code / Class Compiler.\n/// </summary>\n/// <param name=\"serviceProvider\"></param>\n/// <remarks>\n/// This is abstract, as each platform (Dnn/Oqtane) has its own implementation for specific parts of this.\n///\n/// We also have a minimal IClassCompiler interface, for use in the CodeApiService.\n/// </remarks>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class CodeCompiler(IServiceProvider serviceProvider, object[]? connect = default) : ServiceBase(\"Sys.CsCmpl\", connect: connect /* never! serviceProvider */), IClassCompiler\n{\n    public object? InstantiateClass(string virtualPath, HotBuildSpec spec, string? className = null, string? relativePath = null, bool throwOnError = true)\n    {\n        var l = Log.Fn<object>($\"{virtualPath}; {spec}; {nameof(className)}:{className}; {nameof(relativePath)}:{relativePath}; {nameof(throwOnError)}: {throwOnError}\");\n\n        // Perform various checks on the path values\n        var hasErrorMessage = CheckIfPathsOkAndCleanUp(ref virtualPath, relativePath);\n        if (hasErrorMessage != null)\n        {\n            l.A($\"Error: {hasErrorMessage}\");\n            l.ReturnNull(\"failed\");\n            if (throwOnError)\n                throw new(hasErrorMessage);\n            return null; // special, l.Return was already called\n        }\n\n        var pathLowerCase = virtualPath.ToLowerInvariant();\n        var isCs = pathLowerCase.EndsWith(SourceCodeConstants.CsFileExtension);\n        var isCshtml = pathLowerCase.EndsWith(SourceCodeConstants.CsHtmlFileExtension);\n\n        Type? compiledType = null;\n        string? errorMessages;\n        if (isCshtml && string.IsNullOrEmpty(className))\n            (compiledType, errorMessages) = GetCsHtmlType(virtualPath);\n        // compile .cs files\n        else if (isCs || isCshtml)\n            (compiledType, errorMessages) = GetTypeOrErrorMessages(virtualPath, className, throwOnError, spec);\n        else\n            errorMessages = $\"Error: given path '{Path.GetFileName(virtualPath)}' doesn't point to a .cs or .cshtml\";\n\n        if (errorMessages != null)\n        {\n            l.A($\"{errorMessages}; throw error: {throwOnError}\");\n            l.ReturnNull(\"failed\");\n            if (throwOnError) throw new(errorMessages);\n            return null;\n        }\n\n        var instance = serviceProvider.Build<object>(compiledType!, Log);\n        AttachRelativePath(virtualPath, instance);\n\n        return l.Return(instance, $\"found: {instance != null!}\");\n    }\n\n    public (Type? Type, string? ErrorMessages) GetTypeOrErrorMessages(string relativePath, string? className, bool throwOnError, HotBuildSpec spec)\n    {\n        var l = Log.Fn<(Type? Type, string? ErrorMessages)>($\"{nameof(relativePath)}: '{relativePath}'; {nameof(className)} '{className}'; {nameof(throwOnError)}: {throwOnError}; {spec}\");\n\n        // if no name provided, use the name which is the same as the file name\n        className ??= Path.GetFileNameWithoutExtension(relativePath) ?? EavConstants.NullNameId;\n\n        var assResult = GetAssembly(relativePath, className, spec);\n        var assembly = assResult.Assembly;\n        var errorMessages = assResult.ErrorMessages;\n\n        if (errorMessages != null)\n            return l.Return((null, errorMessages), \"error messages\");\n\n        if (assembly == null)\n            return l.Return((null, \"assembly is null\"), \"no assembly\");\n\n        var possibleErrorMessage = $\"Error: Didn't find type '{className}' in {Path.GetFileName(relativePath)}. Maybe the class name doesn't match the file name. \";\n        Type? compiledType = null;\n        try\n        {\n            compiledType = assembly.GetType(className, false, true);\n            if (compiledType == null)\n            {\n                var types = assembly.GetTypes();\n                compiledType = types.FirstOrDefault(t => t.Name.EqualsInsensitive(className));\n            }\n\n            if (compiledType == null && throwOnError)\n                assembly.GetType(className, true, true);\n        }\n        catch (Exception ex)\n        {\n            l.A(possibleErrorMessage);\n            if (throwOnError) throw new TypeLoadException(possibleErrorMessage, ex);\n        }\n\n        if (compiledType == null)\n            errorMessages = possibleErrorMessage;\n\n        return l.Return((compiledType, errorMessages), errorMessages == null ? \"ok\" : \"errors\");\n    }\n\n    public abstract AssemblyResult GetAssembly(string relativePath, string className, HotBuildSpec spec);\n\n\n    protected abstract (Type Type, string? ErrorMessage) GetCsHtmlType(string relativePath);\n\n\n    /// <summary>\n    /// Check the path and perform various corrections\n    /// </summary>\n    /// <param name=\"virtualPath\">primary path to use</param>\n    /// <param name=\"relativePath\">optional second path to which the primary one would be attached to</param>\n    /// <returns>null if all is ok, or an error message if not</returns>\n    private string? CheckIfPathsOkAndCleanUp(ref string virtualPath, string? relativePath)\n    {\n        var l = Log.Fn<string>($\"{nameof(virtualPath)}: '{virtualPath}', {nameof(relativePath)}: '{relativePath}'\");\n        if (string.IsNullOrWhiteSpace(virtualPath))\n            return l.ReturnAndLog(\"no path/name provided\");\n\n        // if path relative, merge with shared code path\n        virtualPath = virtualPath.ForwardSlash();\n        if (!virtualPath.StartsWith(\"/\"))\n        {\n            l.A($\"Trying to resolve relative path: '{virtualPath}' using '{relativePath}'\");\n            if (relativePath == null)\n                return l.ReturnAndLog(\"Unexpected null value on relativePath\");\n\n            // if necessary, add trailing slash\n            relativePath = relativePath.SuffixSlash();\n            virtualPath = Path.Combine(relativePath, virtualPath).ToAbsolutePathForwardSlash();\n            l.A($\"final virtual path: '{virtualPath}'\");\n        }\n\n        if (virtualPath.IndexOf(\":\", InvariantCultureIgnoreCase) > -1)\n            return l.ReturnAndLog($\"Tried to get .cs file, but found '{virtualPath}' containing ':', (not allowed)\");\n\n        return l.ReturnNull(\"all ok\");\n    }\n\n\n    private bool AttachRelativePath(string virtualPath, object instance)\n    {\n        var l = Log.Fn<bool>($\"{nameof(virtualPath)}: {virtualPath}\");\n\n        if (instance is not IGetCodePath codeForwarding)\n            return l.ReturnFalse(\"didn't attach\");\n\n        // in case it supports shared code again, give it the relative path\n        codeForwarding.CreateInstancePath = Path.GetDirectoryName(virtualPath)!;\n        return l.ReturnTrue(\"attached\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using static ToSic.Sxc.Sys.SxcLogging;\nglobal using ToSic.Sys.Utils;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/Properties/AssemblyInternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Custom\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Core\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Razor\")]\n\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Oqt.Server\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/StartupSxcCodeHotBuild.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Code.Sys.HotBuild;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcCodeHotBuild\n{\n    public static IServiceCollection AddSxcCodeHotBuild(this IServiceCollection services)\n    {\n        // V17+ HotBuild\n        services.TryAddTransient<AppCodeLoader>();\n        services.TryAddTransient<AssemblyCacheManager>();\n        services.TryAddTransient<DependenciesLoader>();\n        services.TryAddSingleton<AssemblyResolver>();\n\n        // v18\n        services.TryAddSingleton<Util>();\n        services.TryAddTransient<SourceCodeHasher>();\n\n        // v20\n        services.TryAddTransient<ExtensionCompileReferenceService>();\n\n        return services;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Code.HotBuild/ToSic.Sxc.Code.HotBuild.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Code.HotBuild</AssemblyName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Configuration.Tests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using static Xunit.Assert;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Configuration.Tests/ToSic.Sxc.Core.Configuration.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForTestCode.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Configuration.Tests/Web.Sys.Url/NameValueCollectionSort.cs",
    "content": "﻿using System.Collections.Specialized;\n\nnamespace ToSic.Sxc.Web.Sys.Url;\n\npublic class NameValueCollectionSort\n{\n    [Theory]\n    [InlineData(nameof(Bac), \"a,c\", \"a,c,b\")]\n    [InlineData(nameof(Bac), \"c\", \"c,a,b\")]\n    [InlineData(nameof(BacdeWithDNull), \"a,c\", \"a,c,b,d,e\")]\n    [InlineData(nameof(BacdeWithDNull), \"c,d\", \"c,d,a,b,e\")]\n    [InlineData(nameof(BacdeWithDEmpty), \"a,c\", \"a,c,b,d,e\")]\n    [InlineData(nameof(BacdeWithDEmpty), \"c,d\", \"c,d,a,b,e\")]\n    public void SortWithPrioritization(string name, string sort, string expected)\n    {\n        var sorted = NameCollections[name].Sort(sort);\n        Equal(expected.Split(','), sorted.AllKeys);\n    }\n\n    [Theory]\n    [InlineData(nameof(Bac), \"a,b,c\", \"standard a-z\")]\n    [InlineData(nameof(BacdeWithDNull), \"a,b,c,d,e\", \"the null entry remains where it is\")]\n    [InlineData(nameof(BacdeWithDEmpty), \"a,b,c,d,e\", \"the empty entry is in normal spot\")]\n    public void SortWithoutPrioritization(string name, string expected, string notes)\n    {\n        var sorted = NameCollections[name].Sort();\n        Equal(expected.Split(','), sorted.AllKeys);\n    }\n\n    #region Test Data\n\n    private static NameValueCollection Bac => new()\n    {\n        { \"b\", \"2\" },\n        { \"a\", \"1\" },\n        { \"c\", \"3\" }\n    };\n\n    private static NameValueCollection BacdeWithDNull => new()\n    {\n        { \"b\", \"2\" },\n        { \"a\", \"1\" },\n        { \"c\", \"3\" },\n        { \"d\", null },\n        { \"e\", \"9\" }\n    };\n    private static NameValueCollection BacdeWithDEmpty => new()\n    {\n        { \"b\", \"2\" },\n        { \"a\", \"1\" },\n        { \"c\", \"3\" },\n        { \"d\", \"\" },\n        { \"e\", \"9\" }\n    };\n\n    private static Dictionary<string, NameValueCollection> NameCollections => new()\n    {\n        { nameof(Bac), Bac },\n        { nameof(BacdeWithDNull), BacdeWithDNull },\n        { nameof(BacdeWithDEmpty), BacdeWithDEmpty }\n    };\n\n\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Cms.Settings/GoogleMaps.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Models;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Cms.Settings;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record GoogleMaps() : ModelFromEntityBasic\n{\n    public const string ContentTypeNameId = \"f5764f60-2621-4a5d-9391-100fbe664640\";\n\n    public const string SettingsPath = \"Settings.GoogleMaps\";\n\n    public int Zoom => GetThis(14); // 14 is a kind of neutral default\n\n    public string ApiKey => GetThis(\"\");\n\n    public string Icon => GetThis(\"\");\n\n    public MapsCoordinates DefaultCoordinates => field ??= GetMapsCoordinates();\n\n    private MapsCoordinates GetMapsCoordinates()\n    {\n        var json = Get(nameof(DefaultCoordinates), \"\");\n        if (!json.HasValue())\n            return MapsCoordinates.Defaults;\n        try\n        {\n            return JsonSerializer.Deserialize<MapsCoordinates>(json, JsonOptions.SafeJsonForHtmlAttributes)\n                ?? MapsCoordinates.Defaults;\n        }\n        catch\n        {\n            return MapsCoordinates.Defaults;\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Cms.Settings/InputFields/StringWysiwyg.cs",
    "content": "﻿using ToSic.Eav.Models;\n\nnamespace ToSic.Sxc.Cms.Settings.InputFields;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record StringWysiwyg() : ModelFromEntityBasic\n{\n    public const string ContentTypeNameId = \"f8a6ed24-11c0-42c4-9022-409989489563\";\n\n    public const string SettingsPath = \"Settings.InputFields.StringWysiwyg\";\n\n    public string EditorPlugin\n    {\n        get => field ??= GetThis(\"tinymce\");\n        set;\n    }\n\n    public string ButtonSource\n    {\n        get => field ??= GetThis(\"\");\n        set;\n    }\n\n    public string ButtonSourceInDebugMode\n    {\n        get => field ??= GetThis(\"\");\n        set;\n    }\n\n    internal static StringWysiwyg Defaults = new()\n    {\n        EditorPlugin = \"\",\n        ButtonSource = \"\",\n        ButtonSourceInDebugMode = \"\",\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Cms.Settings/MapsCoordinates.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Settings;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class MapsCoordinates\n{\n    public double Latitude { get; set; }\n    public double Longitude { get; set; }\n\n    /// <summary>\n    /// The default coordinates have a trailing 1.\n    /// This way we can detect if it's using the default or the configured values\n    /// </summary>\n    internal static MapsCoordinates Defaults = new()\n    {\n        Latitude = 47.17471,\n        Longitude = 9.46921,\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Cms.Sys/CmsMetadata.cs",
    "content": "﻿namespace ToSic.Sxc.Cms.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CmsMetadata\n{\n    public static string SitePrefix = \"site:\";\n    public static string UserPrefix = \"user:\";\n    public static string PagePrefix = \"page:\";\n    public static string ModulePrefix = \"module:\";\n    public static string FilePrefix = \"file:\";\n    public static string FolderPrefix = \"folder:\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Code/Sys/CompatibilityLevels.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CompatibilityLevels\n{\n    internal const int CompatibilityLevel9Old = 9;\n\n    /// <summary>\n    /// This enforces certain features to go away or appear, like\n    /// - Off: DynamicEntity.Render\n    /// </summary>\n    public const int CompatibilityLevel10 = 10;\n\n    public const int CompatibilityLevel12 = 12;\n\n    /// <summary>\n    /// Typed code\n    /// </summary>\n    public const int CompatibilityLevel16 = 16;\n\n    /// <summary>\n    /// Old, probably remove EOY 2025\n    /// </summary>\n    public const int MaxLevelForAutoJQuery = CompatibilityLevel9Old;\n    public const int MaxLevelForEntityDotToolbar = CompatibilityLevel9Old;\n    public const int MaxLevelForEntityDotRender = CompatibilityLevel9Old;\n\n    public const int MinLevelForTyped = CompatibilityLevel16;\n\n    //public const int MaxLevelForStaticRender = CompatibilityLevel10;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Code/Sys/IGetCodePath.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IGetCodePath\n{\n    /// <summary>\n    /// Location of the current code. This is important when trying to create instances for\n    /// other code in relative folders - as this is usually not known. \n    /// </summary>\n    /// <returns>The real path to the currently executed code - important for dynamically compiled code like WebApis</returns>\n    string CreateInstancePath { get; set; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Code/Sys/SourceCodeConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys;\n\npublic class SourceCodeConstants\n{\n    public const string CsFileExtension = \".cs\";\n    public const string CsHtmlFileExtension = \".cshtml\";\n    public const string SharedCodeRootPathKeyInCache = \"SharedCodeRootPath\";\n    public const string SharedCodeRootFullPathKeyInCache = \"SharedCodeRootFullPath\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Code/Sys.Documentation/DocsAttribute.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.Documentation;\n\n/// <summary>\n/// This was an experimental way to add attributes to classes, which should generate documentation for the\n/// VS Code Editor in the browser.\n///\n/// It has been dormant for many years now, and will probably be removed since we now include important XML files in the bin,\n/// and should probably retrieve the docs from there if we continue with this.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DocsAttribute: Attribute\n{\n    public required string[] Messages { get; set; }\n\n    public string[] GetMessages(string? fullName)\n    {\n        if (fullName == null)\n            return [];\n\n        if (!AutoLink)\n            return Messages;\n\n        var newMessages = Messages.ToList();\n        var helpLink = $\"[documentation](https://docs.2sxc.org/api/dot-net/{fullName}.html)\";\n        newMessages.Add(helpLink);\n        return newMessages.ToArray();\n    }\n\n\n    public bool AutoLink = true;\n\n    public bool AllProperties = true;\n\n    public string? HelpLink { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Code/Sys.HotBuild/HotBuildSpec.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Code.Sys.HotBuild;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HotBuildSpec(int appId, string? edition, string? appName, string? runtimeKey = null)\n{\n    public int AppId => appId;\n\n    public string? Edition => edition;\n\n    public string EditionToLog => $\"/{Edition}\"; // for logging\n\n    /// <summary>\n    /// AppName for logging - ATM no other purpose, so it can be null\n    /// </summary>\n    public string? AppName => appName;\n\n    /// <summary>\n    /// Runtime key to uniquely identify this app across tenants/platforms.\n    /// </summary>\n    public string? RuntimeKey => runtimeKey;\n\n    /// <summary>\n    /// App key for cache keys (runtime key when available, otherwise AppId).\n    /// </summary>\n    public string AppKeyForCache => field ??= runtimeKey ?? AppId.ToString();\n\n    /// <summary>\n    /// Override ToString for better debugging\n    /// </summary>\n    public override string ToString()\n        => _toString ??= $\"{nameof(HotBuildSpec)} - {nameof(AppId)}: {appId} {(appName.HasValue() ? $\"({appName})\" : \"\")}; {nameof(Edition)}: '{EditionToLog}'\"\n                         + (runtimeKey.HasValue() ? $\"; {nameof(RuntimeKey)}: '{runtimeKey}'\" : \"\");\n    private string? _toString;\n\n    /// <summary>\n    /// Create a dictionary of the specs for logging\n    /// </summary>\n    public IDictionary<string, string> ToDictionary() => new Dictionary<string, string>\n    {\n        { nameof(AppId), AppId.ToString() },\n        { nameof(AppName), AppName ?? \"\"},\n        { nameof(Edition), EditionToLog },\n        { nameof(RuntimeKey), RuntimeKey ?? \"\" },\n    };\n\n    /// <summary>\n    /// CacheKey for this spec\n    /// </summary>\n    /// <remarks>\n    /// should not use optional parameters like: addSharedSuffixToAssemblyName or appName\n    /// </remarks>\n    public string CacheKey() => _cacheKey ??= $\"{nameof(HotBuildSpec)}.{nameof(AppId)}:{AppKeyForCache}.{nameof(Edition)}:{Edition}\";\n    private string? _cacheKey;\n\n    /// <summary>\n    /// Use when fallback from edition to root app\n    /// </summary>\n    /// <returns></returns>\n    public HotBuildSpec CloneWithoutEdition() => new(AppId, null, appName, runtimeKey);\n\n    /// <summary>\n    /// Use in very special case for AppCode in site local path\n    /// need temp name assembly without shared suffix\n    /// </summary>\n    /// <returns></returns>\n    public HotBuildSpecWithSharedSuffix WithoutSharedSuffix()\n        => new(AppId, edition, appName, false, runtimeKey);\n\n    /// <summary>\n    /// Use in very special case for AppCode in shared (global) path\n    /// need temp name assembly with shared suffix\n    /// </summary>\n    /// <returns></returns>\n    public HotBuildSpecWithSharedSuffix WithSharedSuffix()\n        => new(AppId, edition, appName, true, runtimeKey);\n}\n\n\npublic class HotBuildSpecWithSharedSuffix(int appId, string? edition, string? appName, bool addSharedSuffixToAssemblyName, string? runtimeKey = null)\n    : HotBuildSpec(appId, edition, appName, runtimeKey)\n{\n    /// <summary>\n    /// \"addSharedSuffixToAssemblyName\" is optional parameter used just as info for AppCode assembly naming in very special case,\n    /// it has no other purpose, and should not be used for anything else easily\n    /// </summary>\n    /// <remarks>\n    /// Take a care that AppCode assembly could be only one per app,\n    /// and that is located in local app folder per site or in shared location,\n    /// contrary to editions are separate apps (one per edition) again on \"local\" or \"shared\" path.\n    /// </remarks>\n    public string SharedSuffix => addSharedSuffixToAssemblyName ? \"Shared\" : \"\";\n\n    /// <summary>\n    /// Override ToString for better debugging\n    /// </summary>\n    public override string ToString() => _toString ??= $\"{base.ToString()}; {nameof(SharedSuffix)}: '{SharedSuffix}'\";\n    private string? _toString;\n\n    /// <summary>\n    /// Create a dictionary of the specs for logging\n    /// </summary>\n    public new IDictionary<string, string> ToDictionary()\n    {\n        var dictionary = base.ToDictionary();\n        dictionary.Add(nameof(SharedSuffix), SharedSuffix);\n        return dictionary;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Code/Sys.HotBuild/IClassCompiler.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.HotBuild;\n\npublic interface IClassCompiler\n{\n    object? InstantiateClass(string virtualPath, HotBuildSpec spec, string? className = null, string? relativePath = null, bool throwOnError = true);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Context/IParameters.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Context;\n\n/// <summary>\n/// Collection of url parameters of the current page\n///\n/// Note: Has a special ToString() implementation, which gives you the parameters for re-use in other scenarios.\n/// \n/// 🪒 In [Dynamic Razor](xref:Custom.Hybrid.Razor14) it's found on `CmsContext.Page.Parameters`  \n/// 🪒 In [Typed Razor](xref:Custom.Hybrid.RazorTyped) it's found on `MyPage.Parameters`\n/// </summary>\n/// <remarks>\n/// * uses the [](xref:NetCode.Conventions.Functional)\n/// * Added typed accessors such as `Int(...)` etc. in v16.03 implementing <see cref=\"ITyped\"/>\n/// * Made order of parameters automatically sort in 18.06 because of crawler-load issues\n/// * Added `Prioritize` in v19.00\n/// * Added `Flush` in 19.00\n/// </remarks>\n[PublicApi]\npublic interface IParameters: IReadOnlyDictionary<string, string>, ITyped\n{\n\n    #region Get (new v15.04)\n\n    /// <summary>\n    /// Get a parameter.\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Page.Parameters.Get(\"SortOrder\")`  \n    /// 🪒 Use in Typed Razor: `MyPage.Parameters.Get(\"SortOrder\")`\n    /// </summary>\n    /// <param name=\"name\">the key/name in the url</param>\n    /// <returns>a string or null</returns>\n    /// <remarks>\n    /// Added v15.04\n    /// </remarks>\n    new string? Get(string name);\n\n    /// <summary>\n    /// Get a parameter and convert to the needed type - or return the default.\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Page.Parameters.Get&lt;int&gt;(\"id\")`  \n    /// 🪒 Use in Typed Razor: `MyPage.Parameters.Get&lt;int&gt;(\"id\")`\n    /// </summary>\n    /// <typeparam name=\"TValue\"></typeparam>\n    /// <param name=\"name\">Key/name of the parameter</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Added v15.04\n    /// </remarks>\n    TValue? Get<TValue>(string name);\n\n    /// <summary>\n    /// Get a parameter and convert to the needed type - or return the fallback.\n    /// \n    /// 🪒 Use in Dynamic Razor: `CmsContext.Page.Parameters.Get(\"id\", fallback: 0)`  \n    /// 🪒 Use in Typed Razor: `MyPage.Parameters.Get(\"SortOrder\", fallback: 0)`\n    /// </summary>\n    /// <typeparam name=\"TValue\"></typeparam>\n    /// <param name=\"name\">Key/name of the parameter</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">Optional fallback value to use if not found</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Added v15.04\n    /// </remarks>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default);\n\n    #endregion\n\n    #region Add / Set / Remove\n\n    /// <summary>\n    /// Add another URL parameter and return a new <see cref=\"IParameters\"/>.\n    /// If the name/key already exists, it will extend it, add a simple \n    /// Otherwise please use <see cref=\"Set(string,string)\"/>\n    /// </summary>\n    /// <param name=\"key\"></param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    IParameters Add(string key);\n\n    /// <summary>\n    /// Add another URL parameter and return a new <see cref=\"IParameters\"/>.\n    /// If the name/key already exists, it will extend it, so the parameter will have 2 values.\n    /// Otherwise, please use <see cref=\"Set(string,string)\"/>\n    /// </summary>\n    /// <param name=\"key\">the key</param>\n    /// <param name=\"value\">the value</param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    IParameters Add(string key, string value);\n\n    /// <summary>\n    /// Add another URL parameter and return a new <see cref=\"IParameters\"/>.\n    /// If the name/key already exists, it will extend it, so the parameter will have 2 values.\n    /// Otherwise, please use <see cref=\"Set(string,string)\"/>\n    ///\n    /// Note also that this takes an `object` and will do some special conversions.\n    /// For example, bool values are lower case `true`|`false`, numbers are culture invariant and dates\n    /// are treated as is with time removed if it has no time. \n    /// </summary>\n    /// <param name=\"key\">the key</param>\n    /// <param name=\"value\">object! value</param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    /// <remarks>Added in v15.0</remarks>\n    IParameters Add(string key, object value);\n\n    /// <summary>\n    /// Add another URL parameter and return a new <see cref=\"IParameters\"/>.\n    /// If the name/key already exists, it will just overwrite it.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"value\"></param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    IParameters Set(string name, string value);\n\n    /// <summary>\n    /// Add another URL parameter and return a new <see cref=\"IParameters\"/>.\n    /// If the name/key already exists, it will just overwrite it.\n    ///\n    /// Note also that this takes an `object` and will do some special conversions.\n    /// For example, bool values are lower case `true`|`false`, numbers are culture invariant and dates\n    /// are treated as is with time removed if it has no time. \n    /// </summary>\n    /// <param name=\"name\">the key</param>\n    /// <param name=\"value\">object! value</param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    /// <remarks>Added in v15.0</remarks>\n    IParameters Set(string name, object value);\n\n    /// <summary>\n    /// Add another URL parameter and return a new <see cref=\"IParameters\"/>.\n    /// If the name/key already exists, it will just overwrite it.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    IParameters Set(string name);\n\n    /// <summary>\n    /// Remove a parameter and return a new <see cref=\"IParameters\"/>.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    IParameters Remove(string name);\n\n    ///// <summary>\n    ///// Remove a parameter **value** and return a new <see cref=\"IParameters\"/>.\n    ///// This only removes a specific value, for example if you start with `id=27&amp;id=42` and remove `id=27`, then the result will be `id=42`.\n    ///// </summary>\n    ///// <param name=\"name\"></param>\n    ///// <param name=\"value\"></param>\n    ///// <remarks>Added in v17.01</remarks>\n    ///// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    //IParameters Remove(string name, string value);\n\n    /// <summary>\n    /// Remove a parameter **value** and return a new <see cref=\"IParameters\"/>.\n    /// This only removes a specific value, for example if you start with `id=27&amp;id=42` and remove `id=27`, then the result will be `id=42`.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"value\"></param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    /// <remarks>Added in v17.01</remarks>\n    IParameters Remove(string name, object value);\n\n    #endregion\n\n    #region Toggle (new v17)\n\n    ///// <summary>\n    ///// Toggle a parameter value and return a new <see cref=\"IParameters\"/>.\n    /////\n    ///// This means that if the parameter was previously set with the same value, it will be un-set, otherwise it will be added.\n    ///// </summary>\n    ///// <param name=\"name\"></param>\n    ///// <param name=\"value\"></param>\n    ///// <remarks>Added in v17.01</remarks>\n    //IParameters Toggle(string name, string value);\n\n    /// <summary>\n    /// Toggle a parameter value and return a new <see cref=\"IParameters\"/>.\n    ///\n    /// This means that if the parameter was previously set with the same value, it will be un-set, otherwise it will be added.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"value\"></param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    /// <remarks>Added in v17.01</remarks>\n    IParameters Toggle(string name, object value);\n\n    /// <summary>\n    /// Filter all parameters to only keep the keys listed in `names`.\n    /// </summary>\n    /// <param name=\"names\">one or more names to keep, comma-separated.</param>\n    /// <returns>A _new_ <see cref=\"IParameters\"/>, the original is not modified.</returns>\n    /// <remarks>Added in v17.01</remarks>\n    public IParameters Filter(string? names);\n\n    #endregion\n\n    #region ToString to easily create url params from this object\n\n    /// <summary>\n    /// ToString() is specially implemented, to give you the parameters again as they were originally given on the page.\n    /// </summary>\n    /// <returns></returns>\n    new string ToString();\n\n    /// <summary>\n    /// Special sorted ToString - for the moment not public\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"sort\"></param>\n    /// <returns></returns>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    string ToString(NoParamOrder npo = default, bool sort = false);\n\n    #endregion\n\n    #region Handle duplicate interface methods\n\n    /// <inheritdoc cref=\"IHasKeys.ContainsKey\"/>\n    new bool ContainsKey(string name);\n    // ^^^ this is added, because both Dictionary and ITyped have this method, so it could be unclear\n\n    #endregion\n\n    /// <summary>\n    /// Prioritize the order of parameters.\n    /// This allows you to order the parameters in a certain way, which can be important for some systems.\n    ///\n    /// Remember:\n    /// 1. If a parameter doesn't exist, it still won't appear in the list\n    /// 2. If you order the parameters, this can have an unexpected effect on the amount of URLs you generate, possibly causing high server load when crawlers visit.\n    /// </summary>\n    /// <remarks>\n    /// New in v19.00\n    /// </remarks>\n    /// <param name=\"fields\">CSV of names to prioritize, in the specified order</param>\n    /// <returns></returns>\n    IParameters Prioritize(string? fields = default);\n\n    /// <summary>\n    /// Flush all parameters and start anew.\n    /// Note that it does preserve other settings like prioritization.\n    /// </summary>\n    /// <remarks>\n    /// New v19.00\n    /// </remarks>\n    /// <returns></returns>\n    IParameters Flush();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Data/IHasKeys.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\n/// <summary>\n/// Interface for things that can check keys and/or existence of values.\n/// The name isn't quite ideal, but it's not too important as it's not public. \n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IHasKeys\n{\n    /// <summary>\n    /// Check if this typed object has a property of this specified name.\n    /// It's case-insensitive.\n    /// </summary>\n    /// <param name=\"name\">the name like `Image`; some objects also support path to sub-property like `Author.Name`</param>\n    /// <returns></returns>\n    /// <remarks>Adding in 16.03 (WIP)</remarks>\n    bool ContainsKey(string name);\n        \n    /// <summary>\n    /// Get all the keys available in this Model (all the parameters passed in).\n    /// This is used to sometimes run early checks if all the expected parameters have been provided.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"only\">\n    /// Only return the keys specified here, if found.\n    /// Typical use: `only: new [] { \"Key1\", \"Key2\" }`.\n    /// Useful to check if _all_ or _any_ specific keys exist.\n    /// </param>\n    /// <returns></returns>\n    /// <remarks>Added in 16.03</remarks>\n    IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default);\n\n    #region IsEmpty / IsNotEmpty\n\n    /// <summary>\n    /// Check if this typed object has a property of this specified name, and has real data.\n    /// The opposite version of this is `IsNotEmpty(...)`\n    ///\n    /// > [!IMPORTANT]\n    /// > This method is optimized for use in Razor-like scenarios.\n    /// > It's behavior is super-useful but maybe not always expected.\n    /// >\n    /// > * If the value is a string, and is empty or only contains whitespace (even `&amp;nbsp;`) it is regarded as empty.\n    /// > * If the returned value is an empty _list_ (e.g. a field containing relationships, without any items in it) it is regarded as empty.\n    ///\n    /// If you need a different kind of check, just `.Get(...)` the value and perform the checks in your code.\n    /// </summary>\n    /// <param name=\"name\">the property name like `Image`; some objects also support path to sub-property like `Author.Name`</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"language\">\n    /// Optional language like `de`, `de-ch` or `de,en` to determine which values to check.\n    /// Will ignore languages not in the data model.\n    /// On items that don't have ML data it will be ignored. new v17.10\n    /// </param>\n    /// <returns>`true` if the property exists and has a real value. If it returned an empty list, it will also return `false`</returns>\n    /// <remarks>\n    /// * Added in 16.03\n    /// * `language` parameter added in 17.10\n    /// </remarks>\n    ///// >   You can change this behavior by changing the `blankIs` attribute.\n    ///// <param name=\"blankIs\">\n    ///// Change how blank **strings** (empty, whitespace, html-whitespace like `&amp;nbsp;`) are treated.\n    ///// `true` means that empty and whitespace strings return `true`,\n    ///// `false` means every whitespace incl. empty strings return `false`.\n    ///// </param>\n    bool IsEmpty(string name, NoParamOrder npo = default, string? language = default);\n\n    /// <summary>\n    /// Check if this typed object has a property of this specified name, and has real data.\n    /// The opposite version of this is `IsEmpty(...)`\n    /// \n    /// > [!IMPORTANT]\n    /// > This method is optimized for use in Razor-like scenarios.\n    /// > It's behavior is super-useful but maybe not always expected.\n    /// >\n    /// > * If the value is a string, and is empty or only contains whitespace (even `&amp;nbsp;`) it is regarded as empty.\n    /// > * If the returned value is an empty _list_ (e.g. a field containing relationships, without any items in it) it is regarded as empty.\n    ///\n    /// If you need a different kind of check, just `.Get(...)` the value and perform the checks in your code.\n    /// </summary>\n    /// <param name=\"name\">the property name like `Image`; some objects also support path to sub-property like `Author.Name`</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <returns>`true` if the property exists and has a real value. If it returned an empty list, it will also return `false`</returns>\n    /// <param name=\"language\">\n    /// Optional language like `de`, `de-ch` or `de,en` to determine which values to check.\n    /// Will ignore languages not in the data model.\n    /// On items that don't have ML data it will be ignored. new v17.10\n    /// </param>\n    /// <remarks>\n    /// * Added in 16.03\n    /// * `language` parameter added in 17.10\n    /// </remarks>\n    ///// >   You can change this behavior by changing the `blankIs` attribute.\n    ///// <param name=\"blankIs\">\n    ///// Change how blank **strings** (empty, whitespace, html-whitespace like `&amp;nbsp;`) are treated.\n    ///// `true` means that empty and whitespace strings return `true`,\n    ///// `false` means every whitespace incl. empty strings return `false`.\n    ///// </param>\n    bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Data/Sys.Json/DynamicJsonConverter.cs",
    "content": "﻿using System.Text.Json;\nusing System.Text.Json.Serialization;\nusing JsonSerializer = System.Text.Json.JsonSerializer;\n\nnamespace ToSic.Sxc.Data.Sys.Json;\n\n/// <summary>\n/// This is a serializer-helper which System.Text.Json will pick up automatically when converting a DynamicJacket or DynamicReadObject to JSON\n/// </summary>\n/// <remarks>\n///https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to?pivots=dotnet-6-0\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DynamicJsonConverter: JsonConverter<object>\n{\n    public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) \n        => JsonSerializer.Deserialize(ref reader, typeToConvert, options);\n\n    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)\n    {\n        if (value is not IHasJsonSource hasJsonSource)\n            throw new ArgumentException($\"Object should be a {nameof(IHasJsonSource)}\", nameof(value));\n\n        JsonSerializer.Serialize(writer, hasJsonSource.JsonSource(), options);\n    }\n\n    public override bool CanConvert(Type objectType) =>\n        objectType == typeof(IHasJsonSource)\n        || typeof(IHasJsonSource).IsAssignableFrom(objectType)\n        || objectType == typeof(ITyped)\n        || typeof(ITyped).IsAssignableFrom(objectType); // we'll have to keep an eye on it for scenarios where ITypedItem also inherits from ITypedRead, and could have some surprises,\n    // but since the DynamicEntity was never meant to become json, probably there is no code out there that tries to do this. \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Data/Sys.Json/IHasJsonSource.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Json;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IHasJsonSource\n{\n    /// <summary>\n    /// The inner json source to use.\n    /// Will only have an effect if the Attribute [JsonConverter(typeof(DynamicJsonConverter))] is applied.\n    /// </summary>\n    /// <remarks>\n    /// This must be a method - not a property - for safety.\n    /// This ensures it doesn't result in being serialized itself. \n    /// </remarks>\n    /// <returns></returns>\n    object JsonSource();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Data/Typed/ITyped.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Sxc.Data.Sys.Json;\n\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// Objects which usually wrap other objects to provide strictly typed access to properties.\n/// </summary>\n/// <remarks>\n/// The object will have typed Methods to read properties like `.String(propName)`.\n/// \n/// It is usually the result of a `AsTyped(something)` or `AsItem(...)` command.\n/// It is meant to help Razor etc. access Entity and/or dynamic objects in a typed way.\n/// \n/// History: Introduced in 16.02.\n/// </remarks>\n[PublicApi]\n[JsonConverter(typeof(DynamicJsonConverter))] // we'll have to keep an eye on it for scenarios where ITypedItem also inherits from ITypedRead, and could have some surprises. But since the DynamicEntity was never meant to become json, probably there is no code out there that tries to do this. \npublic partial interface ITyped\n{\n    /// <summary>\n    /// Get a property and return the value as a `bool`.\n    /// If conversion fails, will return default `false` or what is specified in the `fallback`.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>Value as `bool`</returns>\n    bool Bool(string name, NoParamOrder npo = default, bool fallback = default, bool? required = default);\n\n\n    /// <summary>\n    /// Get a property and return the value as a `DateTime`.\n    /// If conversion fails, will return default `0001-01-01` or what is specified in the `fallback`.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>Value as `DateTime`</returns>\n    DateTime DateTime(string name, NoParamOrder npo = default, DateTime fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Get a property and return the value as a `string`.\n    /// If conversion fails, will return default `null` or what is specified in the `fallback`.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <param name=\"scrubHtml\">\n    /// If `true`, will remove all HTML tags from the string.\n    /// If `p` will remove all `p` tags, if `div,span` will remove these tags.\n    /// This is the same as using `Kit.Scrub.All(...)` or `.Only(...). For more detailed scrubbing, use the `Kit.Scrub`\n    /// </param>\n    /// <returns>Value as `string`</returns>\n    string? String(string name, NoParamOrder npo = default, string? fallback = default, bool? required = default, object? scrubHtml = default);\n\n    #region Numbers\n\n\n\n\n    /// <summary>\n    /// Get a property and return the value as a `int`.\n    /// If conversion fails, will return default `0` or what is specified in the `fallback`.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>Value as `int`</returns>\n    int Int(string name, NoParamOrder npo = default, int fallback = default, bool? required = default);\n\n\n    /// <summary>\n    /// Get a property and return the value as a `long`.\n    /// If conversion fails, will return default `0` or what is specified in the `fallback`.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>Value as `long`</returns>\n    long Long(string name, NoParamOrder npo = default, long fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Get a property and return the value as a `float`.\n    /// If conversion fails, will return default `0` or what is specified in the `fallback`.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>Value as `float`</returns>\n    float Float(string name, NoParamOrder npo = default, float fallback = default, bool? required = default);\n\n\n    /// <summary>\n    /// Get a property and return the value as a `decimal`.\n    /// If conversion fails, will return default `0` or what is specified in the `fallback`.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>Value as `decimal`</returns>\n    decimal Decimal(string name, NoParamOrder npo = default, decimal fallback = default, bool? required = default);\n\n    /// <summary>\n    /// Get a property and return the value as a `double`.\n    /// If conversion fails, will return default `0` or what is specified in the `fallback`.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>Value as `double`</returns>\n    double Double(string name, NoParamOrder npo = default, double fallback = default, bool? required = default);\n\n    #endregion\n\n    /// <summary>\n    /// Get a url from a field.\n    /// It will do sanitation / url-corrections for special characters etc.\n    /// \n    /// On TypedItems it will also auto-convert values such as `file:72` or `page:14`.\n    /// </summary>\n    /// <param name=\"name\">The field name.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">_optional_ fallback if conversion fails</param>\n    /// <param name=\"required\">throw error if the `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>A url converted if possible. If the field contains anything else such as `hello` then it will not be modified.</returns>\n    string? Url(string name, NoParamOrder npo = default, string? fallback = default, bool? required = default);\n\n    #region Debugging\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    string? ToString();\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Data/Typed/ITyped_Html.cs",
    "content": "﻿using ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Data;\n\npublic partial interface ITyped\n{\n    /// <summary>\n    /// Return a value as a raw HTML string for using inside an attribute.\n    /// Usage like `title='@item.Attribute(\"Title\")'`\n    /// It will do a few things such as:\n    /// \n    /// 1. Ensure dates are in the ISO format\n    /// 1. Ensure numbers are in a neutral format such as `14.27` and never `14,27`\n    /// 1. Html encode any characters which would cause trouble such as quotes\n    /// </summary>\n    /// <param name=\"name\">Name of the property</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">Value to use if the property specified by `name` doesn't exist</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns></returns>\n    IRawHtmlString? Attribute(string name, NoParamOrder npo = default, string? fallback = default, bool? required = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Data/Typed/ITyped_SharedGetGeneric.cs",
    "content": "﻿using ToSic.Sys.GetByName;\n\nnamespace ToSic.Sxc.Data;\n\npublic partial interface ITyped : IHasKeys, ICanGetByName\n{\n    /// <inheritdoc cref=\"IHasKeys.ContainsKey\"/>\n    new bool ContainsKey(string name);\n\n    /// <inheritdoc cref=\"IHasKeys.IsEmpty\"/>\n    new bool IsEmpty(string name, NoParamOrder npo = default, string? language = default);\n    // ^^^ new is just so it's in the docs\n\n    /// <inheritdoc cref=\"IHasKeys.IsNotEmpty\"/>\n    new bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default);\n    // ^^^ new is just so it's in the docs\n\n    /// <inheritdoc cref=\"IHasKeys.Keys\"/>\n    new IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default);\n\n\n    /// <summary>\n    /// Get a property.\n    /// </summary>\n    /// <param name=\"name\">the property name like `Image` - or path to sub-property like `Author.Name` (new v15)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <param name=\"language\">\n    /// Optional language like `de`, `de-ch` or `de,en` to determine which values to check.\n    /// Will ignore languages not in the data model.\n    /// On items that don't have ML data it will be ignored. new v17.10\n    /// </param>\n    /// <returns>The result if found or null; or error if the object is in strict mode</returns>\n    /// <remarks>\n    /// * parameter `languages` added in 17.10\n    /// </remarks>\n    object? Get(string name,\n        NoParamOrder npo = default,\n        bool? required = default,\n        string? language = default\n        );\n\n    /// <summary>\n    /// Get a value using the name - and cast it to the expected strong type.\n    /// For example to get an int even though it's stored as decimal.\n    /// \n    /// Since the parameter `fallback` determines the type `TValue` you can just write this like\n    /// `something.Get(\"Title\", fallback: \"no title\")\n    /// </summary>\n    /// <typeparam name=\"TValue\">\n    /// The expected type, like `string`, `int`, etc.\n    /// Note that you don't need to specify it, if you specify the `fallback` property.\n    /// </typeparam>\n    /// <param name=\"name\">the property name like `Image` - or path to sub-property like `Author.Name` (new v15)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">the fallback value to provide if not found</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <param name=\"language\">\n    /// Optional language like `de`, `de-ch` or `de,en` to determine which values to check.\n    /// Will ignore languages not in the data model.\n    /// On items that don't have ML data it will be ignored. new v17.10\n    /// </param>\n    /// <returns>The typed value, or the `default` like `null` or `0` if casting isn't possible.</returns>\n    /// <remarks>\n    /// * Added in v15\n    /// * parameter `languages` added in 17.10\n    /// </remarks>\n    TValue? Get<TValue>(string name,\n        NoParamOrder npo = default,\n        TValue? fallback = default,\n        bool? required = default,\n        string? language = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Edit.Sys/SxcEditSharedConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcEditSharedConstants\n{\n    /// <summary>\n    /// Additional json-node for metadata in serialized entities, if user has edit rights\n    /// </summary>\n    public const string JsonEntityEditNodeName = \"_2sxcEditInformation\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/LookUp/DocsPlaceholder.cs",
    "content": "﻿namespace ToSic.Sxc.LookUp;\n\n/// <inheritdoc />\n[PublicApi]\npublic class DocsPlaceholder: DocumentationPlaceholder;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/LookUp/Sys/LookUpConstants.cs",
    "content": "﻿namespace ToSic.Sxc.LookUp.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LookUpConstants\n{\n\n    /// <summary>\n    /// This marks a special LookUp provider which is passed around through the system\n    /// As of now, this special source only offers two properties\n    /// * a special property which is not a lookup but contains the Instance object which is sometimes needed passed on\n    /// * a lookup value ShowDrafts which informs if the user may see drafts or not\n    /// </summary>\n    public const string InstanceContext = \"SxcInstance\";\n\n    // !Important - these must all always be lower case, as they are often used in comparisons\n    public const string SourceModule = \"module\";\n    public const string SourcePage = \"page\";\n    public const string SourceSite = \"site\";\n    public const string SourceUser = \"user\";\n\n    public const string KeyId = \"id\";\n    public const string KeyGuid = \"guid\";\n\n    public const string OldDnnModuleId = \"moduleid\";\n    public const string OldDnnPageSource = \"tab\";\n    public const string OldDnnPageId = \"tabid\";\n    public const string OldDnnSiteSource = \"portal\";\n    public const string OldDnnSiteId = \"portalid\";\n\n    public const string SourceQuery = \"query\";\n    public const string SourceQueryString = \"querystring\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Properties/GlobalSuppressions.cs",
    "content": "﻿// This file is used by Code Analysis to maintain SuppressMessage\n// attributes that are applied to this project.\n// Project-level suppressions either have no target or are given\n// a specific target and scoped to a namespace, type, member, etc.\n\nusing System.Diagnostics.CodeAnalysis;\n\n[assembly: SuppressMessage(\"Usage\", \"CA2211:Non-constant fields should not be visible\", Justification = \"<Pending>\", Scope = \"member\", Target = \"~F:ToSic.Sxc.Code.Internal.SourceCode.CodeFileInfo.TemplateUnknown\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Properties/SxcCoreNewAssemblyVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Code.Generate\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Core\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Razor\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Mvc\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Oqtane.Server\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Core.TestHelpers\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Tests\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.UnitTests\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.SystemTests\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Code\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Code.HotBuild\")]\n\n\n// WIP till services are moved\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Services\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Engines\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Edit\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Images\")]\n\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Blocks\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Render\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Cms\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.LightSpeed\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Web\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Apps\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Data\")]"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Services/Features/IFeaturesService.cs",
    "content": "﻿\n\n// Important\n// This is just the public API for this\n// Many other APIs simply shouldn't be public, so the Eav-version isn't fully surfaced here\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Feature`](xref:ToSic.Sxc.Services.ServiceKit16.Feature) to let your code find out what system features are currently enabled/disabled in the environment.\n/// </summary>\n/// <remarks>\n/// It's important to detect if the admin must activate certain features to let your code do it's work.\n/// \n/// This replaces the older static Features accessor - please only use this from now on.\n///\n/// History:\n/// - Added this implementation in 13.01\n/// </remarks>\n[PublicApi]\npublic interface IFeaturesService: IHasLog, ICanDebug\n{\n    /// <summary>\n    /// Checks if a list of features are enabled, in case you need many features to be activated.\n    /// </summary>\n    /// <param name=\"nameIds\">one or many name IDs - can also be the guids (as string)</param>\n    /// <returns>true if all features are enabled, false if any one of them is not</returns>\n    /// <remarks>\n    /// Added in v13.01\n    /// </remarks>\n    bool IsEnabled(params string[] nameIds);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Services/Json/IJsonService.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Json`](xref:ToSic.Sxc.Services.ServiceKit16.Json) to serialize/restore JSON.\n/// </summary>\n/// <remarks>\n/// It works for 2sxc/EAV data but can be used for any data which can be serialized/deserialized.\n/// Since it's a data-operation, we keep it in this namespace, even if most other things in this namespace are 2sxc-data objects.\n///\n/// *Important* This is simple object-string conversion.\n/// It doesn't change entity objects to be serializable.\n/// For that you should use the [](xref:ToSic.Eav.DataFormats.EavLight.IConvertToEavLight) which returns an object that can then be serialized. \n/// Internally it uses System.Text.Json and preserves the case of keys.\n///\n/// History\n/// \n/// * Introduced in 2sxc 12.05.\n///\n/// </remarks>\n[PublicApi]\npublic interface IJsonService\n{\n    /// <summary>\n    /// Convert an object to JSON.\n    /// \n    /// If you need to add the JSON to HTML of a page, make sure you also use `Html.Raw(...)`, otherwise it will be encoded and not usable in JavaScript.\n    /// </summary>\n    /// <param name=\"item\">The object to serialize</param>\n    string ToJson(object item);\n\n    /// <summary>\n    /// Convert an object to JSON - using nicer output / indentation.\n    /// \n    /// If you need to add the JSON to HTML of a page, make sure you also use `Html.Raw(...)`, otherwise it will be encoded and not usable in JavaScript.\n    /// </summary>\n    /// <param name=\"item\">The object to serialize</param>\n    /// <param name=\"indentation\">How much to indent the json - we recommend 4. As of now, it will always use 4, no matter what you set (see remarks)</param>\n    /// <remarks>\n    /// Added in 2sxc 12.11\n    ///\n    /// But as of 2sxc 12.11 we're still using an old Newtonsoft, so we cannot really control the indentation depth.\n    /// If you call this, it will always indent using 4 spaces. In a future release we'll probably use a newer Newtonsoft with which we can then use the indentation as needed.\n    /// </remarks>\n    string ToJson(object item, int indentation);\n\n    /// <summary>\n    /// Convert a JSON to a typed object. \n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"json\"></param>\n    /// <returns></returns>\n    T? To<T>(string json);\n\n    /// <summary>\n    /// Convert a json to an anonymous object.\n    /// This is a very technical thing to do, so only use it if you know why you're doing this.\n    /// </summary>\n    /// <param name=\"json\"></param>\n    /// <returns></returns>\n    object? ToObject(string json);\n\n    /// <summary>\n    /// Creates a <see cref=\"ITyped\"/> object from a json string.\n    ///\n    /// > [!IMPORTANT]\n    /// > This only works on json strings which return an object.\n    /// > If you pass in a simple json such as `27` or `\"hello\"` or an array like `[1, 2, 3]` it will throw an error.\n    /// > For arrays, use <see cref=\"ToTypedList\"/>.\n    /// </summary>\n    /// <param name=\"json\">The string containing json</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">\n    /// Alternate string to use, if the original json can't parse.\n    /// Can also be null or the word \"error\" if you would prefer an error to be thrown.\n    /// </param>\n    /// <param name=\"propsRequired\">make the resulting object [strict](xref:NetCode.Conventions.PropertiesRequired), default `true`</param>\n    /// <returns>A dynamic object representing the original json.\n    /// If it can't be parsed, it will parse the fallback, which by default is an empty dynamic object.\n    /// If you provide null for the fallback, then you will get null back.\n    /// </returns>\n    /// <remarks>\n    /// New in 16.02\n    /// </remarks>\n    [PublicApi]\n    ITyped? ToTyped(string json, NoParamOrder npo = default, string? fallback = default, bool? propsRequired = default);\n\n    /// <summary>\n    /// Creates a list of <see cref=\"ITyped\"/> wrappers around a json string containing an array of objects.\n    ///\n    /// > [!IMPORTANT]\n    /// > This only works on json strings which return an object.\n    /// > If you pass in a simple json such as `27` or `\"hello\"` or an array like `[1, 2, 3]` it will throw an error.\n    /// > For arrays, use <see cref=\"ToTypedList\"/>.\n    /// </summary>\n    /// <param name=\"json\">The string containing json</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">\n    /// Alternate string to use, if the original json can't parse.\n    /// Can also be null or the word \"error\" if you would prefer an error to be thrown.\n    /// </param>\n    /// <param name=\"propsRequired\">make the resulting object [strict](xref:NetCode.Conventions.PropertiesRequired), default `true`</param>\n    /// <returns>A dynamic object representing the original json.\n    /// If it can't be parsed, it will parse the fallback, which by default is an empty dynamic object.\n    /// If you provide null for the fallback, then you will get null back.\n    /// </returns>\n    /// <remarks>\n    /// New in 16.04\n    /// </remarks>\n    IEnumerable<ITyped>? ToTypedList(string json, NoParamOrder npo = default, string? fallback = default,\n        bool? propsRequired = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Services/Page/IPageService.cs",
    "content": "﻿using ToSic.Razor.Blade;\n\n// ReSharper disable UnusedMember.Global\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Page`](xref:ToSic.Sxc.Services.ServiceKit16.Page) to make changes to the page - usually from Razor.\n/// </summary>\n/// <remarks>\n///\n/// History\n/// * Introduced in v12.02 but on another namespace which still works for compatibility\n/// * Moved to ToSic.Sxc.Services in v13\n/// * Added ability to use placeholder `[original]` in v13.11\n/// * Most commands were updated to return an empty string in v14.02 so that they could be used as inline razor (previously `void`)\n/// </remarks>\n[PublicApi]\npublic partial interface IPageService\n{\n    ///// <summary>\n    ///// How changes should be applied to the page.\n    ///// Default is <see cref=\"T:ChangeMode.Auto\"/>\n    ///// </summary>\n    //[PrivateApi(\"not final yet\")]\n    //PageChangeModes ChangeMode { get; set; }\n\n    /// <summary>\n    /// Add a standard base header tag or replace it if one is already provided.\n    /// </summary>\n    /// <param name=\"url\">the optional url for the base tag - if null, will try to default to the real url for the current page</param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.SetBase(...)`</returns>\n    string SetBase(string? url = null);\n\n    /// <summary>\n    /// Set the Page Title. Behavior:\n    ///\n    /// * By default it will _prefix_ the new title - `SetTitle('My New Title - ')` = `My New Title - Blog - 2sxc.org`\n    /// * You can also use the new `[original]` token like `SetTitle('[original] - My New Title')` = `Blog - 2sxc.org - My New Title`\n    /// * You can add a placeholder to the page-title and tell SetTitle what it is. `SetTitle('My New Title', '2sxc.org') = `Blog - My New Title`\n    /// </summary>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.SetTitle(...)`</returns>\n    string SetTitle(string value, string? placeholder = null);\n\n    /// <summary>\n    /// Set the Page Description.\n    /// It will either try to replace the placeholder (second parameter)\n    /// or _prefix_ it to the existing description (unless `[original]` is given).\n    ///\n    /// See also the details with placeholder or `[original]` as explained on <see cref=\"SetTitle\"/>\n    /// </summary>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.SetDescription(...)`</returns>\n    string SetDescription(string value, string? placeholder = null);\n\n    /// <summary>\n    /// Set the Page Keywords. \n    /// It will either try to replace the placeholder (second parameter)\n    /// or _prefix_ it to the existing keywords  (unless `[original]` is given).\n    ///\n    /// See also the details with placeholder or `[original]` as explained on <see cref=\"SetTitle\"/>\n    /// </summary>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.SetKeywords(...)`</returns>\n    string SetKeywords(string value, string? placeholder = null);\n\n    /// <summary>\n    /// Set the page status code if possible (it will work in DNN, but probably not in Oqtane)\n    /// </summary>\n    /// <param name=\"statusCode\">An HTTP status code like 404</param>\n    /// <param name=\"message\">Message / Description text (optional) which would be included in the header</param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.SetHttpStatus(...)`</returns>\n    string SetHttpStatus(int statusCode, string? message = null);\n\n\n    /// <summary>\n    /// Add a tag to the header of the page\n    /// Will simply not do anything if an error occurs, like if the page object doesn't exist\n    /// </summary>\n    /// <param name=\"tag\"></param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddToHead(...)`</returns>\n    string AddToHead(string tag);\n\n    /// <summary>\n    /// Add a RazorBlade Tag to the headers of the page\n    /// Will simply not do anything if an error occurs, like if the page object doesn't exist\n    /// </summary>\n    /// <param name=\"tag\"></param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddToHead(...)`</returns>\n    string AddToHead(IHtmlTag tag);\n\n\n    /// <summary>\n    /// Add a standard meta header tag.\n    /// You may also want to use <see cref=\"AddOpenGraph\"/> or <see cref=\"AddJsonLd(string)\"/>\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"content\"></param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddMeta(...)`</returns>\n    string AddMeta(string name, string content);\n\n    /// <summary>\n    /// Add an open-graph header according to http://ogp.me/\n    /// </summary>\n    /// <param name=\"property\">Open Graph property name, like title or image:width. 'og:' is automatically prefixed if not included</param>\n    /// <param name=\"content\">value of this property</param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddOpenGraph(...)`</returns>\n    string AddOpenGraph(string property, string content);\n\n\n    /// <summary>\n    /// Add a JSON-LD header according https://developers.google.com/search/docs/guides/intro-structured-data\n    /// </summary>\n    /// <param name=\"jsonString\">A prepared JSON string</param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddJsonLd(...)`</returns>\n    string AddJsonLd(string jsonString);\n\n    /// <summary>\n    /// Add a JSON-LD header according https://developers.google.com/search/docs/guides/intro-structured-data\n    /// </summary>\n    /// <param name=\"jsonObject\">A object which will be converted to JSON. We recommend using dictionaries to build the object.</param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddJsonLd(...)`</returns>\n    string AddJsonLd(object jsonObject);\n\n    #region Icon stuff\n\n    /// <summary>\n    /// Add an Icon header tag to the Page. \n    /// </summary>\n    /// <param name=\"path\">Path to the image/icon file</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"rel\">the rel-text, default is 'icon'. common terms are also 'shortcut icon' or 'apple-touch-icon'</param>\n    /// <param name=\"size\">Will be used in size='#x#' tag; only relevant if you want to provide multiple separate sizes</param>\n    /// <param name=\"type\">An optional type. If not provided, will be auto-detected from known types or remain empty</param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddIcon(...)`</returns>\n    string AddIcon(\n        string path,\n        NoParamOrder npo = default,\n        string rel = \"\",\n        int size = 0,\n        string? type = null);\n\n    /// <summary>\n    /// Add a set of icons to the page\n    /// </summary>\n    /// <param name=\"path\">Path to the image/icon file</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"favicon\">path to favicon, default is '/favicon.ico' </param>\n    /// <param name=\"rels\"></param>\n    /// <param name=\"sizes\"></param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddIconSet(...)`</returns>\n    string AddIconSet(\n        string path,\n        NoParamOrder npo = default,\n        object? favicon = null,\n        IEnumerable<string>? rels = null,\n        IEnumerable<int>? sizes = null);\n\n    #endregion\n\n    /// <summary>\n    /// List of all feature keys which were ever added. Will never be cleared.\n    /// </summary>\n    internal List<string> FeatureKeysAdded { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Services/Page/IPageService_Features.cs",
    "content": "﻿namespace ToSic.Sxc.Services;\n\npublic partial interface IPageService\n{\n\n    #region Features\n\n    /// <summary>\n    /// Activate a feature on this page, such as `turnOn`, `2sxc.JsCore` etc.\n    /// For list of features, see [](xref:NetCode.Razor.Services.IPageServiceActivate).\n    /// </summary>\n    /// <param name=\"keys\">One or more strings containing Page-Feature keys</param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.Activate(...)`</returns>\n    string? Activate(params string[] keys);\n\n    /// <summary>\n    /// Activate a feature on this page, such as `turnOn`, `2sxc.JsCore` etc.\n    /// For list of features, see [](xref:NetCode.Razor.Services.IPageServiceActivate).\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"condition\">Condition to determine if activation should happen</param>\n    /// <param name=\"features\">One or more strings containing Page-Feature keys</param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.Activate(...)`</returns>\n    /// <remarks>\n    /// * This overload with `condition` added in v15.03\n    /// </remarks>\n    string? Activate(\n        NoParamOrder npo = default,\n        bool condition = true,\n        params string[] features);\n\n    #endregion\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Services/Page/IPageService_Security.cs",
    "content": "﻿using ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Services;\n\npublic partial interface IPageService\n{\n    #region Security\n\n    /// <summary>\n    /// Add common html attributes to a `script` or `link` tag to [enable optimizations](xref:Basics.Server.AssetOptimization.Index)\n    /// and [automatically whitelist in the Content Security Policy](xref:Abyss.Security.Csp.Parts#auto-white-listing-explicit)\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"optimize\">Activate optimize, default is true</param>\n    /// <param name=\"priority\">Optional priority of optimization. Must be more than 100 to have an effect.</param>\n    /// <param name=\"position\">Optional position of the resource (`head`, `body`, `bottom`)</param>\n    /// <param name=\"whitelist\">Automatically add to CSP-whitelist. This uses a random key to protect against XSS.</param>\n    /// <returns>The asset attributes in a format which will be preserved in HTML</returns>\n    /// <remarks>\n    /// History: Created in 2sxc 13.10\n    /// </remarks>\n    IRawHtmlString AssetAttributes(\n        NoParamOrder npo = default,\n        bool optimize = true,\n        int priority = 0,\n        string? position = null,\n        bool whitelist = true);\n\n    /// <summary>\n    /// Add a CSP rule where you also specify the name.\n    /// Best check the [CSP Guide](xref:Abyss.Security.Csp.Index).\n    ///\n    /// For an example, see [Coded CSP](xref:Abyss.Security.Csp.CodedRules)\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"values\"></param>\n    /// <returns>Empty string, so it can be used on inline razor such as `@Kit.Page.AddCsp(...)`</returns>\n    string AddCsp(string name, params string[] values);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Services/Page/IPageService_TurnOn.cs",
    "content": "﻿namespace ToSic.Sxc.Services;\n\npublic partial interface IPageService\n{\n    #region TurnOn (new v15)\n\n    /// <summary>\n    /// Turn on some javascript code when all requirements have been met.\n    /// Uses [turnOn](xref:JsCode.TurnOn.Index).\n    /// \n    /// Will automatically activate the feature and set hidden data on the page for the turnOn JS to pick up.\n    /// </summary>\n    /// <param name=\"runOrSpecs\">\n    /// * either a run `string` like `window.myObject.myJs()` (must always start with window)\n    /// * or an object containing all the parameters which turnOn requires\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"require\">\n    /// _optional_ One or more requirements which must be met before the code starts.\n    /// Can be one or many values and/or functions.\n    /// * a `string` such as `window.myObject` or `window.myObject.readyToStart()`\n    /// * an array of such strings\n    /// </param>\n    /// <param name=\"data\">_optional_ any value such as a string, or an object - to pass into the run-command</param>\n    /// <param name=\"args\">_optional_ array of values to pass to the run function (new v18.00)</param>\n    /// <param name=\"condition\">_optional_ condition when this should happen - if false, it won't add anything (new v16.02)</param>\n    /// <param name=\"noDuplicates\">Will not add this turnOn if an identical one is already added to the page (new 16.05)</param>\n    /// <param name=\"addContext\">\n    /// _optional_ when `args` is used, the context is usually not needed or given.\n    /// If you do need it, it can be merged with data (if that's also provided and is an object - so use `data`) or added to the end of the args list `end`.\n    /// (new v18.00)\n    /// </param>\n    /// <returns>An empty string, just so you can use it directly in Razor like `@Kit.Page.TurnOn(\"...\")`</returns>\n    /// <remarks>\n    /// * Added in v15.x\n    /// * `condition` added in 16.02\n    /// * `noDuplicates` added in 16.05\n    /// * `args` and `addContext` added in v18.0\n    /// </remarks>\n    string? TurnOn(object runOrSpecs,\n        NoParamOrder npo = default,\n        object? require = default,\n        object? data = default,\n        IEnumerable<object>? args = default,\n        bool condition = true,\n        bool? noDuplicates = default,\n        string? addContext = default\n    );\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/StartupSxcCore.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.Integration;\nusing ToSic.Sxc.Sys.Integration.Installation;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sys.Boot;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcCore\n{\n    public static IServiceCollection AddSxcCore(this IServiceCollection services)\n    {\n        services.TryAddScoped<ILinkPaths, LinkPaths>();\n\n        // Configuration Provider WIP\n        services.TryAddTransient<SxcImportExportEnvironmentBase.Dependencies>();\n\n        // Sxc StartUp Routines - MUST be AddTransient, not TryAddTransient so many start-ups can be registered\n        // Add StartUp Registration of FeaturesCatalog\n        services.AddTransient<IBootProcess, SxcBootFeaturesRegistrations>();\n\n        // v13 Provide page scoped services\n        // This is important, as most services are module scoped, but very few are actually scoped one level higher\n        services.TryAddScoped<PageScopeAccessor>();\n        services.TryAddScoped(typeof(PageScopedService<>));\n\n        // 12.06.01 moved here from WebApi, but it should probably be in Dnn as it's probably just used there\n        services.TryAddTransient<IServerPaths, ServerPaths>();\n\n        return services;\n    }\n\n    /// <summary>\n    /// This will add Do-Nothing services which will take over if they are not provided by the main system\n    /// In general this will result in some features missing, which many platforms don't need or care about\n    /// </summary>\n    /// <param name=\"services\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// All calls in here MUST use TryAddTransient, and never without the Try\n    /// </remarks>\n    public static IServiceCollection AddSxcCoreFallbacks(this IServiceCollection services)\n    {\n        // basic environment, pages, modules etc.\n        services.TryAddTransient<IEnvironmentInstaller, EnvironmentInstallerUnknown>();\n\n        //// ADAM basics\n        //// TODO: this doesn't warn yet, there should be an AdamFileSystemUnknown(WarnUseOfUnknown<AdamFileSystemUnknown> warn)\n        //services.TryAddTransient<IAdamFileSystem<string, string>, AdamFileSystemBasic>();\n\n        // v13.02\n        services.TryAddTransient<ILinkPaths, LinkPathsUnknown>();\n\n        return services;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys/SxcLogging.cs",
    "content": "﻿namespace ToSic.Sxc.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcLogging\n{\n    public const string SxcLogAppCodeLoader = \"global-app-code-compiler\";\n    public const string SxcLogName = \"Sxc\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Configuration/SxcBootFeaturesRegistrations.cs",
    "content": "﻿using ToSic.Sys.Boot;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Sys.Configuration;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcBootFeaturesRegistrations(FeaturesCatalog featuresCatalog)\n    : BootProcessBase($\"{SxcLogName}.SUpReg\", bootPhase: BootPhase.Registrations, connect: [featuresCatalog]), IBootProcess\n{\n    /// <summary>\n    /// Register Dnn features before loading\n    /// </summary>\n    public override void Run() => SxcFeatures.Register(featuresCatalog);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Configuration/SxcFeatures.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Sys.Configuration;\n\n/// <summary>\n/// Internal - built-in features.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[PrivateApi]\npublic partial class SxcFeatures\n{\n    public static void Register(FeaturesCatalog cat) =>\n        cat.Register(\n            // CorePlus\n            RazorThrowPartial,\n            RenderThrowPartialSystemAdmin,\n            PermissionPrioritizeModuleContext,\n\n            // Sentinel CSP\n            ContentSecurityPolicy,\n            ContentSecurityPolicyTestUrl,\n            ContentSecurityPolicyEnforceTemp,\n\n            // Sentinel New 15.04\n            CdnSourcePublic,\n            CdnSourceEdit,\n            // Not yet available\n            //CdnSourceAdmin,\n            //CdnSourceDev,\n\n            // Sentinel new v18.05\n            NetworkDataEncryption,\n\n            // Patrons Perfectionist\n            ImageServiceMultiFormat, // v13\n            ImageServiceMultipleSizes,\n            ImageServiceSetSizes,\n            ImageServiceUseFactors,\n\n            LightSpeedOutputCache,\n            LightSpeedOutputCacheAppFileChanges,\n            LightSpeedOutputCachePartials, // v20\n            LightSpeedOutputCacheCompression, // v21\n            SmartDataCache, // v19.01\n\n            PageShieldFloodGates, // v21.06\n\n            RazorCacheCompiledToDisk    // v20.00-09\n        );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Configuration/SxcFeatures_Beta.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Sys.Configuration;\n\npublic partial class SxcFeatures\n{\n    public static readonly Feature RazorThrowPartial = new()\n    {\n        NameId = \"RazorThrowPartial\",\n        Guid = new(\"d5a327c5-db0f-472b-93b2-94e66b15e16b\"),\n        Name = \"Razor= Handle Errors in sub-components for all users\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Will render most of the page and only error on a partial-render, instead of breaking the entire module. If enabled, then Html.Render or similar activities which throw an error won't stop the entire module, but just that part. \",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = BuiltInFeatures.ForCorePlusEnabled\n    };\n\n    public static readonly Feature RenderThrowPartialSystemAdmin = new()\n    {\n        NameId = \"RenderThrowPartialSystemAdmin\",\n        Guid = new(\"5b0c9379-2fef-4f6e-9022-4d3c50e894e5\"),\n        Name = \"Razor= Handle Errors in sub-components for system admins only (host users)\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Will render most of the page and only error on a partial-render, instead of breaking the entire module. But only when the sys-admin is viewing the page. If enabled, then Html.Render or similar activities which throw an error won't stop the entire module, but just that part. \",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = BuiltInFeatures.ForCorePlusEnabled\n    };\n\n    public static readonly Feature PermissionPrioritizeModuleContext = new()\n    {\n        NameId = nameof(PermissionPrioritizeModuleContext),\n        Guid = new(\"3533a6e7-9cd9-4f2e-8978-f426a1a2694f\"),\n        Name = \"Give restricted editors more permissions when editing inner content. \",\n        IsPublic = false,\n        Ui = false,\n        Description = \"This modifies the permission system to give the user permissions granted by the page or module, even if they switched to another App.\",\n        Security = new(2, \"Reduces security. Restricted editors are able to access other Apps which doesn't make sense for restricted editors.\"),\n        LicenseRules = BuiltInFeatures.ForCorePlusDisabled\n    };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Configuration/SxcFeatures_Csp.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Sys.Configuration;\n\npublic partial class SxcFeatures\n{\n    public static readonly Feature ContentSecurityPolicy = new() {\n        NameId = \"ContentSecurityPolicy\",\n        Guid = new(\"e5c99abf-9bc4-4e6c-9cc4-4bda22c0ab85\"),\n        Name = \"Enable Content Security Policy and related APIs. \",\n        IsPublic = false,\n        Ui = false,\n        Description = \"If enabled, ContentSecurityPolicy headers will be set. Note that APIs will always work, but not result in http headers if this is disabled. \",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelDisabled\n    };\n\n    public static readonly Feature ContentSecurityPolicyTestUrl = new()\n    {\n        NameId = \"ContentSecurityPolicyTestUrl\",\n        Guid = new(\"94c3d7e5-5d89-4a68-b710-95bfc29199ba\"),\n        Name = \"Enable the parameter ?csp=true in URL for testing.\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"If enabled, you can add csp=true to any url to temporarily enable a policy and see if it works. Requires the CSP system to be enabled.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelDisabled\n    };\n    public static readonly Feature ContentSecurityPolicyEnforceTemp = new() {\n        NameId = \"ContentSecurityPolicyEnforceTemp\",\n        Guid = new(\"ece0943d-f3c0-422c-9d06-c20b9b83df8d\"),\n        Name = \"Enable CSP on all pages (temporary setting).\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Enable CSP on all pages. This is a temporary setting, till we have more configuration in normal Settings.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelDisabled\n    };\n\n    public static readonly Feature CdnSourcePublic = new()\n    {\n        NameId = nameof(CdnSourcePublic),\n        Guid = new(\"b8b993d3-a02b-4099-a2a8-c06bf8961a66\"),\n        Name = \"Change CDN source for public Web Resources\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Allow reconfigure of the CDN source for public Web Resources.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelEnabled\n    };\n    public static readonly Feature CdnSourceEdit = new() {\n        NameId = nameof(CdnSourceEdit),\n        Guid = new(\"34dce40e-30fc-4d4f-b1ab-8fcface90e61\"),\n        Name = \"Change CDN source for Edit Web Resources\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Allow reconfigure of the CDN source for Web Resources used in the Edit UI.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelEnabled\n    };\n\n    // Note = not in use ATM\n    public static readonly Feature CdnSourceAdmin = new() {\n        NameId = nameof(CdnSourceAdmin),\n        Guid = new(\"c799c71e-aa4a-4a30-ae8a-e177e615a36c\"),\n        Name = \"Change CDN source for Admin Web Resources\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Allow reconfigure of the CDN source for Web Resources used in the Admin UI.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelEnabled\n    };\n\n    // Note = not in use ATM\n    public static readonly Feature CdnSourceDev = new() {\n        NameId = nameof(CdnSourceDev),\n        Guid = new(\"81a51003-ad55-491e-9749-d74529496465\"),\n        Name = \"Change CDN source for Development Web Resources\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Allow reconfigure of the CDN source for Web Resources used in the Developers UIs.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelEnabled\n    };\n\n\n    public static readonly Feature NetworkDataEncryption = new() {\n        NameId = nameof(NetworkDataEncryption),\n        Guid = new(\"6c333e6f-d552-431a-b47c-0030764a66f3\"),\n        Name = \"Encrypt forms data before sending to server; prevent CDN snooping.\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Encrypt data submitted using forms, so it's unreadable in CDNs.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelEnabled,\n\n        ScopedToModule = true,\n    };\n\n    public static readonly Feature PageShieldFloodGates = new()\n    {\n        NameId = nameof(PageShieldFloodGates),\n        Guid = new(\"429d3b22-4bbd-4fd0-ac4d-4d7c865bac13\"),\n        Name = \"PageShield FloodGates - WIP\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Tight control over URL parameters, to avoid crawlers from multiplying combinations of URL parameters.\",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = SxcLicenseRules.ForPatronsSentinelEnabled,\n    };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Configuration/SxcFeatures_ImageService.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Sys.Configuration;\n\npublic partial class SxcFeatures\n{\n\n    public static readonly Feature ImageServiceMultipleSizes = new()\n    {\n        NameId = \"ImageServiceMultipleSizes\",\n        Guid = new(\"9dab12db-85e5-4fb8-a100-2f009bf32f72\"),\n        Name = \"Image Service - Multiple Sizes\",\n        IsPublic = false,\n        Ui = false,\n        Description =\n            \"Enables the ImageService to provide multiple sizes on <code>srcset</code> for <code>img</code> or <code>source</code> tags on a <code>picture</code>\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsPerfectionist\n    };\n\n    public static readonly Feature ImageServiceUseFactors = new()\n    {\n        NameId = \"ImageServiceUseFactors\",\n        Guid = new(\"7d2ce824-b249-466f-928b-21567f4fa5da\"),\n        Name = \"Image Service - Optimize Sizes by Factor\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Will change how the size of images is calculated to vary by factor. So a 1/2 image will not be 670px but 600 when using Bootstrap5. The exact values are configured in the settings.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsPerfectionist\n    };\n\n\n    public static readonly Feature ImageServiceSetSizes = new()\n    {\n        NameId = \"ImageServiceSetSizes\",\n        Guid = new(\"31c2c0b6-87c2-4014-89ba-98543858bb8a\"),\n        Name = \"Image Service - Set sizes-attribute on Image Tags\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"The browser can pre-load faster if the img-tag has additional information about the final sizes of the image. The exact configuration can be adjusted in the settings.\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsPerfectionist\n    };\n\n\n    public static readonly Feature ImageServiceMultiFormat = new()\n    {\n        NameId = \"ImageServiceMultiFormat\",\n        Guid = new(\"4262df94-3877-4a5a-ac86-20b4f9b38e87\"),\n        Name = \"Image Service - Multiple Formats\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Enables the ImageService to also provide WebP as better alternatives to JPG and PNG\",\n        Security = FeaturesCatalogRules.Security0Improved,\n        LicenseRules = SxcLicenseRules.ForPatronsPerfectionist\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Configuration/SxcFeatures_LightSpeed.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Sys.Configuration;\n\npublic partial class SxcFeatures\n{\n    public static readonly Feature LightSpeedOutputCache = new()\n    {\n        NameId = nameof(LightSpeedOutputCache),\n        Guid = new(\"61654bca-b76b-4c15-9173-5643de6b4baa\"),\n        Name = \"LightSpeed Output Cache\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"High-Performance OutputCache\",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = SxcLicenseRules.ForPatronsPerfectionistAndPerformance,\n    };\n\n    public static readonly Feature LightSpeedOutputCacheAppFileChanges = new()\n    {\n        NameId = nameof(LightSpeedOutputCacheAppFileChanges),\n        Guid = new(\"3f4c7d29-568d-44de-bd76-77e8572560f7\"),\n        Name = \"LightSpeed Output Cache - Monitor App file changes\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"High-Performance OutputCache - Watch App files and flush cache if any App files change\",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = SxcLicenseRules.ForPatronsPerfectionistAndPerformance,\n    };\n\n    public static readonly Feature LightSpeedOutputCachePartials = new()\n    {\n        NameId = nameof(LightSpeedOutputCachePartials),\n        Guid = new(\"1f01d566-1877-40a3-93f2-5485a1718a36\"),\n        Name = \"LightSpeed Output Cache - Partials\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"High-Performance OutputCache - Caching partial razor views.\",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = SxcLicenseRules.ForPatronsPerfectionistAndPerformance,\n    };\n\n    public static readonly Feature LightSpeedOutputCacheCompression = new()\n    {\n        NameId = nameof(LightSpeedOutputCacheCompression),\n        Guid = new(\"64f25cbc-5fb9-4501-bf74-78700ff42591\"),\n        Name = \"LightSpeed Output Cache - Compression\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"High-Performance OutputCache - Compressing cached output.\",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = BuiltInFeatures.ForPatronPerformanceNotEnabled,\n    };\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Configuration/SxcFeatures_Performance.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Sys.Configuration;\n\npublic partial class SxcFeatures\n{\n\n    public static readonly Feature SmartDataCache = new()\n    {\n        NameId = nameof(SmartDataCache),\n        Guid = new(\"8e4f0ea6-6574-4341-89ac-21629584dc1d\"),\n        Name = \"Smart Data Cache\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"High-Performance Smart Data Cache\",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = BuiltInFeatures.ForPatronPerformanceAutoEnabled,\n    };\n\n    public static readonly Feature RazorCacheCompiledToDisk = new()\n    {\n        NameId = nameof(RazorCacheCompiledToDisk),\n        Guid = new(\"d022bf2e-0e0c-4c61-b653-c2be0213e323\"),\n        Name = \"Razor - Cache Compiled Razor to Disk\",\n        IsPublic = false,\n        Ui = false,\n        Description = \"Cache compiled razor for faster restart and code less accessed.\",\n        Security = FeaturesCatalogRules.Security0Neutral,\n        LicenseRules = BuiltInFeatures.ForPatronPerformanceNotEnabled,\n    };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Configuration/SxcLicenseRules.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Capabilities.Licenses;\n\nnamespace ToSic.Sxc.Sys.Configuration;\ninternal class SxcLicenseRules\n{\n    public static List<FeatureLicenseRule> ForPatronsPerfectionist = BuiltInLicenseRules.BuildRule(BuiltInLicenses.PatronPerfectionist, true);\n    public static List<FeatureLicenseRule> ForPatronsSentinelDisabled = BuiltInLicenseRules.BuildRule(BuiltInLicenses.PatronSentinel, false);\n    public static List<FeatureLicenseRule> ForPatronsSentinelEnabled = BuiltInLicenseRules.BuildRule(BuiltInLicenses.PatronSentinel, true);\n\n    public static List<FeatureLicenseRule> ForPatronsPerfectionistAndPerformance =\n    [\n        new(BuiltInLicenses.PatronPerfectionist, true),\n        new(BuiltInLicenses.PatronPerformance, true)\n    ];\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.DI/PageScopeAccessor.cs",
    "content": "﻿// ReSharper disable once CheckNamespace\nnamespace ToSic.Sys.DI;\n\n/// <summary>\n/// Special helper to get a ServiceProvider of the page scope, in scenarios where each module has an own scope. \n/// </summary>\n/// <remarks>\n/// Default constructor will always work, and use the current service provider as the source\n/// </remarks>\n/// <param name=\"serviceProvider\"></param>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PageScopeAccessor(IServiceProvider serviceProvider)\n{\n    public void InitPageOfModule(IServiceProvider pageServiceProvider)\n    {\n        ServiceProvider = pageServiceProvider;\n        ProvidedInModule = true;\n    }\n\n    /// <summary>\n    /// The page level ServiceProvider\n    /// </summary>\n    internal IServiceProvider ServiceProvider { get; private set; } = serviceProvider;\n\n\n    /// <summary>\n    /// Determines if this page-scope accessor is from the PageDI or from the Module\n    /// More for internal use, in case we have trouble debugging\n    /// </summary>\n    public bool ProvidedInModule { get; private set; } = false;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.DI/PageScopedService.cs",
    "content": "﻿\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sys.DI;\n\n/// <summary>\n/// Provide page scoped services\n/// </summary>\n/// <typeparam name=\"T\"></typeparam>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PageScopedService<T>(PageScopeAccessor pageScopeAccessor) where T : class\n{\n    public T Value => pageScopeAccessor.ServiceProvider.Build<T>();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Integration/Installation/EnvironmentInstallerUnknown.cs",
    "content": "﻿#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Sys.Integration.Installation;\n\ninternal class EnvironmentInstallerUnknown(WarnUseOfUnknown<EnvironmentInstallerUnknown> _) : ServiceBase($\"{LogScopes.NotImplemented}.Instll\"), IEnvironmentInstaller, IIsUnknown\n{\n    // for now, always assume installation worked\n    public string UpgradeMessages() => null!;\n\n    // don't do anything for now\n    public bool ResumeAbortedUpgrade() => true;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Integration/Installation/IEnvironmentInstaller.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Integration.Installation;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IEnvironmentInstaller: IHasLog\n{\n    /// <summary>\n    /// Get upgrade messages to show to the user if the upgrade/install needs attention\n    /// </summary>\n    /// <returns></returns>\n    string? UpgradeMessages();\n\n    /// <summary>\n    /// Manually trigger continue-update\n    /// </summary>\n    /// <returns></returns>\n    bool ResumeAbortedUpgrade();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Integration/Paths/ILinkPaths.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Integration.Paths;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ILinkPaths\n{\n    string AsSeenFromTheDomainRoot(string virtualPath);\n\n    string GetCurrentRequestUrl();\n\n    string GetCurrentLinkRoot();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Integration/Paths/LinkPaths.NetCore.cs",
    "content": "﻿#if !NETFRAMEWORK\nusing Microsoft.AspNetCore.Http.Extensions;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace ToSic.Sxc.Sys.Integration.Paths;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LinkPaths(IUrlHelper urlHelper) : ILinkPaths\n{\n    public string AsSeenFromTheDomainRoot(string virtualPath)\n        => urlHelper.Content(virtualPath);\n\n    public string GetCurrentRequestUrl()\n        => urlHelper.ActionContext.HttpContext.Request.GetEncodedUrl();\n\n    public string GetCurrentLinkRoot()\n        => new Uri(urlHelper.ActionContext.HttpContext.Request.GetEncodedUrl())\n            .GetLeftPart(UriPartial.Authority);\n}\n#endif\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Integration/Paths/LinkPaths.NetFramework.cs",
    "content": "﻿#if NETFRAMEWORK\nusing System.Web;\n\nnamespace ToSic.Sxc.Sys.Integration.Paths;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LinkPaths: ILinkPaths\n{\n\n    public string AsSeenFromTheDomainRoot(string virtualPath)\n        => VirtualPathUtility.ToAbsolute(virtualPath);\n\n    public string GetCurrentRequestUrl()\n        => HttpContext.Current?.Request?.Url?.AbsoluteUri ?? string.Empty;\n\n    public string GetCurrentLinkRoot()\n        => HttpContext.Current?.Request?.Url?.GetLeftPart(UriPartial.Authority) ?? string.Empty;\n}\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Integration/Paths/LinkPathsUnknown.cs",
    "content": "﻿#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Sys.Integration.Paths;\n\ninternal class LinkPathsUnknown(WarnUseOfUnknown<LinkPathsUnknown> _) : ILinkPaths, IIsUnknown\n{\n    public string AsSeenFromTheDomainRoot(string virtualPath) => throw new NotImplementedException();\n\n    // Stub CurrentPage\n    public string GetCurrentRequestUrl() => GetCurrentLinkRoot() + \"/folder/sub-folder/current-page\";\n\n    // Stub DomainName\n    public string GetCurrentLinkRoot() => \"https://unknown.2sxc.org\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Integration/Paths/ServerPaths.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\n#if NETFRAMEWORK\nusing System.Web.Hosting;\n#else\nusing Microsoft.AspNetCore.Hosting;\n#endif\n\n\nnamespace ToSic.Sxc.Sys.Integration.Paths;\n\n/// <summary>\n/// In the default implementation, all things have the same root so content-path and app-path\n/// are calculated the same way.\n/// </summary>\ninternal class ServerPaths: ServerPathsBase\n{\n#if !NETFRAMEWORK\n\n    // NOTE: The .net standard is probably never used\n    // As Oqtane has it's own ServerPaths\n    // So we should probably drop this soon\n    // ReSharper disable once ConvertToPrimaryConstructor\n    public ServerPaths(IWebHostEnvironment hostingEnvironment)\n    {\n        _hostingEnvironment = hostingEnvironment;\n    }\n\n    private readonly IWebHostEnvironment _hostingEnvironment;\n\n    protected string MapContentPath(string virtualPath)\n    {\n        return Path.Combine(_hostingEnvironment.ContentRootPath, virtualPath);\n    }\n\n    protected override string? FullPathOfReference(int id)\n    {\n        throw new NotImplementedException(\"leave as not implemented, as we assume this code is never ever used\");\n    }\n\n#else\n    // ReSharper disable once ConvertToPrimaryConstructor\n    public ServerPaths(LazySvc<IValueConverter> valueConverterLazy)\n    {\n        _valueConverterLazy = valueConverterLazy;\n    }\n    private readonly LazySvc<IValueConverter> _valueConverterLazy;\n\n    private string MapContentPath(string virtualPath)\n        => HostingEnvironment.MapPath(virtualPath) ?? \"error mapping path.\";\n\n    protected override string? FullPathOfReference(int id)\n    {\n        var fileRef = \"file:\" + id;\n        var resolved = _valueConverterLazy.Value.ToValue(fileRef);\n        if (string.IsNullOrWhiteSpace(resolved))\n            return null;\n        return FullContentPath(resolved);\n    }\n#endif\n\n\n    /// <inheritdoc />\n    public override string FullAppPath(string virtualPath) => MapContentPath(virtualPath);\n\n    /// <inheritdoc />\n    public override string FullContentPath(string virtualPath) => MapContentPath(virtualPath);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Integration/SxcImportExportEnvironmentBase.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.ImportExport.Integration;\n\nnamespace ToSic.Sxc.Sys.Integration;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class SxcImportExportEnvironmentBase: EavImportExportEnvironmentBase\n{\n    #region constructor / DI\n\n    public record Dependencies(ISite Site, IAppReaderFactory AppReaders, IAppsCatalog AppsCatalog, IAppPathsMicroSvc AppPaths)\n        : DependenciesRecord(connect: [Site, AppReaders, AppPaths]);\n\n\n    /// <summary>\n    /// DI Constructor\n    /// </summary>\n    protected SxcImportExportEnvironmentBase(Dependencies services, string logName) : base(services.Site, services.AppsCatalog, logName)\n    {\n        _services = services.ConnectServices(Log);\n    }\n\n    private readonly Dependencies _services;\n\n    #endregion\n\n    public override string FallbackContentTypeScope => ScopeConstants.Default;\n\n    public override string TemplatesRoot(int zoneId, int appId) \n        => AppPaths(zoneId, appId).PhysicalPath;\n\n    public override string GlobalTemplatesRoot(int zoneId, int appId) \n        => AppPaths(zoneId, appId).PhysicalPathShared;\n\n    private IAppPaths AppPaths(int zoneId, int appId) => _appPaths\n        ??= _services.AppPaths.Get(_services.AppReaders.Get(new AppIdentity(zoneId, appId)), _services.Site);\n    private IAppPaths? _appPaths;\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Plumbing/ParseObject.Double.cs",
    "content": "﻿using System.Globalization;\n\nnamespace ToSic.Sxc.Sys.Plumbing;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static partial class ParseObject\n{\n\n    internal static double? DoubleOrNull(object? value)\n    {\n        if (value is null)\n            return null;\n        if (value is float floatVal)\n            return floatVal;\n        if (value is double dVal)\n            return dVal;\n\n        var strValue = RealStringOrNull(value);\n        if (strValue == null)\n            return null;\n        strValue = strValue.Replace(\",\", \".\");\n        if (!double.TryParse(strValue, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var doubleValue))\n            return null;\n        return doubleValue;\n    }\n\n    internal static double? DoubleOrNullWithCalculation(object? value)\n    {\n        // First, check if it's a string like \"4:2\" or \"16/9\"\n        if (value is string strValue && !string.IsNullOrWhiteSpace(strValue))\n        {\n            // check for separator\n            var separator = strValue.IndexOfAny([':', '/']);\n            if (separator > 0) // if it starts with the separator, something is wrong\n            {\n                var leftPart = strValue.Substring(0, separator);\n                var rightPart = strValue.Substring(separator + 1);\n\n                if (double.TryParse(leftPart, out var top) && double.TryParse(rightPart, out var bottom) &&\n                    top > 0 && bottom > 0)\n                {\n                    var result = top / bottom;\n                    return result;\n                }\n            }\n        }\n\n        return DoubleOrNull(value);\n    }\n\n    /// <summary>\n    /// Special helper to verify a double is near zero by at least 1%.\n    /// To test if it's near another number, subtract that first and then check if near zero. \n    /// </summary>\n    internal static bool DNearZero(double d) => Math.Abs(d) <= 0.01;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Plumbing/ParseObject.Int.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Plumbing;\n\ninternal static partial class ParseObject\n{\n    /// <summary>\n    /// Check if an object\n    /// </summary>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    internal static int? IntOrNull(object? value)\n    {\n        if (value is null)\n            return null;\n        if (value is int intVal)\n            return intVal;\n\n        var floatVal = DoubleOrNull(value);\n        if (floatVal is null)\n            return null;\n\n        var rounded = (int)Math.Round(floatVal.Value);\n        if (rounded < 1)\n            return 0;\n        return rounded;\n    }\n\n\n    internal static int? IntOrZeroAsNull(object? value)\n    {\n        var val = IntOrNull(value);\n        if (val == 0)\n            return null;\n        return val;\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Sys.Plumbing/ParseObject.String.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.Plumbing;\n\ninternal static partial class ParseObject\n{\n    internal static string? RealStringOrNull(object? value)\n    {\n        if (value == null)\n            return null;\n        if (value is string strValue)\n            return strValue;\n        if (!value.GetType().IsValueType)\n            return null;\n\n        // Only do this for value types\n        strValue = value.ToString() ?? \"error-to-string\";\n        return string.IsNullOrEmpty(strValue)\n            ? null\n            : strValue;\n    }\n\n\n    internal static string? KeepBestString(object? given, object? setting)\n    {\n        if (given == null && setting == null)\n            return null;\n        var strGiven = RealStringOrNull(given);\n        if (strGiven != null)\n            return strGiven;\n        var strSetting = RealStringOrNull(setting);\n        return strSetting;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/ToSic.Sxc.Core.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Core</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Context\\ToSic.Eav.Context.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.ImportExport\\ToSic.Eav.ImportExport.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/ToSic.Sxc.Core.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=context_002Eparameters_005Cparameters/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=context_005Cpage/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=context_005Cparameters/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Ctyped/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cfeatures/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cjson/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cjsonservice/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cpage/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cpageservice/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cuser/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cusersservices/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Html/HtmlAttribute.cs",
    "content": "using ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Web.Sys.Html;\n\n[PrivateApi(\"internal use only, may be removed/changed some day\")]\ninternal class HtmlAttribute\n{\n    /// <summary>\n    /// Generate an HTML attribute\n    /// - but only if in edit mode\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// has trailing space to ensure attributes never \"stick\" together\n    /// we also don't want to use {HttpUtility.HtmlAttributeEncode(value)...\n    /// ...because it makes the html hard to work with when debugging\n    /// so we just manually replace all apos to make sure it doesn't create invalid html\n    /// </remarks>\n    public static IRawHtmlString Create(string name, string? value)\n        => new RawHtmlString($\" {Tag.Attr(name, value)} \");\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Html/HybridHtmlString.cs",
    "content": "﻿#if NETFRAMEWORK\nusing IHtmlString = System.Web.IHtmlString;\n#else\nusing HtmlEncoder = System.Text.Encodings.Web.HtmlEncoder;\n#endif\nusing ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Web.Sys.Html;\n\n/// <summary>\n/// Cross-platform (.net core and framework) HTML string implementation\n///\n/// IMPORTANT: this is a 1:1 copy of the RawHtmlString in RazorBlade, but we needed a `record` implementation\n/// </summary>\n[PrivateApi]\npublic record HybridHtmlString : IRawHtmlString\n{\n    /// <summary>\n    /// Constructor to provide initial value.\n    /// </summary>\n    /// <param name=\"value\"></param>\n    public HybridHtmlString(string value) => _value = value;\n\n    /// <summary>\n    /// Constructor with empty initial value.\n    /// Mainly used when overriding this class, and probably never using _value.\n    /// </summary>\n    protected HybridHtmlString() => _value = \"\";\n    private readonly string _value;\n\n    /// <summary>\n    /// Records automatically overwrite ToString(),\n    /// so we must use another method for providing the desired HTML string.\n    ///\n    /// This is also the method used for any other integration, so overwrite this if you need to change the behavior.\n    /// </summary>\n    /// <returns></returns>\n    protected virtual string ToHtmlString() => _value;\n\n#if NETFRAMEWORK\n    /// <summary>\n    /// This is the serialization for the old-style asp.net razor\n    /// </summary>\n    /// <returns></returns>\n    [PrivateApi]\n    string IHtmlString.ToHtmlString() => ToHtmlString();\n#else\n\n        /// <inheritdoc />\n        [PrivateApi]\n        public void WriteTo(System.IO.TextWriter writer, HtmlEncoder encoder)\n        {\n            if (writer == null) throw new System.ArgumentNullException(nameof(writer));\n            writer.Write(ToHtmlString());\n        }\n#endif\n\n    //public static bool IsStringOrHtmlString(object original, out string asString)\n    //{\n    //    asString = null;\n    //    if (original is null) return false;\n    //    if (original is string strOriginal)\n    //    {\n    //        asString = strOriginal;\n    //        return true;\n    //    }\n    //    if (original is IHtmlString)\n    //    {\n    //        asString = original.ToString();\n    //        return true;\n    //    }\n    //    return false;\n    //}\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Html/HybridHtmlStringLog.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.Html;\n\n/// <summary>\n/// 2023-11-14 Can't make this internal, would cause trouble, going public is necessary otherwise IResponsiveImage etc. fail\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract record HybridHtmlStringLog: HybridHtmlString, IHasLog\n{\n    protected HybridHtmlStringLog(string logName)\n    {\n        Log = new Log(logName);\n    }\n\n    protected HybridHtmlStringLog(ILog parentLog, string logName)\n    {\n        Log = new Log(logName, parentLog);\n    }\n\n\n    public ILog Log { get; init; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Http/IHttp.cs",
    "content": "﻿#if NETFRAMEWORK\nusing System.Web;\n#else\nusing Microsoft.AspNetCore.Http;\n#endif\nusing System.Collections.Specialized;\n\nnamespace ToSic.Sxc.Web.Sys.Http;\n\n/// <summary>\n/// Goal is that anything on this will be able to provide HttpContext operations as needed\n/// To abstract .net451 and .net core\n/// </summary>\n[PrivateApi(\"used to be InternalApi_DoNotUse_MayChangeWithoutNotice, hidden 2021-12\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IHttp\n{\n    /// <summary>\n    /// The standardized HttpContext. It's type changes depending on the framework it's running in\n    /// </summary>\n    HttpContext Current { get; }\n\n    /// <summary>\n    /// The standardized HttpRequest object. It's type changes depending on the framework it's running in.\n    /// </summary>\n    HttpRequest Request { get; }\n\n    /// <summary>\n    /// The standardized QueryString parameters so it works on all platforms\n    /// </summary>\n    NameValueCollection QueryStringParams { get; }\n\n    /// <summary>\n    /// QueryString params as KeyValue Pairs.\n    /// We don't use a dictionary, because sometimes the same key can occur twice.\n    /// </summary>\n    /// <returns></returns>\n    List<KeyValuePair<string, string>> QueryStringKeyValuePairs();\n\n    ///// <summary>\n    ///// Items collection from HttpContext\n    ///// </summary>\n    //IDictionary<object, object> Items { get; }\n\n    string? GetCookie(string cookieName);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Parameters/OriginalParameters.cs",
    "content": "﻿using System.Collections.Specialized;\nusing System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\n\nnamespace ToSic.Sxc.Web.Sys.Parameters;\n\ninternal class OriginalParameters\n{\n    public static string NameInUrlForOriginalParameters = \"originalparameters\";\n\n    /// <summary>\n    /// get url parameters and provide override values to ensure all configuration is \n    /// preserved in AJAX calls\n    /// </summary>\n    /// <param name=\"requestParams\"></param>\n    /// <returns></returns>\n    public static NameValueCollection GetOverrideParams(NameValueCollection requestParams)\n    {\n        if (requestParams == null! /* paranoid */)\n            return [];\n\n        var paramSet = requestParams[NameInUrlForOriginalParameters];\n        return string.IsNullOrEmpty(paramSet)\n            ? requestParams  // just return requestParams (when origParams are not provided)\n            : GetOverrideParams(paramSet);\n    }\n\n    public static NameValueCollection GetOverrideParams(string paramSet)\n    {\n        var urlParams = new NameValueCollection();\n\n        // Workaround for deserializing KeyValuePair -it requires lowercase properties(case sensitive),\n        // which seems to be a bug in some Newtonsoft.Json versions: http://stackoverflow.com/questions/11266695/json-net-case-insensitive-property-deserialization\n        var items = JsonSerializer.Deserialize<List<UpperCaseStringKeyValuePair>>(paramSet, JsonOptions.SafeJsonForHtmlAttributes);\n        items?.ForEach(a => urlParams.Add(a.Key, a.Value));\n\n        return urlParams;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Parameters/UpperCaseStringKeyValuePair.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.Parameters;\n\n/// <summary>\n/// Workaround for deserializing KeyValuePair - it requires lowercase properties (case sensitive), \n/// which seems to be a issue in some Newtonsoft.Json versions: http://stackoverflow.com/questions/11266695/json-net-case-insensitive-property-deserialization\n/// </summary>\n// ReSharper disable once ClassNeverInstantiated.Local\ninternal class UpperCaseStringKeyValuePair\n{\n    // ReSharper disable UnusedAutoPropertyAccessor.Local\n    public string? Key { get; set; }\n    public string? Value { get; set; }\n    // ReSharper restore UnusedAutoPropertyAccessor.Local\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Url/NameObjectSet.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.Url;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class NameObjectSet\n{\n\n    public NameObjectSet(string? name, object? value, string? prefix = default)\n    {\n        Name = name;\n        Value = value;\n        Prefix = prefix;\n    }\n\n    public NameObjectSet(NameObjectSet original, string? name = default, object? value = default, bool? keep = default, string? prefix = default)\n    {\n        Prefix = original?.Prefix;\n        Name = name ?? original?.Name;\n        Value = value ?? original?.Value;\n        Keep = keep ?? original?.Keep ?? Keep;\n        Prefix = prefix ?? original?.Prefix;\n    }\n\n    public string? Prefix { get; }\n\n    public string? Name { get; }\n    public object? Value { get; }\n    public bool Keep { get; } = true;\n\n    public string FullName => Prefix + Name;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Url/ObjectToUrl.cs",
    "content": "﻿using System.Collections;\nusing ToSic.Sys.Performance;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Web.Sys.Url;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ObjectToUrl\n{\n    public ObjectToUrl() { }\n\n    internal ObjectToUrl(string? prefix = null, IEnumerable<UrlValueProcess>? preProcessors = null): this()\n    {\n        Prefix = prefix;\n        _preProcessors = preProcessors;\n    }\n\n    private readonly IEnumerable<UrlValueProcess>? _preProcessors;\n\n    private string? Prefix { get; }\n\n    public string ArrayBoxStart { get; set; } = \"\";\n    public string ArrayBoxEnd { get; set; } = \"\";\n    public string ArraySeparator { get; set; } = \",\";\n    public string DepthSeparator { get; set; } = \":\";\n    public string PairSeparator { get; set; } = UrlParts.ValuePairSeparator.ToString();\n\n    public string KeyValueSeparator { get; set; } = \"=\";\n\n\n    public string? Serialize(object? data)\n        => Serialize(data, Prefix);\n\n    public string? SerializeChild(object child, string? prefix)\n        => SerializeWithChild(null, child, prefix);\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"main\"></param>\n    /// <param name=\"child\"></param>\n    /// <param name=\"childPrefix\">Prefix to use for the child - it is not the same as the Prefix of the main object! as that applies to all data, not child-data</param>\n    /// <returns></returns>\n    public string? SerializeWithChild(object? main, object? child, string? childPrefix = null)\n    {\n        // Exit early\n        if (main == null && child == null)\n            return null;\n\n        var asString = Serialize(main, prefix: null);\n        if (child == null)\n            return asString;\n\n        childPrefix ??= \"\"; // null catch\n        var prefillAddOn = \"\";\n        if (child is string strPrefill)\n        {\n            var parts = strPrefill.Split(UrlParts.ValuePairSeparator)\n                .Where(p => p.HasValue())\n                .Select(p => p.StartsWith(childPrefix) ? p : childPrefix + p);\n            prefillAddOn = string.Join(UrlParts.ValuePairSeparator.ToString(), parts);\n        }\n        else\n            prefillAddOn = Serialize(child, childPrefix);\n\n        return UrlParts.ConnectParameters(asString, prefillAddOn);\n    }\n\n    private UrlValuePair? ValueSerialize(NameObjectSet? set)\n    {\n        if (set == null)\n            return null;\n\n        if (_preProcessors.SafeAny())\n            foreach (var pP in _preProcessors)\n            {\n                set = pP.Process(set);\n                if (set?.Keep != true)\n                    return null;\n            }\n\n        if (set.Value == null)\n            return null;\n        if (set.Value is string strValue)\n            return new(set.FullName, strValue);\n\n        var valueType = set.Value.GetType();\n\n        // Check array - not sure yet if we care\n        if (set.Value is IEnumerable enumerable)\n        {\n            var isGeneric = valueType.IsGenericType;\n            var valueElemType = isGeneric\n                ? valueType.GetGenericArguments()[0]\n                : valueType.GetElementType();\n\n            if (valueElemType == null)\n                throw new ArgumentNullException($\"The field: '{set.FullName}', isGeneric: {isGeneric} with base type {valueType} to add to url seems to have a confusing setup\");\n\n            if (valueElemType.IsPrimitive || valueElemType == typeof(string))\n                return new(set.FullName, $\"{ArrayBoxStart}{string.Join(ArraySeparator, enumerable.Cast<object>())}{ArrayBoxEnd}\");\n\n            return new(set.FullName, \"array-like-but-unclear-what\");\n        }\n\n        return valueType.IsSimpleType()\n            // Simple type - just serialize, except for bool, which should be lower-cased\n            ? new(set.FullName, set.Value is bool bln\n                ? bln ? \"true\" : \"false\"\n                : set.Value.ToString()\n                )\n            // Complex object, recursive serialize with current name as prefix\n            : new UrlValuePair(null, Serialize(set.Value, set.FullName + DepthSeparator), true);\n    }\n\n    private string? Serialize(object? data, string? prefix)\n    {\n        // Case #1: Null, return that\n        if (data == null)\n            return null;\n\n        // Case #2: Already a string, return that\n        if (data is string str)\n            return str;\n\n        // Case #3: It's an object or an array of objects (but not a string)\n        var objectList = data as IEnumerable ?? new[] { data };\n\n        // Get all properties on the object\n        var properties = objectList\n            .Cast<object>()\n            .SelectMany(d => PropsOfOne(d, prefix))\n            .ToList();\n\n        // Concat all key/value pairs into a string separated by ampersand\n        return string.Join(PairSeparator, properties.Select(p => p.ToString()));\n\n    }\n\n    // https://ole.michelsen.dk/blog/serialize-object-into-a-query-string-with-reflection/\n    // https://stackoverflow.com/questions/6848296/how-do-i-serialize-an-object-into-query-string-format\n    private IEnumerable<UrlValuePair> PropsOfOne(object? data, string? prefix)\n    {\n        // Case #1: Null, return that\n        if (data == null)\n            return [];\n\n        // Case #2: Already a string, return that\n        if (data is string str)\n            return str.HasValue()\n                ? [new(null, str, true)]\n                : [];\n\n        // Case #3: It's an object or an array of objects (but not a string)\n        // Get all properties on the object\n        var properties = data.GetType()\n            .GetProperties()\n            .Where(x => x.CanRead)\n            .Select(x =>\n            {\n                // Check if it's a key value pair (from a dictionary) - like on note\n                var kvpPair = PropOfKvp(data);\n                var preSerialize = kvpPair != null\n                    ? new(kvpPair.Name, kvpPair.Value, prefix)\n                    : new NameObjectSet(x.Name, x.GetValue(data, null), prefix);\n                return ValueSerialize(preSerialize);\n            })\n            .Where(x => x?.Value != null)\n            .Cast<UrlValuePair>()\n            .ToListOpt();\n\n        // Concat all key/value pairs into a string separated by ampersand\n        return properties;\n\n    }\n\n    // https://stackoverflow.com/questions/2729614/c-sharp-reflection-how-can-i-tell-if-object-o-is-of-type-keyvaluepair-and-then\n    private NameObjectSet? PropOfKvp(object? value)\n    {\n        if (value == null)\n            return null;\n        var valueType = value.GetType();\n        if (!valueType.IsGenericType)\n            return null;\n            \n        var baseType = valueType.GetGenericTypeDefinition();\n        if (baseType != typeof(KeyValuePair<,>))\n            return null;\n            \n        //var argTypes = baseType.GetGenericArguments();\n        // now process the values\n        if (valueType.GetProperty(\"Key\")?.GetValue(value, null) is not string kvpKey)\n            return null;\n\n        return valueType.GetProperty(\"Value\")?.GetValue(value, null) is not { } kvpValue \n            ? null \n            : new NameObjectSet(name: kvpKey, value: kvpValue);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Url/UrlHelpers.cs",
    "content": "﻿using System.Collections.Specialized;\nusing System.Diagnostics.CodeAnalysis;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Web.Sys.Url;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class UrlHelpers\n{\n    /// <summary>\n    /// Safer replacement to the HttpUtility.ParseQueryString because that changes umlauts etc. to %u0043 characters which is not very common\n    /// </summary>\n    /// <param name=\"query\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// See https://stackoverflow.com/questions/68624/how-to-parse-a-query-string-into-a-namevaluecollection-in-net\n    /// </remarks>\n    public static NameValueCollection ParseQueryString(string? query)\n    {\n        // Note that this NameValueCollection is different from the one from HttpUtility\n        // but because that one is internal, we cannot create one directly\n        var nvc = new NameValueCollection();\n        query = query?.Trim() ?? \"\";\n        if (string.IsNullOrWhiteSpace(query))\n            return nvc;\n\n        // remove anything other than query string from url\n        if (query.StartsWith(\"?\"))\n            query = query.Substring(1);\n\n        foreach (var vp in query.Split('&'))\n        {\n            if (string.IsNullOrWhiteSpace(vp))\n                continue;\n\n            var singlePair = vp.Split('=');\n            nvc.Add(singlePair[0], singlePair.Length == 2 ? singlePair[1] : string.Empty);\n        }\n\n        return nvc;\n    }\n\n    /// <summary>\n    /// Converts a NameValueCollection to string.\n    /// Used in link generations and especially also the <see cref=\"Parameters\"/>\n    /// so be very careful if you change anything!\n    /// </summary>\n    /// <param name=\"nvc\"></param>\n    /// <param name=\"prioritize\"></param>\n    /// <returns></returns>\n    public static NameValueCollection Sort(this NameValueCollection nvc, string? prioritize = default)\n    {\n        // Figure Out best key order, respecting the custom prioritization\n        var customKeys = prioritize.CsvToArrayWithoutEmpty().ToList();\n        var keys = customKeys.Count > 0\n            ? nvc.AllKeys.OrderBy(key =>\n            {\n                // find index case-insensitive\n                var index = customKeys.FindIndex(x => x.EqualsInsensitive(key));\n                var prefix = index != -1\n                    ? index.ToString(\"000\")\n                    : \"999\";\n                return $\"{prefix}-{key}\";\n                // 2026-03-23 check if it has a value, because otherwise we want it at the end\n                // goal was to prevent this kind of url: \"details=234&1-this-is-a-title\" from re-sorting and placing the value \"1-...\" in front.\n                // But this does not work, so it's disabled again and left here so the next person won't try it again\n                // we wanted to have slugs at the end, but there is no clear way to detect the slug,\n                // because \"&not-slug=&slug-url-part\" will both have a null-value, so sorting it would not be\n                // what we expect.\n                // So the only reliable way to get slugs at the end is to say \"name=slug\"\n                //return prefix + \"-\" + (nvc.GetValues(key)?.Length > 0 ? $\"a-{key}\" : $\"z-{key}\");\n            })\n            : nvc.AllKeys.OrderBy(key => key\n                // check if it has a value, because otherwise we want it at the end\n                // see note above, this cannot work\n                //nvc.GetValues(key)?.Length > 0 ? $\"a-{key}\" : $\"z-{key}\"\n            );\n\n        // create a new NVC but sorted\n        var sorted = new NameValueCollection();\n        foreach (var key in keys)\n        {\n            var values = nvc.GetValues(key)?.OrderBy(v => v).ToArray();\n            if (values == null || values.Length == 0)\n                sorted.Add(key, null);\n            else\n                foreach (var value in values)\n                    sorted.Add(key, value);\n        }\n        return sorted;\n    }\n\n\n    /// <summary>\n    /// Converts a NameValueCollection to string.\n    /// Used in link generations and especially also the <see cref=\"Parameters\"/>\n    /// so be very careful if you change anything!\n    /// </summary>\n    /// <param name=\"nvc\"></param>\n    /// <returns></returns>\n    public static string NvcToString(this NameValueCollection nvc) \n        => NvcToString(nvc, \"=\", \"&\", \"\", \"\", true, null);\n\n    private class KeyValuePairTemp\n    {\n        public required string Key;\n        public required string? Value;\n    }\n\n    internal static string NvcToString(NameValueCollection nvc, string keyValueSeparator, string pairSeparator,\n        string terminator, string empty, bool repeatKeyForEachValue, string? valueSeparator)\n    {\n        // Note 2dm: reworked this entire logic 2022-04-07, all tests passed, believe it's ok, but there is a minimal risk\n        var allPairs = nvc.AllKeys\n            .SelectMany(key =>\n            {\n                var values = nvc.GetValues(key);\n                var noValues = values == null || values.Length == 0;\n                if (!noValues)\n                {\n                    values = values!\n                        .Where(v => !string.IsNullOrEmpty(v))\n                        .ToArray();\n                    noValues = values.Length == 0;\n                }\n\n                // Key null; 2 options left, values or no values\n                if (key is null)\n                    return noValues\n                        ? []\n                        // If no key, treat the values as standalone keys\n                        : values!\n                            .Select(v => new KeyValuePairTemp { Key = v, Value = null })\n                            .ToArray();\n\n                // Key not null, no values\n                if (noValues)\n                    return [new() { Key = key, Value = null }];\n\n                // Key null, values - two options - give as array or single item\n                return repeatKeyForEachValue \n                    ? values!\n                        .Select(v => new KeyValuePairTemp { Key = key, Value = v.ToString() }) \n                    : [new() { Key = key, Value = string.Join(valueSeparator, values!) }];\n            })\n            .Select(set => set.Key + (string.IsNullOrEmpty(set.Value) ? \"\" : keyValueSeparator + set.Value))\n            //.SelectMany(set =>\n            //{\n            //    var key = set.Key;\n            //    // Important - both key and values can be null; values can be a list of things\n            //    var values = set.AllValues;// nvc.GetValues(key);\n            //    var noValues = (values == null || values.Length == 0);\n            //    if (key is null)\n            //    {\n            //        if (noValues) return Array.Empty<string>();\n            //        if (repeatKeyForEachValue)\n            //            return values.Select(v => v.ToString())\n            //                .ToArray();\n            //        return new[] { string.Join(valueSeparator, values) };\n            //    }\n\n            //    if (noValues) return new[] { key };\n\n            //    if (repeatKeyForEachValue)\n            //        return values.Select(v => key + (string.IsNullOrEmpty(v) ? \"\" : keyValueSeparator + v));\n\n            //    return new[] { key + (values.All(string.IsNullOrEmpty) ? \"\" : keyValueSeparator + string.Join(valueSeparator, values)) };\n            //})\n            .ToArray();\n\n        return allPairs.Any()\n            ? string.Join(pairSeparator, allPairs) + terminator\n            : empty;\n    }\n\n\n    /// <summary>\n    /// Import an NVC into another\n    /// </summary>\n    /// <returns></returns>\n    public static NameValueCollection Merge(this NameValueCollection first, NameValueCollection source, bool replace = false)\n    {\n        var target = new NameValueCollection(first);\n        source.AllKeys\n            .Where(k => !string.IsNullOrEmpty(k))\n            .ToList()\n            .ForEach(k =>\n            {\n                string?[] values = source.GetValues(k) ?? [null!]; // catch null-values\n\n                foreach (var v in values)\n                {\n                    if (replace)\n                        target.Set(k, v);\n                    else\n                        target.Add(k, v);\n                }\n            });\n        return target;\n    }\n\n\n    public static string QuickAddUrlParameter(string url, string name, string value) \n        => $\"{url}{(url.IndexOf('?') > 0 ? '&' : '?')}{name}={value}\";\n\n\n    [return: NotNullIfNotNull(nameof(url))]\n    public static string? AddQueryString(string url, string newParams)\n        => AddQueryString(url, ParseQueryString(newParams));\n\n    [return: NotNullIfNotNull(nameof(url))]\n    public static string? AddQueryString(string? url, NameValueCollection? newParams)\n    {\n        // check do we have any work to do\n        if (newParams == null || newParams.Count == 0)\n            return url;\n\n        // 1. Get only the query string parts\n        var parts = new UrlParts(url);\n\n        // if the url already has some params we should take that and split it into it's pieces\n        var queryParams = ParseQueryString(parts.Query);\n\n        // new params would replace existing queryString params or append new param to queryString\n        var finalParams = queryParams.Merge(newParams);\n\n        // combine new query string in url\n        return GetUrlWithUpdatedQueryString(parts, finalParams);\n    }\n\n\n    private static string GetUrlWithUpdatedQueryString(UrlParts parts, NameValueCollection queryString)\n    {\n        var newUrl = parts.ToLink(suffix: false);\n        if (queryString.Count > 0)\n            newUrl += UrlParts.QuerySeparator + NvcToString(queryString);\n\n        if (!string.IsNullOrWhiteSpace(parts.Fragment))\n            newUrl += UrlParts.FragmentSeparator + parts.Fragment;\n\n        return newUrl;\n\n    }\n\n\n    public static string RemoveQuery(this string url) => RemoveAfterSeparator(url, UrlParts.QuerySeparator);\n    public static string RemoveFragment(this string url) => RemoveAfterSeparator(url, UrlParts.FragmentSeparator);\n    public static string RemoveQueryAndFragment(this string url) => url.RemoveQuery().RemoveFragment();\n    private static string RemoveAfterSeparator(string @string, char separator)\n    {\n        if (string.IsNullOrEmpty(@string)) return @string;\n        var start = @string.IndexOf(separator);\n        return start < 0 ? @string : @string.Substring(0, start);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Url/UrlParts.cs",
    "content": "﻿using System.Text;\n\nnamespace ToSic.Sxc.Web.Sys.Url;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class UrlParts\n{\n    public const char QuerySeparator = '?';\n    public const char FragmentSeparator = '#';\n    public const char ValuePairSeparator = '&';\n    public const string ProtocolColon = \":\";\n    public const string Slash = \"/\";\n    public const string ProtocolSeparator = \"://\";\n    public const string RootWithoutProtocol = \"//\";\n\n\n    public string Url;\n    public string Query = string.Empty;\n    public string Fragment = string.Empty;\n    public string Path = string.Empty;\n    public string Protocol = string.Empty;\n    public string Domain = string.Empty;\n\n    public UrlParts(string? url)\n    {\n        url = (url ?? \"\").Trim();\n        Url = url;\n        if (string.IsNullOrEmpty(url)) return;\n\n        var rest = url;\n        rest = ExtractFragment(url, rest);\n        Path = rest;\n        rest = ExtractQuery(rest);\n        Path = rest;\n        rest = ExtractProtocol(rest);\n        Path = rest;\n\n        // now check domain - only valid if the link had a \"//\" in it to start with or after the protocol\n        var domainAtStartPossible = !string.IsNullOrEmpty(Protocol);\n        rest = ExtractDomain(domainAtStartPossible, rest);\n        Path = rest;\n\n    }\n\n    public void ReplaceRoot(string url)\n    {\n        if (string.IsNullOrEmpty(url)) return;\n\n        if (!url.Contains(Slash) && !url.Contains(ProtocolColon))\n            Domain = url;\n        else\n        {\n            var newParts = new UrlParts(url);\n            if (!string.IsNullOrEmpty(newParts.Domain)) Domain = newParts.Domain;\n            if (!string.IsNullOrEmpty(newParts.Protocol)) Protocol = newParts.Protocol;\n        }\n        if(!string.IsNullOrEmpty(Domain) && string.IsNullOrEmpty(Protocol))\n            Protocol = RootWithoutProtocol;\n    }\n\n    private string ExtractDomain(bool domainAtStartPossible, string rest)\n    {\n        if (domainAtStartPossible && !string.IsNullOrEmpty(rest))\n        {\n            var postDomainSlash = rest.IndexOf('/');\n            if (postDomainSlash == -1) postDomainSlash = rest.Length;\n            Domain = rest.Substring(0, postDomainSlash);\n            rest = rest.Substring(postDomainSlash);\n        }\n\n        return rest;\n    }\n\n    private string ExtractProtocol(string rest)\n    {\n        if (rest.StartsWith(RootWithoutProtocol))\n        {\n            Protocol = RootWithoutProtocol;\n            rest = rest.Substring(RootWithoutProtocol.Length);\n            return rest;\n        }\n\n        var separator = rest.IndexOf(ProtocolSeparator, StringComparison.Ordinal);\n        // protocol would have to be at least 1 char\n        if (separator > 1)\n        {\n            Protocol = rest.Substring(0, separator + ProtocolSeparator.Length);\n            rest = rest.Substring(Protocol.Length); // drop protocol + ':'\n        }\n\n        return rest;\n    }\n\n    private string ExtractQuery(string rest)\n    {\n        var queryStart = rest.IndexOf(QuerySeparator);\n        if (queryStart < 0) return rest;\n        Query = rest.Substring(queryStart + 1);\n        return rest.Substring(0, queryStart);\n    }\n\n    private string ExtractFragment(string url, string rest)\n    {\n        var fragmentStart = rest.IndexOf(FragmentSeparator);\n        if (fragmentStart < 0) return rest;\n        Fragment = url.Substring(fragmentStart + 1);\n        return url.Substring(0, fragmentStart);\n    }\n\n    public bool IsAbsolute => !string.IsNullOrEmpty(Protocol); // Path.StartsWith(\"//\") || Path.StartsWith(\"http://\") || Path.StartsWith(\"https://\");\n    public bool IsRelative => Path.StartsWith(\".\") && !IsAbsolute && !string.IsNullOrEmpty(Domain);\n\n\n    public string ToLink(string? format = null, bool suffix = true)\n    {\n        var endPart = Path + (suffix ? Suffix() : \"\");\n        if (format == \"/\") return endPart;\n        if (format == \"//\")\n            return string.IsNullOrEmpty(Domain)\n                ? endPart\n                : RootWithoutProtocol + Domain + endPart;\n\n        return Protocol + Domain + endPart;\n    }\n\n    public string BuildUrl()\n    {\n        var urlStringBuilder = new StringBuilder(!string.IsNullOrEmpty(Path) ? Path : string.Empty);\n        AppendSuffix(urlStringBuilder);\n        return urlStringBuilder.ToString();\n    }\n\n    // would return the entire suffix starting from the `?` _including_ the `?` or `#` - if nothing is there, empty string\n    public string Suffix()\n    {\n        var urlStringBuilder = new StringBuilder();\n        AppendSuffix(urlStringBuilder);\n        return urlStringBuilder.ToString();\n    }\n\n    private void AppendSuffix(StringBuilder urlStringBuilder)\n    {\n        if (!string.IsNullOrEmpty(Query)) urlStringBuilder.Append($\"{QuerySeparator}{Query}\");\n        if (!string.IsNullOrEmpty(Fragment)) urlStringBuilder.Append($\"{FragmentSeparator}{Fragment}\");\n    }\n\n    public static string ConnectParameters(params string?[]? parameters)\n    {\n        if (parameters == null || parameters.Length == 0)\n            return \"\";\n        var realParams = parameters.Where(p => !string.IsNullOrWhiteSpace(p)).ToArray();\n        return string.Join(ValuePairSeparator.ToString(), realParams);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Url/UrlValueCamelCase.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Web.Sys.Url;\n\n/// <summary>\n/// Helper to process url values - and keep or skip certain properties.\n/// Note that it is case-insensitive\n/// </summary>\ninternal class UrlValueCamelCase : UrlValueProcess\n{\n    public override NameObjectSet? Process(NameObjectSet? set)\n    {\n        if (set == null || !set.Name.HasValue())\n            return set;\n        var firstCharLower = char.ToLowerInvariant(set.Name[0]);\n        if (firstCharLower == set.Name[0]) return set;\n        var newName = firstCharLower + set.Name.Substring(1);\n        return new(set, newName);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Url/UrlValueFilterNames.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.Url;\n\n/// <summary>\n/// Helper to process url values - and keep or skip certain properties.\n/// Note that it is case-insensitive\n/// </summary>\ninternal class UrlValueFilterNames: UrlValueProcess\n{\n    /// <summary>\n    /// Determine names of properties to preserve in the final parameters\n    /// </summary>\n    /// <param name=\"defaultSerialize\"></param>\n    /// <param name=\"opposite\"></param>\n    public UrlValueFilterNames(bool defaultSerialize, IEnumerable<string> opposite)\n    {\n        PropSerializeDefault = defaultSerialize;\n        foreach (var sProp in opposite)\n            PropSerializeMap[sProp] = !PropSerializeDefault;\n    }\n\n    /// <summary>\n    /// Determine if not-found properties should be preserved or not - default is preserve, but init can reverse this\n    /// </summary>\n    internal bool PropSerializeDefault;\n    internal Dictionary<string, bool> PropSerializeMap = new(StringComparer.InvariantCultureIgnoreCase);\n\n\n    public override NameObjectSet? Process(NameObjectSet? set)\n    {\n        if (set?.Name == null)\n            return null;\n\n        return PropSerializeMap.TryGetValue(set.Name, out var reallyUse)\n            ? new(set, keep: reallyUse) \n            : new NameObjectSet(set, keep: PropSerializeDefault); \n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Url/UrlValuePair.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.Url;\n\n/// <summary>\n/// Helper class to prepare data for use in a url parameter.\n/// Especially useful to ensure that the value part is encoded, but not re-encoded.\n/// </summary>\ninternal class UrlValuePair(string? name, string? value, bool isEncoded = false)\n{\n    public string? Name { get; } = name;\n    public string? Value { get; } = value;\n    public bool IsEncoded { get; } = isEncoded;\n\n    public override string ToString()\n    {\n        var start = Name != null\n            ? Name + \"=\"\n            : null;\n        var val = IsEncoded\n            ? Value\n            : Value == null\n                ? null\n                // Note: Uri.EscapeDataString encodes commas as %2C, so we replace them back to commas.\n                // Previously we used Uri.EscapeUriString, but that has been deprecated. It left commas as-is.\n                : Uri.EscapeDataString(Value).Replace(\"%2C\", \",\");\n        return $\"{start}{val}\";\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.Url/UrlValueProcess.cs",
    "content": "﻿using ToSic.Eav.Serialization.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Web.Sys.Url;\n\n/// <summary>\n/// Base class for processing URL Values before keeping / converting to a string-url\n/// </summary>\ninternal abstract class UrlValueProcess\n{\n    public abstract NameObjectSet? Process(NameObjectSet? set);\n\n    // Base64 marker for rule encoding\n    public static string Base64Prefix = \"base64:\";\n    public static string Json64Prefix = \"json64:\";\n\n    public static char[] UnsafeChars =\n    [\n        '\\n', '\\r',\n        '<', '>',\n        '\"', '\\'',\n        '=', '&', '?', '#'\n    ];\n\n    /// <summary>\n    /// Converts any string value which contains unsafe characters to base64\n    /// Works for SVG icons and similar\n    /// Requires the receiving system (in this case the inpage JS) to handle strings starting with \"base64:\" differently. \n    /// </summary>\n    /// <param name=\"set\"></param>\n    /// <returns></returns>\n    protected NameObjectSet MakeSafe(NameObjectSet set)\n    {\n        var obj = set.Value;\n        return obj is string str && str.HasValue() && UnsafeChars.Any(c => str.Contains(c))\n            ? new(set, value: $\"{Base64Prefix}{Base64.Encode(str)}\")\n            : set;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core/Web/Sys.WebResources/WebResourceConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.WebResources;\n\ninternal class WebResourceConstants\n{\n    public static string WebResourcesNode = \"WebResources\";\n\n    public static string CdnSourcePublicField = \"CdnSourcePublic\";\n\n    public static string CdnSourceEditField = \"CdnSourceEdit\";\n\n    // Note: this should not change often\n    // As usually new versions of assets will often run side-by side with older versions\n    // But do keep in sync w/2sxc versions (possibly just not upgrade as only small things change) for clarity\n    public const string VersionSuffix = \"/v15\";\n\n    //internal const string Cdn2SxcRoot = \"https://cdn.2sxc.org/packages\";\n    //internal const string CdnLocalRoot = \"/cdn/packages\";\n\n    internal const string CdnDefault = \"cdn\";\n    //internal const string Cdn2Sxc = \"cdn.2sxc.org\";\n    //internal const string CdnLocal = \"local\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core.TestHelpers/Adam/MockSxcFile.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Field;\n\nnamespace ToSic.Sxc.Adam;\n\npublic class MockSxcFile : Eav.Apps.Assets.MockFile, IFile, IHasLink\n{\n    private IMetadata _metadata;\n    private ITypedMetadata _metadata1;\n    public bool HasMetadata { get; init; } = false;\n\n    ITypedMetadata IAsset.Metadata => _metadata1;\n\n    public string Url { get; init; }\n    public string Type => AssetTypeNames.GetTypeName(Extension);\n\n    IMetadata IHasMetadata.Metadata => _metadata;\n\n    public IField Field { get; set; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core.TestHelpers/Adam/MockSxcFolder.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Adam;\n\npublic class MockSxcFolder: MockFolder, IFolder\n{\n    private IMetadata _metadata;\n    private ITypedMetadata _metadata1;\n    public bool HasMetadata { get; }\n\n    ITypedMetadata IAsset.Metadata => _metadata1;\n\n    public string Url { get; init; }\n    public string Type { get; init; }\n\n    IMetadata IHasMetadata.Metadata => _metadata;\n\n    public IField Field { get; set; }\n    public IEnumerable<IFile> Files { get; init; }\n    public IEnumerable<IFolder> Folders { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core.TestHelpers/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using ToSic.Sys.Coding;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core.TestHelpers/Services.PageService/MockPageService.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Services.PageService;\n\npublic class MockPageService: IPageService\n{\n    public string Activate(params string[] keys) => \"\";\n\n    public string Activate(NoParamOrder npo = default, bool condition = true, params string[] features) => \"\";\n\n    public IRawHtmlString AssetAttributes(NoParamOrder npo = default, bool optimize = true, int priority = 0,\n        string position = null, bool whitelist = true) =>\n        new RawHtmlString(\"\");\n\n    public string AddCsp(string name, params string[] values) => \"\";\n\n    public string SetBase(string url = null) => \"\";\n\n    public string SetTitle(string value, string placeholder = null) => \"\";\n\n    public string SetDescription(string value, string placeholder = null) => \"\";\n\n    public string SetKeywords(string value, string placeholder = null) => \"\";\n\n    public string SetHttpStatus(int statusCode, string message = null) => \"\";\n\n    public string AddToHead(string tag) => \"\";\n\n    public string AddMeta(string name, string content) => \"\";\n\n    public string AddOpenGraph(string property, string content) => \"\";\n\n    public string AddJsonLd(string jsonString) => \"\";\n\n    public string AddJsonLd(object jsonObject) => \"\";\n\n    public string AddIcon(string path, NoParamOrder npo = default, string rel = \"\", int size = 0, string type = null) => \"\";\n\n    public string AddIconSet(string path, NoParamOrder npo = default, object favicon = null, IEnumerable<string> rels = null,\n        IEnumerable<int> sizes = null) =>\n        \"\";\n\n    public List<string> FeatureKeysAdded { get; }\n\n    public string TurnOn(object runOrSpecs, NoParamOrder npo = default, object require = default, object data = default,\n        IEnumerable<object> args = default, bool condition = true, bool? noDuplicates = default, string addContext = default) =>\n        \"\";\n\n    public string AddToHead(IHtmlTag tag) => \"\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Core.TestHelpers/ToSic.Sxc.Core.TestHelpers.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForTestCode.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps.TestsHelpers\\ToSic.Eav.Apps.TestHelpers.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n  </ItemGroup>\n\n  </Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Data/CustomItem.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Models;\nusing ToSic.Eav.Models.Factory;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Models;\nusing ToSic.Sxc.Data.Options;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services.Tweaks;\nusing ToSic.Sys.GetByName;\n\nnamespace Custom.Data;\n\n/// <summary>\n/// Base class for custom data objects, which extend the <see cref=\"ITypedItem\"/> for use in Razor Components.\n/// </summary>\n/// <example>\n///\n/// Usage ca. like this:\n///\n/// 1. A custom data model in `AppCode.Data` which inherits from this class (usually generated by 2sxc Copilot)\n/// 2. Razor code which uses it to convert typed items into this custom data model\n/// \n/// Example trivial custom **ITyped** data model:\n/// ```c#\n/// namespace AppCode.Data\n/// {\n///   class MyPerson : Custom.Data.CustomItem\n///   {\n///     // New custom property\n///     public string Name => _item.String(\"Name\");\n///   }\n/// }\n/// ```\n///\n/// Example usage in Razor:\n///\n/// ```razor#\n/// @inherits Custom.Hybrid.RazorTyped\n/// @using AppCode.Data\n/// @{\n///   var person = As&lt;MyPerson&gt;(MyItem);\n/// }\n/// @* Now you can use the custom properties *@\n/// <span>@person.Name</span>\n/// @* But also all the standard properties like Id, Guid, Title, Type, etc. *@\n/// <span>@person.Id / @person.Guid</span>\n/// ```\n/// </example>\n/// <remarks>\n/// It is used by 2sxc Copilot when generating base classes for custom data objects.\n///\n/// History\n/// \n/// * Released in v17.06\n/// * It's not abstract, even if the most common case is to inherit, as there are cases where you want to use it directly.\n/// </remarks>\n[PublicApi]\n[ModelSpecs(ContentType = ModelSpecsAttribute.ForAnyContentType)]\npublic partial class CustomItem: ITypedItem, IModelSetupWithFactory<ITypedItem>, IHasPropLookup, IModelFactoryRequired\n{\n    #region Explicit Interfaces for internal use - Setup, etc.\n\n\n    void IModelSetupWithFactory<ITypedItem>.Setup(ITypedItem source, IModelFactory modelFactory)\n    {\n        _item = source;\n        _modelFactory = modelFactory;\n    }\n    private IModelFactory _modelFactory = null!;\n\n    /// <summary>\n    /// The actual item which is being wrapped, in rare cases where you must access it.\n    ///\n    /// It's only on the explicit interface, so it is not available from outside or inside, unless you cast to it.\n    /// Goal is that inheriting classes don't access it to keep API surface small.\n    /// </summary>\n    ITypedItem ICanBeItem.Item\n        => _item;\n\n    /// <summary>\n    /// This is necessary so the object can be used in places where an IEntity is expected,\n    /// like toolbars.\n    ///\n    /// It's an explicit interface implementation, so that the object itself doesn't broadcast this.\n    /// </summary>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IEntity ICanBeEntity.Entity => _item.Entity;\n\n    [field: AllowNull, MaybeNull]\n    IPropertyLookup IHasPropLookup.PropertyLookup\n        => field ??= ((IHasPropLookup)((ICanBeItem)this).Item).PropertyLookup;\n\n    #endregion\n\n    /// <summary>\n    /// The item - for inheriting classes to access.\n    /// </summary>\n    /// <remarks>\n    /// * this property is protected, not public, as it should only be used internally.\n    /// * this also prevents it from being serialized in JSON, which is good.\n    /// * it uses an unusual name `_item` to avoid naming conflicts with properties generated in inheriting classes.\n    /// </remarks>\n#pragma warning disable IDE1006\n    // ReSharper disable once InconsistentNaming\n    protected internal ITypedItem _item { get; private set; } = null!;\n#pragma warning restore IDE1006\n\n    /// <summary>\n    /// Override ToString to give more information about the current object\n    /// </summary>\n    public override string ToString() \n        => $\"{nameof(CustomItem)} Data Model {GetType().FullName} \"\n           + (_item == null! ? \"without backing data (null)\" : $\"for id:{Id} ({_item})\");\n\n\n    #region Keys and Empty-Checks\n\n    /// <inheritdoc cref=\"IHasKeys.ContainsKey\"/>\n    public bool ContainsKey(string name)\n        => ((IHasKeys)_item).ContainsKey(name);\n\n    /// <inheritdoc cref=\"IHasKeys.Keys\"/>\n    public IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default)\n        => _item.Keys(npo, only);\n\n    /// <inheritdoc cref=\"IHasKeys.IsEmpty\"/>\n    public bool IsEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => _item.IsEmpty(name, npo, language: language);\n\n    /// <inheritdoc cref=\"IHasKeys.IsNotEmpty\"/>\n    public bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => _item.IsNotEmpty(name, npo, language: language);\n\n    #endregion\n\n\n    #region Basic Get\n\n    /// <inheritdoc />\n    public object? Get(string name, NoParamOrder npo = default, bool? required = default, string? language = default)\n        => _item.Get(name: name, npo: npo, required: required, language: language);\n\n    /// <inheritdoc />\n    public TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default, bool? required = default, string? language = default)\n        => _item.Get(name: name, npo: npo, fallback: fallback, required: required, language: language);\n\n    #endregion\n\n    #region Typed Get\n\n    /// <inheritdoc />\n    public bool Bool(string name, NoParamOrder npo = default, bool fallback = default, bool? required = default) => _item.Bool(name, npo, fallback, required);\n\n    /// <inheritdoc />\n    public DateTime DateTime(string name, NoParamOrder npo = default, DateTime fallback = default,\n        bool? required = default) =>\n        _item.DateTime(name, npo, fallback, required);\n\n    /// <inheritdoc />\n    public string? String(string name, NoParamOrder npo = default, string? fallback = default, bool? required = default, object? scrubHtml = default)\n        => _item.String(name, npo, fallback, required, scrubHtml);\n\n    /// <inheritdoc />\n    public int Int(string name, NoParamOrder npo = default, int fallback = default, bool? required = default) => _item.Int(name, npo, fallback, required);\n\n    /// <inheritdoc />\n    public long Long(string name, NoParamOrder npo = default, long fallback = default, bool? required = default) => _item.Long(name, npo, fallback, required);\n\n    /// <inheritdoc />\n    public float Float(string name, NoParamOrder npo = default, float fallback = default, bool? required = default) => _item.Float(name, npo, fallback, required);\n\n    /// <inheritdoc />\n    public decimal Decimal(string name, NoParamOrder npo = default, decimal fallback = default, bool? required = default) => _item.Decimal(name, npo, fallback, required);\n\n    /// <inheritdoc />\n    public double Double(string name, NoParamOrder npo = default, double fallback = default, bool? required = default) => _item.Double(name, npo, fallback, required);\n\n    /// <inheritdoc />\n    public string? Url(string name, NoParamOrder npo = default, string? fallback = default, bool? required = default) => _item.Url(name, npo, fallback, required);\n\n    #endregion\n\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    public bool IsDemoItem => _item.IsDemoItem;\n\n    #region Advanced Get Methods: Attribute, Html, File, Folder etc.\n\n    /// <inheritdoc />\n    public IRawHtmlString? Attribute(string name, NoParamOrder npo = default, string? fallback = default,\n        bool? required = default) =>\n        _item.Attribute(name, npo, fallback, required);\n\n    /// <inheritdoc />\n    public IHtmlTag? Html(string name, NoParamOrder npo = default, object? container = default, bool? toolbar = default,\n        object? imageSettings = default, bool? required = default, bool debug = default, Func<ITweakInput<string>, ITweakInput<string>>? tweak = default) =>\n        _item.Html(name, npo, container, toolbar, imageSettings, required, debug, tweak);\n\n    /// <inheritdoc />\n    public IResponsivePicture? Picture(string name, NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? settings = default,\n        object? factor = default, object? width = default, string? imgAlt = default, string? imgAltFallback = default,\n        string? imgClass = default, object? imgAttributes = default, string? pictureClass = default,\n        object? pictureAttributes = default, object? toolbar = default, object? recipe = default) =>\n        _item.Picture(name, npo, tweak, settings, factor, width, imgAlt, imgAltFallback, imgClass, imgAttributes, pictureClass, pictureAttributes, toolbar, recipe);\n\n    /// <inheritdoc />\n    public IResponsiveImage? Img(string name, NoParamOrder npo = default, Func<ITweakMedia, ITweakMedia>? tweak = default, object? settings = default, object? factor = default, object? width = default,\n        string? imgAlt = default, string? imgAltFallback = default, string? imgClass = default, object? imgAttributes = default, object? toolbar = default, object? recipe = default) =>\n        _item.Img(name, npo, tweak, settings, factor, width, imgAlt, imgAltFallback, imgClass, imgAttributes, toolbar, recipe);\n\n    /// <inheritdoc />\n    public IFolder? Folder(string name, NoParamOrder npo = default, bool? required = default)\n        => _item.Folder(name, npo, required);\n\n    /// <inheritdoc />\n    public IFile? File(string name, NoParamOrder npo = default, bool? required = default)\n        => _item.File(name, npo, required);\n\n    #endregion\n\n    #region Children and Parents\n\n    /// <inheritdoc />\n    public ITypedItem? Child(string name, NoParamOrder npo = default, bool? required = default, GetRelatedOptions? options = default)\n        => _item.Child(name, npo, required, options: options);\n\n    /// <inheritdoc />\n    public IEnumerable<ITypedItem> Children(string? field, NoParamOrder npo = default, string? type = default, bool? required = default, GetRelatedOptions? options = default)\n        => _item.Children(field, npo, type, required, options);\n\n    /// <inheritdoc />\n    public ITypedItem? Parent(NoParamOrder npo = default, bool? current = default, string? type = default, string? field = default, GetRelatedOptions? options = default)\n        => _item.Parent(npo, current, type, field, options: options);\n\n    /// <inheritdoc />\n    public IEnumerable<ITypedItem> Parents(NoParamOrder npo = default, string? type = default, string? field = default, GetRelatedOptions? options = default)\n        => _item.Parents(npo, type, field, options: options);\n\n    #endregion\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    public bool IsPublished => _item.IsPublished;\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    public IPublishing Publishing => _item.Publishing;\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    public ITypedItem? Presentation => _item.Presentation;\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    public ITypedMetadata Metadata => _item.Metadata;\n\n    /// <inheritdoc />\n    public IField? Field(string name, NoParamOrder npo = default, bool? required = default)\n        => _item.Field(name, npo, required);\n\n\n    #region Core Data: Id, Guid, Title, Type\n\n    /// <inheritdoc />\n    [JsonPropertyOrder(-100)]\n    public int Id => _item.Id;\n\n    /// <inheritdoc />\n    [JsonPropertyOrder(-99)]\n    public Guid Guid => _item.Guid;\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it maps to a property which could be different; better let the inheriting class define it\n    public string? Title => _item.Title;\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    public IContentType Type => _item.Type;\n\n    #endregion\n\n\n    #region New Child<T> / Children<T>\n\n    /// <inheritdoc />\n    public T? Child<T>(string name, NoParamOrder npo = default, bool? required = default, GetRelatedOptions? options = default)\n        where T : class, IModelFromData, new()\n        => _item.Child<T>(name, npo: npo, required: required, options: options);\n\n    /// <inheritdoc />\n    public IEnumerable<T> Children<T>(string? field, NoParamOrder npo = default, string? type = default, bool? required = default, GetRelatedOptions? options = default)\n        where T : class, IModelFromData, new()\n        => _item.Children<T>(field: field, npo: npo, type: type, required: required, options: options);\n\n    /// <inheritdoc />\n    public T? Parent<T>(NoParamOrder npo = default, bool? current = default, string? type = default, string? field = default, GetRelatedOptions? options = default)\n        where T : class, IModelFromData, new()\n        => _item.Parent<T>(npo: npo, current: current, type: type, field: field, options: options);\n\n    /// <inheritdoc />\n    public IEnumerable<T> Parents<T>(NoParamOrder npo = default, string? type = default, string? field = default, GetRelatedOptions? options = default)\n        where T : class, IModelFromData, new()\n        => _item.Parents<T>(npo: npo, type: type ?? typeof(T).Name, field: field, options: options);\n\n    /// <inheritdoc />\n    public GpsCoordinates Gps(string name, NoParamOrder npo = default, bool? required = default)\n        => _item.Gps(name: name, npo: npo, required: required);\n\n    #endregion\n\n    #region As...\n\n    /// <summary>\n    /// Convert an Entity or TypedItem into a strongly typed object.\n    /// Typically, the type will be from your `AppCode.Data`.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"item\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New in v17.03\n    /// </remarks>\n    protected T As<T>(ITypedItem item)\n        where T : class, IModelFromData\n        => _modelFactory.AsCustomFrom<T, ITypedItem>(item);\n\n    /// <summary>\n    /// Convert a list of Entities or TypedItems into a strongly typed list.\n    /// Typically, the type will be from your `AppCode.Data`.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"source\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"nullIfNull\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New in v17.03\n    /// </remarks>\n    protected IEnumerable<T> AsList<T>(IEnumerable<ITypedItem>? source, NoParamOrder npo = default, bool nullIfNull = false)\n        where T : class, IModelFromData\n        => (source ?? (nullIfNull ? null : []))\n            ?.Select(item => _modelFactory.AsCustomFrom<T, ITypedItem>(item))\n            .ToList()!;\n\n    #endregion\n\n    /// <summary>\n    /// Get by name should never throw an error, as it's used to get null if not found.\n    /// </summary>\n    object? ICanGetByName.Get(string name)\n        => (this as ITypedItem).Get(name, required: false);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Data/CustomItem_Equatable.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace Custom.Data;\n\npartial class CustomItem: IMultiWrapper<IEntity>\n{\n    bool IEquatable<ITypedItem>.Equals(ITypedItem? other)\n        => Equals(other);\n\n    /// <summary>\n    /// Ensure that the equality check is done correctly.\n    /// If two objects wrap the same item, they will be considered equal.\n    /// </summary>\n    public override bool Equals(object? b)\n        => MultiWrapperEquality.EqualsObj(this, b);\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public override int GetHashCode()\n        => MultiWrapperEquality.GetWrappedHashCode(this);\n\n    IEntity? IMultiWrapper<IEntity>.RootContentsForEqualityCheck\n        => (_item as IMultiWrapper<IEntity>)?.RootContentsForEqualityCheck;\n\n    /// <summary>\n    /// Ensure that the equality check is done correctly.\n    /// If two objects wrap the same item, they will be considered equal.\n    /// </summary>\n    /// <param name=\"item1\">first item to compare</param>\n    /// <param name=\"item2\">second item to compare</param>\n    /// <returns>true, if both wrappers are the same type and wrap the same entity</returns>\n    public static bool operator ==(CustomItem item1, CustomItem item2)\n        => MultiWrapperEquality.IsEqual(item1, item2);\n\n    /// <summary>\n    /// Ensure that the equality check is done correctly.\n    /// If two objects wrap the same item, they will be considered equal.\n    /// </summary>\n    /// <param name=\"item1\">first item to compare</param>\n    /// <param name=\"item2\">second item to compare</param>\n    /// <returns>false, if both wrappers are the same type and wrap the same entity</returns>\n    public static bool operator !=(CustomItem item1, CustomItem item2)\n        => !MultiWrapperEquality.IsEqual(item1, item2);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Data/CustomModel.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Sxc.Data.Models;\n\nnamespace Custom.Data;\n\n/// <summary>\n/// Base class for custom models. Similar to <see cref=\"CustomItem\"/> but without predefined public properties or methods.\n/// </summary>\n/// <example>\n///\n/// Usage ca. like this:\n///\n/// 1. A custom data model in `AppCode.Data` which inherits from this class (usually generated by 2sxc Copilot)\n/// 2. Razor code which uses it to convert typed items into this custom data model\n/// \n/// Example trivial custom data model:\n/// ```c#\n/// namespace AppCode.Data\n/// {\n///   class MyPersonModel : Custom.Data.CustomModel\n///   {\n///     // New custom property\n///     public string Name => _item.String(\"Name\");\n///   }\n/// }\n/// ```\n///\n/// Example usage in Razor:\n///\n/// ```razor#\n/// @inherits Custom.Hybrid.RazorTyped\n/// @using AppCode.Data\n/// @{\n///   var person = As&lt;MyPersonModel&gt;(MyItem);\n/// }\n/// @* Now you can use the custom properties *@\n/// <span>@person.Name</span>\n/// @* But NOT all the standard properties like Id, Guid, Title, Type, etc. *@\n/// @* this would error: *@\n/// <span>@person.Id / @person.Guid</span>\n/// ```\n/// </example>\n/// <remarks>\n/// This is a lightweight custom object which doesn't have public properties\n/// like `Id` or methods such as `String(...)`.\n///\n/// It's ideal for data models which need full control,\n/// like for serializing or just to reduce the API surface.\n///\n/// You can access the underlying (protected) `_item` property to get the raw data.\n/// And it also has the (protected) `As&lt;...&gt;()` conversion for typed sub-properties.\n///\n/// History: New in 19.03\n/// </remarks>\n[PublicApi]\n[ModelSpecs(ContentType = \"*\")]\npublic class CustomModel: ModelFromItem;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.DataSource/DataSource16.cs",
    "content": "﻿using System.Collections.Immutable;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Sys;\nusing ToSic.Eav.DataSources;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Services;\n\nnamespace Custom.DataSource;\n\n/// <summary>\n/// The Base Class for custom Dynamic DataSources in your App.\n/// </summary>\n[PublicApi]\npublic abstract partial class DataSource16: ServiceBase<DataSource16.Dependencies>, IDataSource, IAppIdentitySync\n{\n    /// <summary>\n    /// Dependencies of DataSource16.\n    /// </summary>\n    /// <remarks>\n    /// This ensures that all users must have this in the constructor, so we can be sure we can add more dependencies as we need them.\n    ///\n    /// Note that this used to be called `MyServices` and that term will still work, but it's deprecated as of v20.\n    ///\n    /// See [](xref:NetCode.Conventions.DependenciesClass).\n    /// </remarks>\n    [PublicApi]\n    [method: PrivateApi]\n    public class Dependencies(CustomDataSource.Dependencies parentServices, ServiceKitLight16 kit)\n        : DependenciesBase(connect: [kit])\n    {\n        [PrivateApi]\n        public CustomDataSource.Dependencies ParentServices { get; } = parentServices;\n        [PrivateApi]\n        public ServiceKitLight16 Kit { get; } = kit;\n    }\n\n    /// <summary>\n    /// This is just for compatibility for any custom data sources which may have used the term `MyServices` since v16.\n    /// </summary>\n    /// <param name=\"parentServices\"></param>\n    /// <param name=\"kit\"></param>\n    [PrivateApi]\n    public class MyServices(CustomDataSource.Dependencies parentServices, ServiceKitLight16 kit)\n        : Dependencies(parentServices, kit);\n\n    /// <summary>\n    /// Constructor with the option to provide a log name.\n    /// </summary>\n    /// <param name=\"services\">All the needed services - see [](xref:NetCode.Conventions.Dependencies)</param>\n    /// <param name=\"logName\">Optional name for logging such as `My.JsonDS`</param>\n    protected DataSource16(Dependencies services, string? logName = default): base(services, logName ?? \"Cus.HybDs\")\n    {\n        _inner = BreachExtensions.CustomDataSourceLight(services.ParentServices, this, logName: logName ?? \"Cus.HybDs\");\n        _inner.BreachProvideOut(GetDefault);\n        Kit = services.Kit.Setup(this, () => Configuration.LookUpEngine);\n    }\n    private readonly CustomDataSource _inner;\n\n    /// <summary>\n    /// A simplified (light) Kit containing a bunch of helpers.\n    /// </summary>\n    /// <remarks>\n    /// This Kit has fewer APIs than in the typical Razor Kits,\n    /// because many of the Razor APIs require a Razor context.\n    /// </remarks>\n    public ServiceKitLight16 Kit { get; }\n\n    /// <summary>\n    /// Optional method to provide default data.\n    /// You can override this, or use one or more <see cref=\"ProvideOut\"/> in your constructor.\n    /// </summary>\n    /// <returns></returns>\n    protected virtual IEnumerable<IRawEntity> GetDefault()\n        => new List<IRawEntity>();\n\n    /// <summary>\n    /// Provide out-data on this data source.\n    /// Typically called in the constructor.\n    ///\n    /// You can call this multiple times, providing different names.\n    /// </summary>\n    /// <param name=\"getList\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"name\"></param>\n    /// <param name=\"options\"></param>\n    protected void ProvideOut(\n        Func<object> getList,\n        NoParamOrder npo = default,\n        string name = DataSourceConstants.StreamDefaultName,\n        Func<DataFactoryOptions>? options = default\n    ) => _inner.BreachProvideOut(getList, name: name, options: options);\n\n\n    #region CodeLog\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => _codeLog.Get(() => new CodeLog(_inner.Log))!;\n    private readonly GetOnce<ICodeLog> _codeLog = new();\n\n    #endregion\n\n    #region Public IDataSource Implementation\n\n    public IDataSourceConfiguration Configuration => _inner.Configuration;\n\n    public DataSourceErrorHelper Error => _inner.Error;\n\n    public int ZoneId => _inner.ZoneId;\n\n    public int AppId => _inner.AppId;\n\n    #endregion\n\n\n    #region IDataTarget - allmost all hidden\n\n    /// <inheritdoc cref=\"BreachExtensions.TryGetIn\"/>\n    public IImmutableList<IEntity>? TryGetIn(string name = DataSourceConstants.StreamDefaultName)\n        => _inner.TryGetIn(name);\n\n    /// <inheritdoc cref=\"BreachExtensions.TryGetOut\"/>\n    public IImmutableList<IEntity>? TryGetOut(string name = DataSourceConstants.StreamDefaultName)\n        => _inner.TryGetOut(name);\n\n    // The rest is all explicit implementation only\n\n    IReadOnlyDictionary<string, IDataStream> IDataSource.In => _inner.In;\n\n    // todo: attach must error - but only once the query has been optimized\n    // note also that temporarily the old interface IDataTarget will already error\n    // but soon the new one must too\n    private static readonly string AttachNotSupported = $\"Attach(...) is not supported on new data sources. Provide 'attach:' in CreateDataSource(...) instead\";\n    void IDataTarget.Attach(IDataSource dataSource)\n        => _inner.Attach(dataSource);\n\n    void IDataTarget.Attach(string streamName, IDataSource dataSource, string sourceName)\n        => _inner.Attach(streamName, dataSource, sourceName ?? DataSourceConstants.StreamDefaultName);\n\n    void IDataTarget.Attach(string streamName, IDataStream dataStream)\n        => _inner.Attach(streamName, dataStream);\n\n    #endregion\n\n    void IAppIdentitySync.UpdateAppIdentity(IAppIdentity appIdentity)\n        => ((IAppIdentitySync)_inner).UpdateAppIdentity(appIdentity);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.DataSource/DataSources16_IDataSourceExplicit.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Caching.Keys;\n\nnamespace Custom.DataSource;\n\npublic abstract partial class DataSource16\n{\n    // These APIs must work, but are typically handled as if they were explicit, to hid them in the docs.\n    // In the old dynamic code, this still worked,\n    // but in the typed code, these APIs are not available unless you cast to IDataSource.\n    // Because of this in v19.01 we'll change many to be not-explicit, but hide from docs.\n\n    #region Visual Query Properties, explicit only\n\n    Guid IDataSource.Guid => _inner.Guid;\n\n    string IDataSource.Name => GetType().Name;\n    string IDataSource.Label => _inner.Label;\n    void IDataSource.AddDebugInfo(Guid? guid, string? label)\n        => _inner.AddDebugInfo(guid, label);\n\n    #endregion\n\n    #region Explicit IDataSource Implementation - mainly \"explicit\" to hide in the docs, so the relevant APIs are visible.\n\n    [PrivateApi(\"Hide in docs to only show important APIs for DataSource creators\")]\n    public IReadOnlyDictionary<string, IDataStream> Out => _inner.Out;\n\n    [Obsolete(\"This is an old API, better use GetStream(...) as it provides more options to handle errors.\")]\n    IDataStream IDataSource.this[string outName] => _inner[outName]!;\n\n    /// <inheritdoc />\n    [PrivateApi(\"Hide in docs to only show important APIs for DataSource creators\")]\n    public IDataStream? GetStream(string? name = null, NoParamOrder npo = default, bool nullIfNotFound = false, bool emptyIfNotFound = false)\n        => _inner.GetStream(name, npo, nullIfNotFound, emptyIfNotFound);\n\n    /// <inheritdoc />\n    [PrivateApi(\"Hide in docs to only show important APIs for DataSource creators\")]\n    public IEnumerable<IEntity> List => _inner.List;\n\n    // Note: changed to explicit in v19.01; not sure why it was not explicit before\n    void IServiceWithSetup<IDataSourceOptions>.Setup(IDataSourceOptions options)\n        => ((IServiceWithSetup<IDataSourceOptions>)_inner).Setup(options);\n\n    ILog IHasLog.Log => _inner.Log;\n\n    #endregion\n\n    [PrivateApi(\"Hide in docs to only show important APIs for DataSource creators\")]\n    public IDataSourceLink GetLink() => ((IDataSourceLinkable)_inner).GetLink();\n\n    #region Caching stuff - all explicit as the DataSource Developer shouldn't need this\n\n    string ICacheKey.CachePartialKey => _inner.CachePartialKey;\n    string ICacheKey.CacheFullKey => _inner.CacheFullKey;\n    long ITimestamped.CacheTimestamp => _inner.CacheTimestamp;\n    bool ICacheExpiring.CacheChanged(long dependentTimeStamp) => _inner.CacheChanged(dependentTimeStamp);\n    ICacheKeyManager IDataSource.CacheKey => _inner.CacheKey;\n    List<string> IDataSource.CacheRelevantConfigurations => _inner.CacheRelevantConfigurations;\n\n    #endregion\n\n    #region Immutability stuff, all explicit\n\n    bool IDataSource.Immutable => _inner.Immutable;\n    void IDataSource.DoWhileOverrideImmutable(Action action) => _inner.DoWhileOverrideImmutable(action);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Hybrid/Code12.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// This is the base class for custom code (.cs) files in your Apps.\n/// By inheriting from this base class, you will automatically have the context like the App object etc. available.\n///\n/// > [!TIP]\n/// > This is an old base class and works, but you should use a newer one such as <see cref=\"CodeTyped\"/>\n/// </summary>\n/// <remarks>\n/// The constructor cannot have parameters, otherwise inheriting code will run into problems.\n/// </remarks>\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[method: PrivateApi]\npublic abstract class Code12() : CustomCodeBase(\"Sxc.Code12\"), IHasCodeLog, IDynamicCode, IDynamicCode12\n{\n    #region Constructor / Setup\n\n    [field: AllowNull, MaybeNull]\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => CompileCodeHlp.CodeLog;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    [PrivateApi] public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n    #endregion\n\n    #region Stuff added by Code12\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Convert\" />\n    [field: AllowNull, MaybeNull]\n    public IConvertService Convert => field ??= CodeApi.Convert;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic? Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    public dynamic? Settings => CodeApi.Settings;\n\n    [PrivateApi(\"Not yet ready\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public IDevTools DevTools => CodeApi.DevTools;\n\n    #endregion\n\n    // Stuff \"inherited\" from DynamicCode (old base class)\n\n    #region App / Data / Content / Header\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi.Data;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic? Content => CodeApi.Content;\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic? Header => CodeApi.Header;\n\n    #endregion\n\n\n\n    #region Link and Edit\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi.Edit!;\n\n    #endregion\n\n    #region SharedCode - must also map previous path to use here\n\n    /// <inheritdoc />\n    [PrivateApi]\n    string IGetCodePath.CreateInstancePath { get; set; } = null!;\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\" />\n    public dynamic? CreateInstance(string virtualPath, NoParamOrder npo = default, string? name = null, string? relativePath = null, bool throwOnError = true) =>\n        CompileCodeHlp.CreateInstance(virtualPath, npo, name, relativePath, throwOnError);\n\n    #endregion\n\n    #region Context, Settings, Resources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    #endregion CmsContext\n\n    #region AsDynamic and AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic? AsDynamic(string json, string? fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic? AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic? AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public dynamic? AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region CreateSource\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n\n    #endregion\n\n    #region AsAdam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Hybrid/Code14.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeErrorHelp;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.Help;\n\n\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Base class for v14 Dynamic Code files.\n/// \n/// Will provide the <see cref=\"ServiceKit14\"/> on property `Kit`.\n/// This contains all the popular services used in v14, so that your code can be lighter. \n/// </summary>\n/// <remarks>\n/// Important: The property `Convert` which exited on Razor12 was removed. use `Kit.Convert` instead.\n/// The constructor cannot have parameters, otherwise inheriting code will run into problems.\n/// </remarks>\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]   // #DocsButNotForIntellisense\npublic abstract class Code14()\n    : CustomCodeBase(\"Sxc.Code14\"), IHasCodeLog, IDynamicCode, IDynamicCode14<object, ServiceKit14>, IHasCodeHelp\n{\n\n    #region Constructor / Setup\n\n    [field: AllowNull, MaybeNull]\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => CompileCodeHlp.CodeLog;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    [PrivateApi]\n    public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n    [field: AllowNull, MaybeNull]\n    private CodeHelperV14 CodeHelper => field ??= new(new(ExCtx, false, \"c# code file\"));\n\n    #endregion\n\n    [field: AllowNull, MaybeNull]\n    public ServiceKit14 Kit => field ??= CodeApi.ServiceKit14;\n\n    #region Stuff added by Code12\n\n    ///// <inheritdoc cref=\"IDynamicCode12Docs.Convert\" />\n    //public IConvertService Convert => _DynCodeRoot.Convert;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic? Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    public dynamic? Settings => CodeApi.Settings;\n\n    [PrivateApi(\"Not yet ready\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public IDevTools DevTools => CodeHelper.DevTools;\n\n    #endregion\n\n\n\n\n    // Stuff \"inherited\" from DynamicCode (old base class)\n\n    #region App / Data / Content / Header\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi.Data;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic? Content => CodeApi.Content;\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic? Header => CodeApi.Header;\n\n    #endregion\n\n\n\n    #region Link and Edit\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi.Edit;\n\n    #endregion\n\n    #region SharedCode - must also map previous path to use here\n\n    /// <inheritdoc />\n    [PrivateApi]\n    string IGetCodePath.CreateInstancePath { get; set; } = null!;\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance\" />\n    public dynamic? CreateInstance(string virtualPath, NoParamOrder npo = default, string? name = null, string? relativePath = null, bool throwOnError = true) =>\n        CompileCodeHlp.CreateInstance(virtualPath: virtualPath, name: name, relativePath: relativePath, throwOnError: throwOnError);\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    [PrivateApi(\"added in 16.05, but not sure if it should be public\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public dynamic? GetCode(string path, NoParamOrder npo = default, string? className = default)\n        => CompileCodeHlp.GetCode(path: path, className: className);\n\n    #endregion\n\n    #region Context, Settings, Resources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    #endregion CmsContext\n\n    #region AsDynamic and AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic? AsDynamic(string json, string? fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic? AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic? AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public dynamic? AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region CreateSource\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n\n    #endregion\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    [PrivateApi] List<CodeHelp> IHasCodeHelp.ErrorHelpers => HelpDbRazor.CompileRazorOrCode14;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Hybrid/CodeTyped.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.Help;\nusing ToSic.Sys.Exceptions;\n\nnamespace Custom.Hybrid;\n\n/// <summary>\n/// Base class for v16 [Typed](xref:NetCode.TypedCode.Index) CSharp files.\n/// Use it to create custom CS code in your App.\n/// \n/// It provides the <see cref=\"ServiceKit16\"/> on property `Kit` which contains all the popular services to create amazing stuff.\n/// </summary>\n/// <remarks>\n/// Important: This is very different from Razor12 or Razor14, as it doesn't rely on `dynamic` code.\n/// Be aware of this since the APIs are very different - see [Typed Code](xref:NetCode.TypedCode.Index).\n/// </remarks>\n[PublicApi]\npublic abstract class CodeTyped : CustomCodeBase, IHasCodeLog, ITypedCode16\n{\n\n    #region Constructor / Setup\n\n    /// <summary>\n    /// Main constructor.\n    /// Doesn't have parameters so it can easily be inherited.\n    /// </summary>\n    protected CodeTyped() : base(\"Cst.CodeTy\") { }\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => CompileCodeHlp.CodeLog;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class\n        => CodeApi().GetService<TService>();\n\n    /// <inheritdoc cref=\"ITypedCode16.GetService{TService}(NoParamOrder, string?)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TService GetService<TService>(NoParamOrder npo = default, string? typeName = default) where TService : class\n        => AppCodeGetNamedServiceHelper.GetService<TService>(owner: this, CodeHelper.Specs, typeName);\n\n    [field: AllowNull, MaybeNull]\n    private TypedCode16Helper CodeHelper\n        => field ??= new(helperSpecs: new(CodeRootOrError(), false, \"c# code file\"), getRazorModel: () => null, getModelDic: () => null);\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel16;\n\n    #endregion\n\n    /// <inheritdoc cref=\"IHasKit{TServiceKit}.Kit\"/>\n    [field: AllowNull, MaybeNull]\n    public ServiceKit16 Kit => field ??= CodeApi().ServiceKit16;\n\n    private ICodeTypedApiHelper CodeApi([CallerMemberName] string? propName = default)\n        => _codeApi ??= CodeRootOrError(propName).GetTypedApi();\n    private ICodeTypedApiHelper? _codeApi;\n\n    private IExecutionContext CodeRootOrError([CallerMemberName] string? propName = default)\n        => ExCtxOrNull\n           ?? throw new ExceptionWithHelp(new CodeHelp\n               {\n                   Name = \"get-kit-without-code-root\",\n                   Detect = \"todo\",\n                   UiMessage =\n                       $\"Can't access properties such as {propName}, because the Code-Context is not known. \" +\n                       $\"This is typical in code which is in the **AppCode** folder. \" +\n                       $\"Make sure the caller of the code uses GetService<{GetType().Name}>() to create the object - \" +\n                       $\"like 'var {GetType().Name}Svc = GetService<{GetType().Name}>()'.\",\n               },\n#pragma warning disable CA2208\n               new ArgumentNullException(nameof(Kit)));\n#pragma warning restore CA2208\n\n\n    #region Stuff added by Code12\n\n    [PrivateApi(\"Not yet ready\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public IDevTools DevTools => CodeHelper.DevTools;\n\n    #endregion\n\n\n    #region Link and Edit\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi().Link;\n\n    #endregion\n\n\n    #region SharedCode - must also map previous path to use here\n\n    /// <inheritdoc />\n    [PrivateApi]\n    string IGetCodePath.CreateInstancePath { get; set; } = null!;\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    public dynamic? GetCode(string path, NoParamOrder npo = default, string? className = default)\n        => CompileCodeHlp.GetCode(path: path, className: className);\n\n\n    #endregion\n\n\n    #region New App, Settings, Resources\n\n    /// <inheritdoc />\n    public IAppTyped App => CodeApi().AppTyped;\n\n    /// <inheritdoc cref=\"ITypedApi.AllResources\" />\n    public ITypedStack AllResources => CodeHelper.AllResources;\n\n    /// <inheritdoc cref=\"ITypedApi.AllSettings\" />\n    public ITypedStack AllSettings => CodeHelper.AllSettings;\n\n\n    public IDataSource MyData => CodeApi().Data;\n\n    #endregion\n\n    #region My... Stuff\n\n    public ITypedItem MyItem => CodeHelper.MyItem;\n\n    public IEnumerable<ITypedItem> MyItems => CodeHelper.MyItems;\n\n    public ITypedItem MyHeader => CodeHelper.MyHeader;\n\n    #endregion\n\n\n    #region As Conversions\n\n    /// <inheritdoc cref=\"ITypedApi.AsItem\" />\n    public ITypedItem AsItem(object data, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi().Cdf.AsItem(data, new() { ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsItems\" />\n    public IEnumerable<ITypedItem> AsItems(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi().Cdf.AsItems(list, new() { ItemIsStrict = propsRequired ?? true });\n\n    /// <inheritdoc cref=\"ITypedApi.AsEntity\" />\n    public IEntity AsEntity(ICanBeEntity thing)\n        => CodeApi().Cdf.AsEntity(thing);\n\n    /// <inheritdoc cref=\"ITypedApi.AsTyped\" />\n    public ITyped AsTyped(object original, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi().Cdf.AsTyped(original, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsTypedList\" />\n    public IEnumerable<ITyped> AsTypedList(object list, NoParamOrder npo = default, bool? propsRequired = default)\n        => CodeApi().Cdf.AsTypedList(list, new() { EntryPropIsRequired = false, ItemIsStrict = propsRequired ?? true })!;\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack\" />\n    public ITypedStack AsStack(params object[] items)\n        => CodeApi().Cdf.AsStack(items);\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack{T}\" />\n    public T AsStack<T>(params object[] items)\n        where T : class, IModelFromData, new()\n        => CodeApi().Cdf.AsStack<T>(items);\n\n    #endregion\n\n    public ITypedRazorModel MyModel => CodeHelper.MyModel;\n\n    #region MyContext & UniqueKey\n\n    /// <inheritdoc cref=\"ITypedApi.MyContext\" />\n    public ICmsContext MyContext => CodeApi().CmsContext;\n\n    /// <inheritdoc cref=\"ITypedApi.MyPage\" />\n    public ICmsPage MyPage => CodeApi().CmsContext.Page;\n\n    /// <inheritdoc cref=\"ITypedApi.MyUser\" />\n    public ICmsUser MyUser => CodeApi().CmsContext.User;\n\n    /// <inheritdoc cref=\"ITypedApi.MyView\" />\n    public ICmsView MyView => CodeApi().CmsContext.View;\n\n    /// <inheritdoc cref=\"ITypedApi.UniqueKey\" />\n    public string UniqueKey => Kit.Key.UniqueKey;\n\n    #endregion\n\n\n    #region As / AsList WIP v17\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= ExCtx.GetCdf();\n\n    /// <inheritdoc />\n    public T As<T>(object source, NoParamOrder npo = default)\n        where T : class, IModelFromData\n        => Cdf.AsCustom<T>(source: source, npo: npo)!;\n\n    /// <inheritdoc />\n    public IEnumerable<T> AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData\n        => Cdf.AsCustomList<T>(source, npo, nullIfNull);\n\n    #endregion\n\n    #region Customize\n\n    /// <summary>\n    /// Helper to create typed objects for App, View etc. - mainly for custom base classes in `AppCode`\n    /// </summary>\n    /// <remarks>\n    /// * Introduced in v17.03 (beta)\n    /// * Stable and ready for production in v18.00\n    /// </remarks>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    [field: AllowNull, MaybeNull]\n    protected ICodeCustomizer Customize\n        => field ??= ExCtx.GetService<ICodeCustomizer>(reuse: true);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Razor.Sys/IRazor.cs",
    "content": "﻿using ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace Custom.Razor.Sys;\n\n[PrivateApi(\"not sure where/if it goes anywhere\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IRazor: /*IHasCodeApiService,*/ INeedsExecutionContext\n{\n    /// <summary>\n    /// The path to this Razor WebControl.\n    /// This is for consistency, because asp.net Framework has a property \"VirtualPath\" whereas .net core uses \"Path\"\n    /// From now on it should always be Path for cross-platform code\n    /// </summary>\n    [PublicApi(\"This is a polyfill to ensure the old Razor has the same property as .net Core Razor\")]\n    string Path { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Razor.Sys/IRazor12.cs",
    "content": "﻿using ToSic.Sxc.Code;\n\nnamespace Custom.Razor.Sys;\n\n[PrivateApi(\"not sure yet if this will stay in Hybrid or go to Web.Razor or something, so keep it private for now\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IRazor12: IRazor, IDynamicCode12\n{\n    [PrivateApi]\n    dynamic DynamicModel { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/Custom.Razor.Sys/IRazor14.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Services.Sys;\n\nnamespace Custom.Razor.Sys;\n\n[PrivateApi(\"not sure yet if this will stay in Hybrid or go to Web.Razor or something, so keep it private for now\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IRazor14<out TModel, out TServiceKit>: IRazor, IDynamicCode14<TModel, TServiceKit>\n    where TModel : class\n    where TServiceKit : ServiceKit\n{\n    /// <summary>\n    /// Dynamic object containing parameters. So in Dnn it contains the PageData, in Oqtane it contains the Model\n    /// </summary>\n    /// <remarks>\n    /// New in v12\n    /// </remarks>\n    [PrivateApi]\n    dynamic DynamicModel { get; }\n    \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Wrappers;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/StartupSxcCustom.cs",
    "content": "﻿using Custom.DataSource;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.DataSource.Sys.AppDataSources;\nusing ToSic.Sxc.DataSources.Sys;\nusing ToSic.Sxc.Services;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcCustom\n{\n    public static IServiceCollection AddSxcCustom(this IServiceCollection services)\n    {\n        // Loader of AppDataSources\n        services.TryAddTransient<IAppDataSourcesLoader, AppDataSourcesLoader>();\n\n        // v15 CustomDataSources - just the dependencies needed\n        services.TryAddTransient<DataSource16.Dependencies>();\n        services.TryAddTransient<DataSource16.MyServices>();    // old name for compatibility\n\n        // Kits for custom code only\n        services.TryAddTransient<ServiceKitLight16>();\n\n        return services;\n    }\n\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Old/DynamicCode.cs",
    "content": "﻿using Custom.Hybrid;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// This is a base class for dynamic code which is compiled at runtime.\n///\n/// > [!TIP]\n/// > This is an old base class and works, but you should use a newer one such as <see cref=\"CodeTyped\"/>\n/// </summary>\n/// <remarks>\n/// The constructor cannot have parameters, otherwise inheriting code will run into problems.\n/// </remarks>\n[PrivateApi(\"Was public till v17\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class DynamicCode() : CustomCodeBase(\"Sxc.DynCod\"), IHasCodeLog, IDynamicCode\n{\n    #region Constructor / Setup\n\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => CompileCodeHlp.CodeLog;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    [PrivateApi] public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel10;\n\n    #endregion\n\n    #region App / Data / Content / Header\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi.Data;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic? Content => CodeApi.Content;\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic? Header => CodeApi.Header;\n\n    #endregion\n\n\n    #region Link and Edit\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi.Edit;\n\n    #endregion\n\n    #region SharedCode - must also map previous path to use here\n\n    /// <inheritdoc />\n    [PrivateApi]\n    string IGetCodePath.CreateInstancePath { get; set; } = null!;\n\n    /// <inheritdoc />\n    public dynamic? CreateInstance(string virtualPath, NoParamOrder npo = default, string? name = null, string? relativePath = null, bool throwOnError = true) =>\n        CompileCodeHlp.CreateInstance(virtualPath, npo, name, relativePath, throwOnError);\n\n    #endregion\n\n    #region Context, Settings, Resources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    #endregion CmsContext\n\n    #region AsDynamic and AsEntity\n\n    /// <inheritdoc />\n    public dynamic? AsDynamic(string json, string? fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc />\n    public dynamic AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc />\n    public dynamic? AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public dynamic? AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region CreateSource\n\n    /// <inheritdoc />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    /// <inheritdoc />\n    public T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n\n    #endregion\n\n    #region AsAdam\n\n    /// <inheritdoc />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Old/DynamicCode12.cs",
    "content": "﻿using Custom.Hybrid;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code;\n\n/// <summary>\n/// Base class for v12 Dynamic Code\n/// Adds new properties and methods, and doesn't keep old / legacy APIs\n///\n/// > [!TIP]\n/// > This is an old base class and works, but you should use a newer one such as <see cref=\"CodeTyped\"/>\n/// </summary>\n/// <remarks>\n/// The constructor cannot have parameters, otherwise inheriting code will run into problems.\n/// </remarks>\n[PrivateApi(\"Was public till v17\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class DynamicCode12(): CustomCodeBase(\"Sxc.DynCod\"), IHasCodeLog, IDynamicCode, IDynamicCode12\n{\n    #region Constructor / Setup\n\n    [field: AllowNull, MaybeNull]\n    internal ICodeDynamicApiHelper CodeApi => field ??= ExCtx.GetDynamicApi();\n\n\n    /// <inheritdoc cref=\"IHasCodeLog.Log\" />\n    public new ICodeLog Log => CompileCodeHlp.CodeLog;\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    public TService GetService<TService>() where TService : class => CodeApi.GetService<TService>();\n\n    [PrivateApi] public override int CompatibilityLevel => CompatibilityLevels.CompatibilityLevel12;\n\n    #endregion\n\n    #region Stuff added by Code12\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Convert\" />\n    [field: AllowNull, MaybeNull]\n    public IConvertService Convert => field ??= CodeApi.Convert;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    public dynamic Resources => CodeApi.Resources;\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    public dynamic Settings => CodeApi.Settings;\n\n    [PrivateApi(\"Not yet ready\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public IDevTools DevTools => CodeApi.DevTools;\n\n    #endregion\n\n    // Stuff \"inherited\" from DynamicCode (old base class)\n\n    #region App / Data / Content / Header\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    public IApp App => CodeApi.App;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    public IDataSource Data => CodeApi.Data;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    public dynamic? Content => CodeApi.Content;\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    public dynamic? Header => CodeApi.Header;\n\n    #endregion\n\n\n\n    #region Link and Edit\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    public ILinkService Link => CodeApi.Link;\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    public IEditService Edit => CodeApi.Edit;\n\n    #endregion\n\n    #region SharedCode - must also map previous path to use here\n\n    /// <inheritdoc />\n    [PrivateApi]\n    string IGetCodePath.CreateInstancePath { get; set; } = null!;\n\n    /// <inheritdoc cref=\"ICreateInstance.CreateInstance(string, NoParamOrder, string, string, bool)\" />\n    public dynamic? CreateInstance(string virtualPath, NoParamOrder npo = default, string? name = null, string? relativePath = null, bool throwOnError = true) =>\n        CompileCodeHlp.CreateInstance(virtualPath, npo, name, relativePath, throwOnError);\n\n    #endregion\n\n    #region Context, Settings, Resources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    public ICmsContext CmsContext => CodeApi.CmsContext;\n\n    #endregion CmsContext\n\n    #region AsDynamic and AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n    public dynamic? AsDynamic(string json, string? fallback = default) => CodeApi.Cdf.Json2Jacket(json, fallback);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    public dynamic? AsDynamic(IEntity entity) => CodeApi.Cdf.CodeAsDyn(entity);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    public dynamic? AsDynamic(object dynamicEntity) => CodeApi.Cdf.AsDynamicFromObject(dynamicEntity);\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    public dynamic? AsDynamic(params object[] entities) => CodeApi.Cdf.MergeDynamic(entities);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    public IEntity AsEntity(object dynamicEntity) => CodeApi.Cdf.AsEntity(dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    public IEnumerable<dynamic> AsList(object list) => CodeApi.Cdf.CodeAsDynList(list);\n\n    #endregion\n\n    #region CreateSource\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    public T CreateSource<T>(IDataStream source) where T : IDataSource\n        => CodeApi.CreateSource<T>(source);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    public T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource\n        => CodeApi.CreateSource<T>(inSource, configurationProvider);\n\n\n    #endregion\n\n    #region AsAdam\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    public IFolder AsAdam(ICanBeEntity item, string fieldName) => CodeApi.AsAdam(item, fieldName);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Sys/CustomCodeBase.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Code.Sys;\n\n[PrivateApi]\n// #NoEditorBrowsableBecauseOfInheritance\n//[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class CustomCodeBase : ServiceWithContext, ICompatibilityLevel\n{\n    #region Constructor / Setup\n\n    /// <summary>\n    /// Main constructor, NOT for DI may never have parameters, otherwise inheriting code will run into problems. \n    /// </summary>\n    protected CustomCodeBase(string logName) : base(logName) { }\n\n    /// <summary>\n    /// Special helper to move all Razor logic into a separate class.\n    /// For architecture of Composition over Inheritance.\n    /// </summary>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    [field: AllowNull, MaybeNull]\n    protected internal CompileCodeHelper CompileCodeHlp => field\n        ??= ExCtx.GetService<CompileCodeHelper>().Init(this as IGetCodePath ?? throw new($\"Can't cast to {nameof(IGetCodePath)}, but inheriting classes must implement it.\"));\n\n\n    //[PrivateApi]\n    //[ShowApiWhenReleased(ShowApiMode.Never)]\n    //public override void ConnectToRoot(IExecutionContext exCtx)\n    //{\n    //    base.ConnectToRoot(exCtx);\n    //}\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public abstract int CompatibilityLevel { get; }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Sys/IDynamicCode14.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing IFolder = ToSic.Sxc.Adam.IFolder;\n// Disable warnings that properties should be marked as new\n// Because we need them here as additional definition because of Razor problems with inherited interfaces\n#pragma warning disable CS0108, CS0114\n\nnamespace ToSic.Sxc.Code.Sys;\n\n/// <summary>\n/// Interface for Dynamic Code with enhancements after v12. It extends <see cref=\"IDynamicCode\"/>\n/// \n/// Dynamic Code is the API for files like Razor or WebApis.\n/// Supports many properties like App, etc. to ensure that the dynamic code has everything you need. <br />\n/// Also provides many Conversions between <see cref=\"IEntity\"/> and <see cref=\"IDynamicEntity\"/>.\n/// Important for dynamic code files like Razor or WebApi. Note that there are many overloads to ensure that AsDynamic and AsEntity \"just work\" even if you give them the original data.\n/// </summary>\n[PrivateApi(\"WIP v14.02\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDynamicCode14<out TModel, out TServiceKit> : /*ICompatibleToCode12,*/ /*IDynamicCode<TModel, TServiceKit>,*/ IHasKit<TServiceKit>\n    where TModel : class\n    where TServiceKit : ServiceKit\n{\n    #region IDynamicCode Repeats - keep this in sync\n    // **************************************************\n    // WARNING\n    // **************************************************\n    // Razor has a small problem with interfaces inheriting interfaces. \n    // If an object is of an interface which inherits another interface\n    // then Razor will not find methods of the root interface and give errors like\n    // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'ToSic.Sxc.Code.IDynamicCode12' does not contain a definition for 'AsList' at CallSite.Target\n    //\n    // Because of this, we repeat the ENTIRE definition for IDynamicCode here\n    // Make sure they remain in-sync\n    // **************************************************\n\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    TService GetService<TService>() where TService : class;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.App\" />\n    IApp App { get; }\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Data\" />\n    IDataSource Data { get; }\n\n    #region Content and Header\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Content\" />\n    dynamic? Content { get; }\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Header\" />\n    dynamic? Header { get; }\n\n    #endregion\n\n    #region AsAdam, Linking, Edit\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsAdam\" />\n    IFolder AsAdam(ICanBeEntity item, string fieldName);\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    ILinkService Link { get; }\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Edit\" />\n    IEditService Edit { get; }\n\n    #endregion\n\n    #region AsDynamic for Strings\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(string, string)\" />\n\n    dynamic? AsDynamic(string json, string? fallback = default);\n\n    #endregion \n\n    #region AsDynamic for Entities\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(IEntity)\" />\n    dynamic? AsDynamic(IEntity entity);\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsDynamic(object)\" />\n    dynamic? AsDynamic(object dynamicEntity);\n\n\n    #endregion\n\n    #region AsEntity\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    IEntity AsEntity(object dynamicEntity);\n\n    #endregion\n\n    #region AsList\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsList\" />\n    IEnumerable<dynamic> AsList(object list);\n\n    #endregion\n\n\n    #region Create Data Sources\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataStream)\" />\n    T CreateSource<T>(IDataStream source) where T : IDataSource;\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CreateSource{T}(IDataSource, ILookUpEngine)\" />\n    T CreateSource<T>(IDataSource? inSource = null, ILookUpEngine? configurationProvider = default) where T : IDataSource;\n\n    #endregion\n\n    #region Context\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    ICmsContext CmsContext { get; }\n\n    #endregion\n\n\n\n    #endregion\n\n    #region Stuff added by DynamicCode12\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.AsDynamic(object[])\" />\n    dynamic? AsDynamic(params object[] entities);\n\n\n    #region Convert-Service - removed in V14!\n\n    #endregion\n\n    #region Resources and Settings\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Resources\" />\n    dynamic? Resources { get; }\n\n    /// <inheritdoc cref=\"IDynamicCode12Docs.Settings\" />\n    dynamic? Settings { get; }\n\n    #endregion\n\n\n    #region DevTools\n\n    [PrivateApi(\"Still WIP\")]\n    IDevTools DevTools { get; }\n\n    #endregion\n\n    #endregion\n\n    /// <inheritdoc cref=\"ITypedCode16.GetCode\"/>\n    [PrivateApi(\"added in 16.05, but not sure if it should be public\")]\n    dynamic? GetCode(string path, NoParamOrder npo = default, string? className = default);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Sys/ITypedCode16.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n// ReSharper disable MethodOverloadWithOptionalParameter\n\nnamespace ToSic.Sxc.Code.Sys;\n\n/// <summary>\n/// Standard interface for all TypedCode such as RazorPro or WebApiPro.\n/// Provides typed APIs to access Settings, Resources and more.\n/// </summary>\n[PrivateApi(\"Shouldn't be visible, as the real API is 100% visible on RazorPro, CodePro etc.\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ITypedCode16 : IGetCodePath, ICompatibilityLevel, IHasLog, IHasKit<ServiceKit16>\n{\n    #region Stuff basically inherited from v12/14\n\n    /// <inheritdoc cref=\"ICanGetService.GetService{TService}\"/>\n    TService GetService<TService>() where TService : class;\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\"/>\n    ILinkService Link { get; }\n\n    #endregion\n\n    /// <summary>\n    /// Advanced GetService which can do more than the standard GetService.\n    /// </summary>\n    /// <typeparam name=\"TService\"></typeparam>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"typeName\">Optional fully qualified type name to get the class based on a string identifier.</param>\n    /// <remarks>New in 17.06.01</remarks>\n    /// <returns></returns>\n    /// <remarks>\n    /// This is commonly used for scenarios where the editor\n    /// might select a file from the AppCode to be used for something specific,\n    /// and then the code needs to run this service.\n    /// \n    /// For example in Mobius Forms, News etc. where a developer might create a new mail template and the editor can select it from the files in the folder.\n    /// </remarks>\n    TService GetService<TService>(NoParamOrder npo = default, string? typeName = default) where TService : class;\n\n    #region Moving Properties\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.CmsContext\" />\n    ICmsContext MyContext { get; }\n        \n    /// <inheritdoc cref=\"ICmsContext.Page\" />\n    ICmsPage MyPage { get; }\n\n    /// <inheritdoc cref=\"ICmsContext.User\" />\n    ICmsUser MyUser { get; }\n\n    /// <inheritdoc cref=\"ICmsContext.View\" />\n    ICmsView MyView { get; }\n\n    /// <inheritdoc cref=\"IKeyService.UniqueKey\"/>\n    string UniqueKey { get; }\n\n    #endregion\n\n\n\n\n    #region App, Resources, Settings\n\n    /// <inheritdoc cref=\"ITypedApi.App\"/>\n    IAppTyped App { get; }\n\n    /// <inheritdoc cref=\"ITypedApi.AllResources\"/>\n    ITypedStack AllResources { get; }\n\n    /// <inheritdoc cref=\"ITypedApi.AllSettings\"/>\n    ITypedStack AllSettings { get; }\n\n    #endregion\n\n    #region AsConversions\n\n    /// <inheritdoc cref=\"ITypedApi.AsItem\"/>\n    ITypedItem AsItem(\n        object data,\n        NoParamOrder npo = default,\n        bool? propsRequired = default\n    );\n\n    /// <inheritdoc cref=\"ITypedApi.AsItems\"/>\n    IEnumerable<ITypedItem> AsItems(\n        object list,\n        NoParamOrder npo = default,\n        bool? propsRequired = default\n    );\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.AsEntity\" />\n    IEntity AsEntity(ICanBeEntity thing);\n\n    /// <inheritdoc cref=\"ITypedApi.AsTyped\"/>\n    ITyped AsTyped(\n        object data,\n        NoParamOrder npo = default,\n        bool? propsRequired = default\n    );\n\n    /// <inheritdoc cref=\"ITypedApi.AsTypedList\"/>\n    IEnumerable<ITyped> AsTypedList(\n        object list,\n        NoParamOrder npo = default,\n        bool? propsRequired = default\n    );\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack\"/>\n    ITypedStack AsStack(params object[] items);\n\n    /// <inheritdoc cref=\"ITypedApi.AsStack{T}\"/>\n    public T AsStack<T>(params object[] items)\n        where T : class, IModelFromData, new();\n\n    #endregion\n\n    #region My... Stuff\n\n    /// <inheritdoc cref=\"ITypedApi.MyItem\"/>\n    ITypedItem MyItem {get; }\n\n    /// <inheritdoc cref=\"ITypedApi.MyItems\"/>\n    IEnumerable<ITypedItem> MyItems { get; }\n\n    /// <inheritdoc cref=\"ITypedApi.MyHeader\"/>\n    ITypedItem MyHeader { get; }\n\n    /// <inheritdoc cref=\"ITypedApi.MyData\"/>\n    IDataSource MyData { get; }\n\n    #endregion\n\n    /// <summary>\n    /// Data passed to this Razor template by a caller.\n    /// This is typical for Razor components which are re-used, and called from other Razor templates using `@Html.Partial(\"filename.cshtml\", new { thing = 7 })`.\n    /// </summary>\n    ITypedRazorModel MyModel { get; }\n\n    #region SharedCode\n\n    /// <summary>\n    /// Create an instance of a class in a `.cs` code file.\n    /// Note that the class name in the file must match the file name, so `MyHelpers.cs` must have a `MyHelpers` class.\n    /// </summary>\n    /// <param name=\"path\">The path, like `Helper.cs`, `./helper.cs`, `../../Helper.cs` or `/SomeFolderInApp/Helper.cs` (new 16.05)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"className\">Optional class name, if it doesn't match the file name (new 16.03)</param>\n    /// <returns>, </returns>\n    /// <remarks>\n    /// * Created in 16.02\n    /// * `className` added in 16.03\n    /// * Ability to give a path beginning with `/` as app-root in 16.05\n    /// \n    /// In older code there was a similar `CreateInstance` method\n    /// </remarks>\n    dynamic? GetCode(string path, NoParamOrder npo = default, string? className = default);\n\n    #endregion\n\n    #region As Conversions\n\n    /// <inheritdoc cref=\"ITypedApi.As{T}\"/>\n    T As<T>(object source, NoParamOrder npo = default)\n        where T : class, IModelFromData;\n\n    /// <inheritdoc cref=\"ITypedApi.AsList{T}\"/>\n    IEnumerable<T> AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Sys.CodeRunHelpers/AppCodeGetNamedServiceHelper.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n/// <summary>\n/// Special helper for GetServiceByName finding a service in AppCode\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppCodeGetNamedServiceHelper\n{\n    public static TService GetService<TService>(object owner, CompileCodeHelperSpecs helperSpecs, string? typeName = default) where TService : class\n    {\n        // Standard case - just a normal GetService<T>()\n        if (typeName.IsEmptyOrWs())\n            return helperSpecs.ExCtx.GetService<TService>();\n\n        var log = helperSpecs.ExCtx.Log;\n\n        var ownType = owner.GetType();\n        var assembly = ownType.Assembly;\n        // Note: don't check the Namespace property, as it may be empty\n        if (!HotBuildConstants.ObjectIsFromAppCode(owner))\n            throw log.Ex(new Exception($\"Type '{ownType.FullName}' is not in the 'AppCode' namespace / dll, so it can't be used to find other types.\"));\n\n        var type = assembly.FindControllerTypeByName(typeName);\n\n        return type == null\n            ? throw log.Ex(new Exception($\"Type '{typeName}' not found in assembly '{assembly.FullName}'\"))\n            : helperSpecs.ExCtx.GetService<TService>(type: type);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Sys.CodeRunHelpers/CodeHelperV14.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CodeHelperV14(CompileCodeHelperSpecs helperSpecs) : CodeHelperV00Base(helperSpecs, $\"{SxcLogName}.C14Hlp\");"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Sys.CodeRunHelpers/CodeHelperV16.cs",
    "content": "﻿namespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n/// <summary>\n/// Code Helper for typed code v16+\n/// </summary>\n/// <param name=\"helperSpecs\"></param>\n/// <param name=\"getRazorModel\"></param>\n/// <param name=\"getModelDic\"></param>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class TypedCode16Helper(CompileCodeHelperSpecs helperSpecs, Func<object?> getRazorModel, Func<IDictionary<string, object>?> getModelDic)\n    : CodeHelperTypedData(helperSpecs, SxcLogName + \".TCd16H\")\n{\n    // Note: we're passing in factory methods so they don't get processed unless needed\n    // Reason is that we have 2 scenarios, which can throw errors if processed in the wrong scenario\n    public object? RazorModel => _razorModel.Get(getRazorModel);\n    private readonly GetOnce<object?> _razorModel = new();\n\n    public IDictionary<string, object> MyModelDic => _myModelDic.Get(getModelDic)!;\n    private readonly GetOnce<IDictionary<string, object>?> _myModelDic = new();\n\n    public TModel GetModel<TModel>()\n    {\n        try\n        {\n            return (TModel)RazorModel!;\n        }\n        catch (Exception ex)\n        {\n            var msg = $\"Failed to cast Razor Model to '{typeof(TModel)}' from '{RazorModel?.GetType().Name}' - value was '{RazorModel}'\";\n            Log.E(msg);\n            throw Log.Ex(new InvalidCastException(msg, ex));\n        }\n    }\n\n    public ITypedRazorModel MyModel => _myModel.Get(() => new TypedRazorModel(Specs, MyModelDic))!;\n    private readonly GetOnce<ITypedRazorModel> _myModel = new();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Sys.CodeRunHelpers/CompileCodeHelper.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Code.Sys.HotBuild;\n\nnamespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n/// <summary>\n/// The CodeHelper for custom code.\n/// Provides the GetCode and CreateInstance methods.\n///\n/// It inherits from the helper base so in Custom Code it will also provide the log,\n/// but when used in APIs it only provides the GetCode and CreateInstance methods.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CompileCodeHelper() : CodeHelperBase(\"Sxc.CdHlp\")\n{\n    #region Setup\n\n    public CompileCodeHelper Init(IGetCodePath parent)\n    {\n        _parent = parent;\n        return this;\n    }\n\n    private IGetCodePath _parent = null!;\n\n    #endregion\n\n    #region GetCode / CreateInstance\n\n    public object? GetCode(string path, NoParamOrder npo = default, string? className = default) \n        => CreateInstance(path, name: className);\n\n    /// <inheritdoc />\n    public object? CreateInstance(string virtualPath, NoParamOrder npo = default, string? name = null, string? relativePath = null, bool throwOnError = true)\n    {\n        var l = Log.Fn<object?>();\n\n        // Prevent GetCode / CreateInstance from being used inside AppCode\n        CodeRunThrowIfParentIsInsideAppCode(_parent);\n\n        // usually we don't have a relative path, so we use the preset path from when this class was instantiated\n        relativePath ??= _parent?.CreateInstancePath;\n        object? instance = ExCtxOrNull?.GetDynamicApi()?.CreateInstance(virtualPath, npo, name, relativePath, throwOnError);\n        return l.Return(instance);\n    }\n\n    public static void CodeRunThrowIfParentIsInsideAppCode(object parent)\n    {\n        if (HotBuildConstants.ObjectIsFromAppCode(parent))\n            throw new(\"Can't use GetCode in objects from inside AppCode as it's a very dynamic operation.\");\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Code/Sys.CodeRunHelpers/RazorHelperBase.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.CodeApi;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Code.Sys.CodeRunHelpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class RazorHelperBase(string logName) : CodeHelperBase(logName)\n{\n    public List<Exception>? ExceptionsOrNull { get; private set; }\n\n    public Exception Add(Exception ex)\n    {\n        (ExceptionsOrNull ??= []).Add(ex);\n        return ex;\n    }\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"path\"></param>\n    /// <param name=\"overrideRootExCtx\">Insert another code Root, ATM a patch for Oqtane Razor</param>\n    /// <returns></returns>\n    protected string? ResolvePathIfAbsoluteToApp(string? path, IExecutionContext? overrideRootExCtx = default)\n    {\n        var l = Log.Fn<string>(path);\n        if (path == null || (!path.StartsWith(\"/\") && !path.StartsWith(\"\\\\\")))\n            return l.ReturnNull(\"not absolute, return null\");\n\n        l.A(\"Will try to use absolute path relative to the app.\");\n\n        if (!path.EndsWith(SourceCodeConstants.CsFileExtension))\n            throw l.Done(new ArgumentException(\"Only '.cs' file paths can start with a slash\"));\n        var app = (overrideRootExCtx ?? ExCtxOrNull)?.GetTypedApi()?.AppTyped\n                  ?? throw l.Done(new Exception(\"Absolute paths require an App, which was null\"));\n        var appFolder = app.Folder?.Path\n                        ?? throw l.Done(new Exception(\"Absolute paths require the App folder, which was null\"));\n        return l.ReturnAndLog(Path.Combine(appFolder, path.TrimPrefixSlash()));\n    }\n\n    #region CreateInstance / GetCode\n\n    public object? GetCode(string path, NoParamOrder npo = default, string? className = default) \n        => GetCode(path, npo: npo, name: className, throwOnError: true);\n\n    /// <summary>\n    /// Creates instances of the shared pages with the given relative path\n    /// </summary>\n    /// <returns></returns>\n    private object? GetCode(string virtualPath,\n        NoParamOrder npo,\n        string? name,\n        bool throwOnError)\n    {\n        // Note: Don't do parameter checks, as they have already been done\n        // and the warnings are a bit different depending on the public signature\n\n        var l = Log.Fn<object?>($\"'{virtualPath}', '{name}'\");\n\n        if (virtualPath.IsEmptyOrWs())\n            return !throwOnError\n                ? null\n                : throw l.Done(new ArgumentException(\"path can't be empty\"));\n\n        var path = ResolvePathIfAbsoluteToApp(virtualPath)?.ForwardSlash().PrefixSlash()\n                   ?? GetCodeNormalizePath(virtualPath);\n\n        if (!File.Exists(GetCodeFullPathForExistsCheck(path)))\n            return !throwOnError\n                ? null\n                : throw l.Done(new FileNotFoundException(\"The file does not exist.\", path));\n\n        try\n        {\n            object? result = path.EndsWith(SourceCodeConstants.CsFileExtension)\n                ? ExCtx.GetDynamicApi().CreateInstance(path, npo, name: name, relativePath: null, throwOnError: throwOnError)\n                : GetCodeCshtml(path);\n            return l.Return(result, \"ok\");\n        }\n        catch (Exception ex)\n        {\n            l.Done(ex);\n            if (throwOnError)\n                throw;\n            return null;\n        }\n    }\n\n\n    public object? CreateInstance(string virtualPath,\n        NoParamOrder npo = default,\n        string? name = null,\n        string? relativePath = null,\n        bool throwOnError = true\n    ) => GetCode(virtualPath: virtualPath, npo: npo, name: name, throwOnError: throwOnError);\n\n    protected abstract object GetCodeCshtml(string path);\n\n    #endregion\n\n    protected abstract string GetCodeFullPathForExistsCheck(string path);\n    protected abstract string GetCodeNormalizePath(string virtualPath);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Custom.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Custom</AssemblyName>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <RootNamespace></RootNamespace>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code.HotBuild\\ToSic.Sxc.Code.HotBuild.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Custom.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tosic_002Esxc_002Ecode_005Cdevtools/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tosic_002Esxc_002Ecode_005Cold/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tosic_002Esxc_002Ecode_005Ctypedmodel/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.DataSources.Sys/AppDataSourcesLoader.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Sys.AppDataSources;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Eav.DataSource.VisualQuery.Sys;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sxc.Code.Sys.SourceCode;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.DataSources.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class AppDataSourcesLoader(\n    ILogStore logStore,\n    ISite site,\n    IAppReaderFactory appReaders,\n    LazySvc<IAppPathsMicroSvc> appPathsLazy,\n    LazySvc<CodeCompiler> codeCompilerLazy,\n    LazySvc<AppCodeLoader> appCodeLoaderLazy,\n    ISxcCurrentContextService ctxService,\n    PolymorphConfigReader polymorphism,\n    MemoryCacheService memoryCacheService)\n    : ServiceBase(\"Eav.AppDtaSrcLoad\",\n        connect:\n        [\n            logStore, site, appReaders, appPathsLazy, codeCompilerLazy, appCodeLoaderLazy, ctxService, polymorphism,\n            memoryCacheService\n        ]), IAppDataSourcesLoader\n{\n    private const string DataSourcesFolder = \"DataSources\";\n\n    public AppLocalDataSources CompileDynamicDataSources(int appId)\n    {\n        logStore.Add(EavLogs.LogStoreAppDataSourcesLoader, Log);\n        // Initial message for insights-overview\n        var l = Log.Fn<AppLocalDataSources>($\"{nameof(appId)}: {appId}\", timer: true);\n        \n        try\n        {\n            var spec = BuildHotBuildSpec(appId);\n            l.A($\"{spec}\");\n\n            // 1. Get Custom Dynamic DataSources from 'AppCode' assembly\n            var data = CreateDataSourceInfos(appId, LoadAppCodeDataSources(spec, out var cacheKey));\n            l.A($\"Custom Dynamic DataSources in {FolderConstants.AppCodeFolder}:{data.Count}\");\n\n            // 2. Get Custom Dynamic DataSources from 'DataSources' folder\n            var (physicalPath, relativePath) = GetAppDataSourceFolderPaths(appId);\n            var physicalPathExists = Directory.Exists(physicalPath);\n            if (physicalPathExists)\n            {\n                var dsInDataSources = CreateDataSourceInfos(appId, LoadAppDataSources(spec, physicalPath, relativePath));\n                l.A($\"Custom Dynamic DataSources in {DataSourcesFolder}:{dsInDataSources.Count}\");\n                data = data.Concat(dsInDataSources).ToList();\n            }\n\n            l.A($\"Total Custom Dynamic DataSources:{data.Count}\");\n\n            // If the directory doesn't exist, return an empty list with a 3 minute policy\n            // just so we don't keep trying to do this on every query\n            if (!data.Any() && !physicalPathExists)\n                return l.Return(new(\n                            Data: [],\n                            SlidingExpiration: new(0, 5, 0),\n                            FolderPaths: [],\n                            CacheKeys: []), \n                            \"error, directory do not exist\");\n\n            return l.ReturnAsOk(new(\n                        Data: data,\n                        SlidingExpiration: new TimeSpan(1, 0, 0),\n                        FolderPaths: physicalPathExists\n                            ? [physicalPath]\n                            : [],\n                        CacheKeys: (data.Any() && !string.IsNullOrEmpty(cacheKey))\n                            ? [cacheKey!]\n                            : [] // cache dependency on existing cache item with AppCode assembly\n                        )\n                );\n        }\n        catch\n        {\n            return l.ReturnAsError(new(\n                    Data: [],\n                    SlidingExpiration: new(0, 5, 0),\n                    FolderPaths: [],\n                    CacheKeys: [])\n            );\n        }\n    }\n\n    private HotBuildSpec BuildHotBuildSpec(int appId)\n    {\n        var l = Log.Fn<HotBuildSpec>($\"{appId}:'{appId}'\", timer: true);\n\n        // Prepare / Get App State\n        var appSpecs = appReaders.Get(appId).Specs;\n\n        // Figure out the current edition\n        var edition = FigureEdition().TrimLastSlash();\n\n        var spec = new HotBuildSpec(appSpecs.AppId, edition: edition, appSpecs?.Name, appSpecs?.RuntimeKey);\n\n        return l.ReturnAsOk(spec);\n    }\n\n    private string? FigureEdition()\n    {\n        var l = Log.Fn<string?>(timer: true);\n\n        var block = ctxService.BlockOrNull();\n        var edition = block.NullOrGetWith(polymorphism.UseViewEditionOrGet);\n\n        return l.Return(edition);\n    }\n\n    private (string physicalPath, string relativePath) GetAppDataSourceFolderPaths(int appId)\n    {\n        var appReader = appReaders.Get(appId);\n        var appPaths = appPathsLazy.Value.Get(appReader, site);\n        var physicalPath = Path.Combine(appPaths.PhysicalPath, DataSourcesFolder);\n        var relativePath = Path.Combine(appPaths.RelativePath, DataSourcesFolder);\n        return (physicalPath, relativePath);\n    }\n\n    private class TempDsInfo\n    {\n        public required string ClassName;\n        public Type? Type;\n        public DataSourceInfoError? Error;\n    }\n\n    /// <summary>\n    /// Load Custom Dynamic DataSources from 'AppCode' assembly\n    /// </summary>\n    /// <param name=\"spec\"></param>\n    /// <param name=\"cacheKey\">return for CacheEntryChangeMonitor</param>\n    /// <returns></returns>\n    private IEnumerable<TempDsInfo> LoadAppCodeDataSources(HotBuildSpec spec, out string? cacheKey)\n    {\n        var l = Log.Fn<IEnumerable<TempDsInfo>>();\n\n        l.A(\"Search for DataSources in AppCode\");\n        var (result, _) = appCodeLoaderLazy.Value.GetAppCode(spec);\n\n        cacheKey = result?.CacheDependencyId; // return for CacheEntryChangeMonitor\n\n        var appCodeAssembly = result?.Assembly;\n        if (appCodeAssembly == null)\n            return l.Return([], \"no AppCode assembly found\");\n\n        l.A($\"AppCode:{appCodeAssembly.GetName().Name}\");\n\n        // find all types in the assembly that are derived from IAppDataSource\n        var types = appCodeAssembly.GetTypes()\n            .Where(t => typeof(Custom.DataSource.DataSource16).IsAssignableFrom(t) && !t.IsAbstract)\n            .Select(type =>\n            {\n                var className = type.Name;\n                try\n                {\n                    return new() { ClassName = className, Type = type };\n                }\n                catch (Exception ex)\n                {\n                    l.Ex(ex);\n                    return new TempDsInfo { ClassName = className, Error = new(\"Unknown Exception\", ex.Message) };\n                }\n            })\n            .ToList();\n\n        return types.Any()\n            ? l.Return(types, $\"OK, DataSources:{types.Count} ({string.Join(\";\", types.Select(t => t.ClassName))}) in AppCode:{appCodeAssembly.GetName().Name}\")\n            : l.Return(types, $\"OK, no working DataSources found in AppCode:{appCodeAssembly.GetName().Name}\");\n    }\n\n    /// <summary>\n    /// Load Custom Dynamic DataSources from 'DataSources' folder\n    /// </summary>\n    /// <param name=\"spec\"></param>\n    /// <param name=\"physicalPath\"></param>\n    /// <param name=\"relativePath\"></param>\n    /// <returns></returns>\n    private IEnumerable<TempDsInfo> LoadAppDataSources(HotBuildSpec spec, string physicalPath, string relativePath)\n    {\n        var l = Log.Fn<IEnumerable<TempDsInfo>>(\n            $\"{spec}; {nameof(physicalPath)}: '{physicalPath}'; {nameof(relativePath)}: '{relativePath}'\");\n\n        if (!Directory.Exists(physicalPath))\n            return l.Return([], $\"no {DataSourcesFolder} folder {physicalPath}\");\n\n        var compiler = codeCompilerLazy.Value;\n\n        var types = Directory\n            .GetFiles(physicalPath, \"*.cs\", SearchOption.TopDirectoryOnly)\n            .Select(dataSourceFile =>\n            {\n                var className = Path.GetFileNameWithoutExtension(dataSourceFile);\n                try\n                {\n                    var (type, errorMessages) = compiler.GetTypeOrErrorMessages(\n                        relativePath: Path.Combine(relativePath, Path.GetFileName(dataSourceFile)),\n                        className: className,\n                        throwOnError: false,\n                        spec: spec);\n\n                    if (!errorMessages.HasValue())\n                        return new() { ClassName = className, Type = type };\n                    l.E(errorMessages);\n                    return new()\n                    {\n                        ClassName = className,\n                        Type = type,\n                        Error = new(\"Error Compiling\", errorMessages)\n                    };\n                }\n                catch (Exception ex)\n                {\n                    l.Ex(ex);\n                    return new TempDsInfo { ClassName = className, Error = new(\"Unknown Exception\", ex.Message) };\n                }\n            })\n            .ToList();\n\n        return types.Any()\n            ? l.Return(types, $\"OK, DataSources:{types.Count} ({string.Join(\";\", types.Select(t => t.ClassName))}), path:{relativePath}\")\n            : l.Return(types, $\"OK, no working DataSources found, path:{relativePath}\");\n    }\n\n    private List<DataSourceInfo> CreateDataSourceInfos(int appId, IEnumerable<TempDsInfo> types)\n    {\n        var l = Log.Fn<List<DataSourceInfo>>($\"{nameof(appId)}: {appId}; has {nameof(types)}: {types != null}\");\n\n        // null check\n        if (types == null) return l.Return([], \"types are null\");\n\n        // App state for automatic lookup of configuration content-types\n        var appState = appReaders.Get(appId);\n        var data = types\n            .Select(pair =>\n            {\n                var l2 = l.Fn<DataSourceInfo>(pair.ClassName);\n\n                // 0. If error then type is null, in this case, return a specially crafted DSI\n                if (pair.Type == null)\n                    return l2.Return(DataSourceInfo.CreateError(pair.ClassName, false, DataSourceType.App, pair.Error), \"error: type==null\");\n\n                // 1. Make sure we only keep DataSources and not other classes in the same folder\n                // but assume all null-types are errors, which we should preserve\n                if (!typeof(IDataSource).IsAssignableFrom(pair.Type))\n                    return l2.ReturnNull($\"error: not a {nameof(IDataSource)}\")!;\n\n                // 2. Get VisualQuery Attribute if available, or create new, since it's optional in DynamicCode\n                var vq = pair.Type.GetDirectlyAttachedAttribute<VisualQueryAttribute>()\n                         ?? new VisualQueryAttribute();\n\n                var typeName = pair.Type.Name;\n\n                // 3. Update various properties which are needed for further functionality\n                // The global name is always necessary\n                vq.NameId = vq.NameId.NullIfNoValue() ?? typeName;\n                // The configuration type is automatically picked as *Configuration (if the type exists)\n                vq.ConfigurationType = vq.ConfigurationType.NullIfNoValue();\n                if (vq.ConfigurationType == null)\n                {\n                    var autoConfigTypeName = $\"{typeName}Configuration\";\n                    var autoConfigType = appState.TryGetContentType(autoConfigTypeName);\n                    vq.ConfigurationType = autoConfigType?.NameId;\n                    l2.A($\"Type name '{typeName}' had no config in definition, checked '{autoConfigTypeName}', found: {autoConfigType != null}\");\n                }\n\n                // Force the type of all local DataSources to be App\n                vq.Type = DataSourceType.App;\n                // Optionally set the star-icon if none is set\n                vq.Icon = vq.Icon.NullIfNoValue() ?? \"star\";\n                // If In has not been set, make sure we show the Default In as an option\n                vq.In ??= [DataSourceConstants.StreamDefaultName];\n                // Only set dynamic in if it was never set\n                if (!vq._DynamicInWasSet)\n                    vq.DynamicIn = true;\n\n                // 4. Build DataSourceInfo with the manually built Visual Query Attribute\n                return l2.ReturnAsOk(new(pair.Type, false, overrideVisualQuery: vq));\n            })\n            .Where(dsi => dsi != null!)\n            .ToList();\n\n        return l.Return(data, $\"{data.Count}\");\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Search/ICustomizeSearch.cs",
    "content": "﻿using ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Search;\n\n/// <summary>\n/// This interface marks custom code which views use to customize how search treats data of that view.\n/// It's meant for customizing the internal indexer of the platform, _not_ for Google Search.\n///\n/// To use it, create a custom code (.cs) file which implements this interface.\n/// You can also inherit from a DynamicCode base class (like Code12) if you need more functionality. \n/// </summary>\n/// <remarks>\n/// History: Released v12.02\n/// </remarks>\n[PublicApi]\npublic interface ICustomizeSearch\n{\n    /// <summary>\n    /// Will be called by the search indexer to pre-process the results. \n    /// </summary>\n    /// <param name=\"searchInfos\">Dictionary containing the streams and items in the stream for this search.</param>\n    /// <param name=\"moduleInfo\">Module information with which you can find out what page it's on etc.</param>\n    /// <param name=\"beginDate\">Last time the indexer ran - because the data you will get is only what was modified since.</param>\n    void CustomizeSearch(Dictionary<string, List<ISearchItem>> searchInfos, IModule moduleInfo, DateTime beginDate);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Search/ISearchItem.cs",
    "content": "﻿//#if !NETFRAMEWORK\n//#pragma warning disable CS0109\n//#endif\n\nnamespace ToSic.Sxc.Search;\n\n/// <summary>\n/// Defines an item in the search system - which is prepared by Sxc, and can be customized as needed\n/// </summary>\n[PublicApi]\npublic interface ISearchItem\n//#if NETFRAMEWORK\n//    : ToSic.SexyContent.Search.ISearchInfo // backward compatibility\n//#endif\n{\n     string UniqueKey { get; set; }\n\n    /// <summary>\n    /// Title in search results\n    /// </summary>\n     string Title { get; set; }\n\n    /// <summary>\n    /// Description in search results\n    /// </summary>\n     string Description { get; set; }\n\n    /// <summary>\n    /// Contents of this item - will be indexed\n    /// </summary>\n     string Body { get; set; }\n\n    /// <summary>\n    /// Url to go to, when looking at the details of this search result\n    /// </summary>\n     string Url { get; set; }\n\n    /// <summary>\n    /// Timestamp in GMT / UTC\n    /// </summary>\n     DateTime ModifiedTimeUtc { get; set; }\n\n    /// <summary>\n    /// Determines if this item should appear in search or be ignored\n    /// </summary>\n     bool IsActive { get; set; }\n\n    /// <summary>\n    /// Query String params to access this item\n    /// </summary>\n     string QueryString { get; set; }\n\n    /// <summary>\n    /// Culture code, for language sensitive searches\n    /// </summary>\n     string CultureCode { get; set; }\n\n    /// <summary>\n    /// The underlying data in the search\n    /// </summary>\n     IEntity Entity { get; set; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Search/ToSic.SexyContent.Search.ISearchInfo.cs",
    "content": "﻿//#if NETFRAMEWORK\n\n//// ReSharper disable once CheckNamespace\n//namespace ToSic.SexyContent.Search;\n\n///// <remarks>\n///// This is part of a public API, so don't touch the name or namespace\n///// </remarks>\n//[ShowApiWhenReleased(ShowApiMode.Never)]\n//public interface ISearchInfo\n//{\n//    string UniqueKey { get; set; }\n//    string Title { get; set; }\n//    string Description { get; set; }\n//    string Body { get; set; }\n//    string Url { get; set; }\n//    DateTime ModifiedTimeUtc { get; set; }\n//    bool IsActive { get; set; }\n//    string QueryString { get; set; }\n//    string CultureCode { get; set; }\n//    IEntity Entity { get; set; }\n//}\n\n//#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Custom/ToSic.Sxc.Services/ServiceKitLight16.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Services.Data.Sys;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Lightweight ServiceKit for 2sxc v16.\n/// Provided in custom data sources as `Kit`.\n/// </summary>\n/// <remarks>\n/// It's primarily used in dynamic code which runs standalone, without a module context.\n///\n/// Example: Custom DataSources can run anywhere without actually being inside a module or content-block.\n/// In such scenarios, certain services like the <see cref=\"IPageService\"/> would not be able to perform any real work.\n/// \n/// History: Added v15.06 - still WIP\n/// </remarks>\n[PublicApi]\npublic class ServiceKitLight16(IServiceProvider serviceProvider) : ServiceBase(\"Sxc.Kit15\", connect: [/* never! serviceProvider */ ])\n{\n    private TService GetService<TService>() => serviceProvider.Build<TService>(Log);\n\n    internal ServiceKitLight16 Setup(IAppIdentity appIdentity, Func<ILookUpEngine> getLookup)\n    {\n        _appIdentity = appIdentity;\n        _getLookup = getLookup;\n        return this;\n    }\n\n    private IAppIdentity _appIdentity = null!;\n    private Func<ILookUpEngine> _getLookup = null!;\n\n    ///// <summary>\n    ///// The ADAM Service, used to retrieve files and maybe more. \n    ///// </summary>\n    //public IAdamService Adam => _adam.Get(GetService<IAdamService>);\n    //private readonly GetOnce<IAdamService> _adam = new GetOnce<IAdamService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Convert\"/>\n    public IConvertService Convert => _convert.Get(GetService<IConvertService>)!;\n    private readonly GetOnce<IConvertService> _convert = new();\n\n    /// <inheritdoc cref=\"ServiceKit14.Data\"/>\n    public IDataService Data => _data.Get(() =>\n    {\n        var dss = GetService<IDataService>();\n        (dss as DataService)?.Setup(new(_appIdentity, _getLookup));\n        return dss;\n    })!;\n    private readonly GetOnce<IDataService> _data = new();\n\n\n    /// <inheritdoc cref=\"ServiceKit14.Feature\"/>\n    public IFeaturesService Feature => _features.Get(GetService<IFeaturesService>)!;\n    private readonly GetOnce<IFeaturesService> _features = new();\n\n    /// <inheritdoc cref=\"ServiceKit14.HtmlTags\"/>\n    public IHtmlTagsService HtmlTags => _ht.Get(GetService<IHtmlTagsService>)!;\n    private readonly GetOnce<IHtmlTagsService> _ht = new();\n\n    /// <inheritdoc cref=\"ServiceKit14.Json\"/>\n    public IJsonService Json => _json.Get(GetService<IJsonService>)!;\n    private readonly GetOnce<IJsonService> _json = new();\n\n    /// <inheritdoc cref=\"ServiceKit14.SystemLog\"/>\n    public ISystemLogService SystemLog => _sysLog.Get(GetService<ISystemLogService>)!;\n    private readonly GetOnce<ISystemLogService> _sysLog = new();\n\n    /// <inheritdoc cref=\"ServiceKit14.SecureData\"/>\n    public ISecureDataService SecureData => _secureData.Get(GetService<ISecureDataService>)!;\n    private readonly GetOnce<ISecureDataService> _secureData = new();\n\n    /// <inheritdoc cref=\"ServiceKit14.Scrub\"/>\n    public IScrub Scrub => _scrub.Get(GetService<IScrub>)!;\n    private readonly GetOnce<IScrub> _scrub = new();\n\n\n    //[PrivateApi(\"Experimental in v15.03\")]\n    //public IUsersService Users => _users.Get(GetService<IUsersService>);\n    //private readonly GetOnce<IUsersService> _users = new GetOnce<IUsersService>();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Adam/AssetTypes.cs",
    "content": "﻿namespace ToSic.Sxc.Adam;\n\n/// <summary>\n/// Provides constant string values that represent common ADAM (Asset Digital Asset Management) item types.\n/// </summary>\n/// <remarks>\n/// The constants can be used to identify or compare asset types such as\n/// folders, files, images, and documents within ADAM-related APIs.\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic class AssetTypes\n{\n    /// <summary>\n    /// The asset is a folder.\n    /// </summary>\n    public const string Folder = \"folder\";\n\n    /// <summary>\n    /// The asset is a file, specifically one which is not detected to be an image or a document.\n    /// </summary>\n    public const string File = \"file\";\n\n    /// <summary>\n    /// The asset is an image.\n    /// </summary>\n    public const string Image = \"image\";\n\n    /// <summary>\n    /// The asset is a document.\n    /// </summary>\n    public const string Document = \"document\";\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Adam/IAsset.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Field;\n\nnamespace ToSic.Sxc.Adam;\n\n/// <summary>\n/// Describes an ADAM (Automatic Digital Asset Management) asset. <br/>\n/// This contains properties which both <see cref=\"IFolder\"/> and <see cref=\"IFile\"/> have in common\n/// in addition to what they inherit from the EAV\n/// </summary>\n[PublicApi]\npublic interface IAsset: IHasMetadata, IFromField\n{\n    #region Metadata\n\n    /// <summary>\n    /// Tells you if this asset has real metadata attached or not. \n    /// </summary>\n    /// <returns>\n    /// `true` if this asset has metadata, `false` if it doesn't (in which case the Metadata property still works, but won't deliver any real values)\n    /// </returns>\n    bool HasMetadata { get; }\n\n    /// <summary>\n    /// List of metadata items - \n    /// will automatically contain a fake item, even if no metadata exits\n    /// to help in razor template etc.\n    /// </summary>\n    /// <returns>\n    /// An `IMetadata` which contains the metadata, or an empty IMetadata which still works if no metadata exists.\n    /// </returns>\n    new ITypedMetadata Metadata { get; }\n\n    #endregion\n\n\n    /// <summary>\n    /// The path to this asset as used from external access.\n    /// Must be a full url beginning with a \"/\" like \"/Portals/0/adam/...\"\n    /// </summary>\n    /// <returns>\n    /// The url to this asset.\n    /// `/Portals/0/2sxc/content/assets/docs/terms/file.pdf` for `C:\\Inetpub\\wwwroot\\www.2sic.com\\Portals\\0\\2sxc\\content\\assets\\docs\\terms\\file.pdf`\n    /// </returns>\n    string? Url { get; }\n\n    /// <summary>\n    /// The type of this asset (folder, file, etc.) - typically for adding icons or similar when listing assets.\n    /// </summary>\n    /// <returns>\n    /// `folder`, `image`, `document`, `file` depending on what it is.\n    /// See <see cref=\"AssetTypes\"/>\n    /// </returns>\n    string Type { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Adam/IFile.cs",
    "content": "﻿namespace ToSic.Sxc.Adam;\n\n/// <summary>\n/// An ADAM (Automatic Digital Asset Management) file\n/// This simple interface assumes that it uses int-IDs.\n/// </summary>\n[PublicApi]\n\npublic interface IFile:\n    IAsset,\n    Eav.Apps.Assets.IFile;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Adam/IFolder.cs",
    "content": "﻿namespace ToSic.Sxc.Adam;\n\n/// <summary>\n/// An ADAM (Automatic Digital Asset Management) folder.\n/// This simple interface assumes that it uses int-IDs.\n/// </summary>\n[PublicApi]\npublic interface IFolder: Eav.Apps.Assets.IFolder, IAsset\n{\n    /// <summary>\n    /// Get the files in this folder\n    /// </summary>\n    /// <returns>A list of files in this folder as <see cref=\"IFile\"/></returns>\n    IEnumerable<IFile> Files { get; }\n\n    /// <summary>\n    /// Get the sub-folders in this folder\n    /// </summary>\n    /// <returns>A list of folders inside this folder - as <see cref=\"IFolder\"/>.</returns>\n    IEnumerable<IFolder> Folders { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Adam/Sys/AssetTypeNames.cs",
    "content": "﻿namespace ToSic.Sxc.Adam.Sys;\n\n/// <summary>\n/// Helper to classify a file by type.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AssetTypeNames\n{\n    public static string GetTypeName(string ext) =>\n        // Make sure it's lower and doesn't have a leading .\n        ext.ToLowerInvariant().Trim('.') switch\n        {\n            \"png\" or \"jpg\" or \"jpgx\" or \"jpeg\" or \"gif\" or \"svg\" or \"webp\" => AssetTypes.Image,\n            \"doc\" or \"docx\" or \"txt\" or \"pdf\" or \"xls\" or \"xlsx\" => AssetTypes.Document,\n            _ => AssetTypes.File\n        };\n\n    public static bool IsImage(string ext) => GetTypeName(ext) == AssetTypes.Image;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Cms.Data/GpsCoordinates.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\n\nnamespace ToSic.Sxc.Cms.Data;\n\n/// <summary>\n/// Represents GPS coordinates.\n/// </summary>\n/// <remarks>\n/// Released in v17.03, still BETA.\n/// </remarks>\n[PublicApi]\npublic class GpsCoordinates\n{\n    /// <summary>\n    /// The latitude (North is +, South is -) of the GPS coordinates.\n    /// </summary>\n    public double Latitude { get; set; }\n\n    /// <summary>\n    /// The longitude (East is +, West is -) of the GPS coordinates.\n    /// </summary>\n    public double Longitude { get; set; }\n\n    /// <summary>\n    /// Parse a json string into a <see cref=\"GpsCoordinates\"/> object.\n    /// It's an own function, to ensure that the deserialization is done with the correct options,\n    /// since it may be used in places where the IJsonService is not available.\n    /// </summary>\n    [PrivateApi]\n    internal static GpsCoordinates FromJson(string? json)\n        => json.HasValue()\n            ? JsonSerializer.Deserialize<GpsCoordinates>(json, options: JsonOptions.SafeJsonForHtmlAttributes)!\n            : new();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/DynamicEntity (no namespace)/IDynamicEntity.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Sxc.Data.Sys.Docs;\nusing ToSic.Sxc.Data.Sys.Factory;\n\n#if !NETFRAMEWORK\n#pragma warning disable CS0108, CS0114\n#pragma warning disable CS0109\n#endif\n\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// This is an older _dynamic_ wrapper for IEntity objects. It provides _dynamic_ access to underlying properties.\n/// </summary>\n/// <remarks>\n/// It provides nicer access to underlying properties\n/// and automatically handles things like multi-language etc.\n/// The underlying IEntity <see cref=\"IEntity\"/> is in the Entity property.\n/// \n/// <blockquote>\n/// This is an older way to work with entities and not recommended anymore.\n/// You should use a newer base class such as `RazorTyped`, there Dynamic objects are not used anymore.\n/// </blockquote>\n/// \n/// Normally you will use it without caring about these internals. <br/>\n/// Please check @HowTo.DynamicCode.DynamicEntity\n/// \n/// </remarks>\n[PublicApi]\npublic partial interface IDynamicEntity:\n    IEntityWrapper, \n    ISxcDynamicObject, \n    ICanDebug\n{\n    /// <summary>\n    /// Get a Field-object of a property of this entity, to use with services like the <see cref=\"Services.IImageService\"/> which also need more information like the metadata.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// History: Added in v13.10\n    /// </remarks>\n    IField? Field(string name);\n\n    /// <summary>\n    /// The type name of the current entity. This provides the nice name like \"Person\" and not the technical internal StaticName\n    /// </summary>\n    /// <remarks>\n    /// * Added in v13\n    /// * Changed type name to `IMetadata` from `IDynamicMetadata` in 16.02; same type, different type name\n    /// * Changed type to `dynamic` in v20 since we believe all use cases in the wild always use dynamic access.\n    /// </remarks>\n    dynamic Metadata { get; }\n\n    #region Publishing / Draft Information\n\n    /// <summary>\n    /// Get the draft item of this item if this is a content-item which is published, and has a draft.\n    /// </summary>\n    /// <returns>Returns a dynamic entity if there is a draft, or null if there is no draft.</returns>\n    dynamic? GetDraft();\n\n    /// <summary>\n    /// Get the published item of this item if this is a content-item which is draft, and has a published.\n    /// </summary>\n    /// <returns>Returns a dynamic entity if there is a draft, or null if there is no draft.</returns>\n    dynamic? GetPublished();\n\n    // This property would also work on the normal dynamic interface, but we want them to appear in the documentation so we're adding them\n    /// <summary>\n    /// Tells us if this data item is published or still draft. Default is true.\n    /// </summary>\n    bool IsPublished { get; }\n\n    #endregion\n\n\n    #region parents / children\n\n    /// <summary>\n    /// A dynamic list of entities which point to this item. Important for LINQ style querying or just\n    /// working with various lists. Note that for getting child items of this item you\n    /// can just use the properties, like content.Authors. <br/>\n    /// Please check the tutorials on 2sxc.org/dnn-tutorials/ for more info. \n    /// </summary>\n    /// <param name=\"type\">Optional type filter - would only return items of this type. </param>\n    /// <param name=\"field\">Optional field filter - would only return items that point to the current item in a specific field name.</param>\n    /// <returns>A list of all items pointing here (filtered), converted to DynamicEntity for convenience.</returns>\n    /// <remarks>New in 9.42 - note also that the parameter-order is reversed to the Children()</remarks>\n    List<IDynamicEntity?> Parents(string? type = null, string? field = null);\n\n    /// <summary>\n    /// A dynamic list of sub-items. Important for LINQ style querying or just\n    /// working with various lists. Note that for getting child items of this item you\n    /// can just use the properties, like content.Authors. <br/>\n    /// But using Children(\"Authors\", typeName) gives you the ability to restrict to a type.  <br/>\n    /// Please check the tutorials on 2sxc.org/dnn-tutorials/ for more info. \n    /// </summary>\n    /// <param name=\"type\">Optional type filter - would only return items of this type. </param>\n    /// <param name=\"field\">Optional field filter - would only return items that point to the current item in a specific field name.</param>\n    /// <returns>A list of all items pointing here (filtered), converted to DynamicEntity for convenience.</returns>\n    /// <remarks>New in 10.21.00 - note also that the parameter-order is reversed to the Parents()</remarks>\n    List<IDynamicEntity?> Children(string? field = null, string? type = null);\n\n    #endregion \n\n    /// <summary>\n    /// Contains presentation settings for an item - if they exist.\n    /// This is a functionality of the CMS, where an instance of an item can be configured to show in a specific way.\n    /// Normally it's used when something like an address has various show-settings (like how the map should visualize this address).\n    /// The presentation-info is therefor not-null IF <br/>\n    /// - the content <em>belongs</em> to this module instance <br/>\n    /// - the view-configuration of this module is configured to have presentation items <br />\n    /// - there is either a default presentation configured in the view, or the user has manually edited the presentation settings\n    /// </summary>\n    /// <returns>\n    /// An <see cref=\"IDynamicEntity\"/> with the presentation item (or the demo-presentation), otherwise null.\n    /// </returns>\n    dynamic? Presentation { get; }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    // ReSharper disable once InconsistentNaming\n    ICodeDataFactory Cdf {get; }\n\n\n    /* IMPORTANT: These are just fake properties for documentation - Keep in Sync between IDynamicEntity and IDynamicStack */\n\n    /// <inheritdoc cref=\"IDynamicAnythingDocs.AnyProperty\"/>\n    public dynamic? AnyProperty { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/DynamicEntity (no namespace)/IDynamicEntity_SharedCms.cs",
    "content": "﻿using ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Data;\n\npublic partial interface IDynamicEntity\n{\n    /// <summary>\n    /// Many templates show demo data.\n    /// If the template code must know if it's the demo item or\n    /// real data, use `.IsDemoItem`.\n    /// </summary>\n    /// <returns>\n    /// True if this is the item configured in the view-settings, false if not.\n    /// </returns>\n    /// <remarks>New in 10.07 on IDynamicEntity, new in 16.02 on ITypedEntity</remarks>\n    bool IsDemoItem { get; }\n\n    /// <summary>\n    /// Show a field in the expected / the best possible way.\n    /// As of now it's meant for WYSIWYG fields with Very-Rich Text.\n    /// See [](xref:NetCode.DynamicData.DynamicEntityHtml)\n    /// </summary>\n    /// <param name=\"name\">the field name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"container\">\n    /// A wrapper tag for the result.\n    /// It's either a RazorBlade tag such as `Kit.HtmlTag.Div()`, a string such as `span` or an empty string `` to indicate no container.\n    /// If not set it will default to a div-tag.\n    /// See [docs](xref:NetCode.DynamicData.DynamicEntityHtml)\n    /// </param>\n    /// <param name=\"toolbar\">Override default toolbar behavior on this field. See [docs](xref:NetCode.DynamicData.DynamicEntityHtml)</param>\n    /// <param name=\"imageSettings\">Settings for resizing. Default is `Wysiwyg` but it can also be `Content` or a settings object.</param>\n    /// <param name=\"debug\">Activate debug visualization to better see alignments and such.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Added in 2sxc 16.01\n    /// * Only works on Razor files inheriting from Hybrid14 or newer\n    /// </remarks>\n    IHtmlTag? Html(\n        string name,\n        NoParamOrder npo = default,\n        object? container = default,\n        bool? toolbar = default,\n        object? imageSettings = default,\n        bool debug = default\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/DynamicEntity (no namespace)/IDynamicEntity_SharedEntityProperties.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\npublic partial interface IDynamicEntity\n{\n    /// <summary>\n    /// The ID of the underlying entity.\n    /// Use it for edit-functionality or just to have a unique number for this item.\n    /// </summary>\n    /// <remarks>If the entity doesn't exist, it will return 0</remarks>\n    int EntityId { get; }\n\n    /// <summary>\n    /// The guid of the underlying entity.\n    /// </summary>\n    /// <remarks>If the entity doesn't exist, it will return an empty guid</remarks>\n    Guid EntityGuid { get; }\n\n    /// <summary>\n    /// The title of this item. This is always available no matter what the underlying field for the title is. \n    /// </summary>\n    /// <returns>\n    /// The title of the underlying entity.\n    /// In rare cases where no title-field is known, it can be null.\n    /// It can also be null if there is no underlying entity. \n    /// </returns>\n    /// <remarks>This returns a string which is usually what's expected. In previous versions (before v15) 2sxc it returned an object.</remarks>\n    string? EntityTitle { get; }\n\n    /// <summary>\n    /// The type name of the current entity. This provides the nice name like \"Person\" and not the technical internal StaticName\n    /// </summary>\n    string? EntityType { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/DynamicEntity (no namespace)/IDynamicEntity_SharedGet.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Docs;\n\nnamespace ToSic.Sxc.Data;\n\npublic partial interface IDynamicEntity\n{\n    /* IMPORTANT: KEEP THIS DEFINITION AND DOCS IN SYNC BETWEEN IDynamicEntity, IDynamicEntityBase and IDynamicStack */\n    /// <inheritdoc cref=\"DynamicEntityDocs.Get(string)\"/>\n    dynamic? Get(string name);\n\n\n    /* IMPORTANT: KEEP THIS DEFINITION AND DOCS IN SYNC BETWEEN IDynamicEntity, IDynamicEntityBase and IDynamicStack */\n    /// <inheritdoc cref=\"DynamicEntityDocs.Get(string, NoParamOrder, string?, bool, bool?)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    dynamic? Get(string name, NoParamOrder npo = default, string? language = null, bool convertLinks = true, bool? debug = null);\n\n    /// <inheritdoc cref=\"DynamicEntityDocs.Get{TValue}(string)\"/>\n    TValue? Get<TValue>(string name);\n\n    /// <inheritdoc cref=\"DynamicEntityDocs.Get{TValue}(string, NoParamOrder, TValue)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/ICanBeItem.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\n/// <summary>\n/// This is just a helper interface.\n/// Reason is that we have different types of objects representing real entity-data such as:\n/// \n/// * <see cref=\"IDynamicEntity\"/>\n/// * <see cref=\"ITypedItem\"/>\n///\n/// To make sure that APIs which use this have a consistent structure, these objects all implement this interface.\n/// </summary>\n[PrivateApi(\"Was InternalApi till v17, but Just FYI\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ICanBeItem: ICanBeEntity\n{\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    ITypedItem Item { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/IDynamicStack.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Docs;\n\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// This is a dynamic object which contains multiple dynamic objects (Sources).\n/// </summary>\n/// <remarks>\n/// It will try to find a value inside each source in the order of the provided Sources. \n/// \n/// History: Introduced in 12.02\n/// </remarks>\n[PublicApi]\npublic interface IDynamicStack: ISxcDynamicObject, ICanDebug, ICanGetByName\n{\n    /// <summary>\n    /// Get a source object which is used in the stack. Returned as a dynamic object. \n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <returns>A dynamic object like a <see cref=\"IDynamicEntity\"/> or similar. If not found, it will return a source which just-works, but doesn't have data. </returns>\n    /// <remarks>\n    /// Added in 2sxc 12.03\n    /// </remarks>\n    [PrivateApi(\"was public till v16.02, but since I'm not sure if it is really used, we decided to hide it again since it's probably not an important API\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)] \n    dynamic? GetSource(string name);\n\n    [PrivateApi(\"Never published in docs\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)] \n    dynamic GetStack(params string[] names);\n\n    #region Get and Get<T>\n\n    /* IMPORTANT: KEEP THIS DEFINITION AND DOCS IN SYNC BETWEEN IDynamicEntity, IDynamicEntityBase and IDynamicStack */\n    /// <inheritdoc cref=\"DynamicEntityDocs.Get(string)\"/>\n    new dynamic? Get(string name);\n\n    /* IMPORTANT: KEEP THIS DEFINITION AND DOCS IN SYNC BETWEEN IDynamicEntity, IDynamicEntityBase and IDynamicStack */\n    /// <inheritdoc cref=\"DynamicEntityDocs.Get(string, NoParamOrder, string, bool, bool?)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    dynamic? Get(string name, NoParamOrder npo = default, string? language = null, bool convertLinks = true, bool? debug = null);\n\n    /// <inheritdoc cref=\"DynamicEntityDocs.Get{TValue}(string)\"/>\n    TValue? Get<TValue>(string name);\n\n    /// <inheritdoc cref=\"DynamicEntityDocs.Get{TValue}(string, NoParamOrder, TValue)\"/>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default);\n\n    #endregion\n\n    #region Any** IMPORTANT: These are just fake properties for documentation - Keep in Sync between IDynamicEntity and IDynamicStack\n\n    /// <inheritdoc cref=\"IDynamicAnythingDocs.AnyProperty\"/>\n    public dynamic AnyProperty { get; }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/IField.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data.Sys.Field;\n\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// This describes a field-property of an item/entity. \n/// </summary>\n/// <remarks>\n/// It's used for APIs which can need to know more about the field holding an item, like:\n///\n/// - The field name and parent reference\n/// - The values in raw and converted\n/// - Any metadata of the field\n/// \n/// History\n/// \n/// * Created in v13.10, originally as `IDynamicField`\n/// * In v16.02 renamed `IField` as it's not dynamic, and published\n/// * In 16.02 changed types of `Value` and `Raw` to `object` - previously `dynamic`\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"This is just FYI so you see how it works; you shouldn't use any of these properties in your code\")]\npublic interface IField: IHasLink, IHasMetadata\n{\n    /// <summary>\n    /// The field name\n    /// </summary>\n    string Name { get; }\n\n    /// <summary>\n    /// The parent object of this field\n    /// </summary>\n    ITypedItem Parent { get; }\n\n    /// <summary>\n    /// The raw value of the field, without any modifications.\n    /// If the value is `file:22` then Raw will also return `file:22`.\n    /// To get the value as a link, use <see cref=\"Value\"/>\n    /// </summary>\n    [PrivateApi(\"Was public till 16.03, but don't think it should be surfaced...\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    object? Raw { get; }\n\n    /// <summary>\n    /// The value of the field with modifications.\n    /// For example, `file:22` would be converted to the real link.\n    /// To get the raw value, use <see cref=\"Raw\"/>\n    /// </summary>\n    [PrivateApi(\"Was public till 16.03, but don't think it should be surfaced...\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    object? Value { get; }\n\n    ///// <summary>\n    ///// Metadata of the thing in the field - if it has such metadata.\n    /////\n    ///// The object will never be null, but it can of course not have any data if there is no metadata. \n    ///// </summary>\n    //new IMetadata Metadata { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/IMetadataDynamic.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Data;\n\n[PrivateApi(\"old, should not be promoted any more\")]\npublic interface IMetadataDynamic : IHasMetadata, ICanDebug, ISxcDynamicObject, IEntityWrapper\n{\n    /// <inheritdoc cref=\"ITypedMetadata.HasType\"/>\n    bool HasType(string type);\n\n    /// <inheritdoc cref=\"ITypedMetadata.OfType\"/>\n    IEnumerable<IEntity> OfType(string type);\n\n    /// <summary>\n    /// Old property for the ID of the first type.\n    /// It was necessary to re-instate this because it's used in old Apps such as BlueImp Gallery.\n    /// </summary>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    int EntityId { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/ISxcDynamicObject.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\n/// <summary>\n/// Marks 2sxc dynamic objects.\n/// Mainly to ensure that they are not re-converted if they already are such dynamic objects\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ISxcDynamicObject;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/ITypedMetadata.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\n\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// Metadata on Dynamic Objects - like <see cref=\"IDynamicEntity\"/> or <see cref=\"ToSic.Sxc.Adam.IAsset\"/> (files/folders).\n/// </summary>\n/// <remarks>\n/// Behaves like a normal DynamicEntity, but has additional commands to detect if specific Metadata exists.\n/// \n/// History:\n/// \n/// * Added in v13\n/// * Made compatible to <see cref=\"ITypedItem\"/> in 16.02 to allow typed commands such as `.String(...)`\n/// * Renamed in v16.02 from `IDynamicMetadata` to `IMetadata` since it's not necessarily `dynamic` any more (but still supports `dynamic` where needed)\n///     _Note that this is a breaking change, but we believe the type is never directly mentioned in any code_\n/// * Renamed in v20 to `ITypedMetadata` from `IMetadata` because it kept on causing confusions\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"The name can change, but the APIs are safe to use.\")]\npublic interface ITypedMetadata: /*IHasMetadata, */ITypedItem, ICanDebug, /*ISxcDynamicObject,*/ IEntityWrapper\n{\n    /// <summary>\n    /// Ask if there is metadata of the type specified.\n    /// This is important in scenarios where an item could have a lot of metadata, but we only want one specific type to look at.\n    /// </summary>\n    /// <param name=\"type\"></param>\n    /// <returns>`true` if metadata of that type exists</returns>\n    // ReSharper disable once UnusedMember.Global\n    bool HasType(string type);\n\n    /// <summary>\n    /// Get all the metadata Entities of a specific type.\n    /// </summary>\n    /// <param name=\"type\"></param>\n    /// <returns></returns>\n    IEnumerable<IEntity> OfType(string type);\n\n    /// <summary>\n    /// WIP v21.02\n    /// </summary>\n    /// <returns></returns>\n    IEnumerable<IEntity> GetAll();\n\n    // TODO: REMOVE\n    ///// <summary>\n    ///// Old property for the ID of the first type.\n    ///// It was necessary to re-instate this because it's used in old Apps such as BlueImp Gallery.\n    ///// </summary>\n    //[PrivateApi]\n    //[ShowApiWhenReleased(ShowApiMode.Never)]\n    //int EntityId { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/ITypedStack.cs",
    "content": "﻿\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// The stack as typed object.\n/// </summary>\n/// <remarks>\n/// Enhanced in v17.07 to fully support `ITypedItem`, before it only supported `ITyped`.\n/// </remarks>\n[PublicApi]\npublic interface ITypedStack: ITypedItem, ICanDebug\n{\n    ///// <inheritdoc cref=\"ITypITypedRelationshipsDocsld\"/>\n    //ITypedItem Child(string name, NoParamOrder npo = default, bool? required = default);\n\n    ///// <inheritdoc cref=\"ITypedRelationshipsDocs.Children\"/>\n    //IEnumerable<ITypedItem> Children(string field = default, NoParamOrder npo = default, string type = default, bool? required = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Models/ModelFromItem.cs",
    "content": "﻿using System.Data;\nusing ToSic.Eav.Models.Factory;\nusing ToSic.Sxc.Data.Models.Sys;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Models;\n\n\n/// <summary>\n/// BETA / WIP: Base class for **plain** data models and can be used in Razor Components.\n/// It wraps an <see cref=\"ITypedItem\"/> and provides a simple way to access the data.\n/// </summary>\n/// <example>\n///\n/// Usage ca. like this:\n///\n/// 1. A custom data model in `AppCode.Data` which inherits from this class (usually generated by 2sxc Copilot)\n/// 2. Razor code which uses it to convert typed items into this custom data model\n/// \n/// Example trivial custom **plain** data model:\n/// \n/// ```c#\n/// namespace AppCode.Data\n/// {\n///   class MyPerson : DataModelOfItem\n///   {\n///     public int Id => _item.Id;\n///     public string Name => _item.String(\"Name\");\n///   }\n/// }\n/// ```\n///\n/// Example usage in Razor:\n///\n/// ```razor#\n/// @inherits Custom.Hybrid.RazorTyped\n/// @using AppCode.Data\n/// @{\n///   var person = As&lt;MyPerson&gt;(MyItem);\n/// }\n/// <span>@person.Name</span>\n/// ```\n/// </example>\n/// <remarks>\n/// This is much lighter than the [](xref:Custom.Data.CustomItem) which also wraps data, as it doesn't have any predefined properties and doesn't have the <see cref=\"ITypedItem\"/> APIs.\n/// \n/// History\n/// \n/// - Released in v19.01 (BETA)\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"Still beta, name may change to DataModelWithItem or something\")]\npublic abstract partial class ModelFromItem : IModelSetupWithFactory<ITypedItem>, ICanBeItem, ICanBeEntity\n{\n    #region Explicit Interfaces for internal use - Setup, etc.\n\n    void IModelSetupWithFactory<ITypedItem>.Setup(ITypedItem source, IModelFactory modelFactory)\n    {\n        _item = source;\n        _modelFactory = modelFactory;\n    }\n\n    private IModelFactory _modelFactory = null!;\n\n    /// <summary>\n    /// The actual item which is being wrapped, in rare cases where you must access it from outside.\n    /// It's only on the explicit interface, so it is not available from outside or inside, unless you cast to it.\n    /// Goal is that inheriting classes don't access it to keep API surface small.\n    /// </summary>\n    ITypedItem ICanBeItem.Item => _item;\n\n    /// <summary>\n    /// This is necessary so the object can be used in places where an IEntity is expected, like toolbars.\n    /// It's an explicit interface implementation, so that the object itself doesn't broadcast this.\n    /// </summary>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IEntity ICanBeEntity.Entity => _item.Entity;\n\n    //IPropertyLookup IHasPropLookup.PropertyLookup => _propLookup ??= ((IHasPropLookup)((ICanBeItem)this).Item).PropertyLookup;\n    //private IPropertyLookup _propLookup;\n\n    #endregion\n\n    /// <summary>\n    /// The underlying item - for inheriting classes to access.\n    /// </summary>\n    /// <remarks>\n    /// * this property is protected, not public, as it should only be used internally.\n    /// * this also prevents it from being serialized in JSON, which is good.\n    /// * it uses an unusual name `_item` to avoid naming conflicts with properties generated in inheriting classes.\n    /// </remarks>\n#pragma warning disable IDE1006\n    // ReSharper disable once InconsistentNaming\n    protected internal ITypedItem _item { get; private set; } = null!;\n#pragma warning restore IDE1006\n\n    /// <summary>\n    /// Override ToString to give more information about the current object\n    /// </summary>\n    public override string ToString() \n        => $\"{nameof(ModelFromItem)} Data Model {GetType().FullName} \" + (_item == null! ? \"without backing data (null)\" : $\"for id:{_item.Id} ({_item})\");\n\n\n    #region As...\n\n    /// <inheritdoc cref=\"DataModelHelpers.As{TCustom}\"/>\n    protected T? As<T>(object item)\n        where T : class, IModelFromData\n        => DataModelHelpers.As<T>(_modelFactory, item);\n\n    /// <inheritdoc cref=\"DataModelHelpers.AsList{T}\"/>\n    protected IEnumerable<T>? AsList<T>(object source, NoParamOrder npo = default, bool nullIfNull = false)\n        where T : class, IModelFromData\n        => DataModelHelpers.AsList<T>(_modelFactory, source, new() { ItemIsStrict = true }, nullIfNull: nullIfNull);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Models/ModelFromItem_Equatable.cs",
    "content": "﻿\nnamespace ToSic.Sxc.Data.Models;\n\npartial class ModelFromItem : IMultiWrapper<IEntity>, IEquatable<ITypedItem>\n{\n    bool IEquatable<ITypedItem>.Equals(ITypedItem? other) => Equals(other);\n\n    /// <summary>\n    /// Ensure that the equality check is done correctly.\n    /// If two objects wrap the same item, they will be considered equal.\n    /// </summary>\n    public override bool Equals(object? b)\n        => MultiWrapperEquality.EqualsObj(this, b);\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public override int GetHashCode()\n        => MultiWrapperEquality.GetWrappedHashCode(this);\n\n    IEntity? IMultiWrapper<IEntity>.RootContentsForEqualityCheck\n        => (_item as IMultiWrapper<IEntity>)?.RootContentsForEqualityCheck;\n\n    /// <summary>\n    /// Ensure that the equality check is done correctly.\n    /// If two objects wrap the same item, they will be considered equal.\n    /// </summary>\n    /// <param name=\"a\">first item to compare</param>\n    /// <param name=\"b\">second item to compare</param>\n    /// <returns>true, if both wrappers are the same type and wrap the same entity</returns>\n    public static bool operator ==(ModelFromItem a, ModelFromItem b)\n        => MultiWrapperEquality.IsEqual(a, b);\n\n    /// <summary>\n    /// Ensure that the equality check is done correctly.\n    /// If two objects wrap the same item, they will be considered equal.\n    /// </summary>\n    /// <param name=\"a\">first item to compare</param>\n    /// <param name=\"b\">second item to compare</param>\n    /// <returns>false, if both wrappers are the same type and wrap the same entity</returns>\n    public static bool operator !=(ModelFromItem a, ModelFromItem b)\n        => !MultiWrapperEquality.IsEqual(a, b);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Models/Sys/DataModelHelpers.cs",
    "content": "﻿using ToSic.Eav.Models.Factory;\nusing ToSic.Eav.Models.Sys;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Models.Sys;\n\ninternal class DataModelHelpers\n{\n    /// <summary>\n    /// Convert an Entity or TypedItem into a strongly typed object.\n    /// Typically, the type will be from your `AppCode.Data`.\n    /// </summary>\n    /// <returns></returns>\n    internal static TCustom? As<TCustom>(IModelFactory modelFactory, object? item)\n        where TCustom : class, IModelFromData\n        => item switch\n        {\n            null => null,\n            ITypedItem typedItem => modelFactory.AsCustomFrom<TCustom, ITypedItem>(typedItem),\n            IEntity entity => modelFactory.AsCustomFrom<TCustom, IEntity>(entity),\n            ICanBeItem canBeItem => modelFactory.AsCustomFrom<TCustom, ICanBeItem>(canBeItem.Item),\n            ICanBeEntity canBeEntity => modelFactory.AsCustomFrom<TCustom, ICanBeEntity>(canBeEntity.Entity),\n            _ => throw new(\n                $\"Type {typeof(TCustom).Name} not supported. \" +\n                $\"Only {typeof(IEntity)}, {nameof(ITypedItem)}, {nameof(ICanBeEntity)} and {nameof(ICanBeItem)} are allowed as data\"),\n        };\n\n\n    /// <summary>\n    /// Convert a list of Entities or TypedItems into a strongly typed list.\n    /// Typically, the type will be from your `AppCode.Data`.\n    /// </summary>\n    /// <returns></returns>\n    internal static IEnumerable<TCustom> AsList<TCustom>(IModelFactory modelFactory, object? source, ModelSettings settings, NoParamOrder npo = default, bool nullIfNull = false)\n        where TCustom : class, IModelFromData\n    {\n        var list = source switch\n        {\n            null => nullIfNull\n                ? null!\n                : [],\n            IEnumerable<ITypedItem> typedItems => typedItems\n                .Select(item => modelFactory.AsCustomFrom<TCustom, ITypedItem>(item))\n                .ToList(),\n            IEnumerable<IEntity> entities => entities\n                .Select(entity => modelFactory.AsCustomFrom<TCustom, IEntity>(entity))\n                .ToList(),\n            _ => throw new(\n                $\"Type {typeof(TCustom).Name} not supported, only {typeof(IEntity)} and {nameof(ITypedItem)} are allowed as data\"),\n        };\n\n        return list;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Options/GetRelatedOptions.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Options;\n\n// 2025-07-04 2dm - experimental ideas for more sophisticated options\n// on Children<T> etc. to choose which children can be shown.\n// Not in use yet, also not clear if we would have an object with all these settings/options\n// or have more parameters in the command.\n\n/// <summary>\n/// WIP\n/// </summary>\npublic record GetRelatedOptions\n{\n    public ProcessNull ProcessNull { get; set; }\n\n    public ProcessDraft ProcessDraft { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Options/ProcessDraft.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Options;\n\n// 2025-07-04 2dm - experimental ideas for more sophisticated options\n// on Children<T> etc. to choose which children can be shown.\n// Not in use yet, also not clear if we would have an object with all these settings/options\n// or have more parameters in the command.\n\n/// <summary>\n/// WIP\n/// </summary>\npublic enum ProcessDraft\n{\n    /// <summary>\n    /// Automatic (default) shows draft-data to the editors and published data to visitors. Draft-only data is skipped.\n    /// </summary>\n    Auto = 0,\n\n    /// <summary>\n    /// No Draft means that only published data is used; drafts are filtered out (just like Auto for visitors).\n    /// </summary>\n    NoDraft = 1,\n\n    ///// <summary>\n    ///// Prefer Draft means that if data exists as draft, that will be preferred (just like Auto for Editors).\n    ///// </summary>\n    //PreferDraft = 2,\n\n\n    //ToNull = 4,\n\n    ///// <summary>\n    ///// Prefer Published means that published data is preferred, but that draft is also used if no published data is available.\n    ///// </summary>\n    ///// <remarks>\n    ///// This is probably never used, since there is no clear use case where this makes sense.\n    ///// </remarks>\n    //PreferPublished = 3,\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Options/ProcessNull.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Options;\n\n// 2025-07-04 2dm - experimental ideas for more sophisticated options\n// on Children<T> etc. to choose which children can be shown.\n// Not in use yet, also not clear if we would have an object with all these settings/options\n// or have more parameters in the command.\n\n/// <summary>\n/// WIP\n/// </summary>\npublic enum ProcessNull\n{\n    /// <summary>\n    /// Auto means that nulls will be filtered out by default, so the list doesn't contain any null-values.\n    /// </summary>\n    Auto = 0,\n\n    /// <summary>\n    /// Skip means that nulls will be filtered out by default, so the list doesn't contain any null-values (same as Auto for now)\n    /// </summary>\n    Skip = 1,\n\n    /// <summary>\n    /// Preserve means that a null entry will be preserved as a null in the returned list.\n    /// </summary>\n    Preserve = 2,\n\n    /// <summary>\n    /// Wrap means that a null value will be given to the typed item / custom item, so that it is wrapped.\n    /// </summary>\n    /// <remarks>\n    /// This is usually a bad idea, unless the object itself has special null-handling logic.\n    /// </remarks>\n    Wrap = 3,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Publishing (no namespace)/ILifecycle.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\n/// <summary>\n/// Experimental 2dm - not done yet 2024-08\n/// 2dm Experimental - trying to get the lifecycle info into ITypedItem\n/// \n/// Idea is to provide versioning information for items - different for original item, latest item, etc.\n///\n/// See IVersion / ILifecycle - not yet in use.\n/// </summary>\n[PrivateApi]\npublic interface ILifecycle\n{\n    /// <summary>\n    /// The version, starting at 1 when the item is created.\n    /// Future draft versions may not have a number yet, specs still missing.\n    /// </summary>\n    int Version { get; }\n\n    /// <summary>\n    /// The date when this thing was created.\n    /// </summary>\n    DateTime Created { get; }\n    //IUserModel CreatedUser { get; }\n    ///// <summary>\n    ///// The user who initially created this item.\n    ///// </summary>\n    //int CreatedUserId { get; }\n\n    /// <summary>\n    /// The date when this thing was last modified.\n    /// </summary>\n    DateTime Modified { get; }\n    //IUserModel ModifiedUser { get; }\n    ///// <summary>\n    ///// The user who modified this version.\n    ///// </summary>\n    //int ModifiedUserId { get; }\n\n    /// <summary>\n    /// The user Id of the owner of this thing.\n    /// </summary>\n    /// <returns>The User Id or -1 if unknown.</returns>\n    int OwnerId { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Publishing (no namespace)/IPublishing.cs",
    "content": "﻿// ReSharper disable UnusedMemberInSuper.Global\n// ReSharper disable UnusedMember.Global\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// Publishing Information for <see cref=\"ITypedItem\"/>s.\n/// </summary>\n/// <remarks>\n/// New v17\n/// </remarks>\n[PublicApi]\npublic interface IPublishing\n{\n    /// <summary>\n    /// Informs you if the current Item support publishing.\n    /// Basically all real Items based on IEntity support publishing, but in some cases you will have\n    /// <see cref=\"ITypedItem\"/>s which are not based on an entity, and those will not support publishing.\n    ///\n    /// By default, those objects will say `IsPublished` == `true`, `HasPublished` == `true` and `HasUnpublished` == `false`.\n    /// </summary>\n    bool IsSupported { get; }\n\n    /// <summary>\n    /// True if this item has a published version.\n    /// Note that this is also true if the current item is the published version.\n    /// </summary>\n    bool HasPublished { get; }\n\n    /// <summary>\n    /// True if this item has an unpublished version.\n    /// Note that this is also true if the current item is the unpublished version.\n    /// </summary>\n    bool HasUnpublished { get; }\n\n    /// <summary>\n    /// True if this item **branches** meaning it has a published version _and_ an unpublished draft version.\n    /// </summary>\n    bool HasBoth { get; }\n\n    /// <summary>\n    /// Get the published version of this item.\n    /// If the initial item was already published, it will return that item.\n    /// </summary>\n    /// <returns>the published item or `null`</returns>\n    ITypedItem? GetPublished();\n\n    /// <summary>\n    /// Get the unpublished version of this item.\n    /// If the initial item was already unpublished, it will return that item.\n    /// </summary>\n    /// <returns>the unpublished item or `null`</returns>\n    ITypedItem? GetUnpublished();\n\n    /// <summary>\n    /// Get the opposite version of this item.\n    /// So if your initial item was published, it will try to get the unpublished, and vice versa.\n    /// </summary>\n    /// <returns>the other version of this item or `null`</returns>\n    ITypedItem? GetOpposite();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Publishing (no namespace)/Lifecycle.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\ninternal class Lifecycle(IEntity entity): ILifecycle\n{\n    public int Version => entity.Version;\n    public DateTime Created => entity.Created;\n    public DateTime Modified => entity.Modified;\n    public int OwnerId => entity.OwnerId;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Publishing (no namespace)/PublishingUnsupported.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\ninternal class PublishingUnsupported(ITypedItem item) : IPublishing\n{\n    public bool IsSupported => false;\n\n    public bool HasPublished => true;\n\n    public bool HasUnpublished => false;\n\n    public bool HasBoth => false;\n\n    public ITypedItem GetPublished() => item;\n\n    public ITypedItem? GetUnpublished() => null;\n\n    public ITypedItem? GetOpposite() => null;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Secret (no namespace)/ISecureData.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\n/// <summary>\n/// Objects which contain secure/encrypted data and can be decrypted / verified.\n/// </summary>\n/// <remarks>\n/// This object contains decrypted data (if it was encrypted originally) and tells you if the data was encrypted, signed etc.\n/// It's still very basic, and will grow in functionality to assist in handling secure / encrypted / signed data.\n/// \n/// History: Introduced in 2sxc 12.05\n/// </remarks>\n/// <typeparam name=\"TValue\">\n/// Type of the value in this secure data. As of now it's always a `string`.\n/// </typeparam>\n[PublicApi]\npublic interface ISecureData<out TValue>\n{\n    /// <summary>\n    /// The value returned by the secure data - usually a string. \n    /// </summary>\n    TValue Value { get; }\n\n    //[PrivateApi(\"not final yet\")]\n    //bool IsEncrypted { get; }\n\n    //[PrivateApi(\"not final yet\")]\n    //bool IsSigned { get; }\n\n    //[PrivateApi(\"not final yet\")]\n    //SecureDataAuthorities Authority { get; }\n\n    /// <summary>\n    /// Determines if the data is secure data, so it's either encrypted or signed\n    /// </summary>\n    /// <remarks>made public in v17.01</remarks>\n    bool IsSecured { get; }\n\n\n    /// <summary>\n    /// Determines what authority secured this secure data.\n    /// This is to figure out what certificate or source verified the decryption / signing\n    ///\n    /// As of 2sxc 12.05, it can only be \"preset\", other keys are currently not handled yet\n    /// </summary>\n    /// <param name=\"authorityName\"></param>\n    /// <returns></returns>\n    bool IsSecuredBy(string authorityName);\n\n    /// <summary>\n    /// This object explicitly has a ToString, so you can use the result in string concatenation like `\"key:\" + secureResult`\n    /// </summary>\n    /// <returns></returns>\n    string? ToString();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Secret (no namespace)/SecureDataAuthorities.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\n[Flags]\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic enum SecureDataAuthorities\n{\n    /// <summary>\n    /// No authority / not a secret or wasn't able to decipher\n    /// </summary>\n    None = 0,\n\n    /// <summary>\n    /// Root authority, ATM not in use yet\n    /// </summary>\n    Root = 1,\n\n    /// <summary>\n    /// System authority (similar to root), ATM not in use yet\n    /// </summary>\n    System = 2,\n\n    /// <summary>\n    /// Platform authority, meaning the secret was decrypted or authorized by the platform like Dnn or Oqtane\n    /// </summary>\n    Platform = 4,\n\n    [PrivateApi] Reserved1 = 8,\n    [PrivateApi] Reserved2 = 16,\n    [PrivateApi] Reserved3 = 32,\n    [PrivateApi] Reserved4 = 64,\n    [PrivateApi] Reserved5 = 128,\n    [PrivateApi] Reserved6 = 256,\n\n    /// <summary>\n    /// Authority is a preset of 2sxc / EAV\n    /// </summary>\n    Preset = 512,\n\n    /// <summary>\n    /// The installation / global authorized this, so it's a key given by the installation\n    /// </summary>\n    Global = 1024,\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Decorators/CmsEditDecorator.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\n\nnamespace ToSic.Sxc.Data.Sys.Decorators;\n\n/// <summary>\n/// Decorator for demo entities and similar, to disable editing so that the demo data isn't accidentally changed.\n/// </summary>\npublic record CmsEditDecorator(bool DisableEdit)\n    : IDecorator<IEntity>\n{\n    public static EntityWithDecorator<CmsEditDecorator> Wrap(IEntity entity, bool enableEdit) =>\n        new(entity, new(!enableEdit));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Decorators/EntityInBlockDecorator.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\n\nnamespace ToSic.Sxc.Data.Sys.Decorators;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EntityInBlockDecorator: EntityInListDecorator\n{\n    private EntityInBlockDecorator(string? fieldName, \n        int index = DefIndex,\n        IEntity? presentation = DefPresentation, \n        bool isDemoItem = DefDemo,\n        IEntity? parent = default)\n        :base(fieldName, index, parent: parent)\n    {\n        Presentation = presentation;\n        IsDemoItem = isDemoItem;\n    }\n\n    public static EntityWithDecorator<EntityInBlockDecorator> Wrap(\n        IEntity entity,\n        string? fieldName,\n        int index = DefIndex,\n        IEntity? presentation = DefPresentation,\n        bool isDemoItem = DefDemo, \n        IEntity? parent = default)\n        => new(entity, new(fieldName, index, presentation, isDemoItem, parent: parent));\n\n    protected const IEntity? DefPresentation = null;\n    protected const bool DefDemo = false;\n\n\n    /// <summary>\n    /// Presentation entity of this content-item.\n    /// Important to keep content and presentation linked together\n    /// </summary>\n    public IEntity? Presentation { get; set; }\n\n    /// <summary>\n    /// Info if the item is a plain demo/fake item, or if it was added on purpose.\n    /// new 2019-09-18 trying to mark demo-items for better detection in output #1792\n    /// </summary>\n    internal bool IsDemoItem { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Decorators/EntityInListDecorator.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Decorators;\n\n/// <summary>\n/// Important: for now it should be abstract, because we're not sure in which cases\n/// something will check if the derived decorator is there, and then get wrong conclusions\n/// So for now, only the EntityInBlockDecorator should be used anywhere explicitly\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class EntityInListDecorator(string? fieldName, int index = 0, IEntity? parent = default)\n    : IDecorator<IEntity>\n{\n    protected const int DefIndex = 0;\n\n    /// <summary>\n    /// The position in the list\n    /// </summary>\n    /// <remarks>\n    /// This has been in use since ca. 2sxc 2.0\n    /// </remarks>\n    public int SortOrder { get; } = index;\n\n    /// <summary>\n    /// The field which has the list containing this item.\n    /// </summary>\n    /// <remarks>\n    /// Added in 2sxc 11.01\n    /// </remarks>\n    public string? FieldName { get; } = fieldName;\n\n    /// <summary>\n    /// The parent item which has the list containing this item.\n    /// </summary>\n    /// <remarks>\n    /// Important: as of now this is NOT the content-block guid, and shouldn't be because there is code checking for this to be empty\n    /// on content-blocks.\n    ///\n    /// Added in 2sxc 11.01\n    /// </remarks>\n    public Guid? ParentGuid { get; private set; } = parent?.EntityGuid; // parentGuid;\n\n    /// <summary>\n    /// Parent is null in special cases where this is a fake item, like when the block is not initialized.\n    /// </summary>\n    public IEntity? Parent { get; private set; } = parent;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Decorators/IEntityExtensions.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\n\nnamespace ToSic.Sxc.Data.Sys.Decorators;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class IEntityExtensions\n{\n    public static bool IsDemoItemSafe(this IEntity? entity)\n        => entity?.GetDecorator<EntityInBlockDecorator>()?.IsDemoItem\n           ?? false;\n\n    public static bool DisableInlineEditSafe(this IEntity? entity)\n        => entity == null\n           || (entity.GetDecorator<CmsEditDecorator>()?.DisableEdit ?? IsDemoItemSafe(entity));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Docs/DynamicEntityDocs.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Docs;\n\n/// <summary>\n/// This is minor cross-concerns aspect of Dynamic-Entity-like objects\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class DynamicEntityDocs\n{\n    /* IMPORTANT: KEEP THIS DEFINITION AND DOCS IN SYNC BETWEEN IDynamicEntity, IDynamicEntityBase and IDynamicStack */\n    /// <summary>\n    /// Get a value of the entity. Usually you will prefer the quick access like\n    /// @content.FirstName - which will give you the same things as content.Get(\"FirstName\").\n    /// There are two cases to use this:\n    /// - when you dynamically assemble the field name in your code, like when using App.Resources or similar use cases.\n    /// - to access a field which has a conflicting name with this object, like Get(\"Parents\")\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <returns>An object which can be either a string, number, boolean or List&lt;IDynamicEntity&gt;, depending on the field type. Will return null if the field was not found. </returns>\n    public abstract dynamic Get(string name);\n\n\n    /* IMPORTANT: KEEP THIS DEFINITION AND DOCS IN SYNC BETWEEN IDynamicEntity, IDynamicEntityBase and IDynamicStack */\n    /// <summary>\n    /// Get a property using the string name. Only needed in special situations, as most cases can use the object.name directly\n    /// </summary>\n    /// <param name=\"name\">the property name like `Image` - or path like `Author.Name` (new v15)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"language\">Optional language code - like \"de-ch\" to prioritize that language</param>\n    /// <param name=\"convertLinks\">Optionally turn off if links like file:72 are looked up to a real link. Default is true.</param>\n    /// <param name=\"debug\">Set true to see more details in [Insights](xref:NetCode.Debug.Insights.Index) how the value was retrieved.</param>\n    /// <returns>a dynamically typed result, can be string, bool, etc.</returns>\n    public abstract dynamic Get(string name,\n        // ReSharper disable once MethodOverloadWithOptionalParameter\n        NoParamOrder npo = default,\n        string? language = null,\n        bool convertLinks = true,\n        bool? debug = null\n    );\n\n    /// <summary>\n    /// Get a value using the name - and cast it to the expected strong type.\n    /// For example to get an int even though it's stored as decimal.\n    /// </summary>\n    /// <typeparam name=\"TValue\">The expected type, like `string`, `int`, etc.</typeparam>\n    /// <param name=\"name\">the property name like `Image` - or path like `Author.Name` (new v15)</param>\n    /// <returns>The typed value, or the `default` like `null` or `0` if casting isn't possible.</returns>\n    /// <remarks>Added in v15</remarks>\n    public abstract TValue Get<TValue>(string name);\n\n    /// <summary>\n    /// Get a value using the name - and cast it to the expected strong type.\n    /// For example to get an int even though it's stored as decimal.\n    /// \n    /// Since the parameter `fallback` determines the type `TValue` you can just write this like\n    /// `Content.Get(\"Title\", fallback: \"no title\")\n    /// </summary>\n    /// <typeparam name=\"TValue\">\n    /// The expected type, like `string`, `int`, etc.\n    /// Note that you don't need to specify it, if you specify the `fallback` property.\n    /// </typeparam>\n    /// <param name=\"name\">the property name like `Image` - or path like `Author.Name` (new v15)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">the fallback value to provide if not found</param>\n    /// <returns>The typed value, or the `default` like `null` or `0` if casting isn't possible.</returns>\n    /// <remarks>Added in v15</remarks>\n    public abstract TValue Get<TValue>(string name,\n        // ReSharper disable once MethodOverloadWithOptionalParameter\n        NoParamOrder npo = default,\n        TValue? fallback = default);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Docs/IDynamicAnythingDocs.cs",
    "content": "﻿\n\n// ReSharper disable UnusedMember.Global\n// ReSharper disable UnassignedGetOnlyAutoProperty\n\nnamespace ToSic.Sxc.Data.Sys.Docs;\n/* IMPORTANT: These are just fake properties for documentation - Keep in Sync between IDynamicEntity and IDynamicStack */\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDynamicAnythingDocs\n{\n    /// <summary>\n    /// A Dynamic Entity always contains an item of your data - a book, person, blog-post or a piece of content.\n    /// Since the object is dynamic, you can just use `.IsFemale` or whatever other property your item has.\n    /// It is treated as a `dynamic` so you can just output it, or cast it to the expected type.\n    /// </summary>\n    dynamic AnyProperty { get; }\n    \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Docs/ITypedRelationshipsDocs.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Docs;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ITypedRelationshipsDocs\n{\n    /// <summary>\n    /// A single item from a field.\n    /// </summary>\n    /// <param name=\"name\">Name of the field</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>The ITypedItem. If the field doesn't exist or is empty, will return null.</returns>\n    ITypedItem Child(string name, NoParamOrder npo = default, bool? required = default);\n\n    /// <summary>\n    /// A **typed** list of sub-items. Important for LINQ style querying or just\n    /// working with various lists. Note that for getting child items of this item you\n    /// can just use the properties, like content.Authors. <br/>\n    /// But using Children(\"Authors\", type: typeName) gives you the ability to restrict to a type.  <br/>\n    /// Please check the tutorials on 2sxc.org/dnn-tutorials/ for more info. \n    /// </summary>\n    /// <param name=\"field\">Optional field filter - would only return items that point to the current item in a specific field name.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"type\">Optional type filter - would only return items of this type. </param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>A list of all items pointing here (filtered), converted to DynamicEntity for convenience.</returns>\n    /// <remarks>Note that the parameter-order is reversed to the Parents()</remarks>\n    IEnumerable<ITypedItem> Children(string? field = default, NoParamOrder npo = default, string? type = default, bool? required = default);\n\n    /// <summary>\n    /// Get either the _current_ parent or the first parent which would be found on `.Parents(...)`.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"current\">if set to `true`, will get the Item which created the current item (the parent) which called `.Child(...)` or `.Children(...)`</param>\n    /// <param name=\"type\">Optional type filter - would only return items of this type. </param>\n    /// <param name=\"field\">Optional field filter - would only return items that point to the current item in a specific field name.</param>\n    /// <returns>_either_ the current parent _or_ the first parent returned by the same `.Parents(...)` call.</returns>\n    ITypedItem Parent(NoParamOrder npo = default, bool? current = default, string? type = default, string? field = default);\n\n    /// <summary>\n    /// A **typed** list of entities which point to this item. Important for LINQ style querying or just\n    /// working with various lists. Note that for getting child items of this item you\n    /// can just use the properties, like content.Authors. <br/>\n    /// Please check the tutorials on 2sxc.org/dnn-tutorials/ for more info. \n    /// </summary>\n    /// <param name=\"type\">Optional type filter - would only return items of this type. </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"field\">Optional field filter - would only return items that point to the current item in a specific field name.</param>\n    /// <returns>A list of all items pointing here (filtered), converted to DynamicEntity for convenience.</returns>\n    /// <remarks>Note that the parameter-order is reversed to the Children()</remarks>\n    IEnumerable<ITypedItem> Parents(string? type = default, NoParamOrder npo = default, string? field = default);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Docs/readme.md",
    "content": "﻿# Data Docs\n\nThis contains fake classes which are only the anchor point for documentation.\n\nSo these classes are not in use, but their docs are referenced by other classes"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Dynamic/CodeDynHelper.cs",
    "content": "﻿using System.Dynamic;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.Dynamic;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CodeDynHelper(IEntity entity, SubDataFactory subDataFactory)\n{\n    public IEntity Entity { get; } = entity;\n    public SubDataFactory SubDataFactory { get; } = subDataFactory;\n\n    public IDynamicEntity? Presentation => _prs.Get(() => SubDataFactory.SubDynEntityOrNull(Entity.GetDecorator<EntityInBlockDecorator>()?.Presentation));\n    private readonly GetOnce<IDynamicEntity?> _prs = new();\n\n    public object Metadata => _md.Get(() => SubDataFactory.Cdf.MetadataDynamic(Entity.Metadata))!;\n    private readonly GetOnce<object?> _md = new();\n\n    public IDynamicEntity? Parent => _dp.Get(() => SubDataFactory.SubDynEntityOrNull(Entity.GetDecorator<EntityInBlockDecorator>()?.Parent));\n    private readonly GetOnce<IDynamicEntity?> _dp = new();\n\n\n\n    #region TryGetMember for dynamic access\n\n    public static bool TryGetMemberAndRespectStrict(GetAndConvertHelper helper, GetMemberBinder binder, out object? result)\n    {\n        var findResult = helper.TryGet(binder.Name, lookupLink: true);\n        // ReSharper disable once ExplicitCallerInfoArgument\n        if (!findResult.Found && helper.PropsRequired)\n            throw TypedHelpers.ErrStrict(binder.Name, cName: \".\");\n        result = findResult.Result;\n        return true;\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Dynamic/CodeItemHelper.cs",
    "content": "﻿using System.Net;\nusing System.Runtime.CompilerServices;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.Dynamic;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CodeItemHelper(GetAndConvertHelper helper, ITyped data)\n{\n    public ITyped Data { get; } = data;\n    public readonly GetAndConvertHelper Helper = helper;\n\n    #region Keys\n    public bool IsEmpty(string name, NoParamOrder npo, bool? isBlank, string? language)\n    {\n        var result = Get(name, npo, required: false, language: language);\n        return HasKeysHelper.IsEmpty(result, isBlank);\n    }\n\n    public bool IsNotEmpty(string name, NoParamOrder npo, bool? isBlank, string? language)\n    {\n        var result = Get(name, npo, required: false, language: language);\n        return HasKeysHelper.IsNotEmpty(result, isBlank);\n    }\n\n\n    #endregion\n\n    #region Get\n\n    public object? Get(string name, NoParamOrder npo, bool? required, string? language = default, [CallerMemberName] string? cName = default)\n    {\n        var findResult = Helper.TryGet(name, language);\n        return IsErrStrict(findResult.Found, required, Helper.PropsRequired)\n            ? throw ErrStrictForTyped(Data, name, cName: cName)\n            : findResult.Result;\n    }\n\n    public TValue G4T<TValue>(string name, NoParamOrder npo, TValue fallback, bool? required, [CallerMemberName] string? cName = default)\n    {\n        var findResult = Helper.TryGet(name);\n        return IsErrStrict(findResult.Found, required, Helper.PropsRequired)\n            ? throw ErrStrictForTyped(Data, name, cName: cName)\n            : findResult.Result.ConvertOrFallback(fallback);\n    }\n\n    public TValue GetT<TValue>(string name, NoParamOrder npo, TValue fallback, bool? required, string? language = default, [CallerMemberName] string? cName = default)\n    {\n        var findResult = Helper.TryGet(field: name, language: language);\n        return IsErrStrict(findResult.Found, required, Helper.PropsRequired)\n            ? throw ErrStrictForTyped(Data, name, cName: cName)\n            : findResult.Result.ConvertOrFallback(fallback);\n    }\n\n\n    #endregion\n\n    public IRawHtmlString? Attribute(string name, NoParamOrder npo, string? fallback, bool? required)\n    {\n        var result = Get(name, npo, required);\n        var strValue = Helper.Cdf.Services.ForCode.Value.ForCode(result, fallback: fallback);\n        return strValue is null\n            ? null\n            : new RawHtmlString(WebUtility.HtmlEncode(strValue));\n    }\n\n    public string? String(string name, NoParamOrder npo, string? fallback, bool? required, object? scrubHtml = default)\n    {\n        var value = G4T(name, npo: npo, fallback: fallback, required: required);\n        return TypedItemHelpers.MaybeScrub(value, scrubHtml, () => Helper.Cdf.Services.Scrub.Value);\n    }\n\n\n    public string? Url(string name, NoParamOrder npo, string? fallback, bool? required)\n    {\n        // TODO: STRICT\n        var url = Helper.TryGet(name, lookupLink: true).Result as string;\n        return Tags.SafeUrl(url).ToString();\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Dynamic/DynamicEntityListHelper.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Sys.Dynamic;\n\n/// <summary>\n/// This is a helper in charge of the list-behavior of a DynamicEntity\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class DynamicEntityListHelper\n{\n    protected bool PropsRequired { get; }\n    public readonly IEntity? ParentOrNull;\n    public readonly string? FieldNameOrNull;\n    private readonly ICodeDataFactory _cdf;\n\n    private readonly Func<bool> _getDebug;\n\n    public DynamicEntityListHelper(IDynamicEntity singleItem, Func<bool> getDebug, bool propsRequired, ICodeDataFactory cdf)\n        : this(cdf, propsRequired, getDebug)\n    {\n        DynEntities = [singleItem ?? throw new ArgumentException(nameof(singleItem))];\n    }\n        \n    public DynamicEntityListHelper(IEnumerable<IEntity>? entities, IEntity? parentOrNull, string? fieldNameOrNull, Func<bool> getDebug, bool propsRequired, ICodeDataFactory cdf)\n        : this(cdf, propsRequired, getDebug)\n    {\n        ParentOrNull = parentOrNull;\n        FieldNameOrNull = fieldNameOrNull;\n        _entities = entities?.ToArray() ?? throw new ArgumentNullException(nameof(entities));\n    }\n\n    private DynamicEntityListHelper(ICodeDataFactory cdf, bool propsRequired, Func<bool> getDebug)\n    {\n        _cdf = cdf ?? throw new ArgumentNullException(nameof(cdf));\n        PropsRequired = propsRequired;\n        _getDebug = getDebug;\n    }\n\n    /// <summary>\n    /// Alternate source list if DynEntities was not set.\n    /// </summary>\n    private readonly IEntity[]? _entities;\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    public List<IDynamicEntity?> DynEntities\n    {\n        get\n        {\n            // Case #1 & Case #2- already created before or because of Single-Item\n            if (field != null)\n                return field;\n\n            // Case #3 - Real sub-list\n            // If it has a parent, it should apply numbering to the things inside\n            // If not, it's coming from a stream or something and shouldn't do that\n            var reWrapWithListNumbering = ParentOrNull != null;\n\n            var debug = _getDebug.Invoke();\n            return field = _entities!\n                .Select(IDynamicEntity? (e, i) =>\n                {\n                    // If we should re-wrap, we create an Entity with some metadata-decoration, so that toolbars know it's part of a list\n                    var blockEntity = reWrapWithListNumbering\n                        ? EntityInBlockDecorator.Wrap(entity: e, fieldName: FieldNameOrNull, index: i, parent: ParentOrNull)\n                        : e;\n                    return SubDataFactory.SubDynEntityOrNull(blockEntity, _cdf, debug, propsRequired: PropsRequired);\n                })\n                .ToList();\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Dynamic/DynamicFromDictionary.cs",
    "content": "﻿using System.Dynamic;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.Dynamic;\n\n// WIP\n// Inspired by https://stackoverflow.com/questions/46948289/how-do-you-convert-any-c-sharp-object-to-an-expandoobject\n// That was more complex with ability so set new values and switch between case-insensitive or not but that's not the purpose of this\n/// <summary>\n/// \n/// </summary>\n/// <remarks>\n/// Will always return true even if the property doesn't exist, in which case it resolves to null.\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class DynamicFromDictionary<TKey, TVal>: DynamicObject, IWrapper<IDictionary<TKey, TVal>>, IHasKeys\n{\n    protected readonly IDictionary<TKey, TVal> UnwrappedDictionary;\n    private readonly ICodeDataPoCoWrapperService _wrapperSvc;\n\n    [PrivateApi]\n    public IDictionary<TKey, TVal> GetContents() => UnwrappedDictionary;\n    private readonly Dictionary<string, object> _ignoreCaseLookup = new(StringComparer.InvariantCultureIgnoreCase);\n\n    public DynamicFromDictionary(IDictionary<TKey, TVal> dictionary, ICodeDataPoCoWrapperService wrapperSvc)\n    {\n        UnwrappedDictionary = dictionary;\n        _wrapperSvc = wrapperSvc;\n        \n        foreach (var de in dictionary) \n            _ignoreCaseLookup[de.Key!.ToString()!] = de.Value!;\n    }\n        \n    public override bool TryGetMember(GetMemberBinder binder, out object? result)\n    {\n        // if nothing found, just return true/done\n        if(!_ignoreCaseLookup.TryGetValue(binder.Name, out result))\n            return true;\n\n        // if result is an anonymous object, re-wrap again for consistency with other APIs\n        if (result is null)\n            return true;\n        if (result.IsAnonymous())\n            result = _wrapperSvc.ChildNonJsonWrapIfPossible(data: result, wrapNonAnon: false, WrapperSettings.Dyn(children: true, realObjectsToo: false));\n\n        return true;\n    }\n\n    public override bool TrySetMember(SetMemberBinder binder, object? value) \n        => throw new NotSupportedException($\"Setting a value on DynamicReadDictionary is not supported\");\n\n\n    [PrivateApi]\n    bool IHasKeys.ContainsKey(string name)\n        => _ignoreCaseLookup.ContainsKey(name);\n\n    public bool IsEmpty(string name, NoParamOrder npo = default, string? language = default /* ignore */)\n        => !_ignoreCaseLookup.TryGetValue(name, out var result) || HasKeysHelper.IsEmpty(result, blankIsEmpty: default);\n\n    public bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default /* ignore */)\n        => _ignoreCaseLookup.TryGetValue(name, out var result) && HasKeysHelper.IsNotEmpty(result, blankIsEmpty: default);\n\n\n    IEnumerable<string> IHasKeys.Keys(NoParamOrder npo, IEnumerable<string>? only) \n        => TypedHelpers.FilterKeysIfPossible(npo, only, _ignoreCaseLookup.Keys);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Dynamic/GetAndConvertConverter.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Sxc.Data.Options;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sys.Performance;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Data.Sys.Dynamic;\n\n\ninternal class GetAndConvertConverter(ICodeDataFactory cdf, bool propsRequired, bool childrenShouldBeDynamic, ICanDebug canDebug, IValueOverrider? overrider = default)\n{\n    [field: AllowNull, MaybeNull]\n    internal SubDataFactory SubDataFactory => field ??= new(cdf, propsRequired, canDebug);\n\n    internal object? ValueAutoConverted(PropReqResult original, bool lookupLink, string field, ILog? logOrNull)\n    {\n        var l = logOrNull.Fn<object?>($\"..., {nameof(lookupLink)}: {lookupLink}, {nameof(field)}: {field}\");\n        var value = original.Result;\n        var parent = original.Source as IEntity;\n\n        // If it's a reference like \"file:72\", try to convert it\n        if (lookupLink && value is string strMaybeLink && original.ValueType == ValueTypesWithState.Hyperlink)\n        {\n            var strMaybeReference = overrider != null\n                ? overrider.ProcessString(field, strMaybeLink)\n                : strMaybeLink;\n            if (ValueConverterBase.CouldBeReference(strMaybeReference))\n            {\n                l.A(\"Try to convert value\");\n                // ReSharper disable once ConstantNullCoalescingCondition - paranoid\n                value = cdf.Services.ValueConverter.Value.ToValue(strMaybeReference, parent?.EntityGuid ?? Guid.Empty) ?? value;\n                return l.Return(value, \"link-conversion\");\n            }\n        }\n\n\n        // note 2021-06-07 previously in created sub-entities with modified language-list; I think this is wrong\n        // Note 2021-06-08 if the parent is _not_ an IEntity, this will throw an error. Could happen in the DynamicStack, but that should never have such children\n        if (value is IEnumerable<IEntity> children)\n        {\n            if (childrenShouldBeDynamic)\n            {\n                l.A(\"Convert entity list as DynamicEntity\");\n                var dynEnt = cdf.AsDynamicFromEntities(children.ToArray(), new() { ItemIsStrict = propsRequired }, parent: parent, field: field);\n                if (canDebug.Debug)\n                    dynEnt.Debug = true;\n                return l.Return(dynEnt, \"ent-list, now dyn\");\n            }\n            l.A($\"Convert entity list as {nameof(ITypedItem)}\");\n            var converted = AsChildrenItems(entities: children, field: field, parentEntity: parent, new());\n\n            // if (Debug) converted.ForEach(c => c.Debug = true);\n            return l.Return(converted, \"ent-list, now dyn\");\n        }\n\n        // special debug of path if possible\n        if (canDebug.Debug)\n            try\n            {\n                var finalPath = string.Join(\" > \", original.Path?.Parts?.ToArray() ?? []);\n                l.A($\"Debug path: {finalPath}\");\n            }\n            catch {/* ignore */}\n\n        if (value is string strResult && overrider != null)\n        {\n            var maybeOverride = overrider.ProcessString(field, strResult);\n            return l.Return(maybeOverride, \"parsed\");\n        }\n\n        return l.Return(value, \"unmodified\");\n    }\n    #region Parents / Children - ATM still dynamic\n\n    public List<IDynamicEntity?> ParentsDyn(IEntity entity, string? type, string? field)\n        => entity.Parents(type, field)\n            .Select(SubDataFactory.SubDynEntityOrNull)\n            .ToList();\n\n    public List<ITypedItem> ParentsItems(IEntity entity, string? type, string? field, GetRelatedOptions options)\n    {\n        var list = entity.Parents(type, field);\n        var processed = ProcessOptions(list, options, cdf.Services.User.Value);\n\n        var preserveNull = options.ProcessNull == ProcessNull.Preserve;\n\n        return processed\n            .Select(ITypedItem (e) => e == null && preserveNull\n                ? null!\n                : new TypedItemOfEntity(e!, cdf, propsRequired)\n            )\n            .ToList();\n    }\n\n\n    public List<IDynamicEntity?> ChildrenDyn(IEntity entity, string? field, string? type)\n        => AsChildrenDyn(entity.Children(field, type), field, parentEntity: entity);\n\n    public List<ITypedItem> ChildrenItems(IEntity entity, string field, string? type, GetRelatedOptions options)\n        => AsChildrenItems(entity.Children(field, type), field, parentEntity: entity, options);\n\n    private List<IDynamicEntity?> AsChildrenDyn(IEnumerable<IEntity?> entities, string? field, IEntity? parentEntity)\n        => AsChildrenOf(\n            ProcessOptions(entities, new(), cdf.Services.User.Value),\n            field,\n            parentEntity,\n            SubDataFactory.SubDynEntityOrNull,\n            new()\n        );\n\n    private List<ITypedItem> AsChildrenItems(IEnumerable<IEntity?> entities, string field, IEntity? parentEntity, GetRelatedOptions options)\n        => AsChildrenOf(\n            ProcessOptions(entities, options, cdf.Services.User.Value),\n            field,\n            parentEntity,\n            ITypedItem (e) => new TypedItemOfEntity(e, cdf, propsRequired),\n            options\n        );\n\n    private static List<T> AsChildrenOf<T>(\n        IEnumerable<IEntity?> entities,\n        string? fieldNameForWrapperInfo,\n        IEntity? parentEntity,\n        Func<IEntity, T> convert,\n        GetRelatedOptions options)\n        where T : class?, ICanBeEntity?\n    {\n        var preserveNull = options.ProcessNull == ProcessNull.Preserve;\n\n        var list = entities\n            .Select((e, i) =>\n            {\n                if (e == null && preserveNull)\n                    return null!;\n                var wrapped = EntityInBlockDecorator.Wrap(entity: e!, fieldName: fieldNameForWrapperInfo, index: i, parent: parentEntity);\n                var converted = convert(wrapped);\n                return converted;\n            })\n            .ToList();\n        return new ListTypedItems<T>(list, null);\n    }\n\n    private static ICollection<IEntity?> ProcessOptions(IEnumerable<IEntity?> entities, GetRelatedOptions options, IUser user)\n    {\n        // 1. Check if we should remove drafts - default for non-admins\n        if (options.ProcessDraft == ProcessDraft.NoDraft ||\n            (options.ProcessDraft == ProcessDraft.Auto && !user.IsContentEditor))\n            entities = entities\n                .Where(e => e?.IsPublished == true);\n\n        // 2. filter out nulls, as the razor code will usually not be able to handle them\n        // in future, we should maybe add a trigger to optionally allow nulls,\n        // in which case the result should then also be null\n        var preserveNull = options.ProcessNull == ProcessNull.Preserve;\n        if (!preserveNull)\n            entities = entities\n                .Where(e => e != null);\n\n        return entities.ToListOpt();\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Dynamic/GetAndConvertHelper.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.Dynamic;\n\n/// <param name=\"overrider\">Optional helper for templating scenarios, which can replace the source with something else - typically for replacing \"file:72\" with something from a template</param>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class GetAndConvertHelper(\n    IHasPropLookup parent,\n    ICodeDataFactory cdf,\n    bool propsRequired,\n    bool childrenShouldBeDynamic,\n    ICanDebug canDebug,\n    IValueOverrider? overrider = default)\n{\n    #region Setup and Log\n\n    public ICodeDataFactory Cdf { get; } = cdf;\n\n    public bool PropsRequired { get; } = propsRequired;\n\n    public bool Debug => _debug ?? canDebug.Debug;\n    private bool? _debug;\n\n    [field: AllowNull, MaybeNull]\n    internal GetAndConvertConverter Converter => field ??= new(Cdf, PropsRequired, childrenShouldBeDynamic, canDebug, overrider);\n\n    public ILog? LogOrNull => _logOrNull.Get(() => Cdf.Log.SubLogOrNull(\"Sxc.GetCnv\", Debug));\n    private readonly GetOnce<ILog?> _logOrNull = new();\n\n    #endregion\n\n    #region Get Implementations 1:1 - names must be identical with caller, so the exceptions have the right names\n\n    public object? Get(string name) => TryGet(name, lookupLink: true).Result;\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public object? Get(string name, NoParamOrder npo = default, string? language = null, bool convertLinks = true, bool? debug = null)\n    {\n        _debug = debug;\n        var result = TryGet(name, language: language, lookupLink: convertLinks).Result;\n        _debug = null;\n\n        return result;\n    }\n\n    public TValue? Get<TValue>(string name)\n        => TryGet(name).Result.ConvertOrDefault<TValue>();\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default)\n        => TryGet(name).Result.ConvertOrFallback(fallback);\n\n    #endregion\n\n    #region Try-Get Values\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"field\"></param>\n    /// <param name=\"language\"></param>\n    /// <param name=\"lookupLink\"></param>\n    /// <returns></returns>\n    public TryGetResult TryGet(string? field, string? language = null, bool lookupLink = false)\n    {\n        var logOrNull = LogOrNull.SubLogOrNull(\"GnC.GetInt\", Debug);\n        var l = logOrNull.Fn<TryGetResult>($\"Type: {parent.GetType().Name}, {nameof(field)}:{field}, {nameof(language)}:{language}, {nameof(lookupLink)}:{lookupLink}\");\n\n        if (!field.HasValue())\n            return l.Return(new(false, null), \"field null/empty\");\n\n        // This determines if we should access & store in cache\n        // check if we already have it in the cache - but only in default case (no language, lookup=true)\n        var cacheKey = (field + \"$\" + lookupLink + \"-\" + language).ToLowerInvariant();\n        if (_rawValCache.TryGetValue(cacheKey, out var cached))\n            return l.Return(cached, \"cached\");\n\n        // Figure out best order of languages to look up\n        var languages = LanguagePreprocessor.GetLookupLanguages(language, Cdf);\n\n        l.A($\"cache-key: {cacheKey}, {nameof(languages)}:{languages.Length}\");\n\n        // check if we have an explicitly set language resulting in an empty language list - then exit now\n        if (!languages.Any())\n            return l.Return(new(false, null), \"no languages to look-up, exit\");\n\n        // Get the field or the path if it has one\n        // Classic field case\n        var specs = new PropReqSpecs(field, languages, true, logOrNull);\n        var path = new PropertyLookupPath().Add(\"DynEntStart\", field);\n        var resultSet = parent.PropertyLookup.FindPropertyInternal(specs, path);\n\n        // check Entity is null (in cases where null-objects are asked for properties)\n        if (resultSet == null! /* paranoid */)\n            return l.Return(new(false, null), \"result null\");\n\n        l.A($\"Result... IsFinal: {resultSet.IsFinal}, Source Name: {resultSet.Name}, SourceIndex: {resultSet.SourceIndex}, FieldType: {resultSet.ValueType}\");\n\n        var result = Converter.ValueAutoConverted(resultSet, lookupLink, field, logOrNull);\n\n        // cache result, but only if using default languages\n        l.A(\"add to cache\");\n        var found = resultSet.ValueType != ValueTypesWithState.NotFound;\n        var final = new TryGetResult(found, result);\n        if (found)\n            _rawValCache.Add(cacheKey, final);\n\n        return l.Return(final, \"ok\");\n    }\n\n    private readonly Dictionary<string, TryGetResult> _rawValCache = new();\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Dynamic/LanguagePreprocessor.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Sys.Dynamic;\ninternal class LanguagePreprocessor\n{\n    internal static string?[] GetLookupLanguages(string? language, ICodeDataFactory cdf)\n    {\n        // use the standard dimensions or overload\n        var languages = language == null\n            ? cdf.Dimensions\n            : GetFinalLanguagesList(language, cdf.SiteCultures, cdf.Dimensions);\n        return languages;\n    }\n\n    /// <summary>\n    /// Full logic, as static, testable method\n    /// </summary>\n    /// <param name=\"language\"></param>\n    /// <param name=\"possibleDims\"></param>\n    /// <param name=\"defaultDims\"></param>\n    /// <returns></returns>\n    internal static string?[] GetFinalLanguagesList(string language, List<string> possibleDims, string?[] defaultDims)\n    {\n        // if nothing specified, use default\n        if (language == null! /* paranoid */)\n            return defaultDims;\n\n        var languages = language.ToLowerInvariant()\n            .Split(',')\n            .Select(s => s.Trim())\n            .ToArray();\n\n        // expand language codes, e.g.\n        // - \"en\" should become \"en-us\" if available\n        // - \"\" should become null to signal fallback to default\n        var final = languages\n            .Select(l =>\n            {\n                if (l == \"\")\n                    return null;\n                // note: availableDims usually has a null-entry at the end\n                // note: both l and availableDims are lowerInvariant\n                var found = possibleDims.FirstOrDefault(ad => ad?.StartsWith(l) == true);\n                return found ?? \"not-found\";\n            })\n            .Where(s => s != \"not-found\")\n            .ToArray();\n\n        return final;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Dynamic/WrapObjectDynamic.cs",
    "content": "﻿using System.Dynamic;\nusing System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.Dynamic;\n\n// WIP\n// Inspired by https://stackoverflow.com/questions/46948289/how-do-you-convert-any-c-sharp-object-to-an-expandoobject\n// That was more complex with ability so set new values and switch between case-insensitive or not but that's not the purpose of this\n/// <summary>\n/// \n/// </summary>\n/// <remarks>\n/// Will always return a value even if the property doesn't exist, in which case it resolves to null.\n/// </remarks>\n[JsonConverter(typeof(DynamicJsonConverter))]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WrapObjectDynamic: DynamicObject, IWrapper<object>, IPropertyLookup, IHasJsonSource, ICanGetByName\n{\n    [PrivateApi]\n    public object GetContents() => ((IWrapper<object>)PreWrap).GetContents()!;\n\n    [PrivateApi]\n    internal readonly PreWrapObject PreWrap;\n\n    [PrivateApi]\n    internal WrapObjectDynamic(PreWrapObject preWrap, ICodeDataPoCoWrapperService wrapperSvc)\n    {\n        WrapperSvc = wrapperSvc;\n        PreWrap = preWrap;\n    }\n    protected readonly ICodeDataPoCoWrapperService WrapperSvc;\n\n    public override bool TryGetMember(GetMemberBinder binder, out object? result)\n    {\n        result = PreWrap.TryGetWrap(binder.Name, true).Result;\n        return true;\n    }\n\n    public override bool TrySetMember(SetMemberBinder binder, object? value) \n        => throw new NotSupportedException($\"Setting a value on {nameof(WrapObjectDynamic)} is not supported\");\n\n\n    /// <inheritdoc />\n    [PrivateApi(\"Internal\")]\n    public PropReqResult FindPropertyInternal(PropReqSpecs specs, PropertyLookupPath path) \n        => PreWrap.FindPropertyInternal(specs, path);\n\n\n    object IHasJsonSource.JsonSource()\n        => ((IWrapper<object>)PreWrap).GetContents()!;\n\n    public dynamic? Get(string name)\n        => PreWrap.TryGetWrap(name, true).Result;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicEntity/DynamicEntity.cs",
    "content": "﻿using System.Dynamic;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Metadata;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Data.Sys.Dynamic;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\n\n// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract\n\n// This is so we can have a lot of paranoid Entity? null checks\n// ReSharper disable ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n\nnamespace ToSic.Sxc.Data.Sys;\n\n/// <summary>\n/// A dynamic entity object - the main object you use when templating things in RazorComponent objects <br/>\n/// Note that it will provide many things not listed here, usually things like `.Image`, `.FirstName` etc. based on your ContentType.\n/// </summary>\n[PrivateApi(\"Changed to private in v16.01, previously was public/stable\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class DynamicEntity : DynamicObject, IDynamicEntity, IHasMetadata, IHasPropLookup, ISxcDynamicObject, ICanDebug, ICanBeItem, ICanGetByName\n{\n    #region Constructor / Setup\n\n    /// <summary>\n    /// Constructor with EntityModel and DimensionIds\n    /// </summary>\n    [PrivateApi]\n    public DynamicEntity(IEntity entity, ICodeDataFactory cdf, bool propsRequired)\n        : this(cdf, propsRequired, entity)\n    {\n        ListHelper = new(this, () => Debug, propsRequired: propsRequired, cdf);\n    }\n\n    internal DynamicEntity(IEnumerable<IEntity> list, IEntity? parent, string? field, int? appIdOrNull, bool propsRequired, ICodeDataFactory cdf)\n        : this(cdf, propsRequired,\n            // Set the entity - if there was one, or if the list is empty, create a dummy Entity so toolbars will know what to do\n            entity: list.FirstOrDefault() ?? cdf.PlaceHolderInBlock(appIdOrNull ?? 0, parent, field))\n    {\n        ListHelper = new(list, parent, field, () => Debug, propsRequired: propsRequired, cdf);\n    }\n\n    bool IModelSetup<IEntity>.SetupModel(IEntity? source)\n        => throw new NotSupportedException($\"SetupContents is not supported for {GetType().Name}, as it requires more information.\");\n\n    /// <summary>\n    /// Internal helper to make a entity behave as a list, new in 12.03\n    /// </summary>\n    [PrivateApi]\n    internal readonly DynamicEntityListHelper ListHelper = null!;\n\n    private DynamicEntity(ICodeDataFactory cdf, bool propsRequired, IEntity entity)\n    {\n        Cdf = cdf;\n        _propsRequired = propsRequired;\n        Entity = entity;\n        var entAsWrapper = Entity as IEntityWrapper;\n        RootContentsForEqualityCheck = entAsWrapper?.RootContentsForEqualityCheck ?? Entity;\n        Decorators = entAsWrapper?.Decorators ?? [];\n    }\n\n\n    // ReSharper disable once InconsistentNaming\n    [PrivateApi] public ICodeDataFactory Cdf { get; }\n    [PrivateApi] public IEntity Entity { get; }\n    private readonly bool _propsRequired;\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    IPropertyLookup IHasPropLookup.PropertyLookup => field ??= new PropLookupWithPathEntity(Entity, canDebug: this);\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal GetAndConvertHelper GetHelper => field ??= new(this, Cdf, _propsRequired, childrenShouldBeDynamic: true, canDebug: this);\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal SubDataFactory SubDataFactory => field ??= new(Cdf, _propsRequired, canDebug: this);\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal CodeDynHelper DynHelper => field ??= new(Entity, SubDataFactory);\n\n    /// <summary>\n    /// TypedItem is only internal, for use in APIs which should only have one way to handle data.\n    /// Since DynamicEntity is an old API, we don't want to surface TypedItem in the public API.\n    /// </summary>\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal ITypedItem TypedItem => field ??= new TypedItemOfEntity(Entity, Cdf, _propsRequired);\n\n    /// <inheritdoc />\n    public bool Debug { get; set; }\n\n    #endregion\n\n    #region Basic Entity props: Id, Guid, Title, Type\n\n    /// <inheritdoc />\n    public int EntityId => Entity?.EntityId ?? 0;\n\n    /// <inheritdoc />\n    public Guid EntityGuid => Entity?.EntityGuid ?? Guid.Empty;\n\n    /// <inheritdoc />\n    public string? EntityTitle => Entity?.GetBestTitle(Cdf.Dimensions);\n\n    /// <inheritdoc />\n    public string? EntityType => Entity?.Type?.Name;\n\n    #endregion\n\n    #region Advanced: Fields, Html\n\n    /// <inheritdoc />\n    public IField? Field(string name) => Cdf.Field(TypedItem, supportOldMetadata: true, name, new() { ItemIsStrict = _propsRequired });\n\n    /// <inheritdoc/>\n    [PrivateApi(\"Should not be documented here, as it should only be used on ITyped\")]\n    public IHtmlTag? Html(\n        string name,\n        NoParamOrder npo = default,\n        object? container = default,\n        bool? toolbar = default,\n        object? imageSettings = default,\n        bool debug = default\n    ) => Cdf.CompatibilityLevel < CompatibilityLevels.CompatibilityLevel12\n        // Only do compatibility check if used on DynamicEntity\n        ? throw new NotSupportedException($\"{nameof(Html)}(...) not supported in older Razor templates. Use Razor14, RazorTyped or newer.\")\n        : TypedItemHelpers.Html(Cdf, TypedItem, name: name, npo: npo, container: container,\n            toolbar: toolbar, imageSettings: imageSettings, required: false, debug: debug);\n\n    #endregion\n\n    #region Special: IsDemoItem, IsFake\n\n    // ReSharper disable once InheritdocInvalidUsage\n    /// <inheritdoc />\n    public virtual bool IsDemoItem => _isDemoItem ??= Entity.IsDemoItemSafe();\n    private bool? _isDemoItem;\n\n    [PrivateApi(\"Not in use yet, and I believe not communicated\")]\n    public bool IsFake => _isFake ??= (Entity?.EntityId ?? DataConstants.DataFactoryDefaultEntityId) == DataConstants.DataFactoryDefaultEntityId;\n    private bool? _isFake;\n\n    #endregion\n\n    #region Metadata\n\n    /// <inheritdoc />\n    public dynamic Metadata => DynHelper.Metadata!;\n\n    /// <summary>\n    /// Explicit implementation, so it's not really available on DynamicEntity, only when cast to IHasMetadata\n    /// This is important, because it uses the same name \"Metadata\"\n    /// </summary>\n    [PrivateApi]\n    IMetadata IHasMetadata.Metadata => Entity?.Metadata!;\n\n\n    #endregion\n\n    #region Relationships: Presentation, Children, Parents\n\n    /// <inheritdoc />\n    public dynamic? Presentation => DynHelper.Presentation;\n\n    /// <inheritdoc />\n    public List<IDynamicEntity?> Parents(string? type = null, string? field = null)\n        => GetHelper.Converter.ParentsDyn(entity: Entity!, type: type, field: field);\n\n    /// <inheritdoc />\n    public List<IDynamicEntity?> Children(string? field = null, string? type = null)\n        => GetHelper.Converter.ChildrenDyn(Entity!, field: field, type: type);\n\n    #endregion\n\n    #region Publishing: IsPublished, GetDraft(), GetPublished()\n\n    /// <inheritdoc />\n    public bool IsPublished => Entity?.IsPublished ?? true;\n\n    /// <inheritdoc />\n\n    public dynamic? GetDraft() => SubDataFactory.SubDynEntityOrNull(Entity == null\n        ? null\n        : (Cdf as ICodeDataFactoryDeepWip)?.AppReaderOrNull?.GetDraft(Entity)\n    );\n\n    /// <inheritdoc />\n    public dynamic? GetPublished() => SubDataFactory.SubDynEntityOrNull(Entity == null\n        ? null\n        : (Cdf as ICodeDataFactoryDeepWip)?.AppReaderOrNull?.GetPublished(Entity)\n    );\n\n    #endregion\n\n    #region Get / Get<T>\n\n    public dynamic? Get(string name) => GetHelper.Get(name);\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public dynamic? Get(string name, NoParamOrder npo = default, string? language = null, bool convertLinks = true, bool? debug = null)\n        => GetHelper.Get(name, npo, language, convertLinks, debug);\n\n    public TValue? Get<TValue>(string name)\n        => GetHelper.Get<TValue>(name);\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default)\n        => GetHelper.Get(name, npo, fallback);\n\n    #endregion\n\n\n    #region Any*** properties just for documentation\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public dynamic? AnyProperty => null;\n\n    #endregion\n\n    [PrivateApi] ITypedItem ICanBeItem.Item => TypedItem;\n\n\n    #region Metadata - Enable Metadata.Methods()\n\n    // Background: 2023-08-15 2dm\n    // For reasons we don't fully understand, the razor dynamic binder can't find methods on inherited objects.\n    // If we add their signatures here, and then override them in the implementation, it works\n    // This is probably not the best way to do it, but for now it should work.\n\n    [PrivateApi(\"This doesn't work until overriden by the Metadata object\")]\n    public virtual bool HasType(string type) => throw new NotSupportedException(\"This is just a stub for Metadata\");\n\n    [PrivateApi(\"This doesn't work until overriden by the Metadata object\")]\n    public virtual IEnumerable<IEntity> OfType(string type) => throw new NotSupportedException(\"This is just a stub for Metadata\");\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicEntity/DynamicEntity_Equality.cs",
    "content": "﻿// Since DynamicEntity... is a wrapper,\n// These things ensure that various standalone wrappers are still regarded as equals\n// If the underlying entity is the same\n\nusing ToSic.Eav.Data.Sys.Entities;\n\nnamespace ToSic.Sxc.Data.Sys;\n\npublic partial class DynamicEntity: IEquatable<IEntityWrapper>\n{\n    [PrivateApi] public IEntity? RootContentsForEqualityCheck { get; }\n    [PrivateApi] public IEnumerable<IDecorator<IEntity>> Decorators { get; }\n\n    #region Changing comparison operation to internally compare the entities, not this wrapper\n\n    [PrivateApi]\n    public static bool operator ==(DynamicEntity d1, IEntityWrapper d2) => MultiWrapperEquality.IsEqual(d1, d2);\n\n    [PrivateApi]\n    public static bool operator !=(DynamicEntity d1, IEntityWrapper d2) => !MultiWrapperEquality.IsEqual(d1, d2);\n\n    [PrivateApi]\n    public bool Equals(IEntityWrapper? other) => MultiWrapperEquality.EqualsWrapper(this, other);\n\n    /// <inheritdoc />\n    [PrivateApi]\n    public override bool Equals(object? obj) => MultiWrapperEquality.EqualsObj(this, obj);\n\n    /// <summary>\n    /// This is used by various equality comparison. \n    /// Since we define two DynamicEntities to be equal when they host the same entity, this uses the Entity.HashCode\n    /// </summary>\n    /// <returns></returns>\n    [PrivateApi]\n#pragma warning disable RS1024 // Compare symbols correctly\n    public override int GetHashCode() => MultiWrapperEquality.GetWrappedHashCode(this);\n#pragma warning restore RS1024 // Compare symbols correctly\n\n    /// <inheritdoc />\n    [PrivateApi]\n    public bool Equals(IDynamicEntity? dynObj) => MultiWrapperEquality.EqualsWrapper(this, dynObj);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicEntity/DynamicEntity_GetValues.cs",
    "content": "﻿using System.Dynamic;\nusing ToSic.Sxc.Data.Sys.Dynamic;\n\nnamespace ToSic.Sxc.Data.Sys;\n\npublic partial class DynamicEntity\n{\n    [PrivateApi]\n    public override bool TryGetMember(GetMemberBinder binder, out object? result)\n    {\n        // Check special cases #1 Toolbar - only in DNN and only on the explicit dynamic entity; not available in Oqtane\n#if NETFRAMEWORK\n#pragma warning disable 618 // ignore Obsolete\n        if (binder.Name == nameof(Toolbar))\n        {\n            result = Toolbar.ToString();\n            return true;\n        }\n#pragma warning restore 618\n#endif\n\n        return CodeDynHelper.TryGetMemberAndRespectStrict(GetHelper, binder, out result);\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicEntity/DynamicEntity_IListIDynamicEntity.cs",
    "content": "﻿using System.Collections;\n\nnamespace ToSic.Sxc.Data.Sys;\n\npublic partial class DynamicEntity: IList<IDynamicEntity>\n{\n    [PrivateApi(\"Hide, will only confuse\")]\n    public IEnumerator<IDynamicEntity> GetEnumerator() => ListHelper.DynEntities.GetEnumerator();\n\n    [PrivateApi(\"Hide, will only confuse\")]\n    IEnumerator IEnumerable.GetEnumerator() => ListHelper.DynEntities.GetEnumerator();\n\n    /// <summary>\n    /// Shows how many Entities are available if you use foreach. Will usually return an `int`.\n    /// </summary>\n    /// <remarks>\n    /// If the Entity contains a field `Count`, that will be returned instead.\n    /// </remarks>\n    /// <returns>Usually an `int` but if the Entity contains such a property, then it has the type of that property. </returns>\n    public object Count => Get(\"Count\") ?? ListHelper.DynEntities.Count;\n        \n    [PrivateApi]\n    int ICollection<IDynamicEntity>.Count => ListHelper.DynEntities.Count;\n\n    [PrivateApi(\"would only confuse users, not useful in Razor / DynamicCode\")]\n    public IDynamicEntity this[int index]\n    {\n        get => ListHelper.DynEntities[index]!; // actually it can be null, but the `this[...]` interface would complain\n        // note: set must be defined for IList<IDynamicEntity>\n        set => throw new NotSupportedException();\n    }\n\n\n    #region Implemented features as read-only List\n\n    [PrivateApi(\"Hide, necessary because of an Interface but would only confuse users\")]\n    bool ICollection<object>.IsReadOnly => true;\n\n    [PrivateApi(\"Hide, necessary because of an Interface but would only confuse users\")]\n    bool ICollection<IDynamicEntity>.IsReadOnly => true;\n\n\n    [PrivateApi(\"Hide, necessary because of an Interface but would only confuse users\")]\n    public bool Contains(IDynamicEntity item) => ListHelper.DynEntities.Contains(item);\n\n    [PrivateApi(\"Hide, necessary because of an Interface but would only confuse users\")]\n    public void CopyTo(IDynamicEntity[] array, int arrayIndex) => ListHelper.DynEntities.CopyTo(array, arrayIndex);\n\n    [PrivateApi(\"Hide, necessary because of an Interface but would only confuse users\")]\n    public int IndexOf(IDynamicEntity item) => ListHelper.DynEntities.IndexOf(item);\n\n    #endregion\n\n    #region Not implemented ICollection<T> & IList<T> interfaces\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void ICollection<IDynamicEntity>.Add(IDynamicEntity item) => throw new NotSupportedException();\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void ICollection<object>.Clear() => throw new NotSupportedException();\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void ICollection<IDynamicEntity>.Clear() => throw new NotSupportedException();\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    bool ICollection<IDynamicEntity>.Remove(IDynamicEntity item) => throw new NotSupportedException();\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void IList<IDynamicEntity>.Insert(int index, IDynamicEntity item) => throw new NotSupportedException();\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void IList<object>.RemoveAt(int index) => throw new NotSupportedException();\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void IList<IDynamicEntity>.RemoveAt(int index) => throw new NotSupportedException();\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicEntity/DynamicEntity_IListObject.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys;\n// Backward compatible enumeration interface for people casting as IList<dynamic>\n\npublic partial class DynamicEntity: IList<object>\n{\n    #region IList explicit implementations (were already explicit before v16.03\n\n    [PrivateApi(\"would confuse\")]\n    int ICollection<object>.Count => ListHelper.DynEntities.Count;\n\n    [PrivateApi(\"Hide, will only confuse\")]\n    IEnumerator<object> IEnumerable<object>.GetEnumerator() => ListHelper.DynEntities.GetEnumerator();\n\n    #endregion\n\n    #region IList Things which were implicit before v16.03 and made explicit, in hope it was never used\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    bool ICollection<object>.Contains(object item) => ListHelper.DynEntities.Contains(item);\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    int IList<object>.IndexOf(object item) => -1; // not supported, so always return -1\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void ICollection<object>.CopyTo(object[] array, int arrayIndex)\n    {\n        var target = new IDynamicEntity[ListHelper.DynEntities.Count];\n        ListHelper.DynEntities.CopyTo(target, arrayIndex);\n        target.CopyTo(array, arrayIndex);\n    }\n\n    #endregion\n\n    #region Not implemented IList interfaces - changed to explicit implementation v16.03\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void ICollection<object>.Add(object item) => throw new NotSupportedException();\n\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    bool ICollection<object>.Remove(object item) => throw new NotSupportedException();\n\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    void IList<object>.Insert(int index, object item) => throw new NotSupportedException();\n\n    #endregion\n\n    [PrivateApi(\"Hide as it won't work\")]\n    [Obsolete(\"Don't use this, it's not supported\")]\n    object IList<object>.this[int index]\n    {\n        get => (this as IList<IDynamicEntity>)[index];\n        set => throw new NotSupportedException();\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicEntity/DynamicEntity_Obsolete.cs",
    "content": "﻿#if NETFRAMEWORK\n\nusing ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Data.Sys\n{\n    public partial class DynamicEntity\n    {\n        /// <inheritdoc />\n        [Obsolete(\"use Edit.Toolbar instead\")]\n        [PrivateApi]\n        public System.Web.IHtmlString Toolbar => Cdf.GetService<IOldDynamicEntityFeatures>().GenerateOldToolbar(Cdf, Entity);\n\n        [Obsolete]\n        [PrivateApi(\"probably we won't continue recommending to use this, but first we must provide an alternative\")]\n        public IRawHtmlString Render() => Cdf.GetService<IOldDynamicEntityFeatures>().Render(Cdf, this);\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicEntity/IOldDynamicEntityFeatures.cs",
    "content": "﻿using ToSic.Razor.Markup;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Sys;\n\n\npublic interface IOldDynamicEntityFeatures\n{\n    System.Web.IHtmlString GenerateOldToolbar(ICodeDataFactory cdf, IEntity entity);\n    IRawHtmlString Render(ICodeDataFactory cdf, ICanBeItem target);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/CodeJsonWrapper.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing System.Text.Json;\nusing System.Text.Json.Nodes;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing static ToSic.Sxc.Data.Sys.Wrappers.JsonProcessingHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeJsonWrapper(Generator<WrapObjectTyped> wrapTypeGenerator)\n    : ServiceBase($\"{SxcLogName}.CdJsWr\", connect: [wrapTypeGenerator])\n{\n    #region Constructor / Setup\n\n    public WrapperSettings Settings { get; private set; }\n\n    public CodeJsonWrapper Setup(WrapperSettings settings)\n    {\n        Settings = settings;\n        return this;\n    }\n\n    #endregion\n\n\n    internal DynamicJacketBase? Json2Jacket(string? json, NoParamOrder npo = default, string? fallback = default)\n        => IfJsonTryConvertToJacket(AsJsonNode(json, fallback)).Final;\n\n    public ITyped? JsonToTyped(string json, NoParamOrder npo = default, string? fallback = default)\n    {\n        if (!json.HasValue())\n            return null;\n        ThrowIfNotExpected(json, false);\n        var node = AsJsonNode(json, fallback);\n        var result = IfJsonTryConvertTo<ITyped>(node, CreateTypedObject, _ => null);\n        return result.Final;\n    }\n\n    public IEnumerable<ITyped>? JsonToTypedList(string json, NoParamOrder npo = default, string? fallback = default)\n    {\n        if (!json.HasValue())\n            return null;\n        ThrowIfNotExpected(json, true);\n        var node = AsJsonNode(json, fallback);\n        var result = IfJsonTryConvertTo(node, _ => null, arr => JsonArrayToTypedList(arr, true)!);\n        return result.Final;\n    }\n\n    private IEnumerable<ITyped>? JsonArrayToTypedList(JsonArray array, bool errorIfNotPossible)\n    {\n        if (!errorIfNotPossible && array.Any(jItem => jItem is not JsonObject))\n            return null;\n\n        return array.Select((j, index) => j is JsonObject jo\n                ? CreateTypedObject(jo)\n                : throw new ArgumentException(\n                    $\"Tried to create array of objects but array seems to contain simple values or something else. '{j}', index: {index}\"))\n            .ToList();\n    }\n\n    private void ThrowIfNotExpected(string json, bool expectArray, [CallerMemberName] string? cName = default)\n    {\n        var (isComplex, isArray) = AnalyzeJson(json);\n        if (!isComplex)\n            throw new ArgumentException(\n                @\"Wrapping Json only works for complex objects. This value is either null, empty or a value type.\",\n                nameof(json));\n\n        // If Array-state and expectations match, it's ok\n        if (isArray == expectArray)\n            return;\n\n        // Throw if IsArray and it wasn't expected\n        if (isArray)\n            throw new ArgumentException($@\"Expected an object but got an array. For arrays you should use ToTypedList(...), not {cName}\", nameof(json));\n\n        // Not array, but apparently expected\n        throw new ArgumentException($@\"Expected an array but got an object. For objects you should use ToTyped(...), not {cName}\",\n            nameof(json));\n    }\n\n\n\n\n    private (DynamicJacketBase? Final, bool Ok, JsonValueKind ValueKind) IfJsonTryConvertToJacket(object? original)\n        => IfJsonTryConvertTo<DynamicJacketBase>(original, CreateDynJacketObject, CreateDynJacketList);\n\n\n    internal DynamicJacket CreateDynJacketObject(JsonObject jsonObject) =>\n        new(this, new(this, jsonObject));\n\n    private DynamicJacketList CreateDynJacketList(JsonArray jsonArray) =>\n        new(this, new(this, jsonArray));\n\n    //private WrapObjectTyped CreateTypedList(JsonArray jsonArray) => \n    //    _wrapTypeGenerator.New().Setup(new PreWrapJsonArray(this, jsonArray));\n\n    private WrapObjectTyped CreateTypedObject(JsonObject jsonObject) => \n        wrapTypeGenerator.New().Setup(new PreWrapJsonObject(this, jsonObject));\n\n    private (TResult? Final, bool Ok, JsonValueKind ValueKind)\n        IfJsonTryConvertTo<TResult>(object? original, Func<JsonObject, TResult?> toObj, Func<JsonArray, TResult?> toArr)\n        where TResult : class\n    {\n        var l = Log.Fn<(TResult? Jacket, bool Ok, JsonValueKind ValueKind)>();\n        if (original is not JsonNode jsonNode)\n            return l.Return((null, false, JsonValueKind.Undefined), \"not json node\");\n\n        // 2023-08-24 2dm simplified this by preprocessing. Leave the code in till end of September 2023 \n        var (node, repackaged) = NeutralizeValueToObjectOrArray(jsonNode);\n        jsonNode = node ?? jsonNode;\n        var logPrefix = repackaged ? \"val \" : \"\";\n\n        switch (jsonNode)\n        {\n            case JsonArray jArray:\n                return l.Return((toArr(jArray), true, JsonValueKind.Array), $\"{logPrefix}array\");\n            case JsonObject jResult: // it's another complex object, so return another wrapped reader\n                return l.Return((toObj(jResult), true, JsonValueKind.Object), $\"{logPrefix}obj\");\n            // 2023-08-24 2dm simplified this by preprocessing. Leave the code in till end of September 2023 \n            //case JsonValue jValue: // it's a simple value - so we want to return the underlying real value\n            //    {\n            //        // TODO: 2dm must discuss w/STV - is this code even reachable?\n            //        // My guess is that all these cases are handled before\n            //        var je = jValue.GetValue<JsonElement>();\n            //        switch (je.ValueKind)\n            //        {\n            //            case JsonValueKind.Array:\n            //                return l.Return((toArr(JsonArray.Create(je)), true, JsonValueKind.Array), \"val array\");\n            //            case JsonValueKind.Object:\n            //                return l.Return((toObj(JsonObject.Create(je)), true, JsonValueKind.Object), \"val obj\");\n            //            default:\n            //                return l.Return((null, false, JsonValueKind.Undefined), \"val not handled\");\n            //        }\n            //    }\n            default: // it's something else, let's just return that\n                return l.Return((null, false, JsonValueKind.Undefined), $\"{nameof(jsonNode)} not handled\");\n        }\n    }\n\n\n    /// <summary>\n    /// Takes a JSON Node and if it's just a value, return that.\n    /// If it's a complex object, place it in a jacket again for dynamic code to be able to navigate it. \n    /// So if it's a simple value, it's returned as a value, otherwise it's wrapped into a DynamicJacket again.\n    /// </summary>\n    /// <param name=\"original\"></param>\n    /// <returns></returns>\n    [PrivateApi]\n    internal object? IfJsonGetValueOrJacket(object? original)\n    {\n        if (original is not JsonNode jsonNode)\n            return original;\n\n        if (!Settings.WrapToDynamic)\n        {\n            var wrapTyped = IfJsonTryConvertTo<object>(original,\n                CreateTypedObject,\n                jArr => JsonArrayToTypedList(jArr, errorIfNotPossible: false));\n            if (wrapTyped is { Ok: true, Final: not null })\n                return wrapTyped.Final;\n\n            // New case in Typed only, as it won't wrap arrays which are not complex object\n            if (jsonNode is JsonArray jsonArray)\n                return jsonArray.Select(JsonValueGetContents).ToList();\n        }\n        else\n        {\n            var (wrapResult, wrapOk, _) = IfJsonTryConvertToJacket(original);\n            if (wrapOk)\n                return wrapResult;\n        }\n\n\n\n        // If not a value-type, assume we can't process it\n        if (jsonNode is not JsonValue jValue) return original;\n\n        return JsonValueGetContents(jValue);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/DynamicJacket.cs",
    "content": "﻿using System.Dynamic;\nusing System.Text.Json.Nodes;\nusing System.Text.Json.Serialization;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\n\n/// <summary>\n/// Case-insensitive dynamic read-object for JSON. <br/>\n/// Used in various cases where you start with JSON and want to\n/// provide the contents to custom code without having to mess with\n/// JS/C# code style differences. <br/>\n/// You will usually do things like `AsDynamic(jsonString).FirstName` etc.\n/// </summary>\n[PrivateApi(\"was Internal-API till v17 - just use the objects from AsDynamic(...), don't use this directly\")]\n[JsonConverter(typeof(DynamicJsonConverter))]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class DynamicJacket: DynamicJacketBase<JsonObject>\n{\n    /// <inheritdoc />\n    [PrivateApi]\n    internal DynamicJacket(CodeJsonWrapper wrapper, PreWrapJsonObject preWrap) : base(wrapper, preWrap.GetContents())\n    {\n        PreWrapJson = preWrap;\n    }\n\n    private PreWrapJsonObject PreWrapJson { get; }\n\n    internal override IPreWrap PreWrap => PreWrapJson;\n\n    #region Basic Jacket Properties\n\n    public override bool IsList => false;\n\n    /// <summary>\n    /// Count array items or object properties\n    /// </summary>\n    public override int Count => UnwrappedContents.Count;\n\n    #endregion\n\n    /// <inheritdoc />\n\n\n\n    /// <summary>\n    /// Enable enumeration. Will return the keys, not the values. <br/>\n    /// Use the [key] accessor to get the values as <see cref=\"DynamicJacket\"/> or <see cref=\"DynamicJacketList\"/>\n    /// </summary>\n    /// <returns>the string names of the keys</returns>\n    [InternalApi_DoNotUse_MayChangeWithoutNotice]\n    public override IEnumerator<object> GetEnumerator() => UnwrappedContents.Select(p => p.Key).GetEnumerator();\n\n\n    /// <summary>\n    /// Access the properties of this object.\n    /// </summary>\n    /// <remarks>\n    /// Note that <strong>this</strong> accessor is case insensitive\n    /// </remarks>\n    /// <param name=\"key\">the key, case-insensitive</param>\n    /// <returns>A value (string, int etc.), <see cref=\"DynamicJacket\"/> or <see cref=\"DynamicJacketList\"/></returns>\n    public object? this[string key] => PreWrap.TryGetWrap(key).Result;\n\n    // 2023-08-17 2dm - completely removed this, I can't imagine it actually being used anywhere.\n    ///// <summary>\n    ///// Access the properties of this object.\n    ///// </summary>\n    ///// <param name=\"key\">the key</param>\n    ///// <param name=\"caseSensitive\">true if case-sensitive, false if not</param>\n    ///// <returns>A value (string, int etc.), <see cref=\"DynamicJacket\"/> or <see cref=\"DynamicJacketList\"/></returns>\n    //[PrivateApi(\"2023-08-07 2dm made private now, before it was public. It's very exotic, so I don't think it's used anywhere, consider removing this later on\")]\n    //public object this[string key, bool caseSensitive]\n    //    => PreWrap.FindValueOrNull(key, caseSensitive \n    //        ? Ordinal\n    //        : InvariantCultureIgnoreCase, null);\n\n\n    #region Private TryGetMember\n\n    /// <summary>\n    /// Performs a case-insensitive value look-up\n    /// </summary>\n    /// <param name=\"binder\">.net binder object</param>\n    /// <param name=\"result\">usually a <see cref=\"DynamicJacket\"/>, <see cref=\"DynamicJacketList\"/> or null</param>\n    /// <returns>always returns true, to avoid errors</returns>\n    public override bool TryGetMember(GetMemberBinder binder, out object? result)\n    {\n        result = PreWrap.TryGetWrap(binder.Name).Result;\n        // always say it was found to prevent runtime errors\n        return true;\n    }\n\n    #endregion\n\n    /// <inheritdoc />\n    public override object? this[int index] => (_propertyArray ??= UnwrappedContents.Select(p => p.Value).ToArray())[index];\n    private JsonNode?[]? _propertyArray;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/DynamicJacketBase.cs",
    "content": "﻿using System.Collections;\nusing System.Dynamic;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\n\n/// <summary>\n/// Base class for DynamicJackets. You won't use this, just included in the docs. <br/>\n/// To check if something is an array or an object, use \"IsArray\"\n/// </summary>\n[PrivateApi(\"was Internal-API till v17 - just use the objects from AsDynamic, don't use this directly\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class DynamicJacketBase(CodeJsonWrapper wrapper): DynamicObject, IReadOnlyList<object?>, ISxcDynamicObject, ICanGetByName, IHasPropLookup, IHasJsonSource\n{\n    #region Constructor / Setup\n\n    [PrivateApi] internal CodeJsonWrapper Wrapper { get; } = wrapper;\n\n    [PrivateApi]\n    internal abstract IPreWrap PreWrap { get; }\n\n    [PrivateApi]\n    IPropertyLookup IHasPropLookup.PropertyLookup => PreWrap;\n\n    [PrivateApi]\n    object IHasJsonSource.JsonSource() => PreWrap.JsonSource();\n\n    #endregion\n\n    /// <summary>\n    /// Check if it's an array.\n    /// </summary>\n    /// <returns>True if an array/list, false if an object.</returns>\n    public abstract bool IsList { get; }\n\n    /// <summary>\n    /// Enable enumeration. When going through objects (properties) it will return the keys, not the values. <br/>\n    /// Use the [key] accessor to get the values as <see cref=\"DynamicJacketList\"/> or <see cref=\"Data\"/>\n    /// </summary>\n    /// <returns></returns>\n    [InternalApi_DoNotUse_MayChangeWithoutNotice]\n    public abstract IEnumerator<object?> GetEnumerator();\n\n\n    /// <inheritdoc />\n    [PrivateApi]\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n    /// <inheritdoc />\n    public dynamic? Get(string name) => PreWrap.TryGetWrap(name).Result;\n\n    /// <summary>\n    /// Count array items or object properties\n    /// </summary>\n    public abstract int Count { get; }\n\n    /// <summary>\n    /// Not yet implemented accessor - must be implemented by the inheriting class.\n    /// </summary>\n    /// <param name=\"index\"></param>\n    /// <returns>a <see cref=\"System.NotImplementedException\"/></returns>\n#pragma warning disable CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes).\n    public abstract object? this[int index] { get; }\n#pragma warning restore CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes).\n\n    /// <summary>\n    /// Fake property binder - just ensure that simple properties don't cause errors. <br/>\n    /// Must be overriden in inheriting objects\n    /// like <see cref=\"DynamicJacketList\"/>, <see cref=\"DynamicJacket\"/>\n    /// </summary>\n    /// <param name=\"binder\">.net binder object</param>\n    /// <param name=\"result\">always null, unless overriden</param>\n    /// <returns>always returns true, to avoid errors</returns>\n    [PrivateApi]\n    public abstract override bool TryGetMember(GetMemberBinder binder, out object? result);\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/DynamicJacketBaseT.cs",
    "content": "﻿using System.Collections;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\n\n/// <summary>\n/// Base class for DynamicJackets. You won't use this, just included in the docs. <br/>\n/// To check if something is an array or an object, use \"IsArray\"\n/// </summary>\n/// <typeparam name=\"T\">The underlying type, either a JObject or a JToken</typeparam>\n[PrivateApi(\"was Internal-API till v17 - just use the objects from AsDynamic, don't use this directly\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class DynamicJacketBase<T>: DynamicJacketBase, IReadOnlyList<object?>, IWrapper<T>, ISxcDynamicObject, ICanGetByName\n{\n    [PrivateApi]\n    protected T UnwrappedContents;\n    public T GetContents() => UnwrappedContents;\n\n    /// <summary>\n    /// Primary constructor expecting a internal data object\n    /// </summary>\n    /// <param name=\"wrapper\">Wrapper helper</param>\n    /// <param name=\"originalData\">the original data we're wrapping</param>\n    [PrivateApi]\n    internal DynamicJacketBase(CodeJsonWrapper wrapper, T originalData): base(wrapper)\n    {\n        UnwrappedContents = originalData;\n    }\n\n    ///// <summary>\n    ///// Enable enumeration. When going through objects (properties) it will return the keys, not the values. <br/>\n    ///// Use the [key] accessor to get the values as <see cref=\"DynamicJacketList\"/> or <see cref=\"Data\"/>\n    ///// </summary>\n    ///// <returns></returns>\n    //[PrivateApi]\n    //public abstract IEnumerator<object> GetEnumerator();\n\n\n    /// <inheritdoc />\n    [PrivateApi]\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n    /// <summary>\n    /// If the object is just output, it should show the underlying json string\n    /// </summary>\n    /// <returns>the inner json string</returns>\n    public override string? ToString() => UnwrappedContents?.ToString();\n\n    ///// <summary>\n    ///// Not yet implemented accessor - must be implemented by the inheriting class.\n    ///// </summary>\n    ///// <param name=\"index\"></param>\n    ///// <returns>a <see cref=\"System.NotImplementedException\"/></returns>\n    //public abstract object this[int index] { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/DynamicJacketList.cs",
    "content": "﻿using System.Dynamic;\nusing System.Text.Json.Nodes;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\n\n/// <summary>\n/// This is a DynamicJacket for JSON arrays. You can enumerate through it. \n/// </summary>\n[PrivateApi(\"was Internal-API till v17 - just use the objects from AsDynamic, don't use this directly\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class DynamicJacketList : DynamicJacketBase<JsonArray>, IReadOnlyList<object?>\n{\n    /// <inheritdoc />\n    internal DynamicJacketList(CodeJsonWrapper wrapper, PreWrapJsonArray preWrap) : base(wrapper, preWrap.GetContents())\n    {\n        PreWrapList = preWrap;\n    }\n    private PreWrapJsonArray PreWrapList { get; }\n\n    internal override IPreWrap PreWrap => PreWrapList;\n\n    #region Basic Jacket Properties\n\n    /// <inheritdoc />\n    public override bool IsList => true;\n\n    /// <summary>\n    /// Count array items or object properties\n    /// </summary>\n    public override int Count => UnwrappedContents.Count;\n\n    #endregion\n\n\n\n    [PrivateApi]\n    public override IEnumerator<object?> GetEnumerator() \n        => UnwrappedContents.Select(o => Wrapper.IfJsonGetValueOrJacket(o)).GetEnumerator();\n\n    [PrivateApi]\n    public override bool TryGetMember(GetMemberBinder binder, out object? result)\n    {\n        result = null;\n        return true;\n    }\n\n\n    /// <summary>\n    /// Access the items in this object - but only if the underlying object is an array. \n    /// </summary>\n    /// <param name=\"index\">array index</param>\n    /// <returns>the item or an error if not found</returns>\n    public override object? this[int index] => Wrapper.IfJsonGetValueOrJacket(UnwrappedContents[index]);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/PreWrapJsonArray.cs",
    "content": "﻿using System.Text.Json.Nodes;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class PreWrapJsonArray(CodeJsonWrapper wrapper, JsonArray jsonArray)\n    : PreWrapJsonBase(wrapper, jsonArray), IWrapper<JsonArray>\n{\n    protected readonly JsonArray UnwrappedContents = jsonArray;\n\n    public JsonArray GetContents() => UnwrappedContents;\n\n    public override object JsonSource() => UnwrappedContents;\n\n    #region Keys\n\n    public override IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default)\n        // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n        => TypedHelpers.FilterKeysIfPossible(npo, only, UnwrappedContents?.Select((p, i) => i.ToString()));\n\n    public override bool ContainsKey(string name)\n    {\n        if (name.IsEmpty() || UnwrappedContents == null!)\n            return false;\n        var index = name.ConvertOrFallback(fallback: -1, numeric: true);\n        if (index == -1)\n            return false;\n        return index < UnwrappedContents.Count;\n    }\n\n    #endregion\n\n    public override TryGetResult TryGetWrap(string? name, bool wrapDefault = true)\n    {\n        if (UnwrappedContents == null! /* paranoid */ || !UnwrappedContents.Any())\n            return new(false, null, null);\n\n        var found = UnwrappedContents\n            .FirstOrDefault(p =>\n            {\n                if (p is not JsonObject pJObject)\n                    return false;\n                return HasPropertyWithValue(obj: pJObject, propertyName: \"Name\", value: name)\n                       || HasPropertyWithValue(obj: pJObject, propertyName: \"Title\", value: name);\n            });\n\n        return new(false, found,\n            Wrapper.IfJsonGetValueOrJacket(found));\n    }\n\n\n    private static bool HasPropertyWithValue(JsonObject obj, string propertyName, string? value)\n    {\n        if (obj.TryGetPropertyValue(propertyName, out var propVal)\n            && propVal is JsonValue jVal\n            && jVal.TryGetValue<string>(out var strVal)\n           )\n            return strVal.EqualsInsensitive(value);\n\n        return false;\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/PreWrapJsonBase.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class PreWrapJsonBase(CodeJsonWrapper wrapper, object data)\n    : PreWrapBase(data), IPreWrap, IPropertyLookup\n{\n    public readonly CodeJsonWrapper Wrapper = wrapper;\n\n    public override WrapperSettings Settings => Wrapper.Settings;\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/PreWrapJsonDumperHelper.cs",
    "content": "﻿using System.Text.Json.Nodes;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyDump;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\ninternal class PreWrapJsonDumperHelper\n{\n    private const string DumpSourceName = \"Dynamic\";\n\n    public List<PropertyDumpItem> Dump(PreWrapJsonObject parent, CodeJsonWrapper wrapper, JsonObject item,\n        PropReqSpecs specs, string path, IPropertyDumpService dumpService)\n    {\n        if (!item.Any())\n            return [];\n\n        if (string.IsNullOrEmpty(path))\n            path = DumpSourceName;\n\n        var allProperties = item.ToList();\n\n        var simpleProps = allProperties\n            .Where(p => p.Value is not JsonObject);\n        var resultDynChildren = simpleProps\n            .Select(p => new PropertyDumpItem\n            {\n                Path = path + PropertyDumpItem.Separator + p.Key,\n                Property = parent.FindPropertyInternal(specs.ForOtherField(p.Key),\n                    new PropertyLookupPath().Add(\"DynJacket\", p.Key)),\n                SourceName = DumpSourceName\n            })\n            .ToList();\n\n        var objectProps = allProperties\n            .Where(p => p.Value is JsonObject)\n            .SelectMany(p =>\n            {\n                var jacket = wrapper.CreateDynJacketObject(p.Value!.AsObject());\n                return ((IHasPropLookup)jacket).PropertyLookup is IPropertyDumpCustom dumper\n                    ? dumper._DumpProperties(specs, path + PropertyDumpItem.Separator + p.Key, dumpService)\n                    : [];\n            })\n            .Where(p => p is not null);\n\n        resultDynChildren.AddRange(objectProps);\n\n        // TODO: JArrays\n\n        return resultDynChildren\n            .OrderBy(p => p.Path)\n            .ToList();\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicJacket/PreWrapJsonObject.cs",
    "content": "﻿using System.Text.Json.Nodes;\nusing ToSic.Eav.Data.Sys.PropertyDump;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicJacket;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class PreWrapJsonObject(CodeJsonWrapper wrapper, JsonObject item)\n    : PreWrapJsonBase(wrapper, item), IWrapper<JsonObject>,\n        IPropertyDumpCustom\n{\n    public JsonObject GetContents() => item;\n\n    public override object JsonSource() => item;\n\n    #region Keys\n\n    public override IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default) \n        => TypedHelpers.FilterKeysIfPossible(npo, only, item.Select(p => p.Key));\n\n    public override bool ContainsKey(string name)\n    {\n        if (name.IsEmptyOrWs() || item == null) \n            return false;\n\n        var isPath = name.Contains(PropertyStack.PathSeparator.ToString());\n        if (!isPath)\n            return JsonObjectContainsKey(item, name);\n\n        var pathParts = PropertyStack.SplitPathIntoParts(name);\n        var node = item;\n        for (var i = 0; i < pathParts.Length; i++)\n        {\n            var part = pathParts[i];\n            var result = TryGetFromNode(part, node);\n            // last one or not found - return a not-found\n            if (i == pathParts.Length - 1 || !result.Found) return result.Found;\n            node = result.Raw as JsonObject;\n            if (node == null) return false;\n        }\n\n        return false;\n    }\n\n    private bool JsonObjectContainsKey(JsonObject jsonObject, string name)\n        => jsonObject.Any(p => name.EqualsInsensitive(p.Key));\n\n    #endregion\n\n    #region TryGet\n\n    public override TryGetResult TryGetWrap(string? name, bool wrapDefault = true)\n    {\n        if (name.IsEmptyOrWs() || item == null || !item.Any())\n            return new(false, null, null);\n\n        var isPath = name.Contains(PropertyStack.PathSeparator.ToString());\n        if (!isPath)\n            return TryGetFromNode(name, item);\n\n        var pathParts = PropertyStack.SplitPathIntoParts(name);\n        var node = item;\n        for (var i = 0; i < pathParts.Length; i++)\n        {\n            var part = pathParts[i];\n            var result = TryGetFromNode(part, node);\n            // last one or not found - return a not-found\n            if (i == pathParts.Length -1 || !result.Found)\n                return result;\n            node = result.Raw as JsonObject;\n            if (node == null)\n                return new(false, null, null);\n        }\n        return new(false, null, null);\n    }\n\n    private TryGetResult TryGetFromNode(string name, JsonObject node)\n    {\n        var result = node\n            .FirstOrDefault(p => p.Key.EqualsInsensitive(name));\n\n        var found = !result.Equals(default(KeyValuePair<string, JsonNode>));\n        return new(found, result.Value, found ? Wrapper.IfJsonGetValueOrJacket(result.Value) : null);\n    }\n\n    #endregion\n\n    #region Debug / Dump\n\n    public List<PropertyDumpItem> _DumpProperties(PropReqSpecs specs, string path, IPropertyDumpService dumpService)\n        => item == null || !item.Any()\n            ? []\n            : new PreWrapJsonDumperHelper().Dump(this, Wrapper, item, specs, path, dumpService);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/DynamicStack/DynamicStack.cs",
    "content": "﻿using System.Collections;\nusing System.Dynamic;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Sxc.Data.Sys.Dynamic;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Stack;\n\nnamespace ToSic.Sxc.Data.Sys.DynamicStack;\n\n// Must be pbulic so that `Resources.Get...` work\n[PrivateApi(\"Keep implementation hidden, only publish interface\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DynamicStack: DynamicObject,\n    IWrapper<IPropertyStack>,\n    IDynamicStack,\n    IHasPropLookup,\n    ISxcDynamicObject,\n    IEnumerable, // note: not sure why it supports this, but it has been this way for a long time\n    ICanDebug\n{\n    #region Constructor and Helpers (Composition)\n\n    public DynamicStack(string name, ICodeDataFactory cdf, IReadOnlyCollection<KeyValuePair<string, IPropertyLookup>> sources)\n    {\n        Cdf = cdf;\n        var stack = new PropertyStack().Init(name, sources);\n        _stack = stack;\n        PropertyLookup = new PropLookupStack(stack, () => Debug);\n    }\n    // ReSharper disable once InconsistentNaming\n    [PrivateApi] public ICodeDataFactory Cdf { get; }\n    private readonly IPropertyStack _stack;\n    private const bool Strict = false;\n\n    [PrivateApi]\n    public IPropertyLookup PropertyLookup { get; }\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal GetAndConvertHelper GetHelper => field ??= new(this, Cdf, Strict, childrenShouldBeDynamic: true, canDebug: this);\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal SubDataFactory SubDataFactory => field ??= new(Cdf, Strict, canDebug: this);\n\n    /// <inheritdoc />\n    public bool Debug { get; set; }\n\n    #endregion\n\n\n\n    public override bool TryGetMember(GetMemberBinder binder, out object? result) \n        => CodeDynHelper.TryGetMemberAndRespectStrict(GetHelper, binder, out result);\n\n\n    /// <inheritdoc />\n    [PrivateApi]\n    public IPropertyStack GetContents() => _stack;\n\n    /// <inheritdoc />\n    [PrivateApi(\"was public till v16.02, but since I'm not sure if it is really used, we decided to hide it again since it's probably not an important API\")]\n    public dynamic? GetSource(string name)\n    {\n        var source = _stack.GetSource(name)\n                     // If not found, create a fake one\n                     ?? Cdf.FakeEntity(((ICodeDataFactoryDeepWip)Cdf).AppIdOrZero);\n\n        return SourceToDynamicEntity(source);\n    }\n\n    /// <inheritdoc />\n    [PrivateApi(\"Never published in docs\")]\n    public dynamic GetStack(params string[] names)\n    {\n        var l = GetHelper.LogOrNull.Fn<object>();\n        var newStack = _stack.GetStack(GetHelper.LogOrNull, names);\n        var newDynStack = new DynamicStack(\"New\", Cdf, newStack.Sources);\n        return l.Return(newDynStack);\n    }\n\n    private IDynamicEntity? SourceToDynamicEntity(IPropertyLookup? source)\n    {\n        if (source == null)\n            return null;\n        // ReSharper disable once SuspiciousTypeConversion.Global\n        if (source is IDynamicEntity dynEnt)\n            return dynEnt;\n        if (source is ICanBeEntity canBe)\n            return SubDataFactory.SubDynEntityOrNull(canBe.Entity);\n        //if (source is IEntity ent) return SubDataFactory.SubDynEntityOrNull(ent);\n        return null;\n    }\n\n\n    [PrivateApi(\"not implemented\")]\n    public override bool TrySetMember(SetMemberBinder binder, object? value)\n        => throw new NotSupportedException($\"Setting a value on {nameof(IDynamicStack)} is not supported\");\n\n    #region Get / Get<T>\n\n    public dynamic? Get(string name) => GetHelper.Get(name);\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public dynamic? Get(string name, NoParamOrder npo = default, string? language = null, bool convertLinks = true, bool? debug = null)\n        => GetHelper.Get(name, npo, language, convertLinks, debug);\n\n    public TValue? Get<TValue>(string name)\n        => GetHelper.Get<TValue>(name);\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    public TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default)\n        => GetHelper.Get(name, npo, fallback);\n\n    #endregion\n\n    #region IEnumerable<IDynamicEntity>\n\n    [field: AllowNull, MaybeNull]\n    private List<IDynamicEntity> List => field ??= _stack.Sources\n        .Select(src => SourceToDynamicEntity(src.Value)!)\n        .Where(e => e != null!)\n        .ToList();\n\n    public IEnumerator<IDynamicEntity> GetEnumerator() => List.GetEnumerator();\n\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n    #endregion\n\n    #region Any*** properties just for documentation\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public dynamic AnyProperty => null!;\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Factory/CodeDataServices.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Services.Sys.ConvertService;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Data.Sys.Factory;\n\n/// <summary>\n/// Helper services published by the CodeDataFactory for use in certain other objects which depend on it.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record CodeDataServices(\n    LazySvc<IValueConverter> ValueConverter,\n    LazySvc<IScrub> Scrub,\n    LazySvc<ConvertForCodeService> ForCode,\n    LazySvc<IDataFactory> DataFactory,\n    LazySvc<IUser> User)\n    : DependenciesRecord(connect: [ValueConverter, Scrub, ForCode, DataFactory])\n{\n    ///// <summary>\n    ///// The ValueConverter is used to parse links in the format like \"file:72\"\n    ///// </summary>\n    ///// <remarks>\n    ///// Before 2025-06-18 was called ValueConverterOrNull - but it's from a service so it should always be there...\n    ///// </remarks>\n    //internal IValueConverter ValueConverter => ValueConverterLazy.Value;\n\n    ///// <summary>\n    ///// This is provided so that ITypedItems can use Scrub in the String APIs\n    ///// </summary>\n    //internal LazySvc<IScrub> Scrub => Scrub;\n\n    //internal LazySvc<ConvertForCodeService> ForCode => ForCode;\n\n    //internal LazySvc<IDataFactory> DataFactory => DataFactory;\n\n    ///// <summary>\n    ///// User information for detecting if draft data is allowed.\n    ///// </summary>\n    //internal LazySvc<IUser> User => UserLazy;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Factory/ICodeDataFactory.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Metadata;\nusing ToSic.Eav.Models.Sys;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services.Tweaks;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Code.InfoSystem;\n\nnamespace ToSic.Sxc.Data.Sys.Factory;\n\npublic interface ICodeDataFactory: ICanGetService, IHasLog\n{\n    object MetadataDynamic(IMetadata mdOf);\n    ITypedMetadata MetadataTyped(IMetadata mdOf);\n\n    /// <summary>\n    /// Convert an object to a custom type, if possible.\n    /// If the object is an entity-like thing, that will be converted.\n    /// If it's a list of entity-like things, the first one will be converted.\n    /// </summary>\n    [return: NotNullIfNotNull(nameof(source))]\n    TCustom? AsCustom<TCustom>(object? source, NoParamOrder npo = default, bool mock = false)\n        where TCustom : class, IModelFromData;\n\n    [return: NotNullIfNotNull(nameof(item))]\n    TCustom? AsCustomFrom<TCustom, TData>(TData? item, ModelSettings? settings = default)\n        where TCustom : class, IModelFromData;\n\n    /// <summary>\n    /// Create list of custom-typed ITypedItems\n    /// </summary>\n    /// <remarks>\n    /// Never null, unless explicitly requested with `nullIfNull`, otherwise it would return an empty list.\n    /// </remarks>\n    IEnumerable<TCustom> AsCustomList<TCustom>(object? source, NoParamOrder npo, bool nullIfNull)\n        where TCustom : class, IModelFromData;\n\n    [return: NotNullIfNotNull(nameof(data))]\n    ITyped? AsTyped(object data, ModelSettings settings, string? detailsMessage = default);\n    IEnumerable<ITyped>? AsTypedList(object list, ModelSettings settings);\n    int CompatibilityLevel { get; }\n    CodeDataServices Services { get; }\n\n    /// <summary>\n    /// WIP, we need this in the GetAndConvertHelper, and want to make sure it's not executed on every entity used,\n    /// so for now we're doing this once only here.\n    /// </summary>\n    /// <remarks>\n    /// IMPORTANT: LOWER-CASE guaranteed.\n    /// </remarks>\n    List<string> SiteCultures { get; }\n\n    bool Debug { get; set; }\n\n    /// <summary>\n    /// List of dimensions for value lookup, incl. priorities etc. and null-trailing.\n    /// lower case safe guaranteed. \n    /// </summary>\n    // If we don't have a DynCodeRoot, try to generate the language codes and compatibility\n    // There are cases where these were supplied using SetFallbacks, but in some cases none of this is known\n    string?[] Dimensions { get; }\n\n    CodeInfoService CodeInfo { get; }\n\n    /// <summary>\n    /// Implement AsDynamic for DynamicCode - not to be used in internal APIs.\n    /// Always assumes Strict is false\n    /// </summary>\n    /// <param name=\"entity\"></param>\n    /// <returns></returns>\n    IDynamicEntity CodeAsDyn(IEntity entity);\n\n    IDynamicEntity AsDynamic(IEntity entity, ModelSettings settings);\n\n    /// <summary>\n    /// Convert a list of Entities into a DynamicEntity.\n    /// Only used in DynamicCodeRoot.\n    /// </summary>\n    IDynamicEntity AsDynamicFromEntities(IEnumerable<IEntity> list, ModelSettings settings, NoParamOrder npo = default, IEntity? parent = default, string? field = default);\n\n    /// <summary>\n    /// Convert any object into a dynamic list.\n    /// Only used in Dynamic Code for the public API.\n    /// </summary>\n    IEnumerable<dynamic> CodeAsDynList(object list);\n\n    /// <summary>\n    /// Convert any object into a dynamic object.\n    /// Only used in Dynamic Code for the public API.\n    /// </summary>\n    object? AsDynamicFromObject(object dynObject);\n\n    dynamic? MergeDynamic(object[] entities);\n    ITypedItem? AsItem(object? data, ModelSettings settings, NoParamOrder npo = default, ITypedItem? fallback = default);\n\n    /// <summary>\n    /// Quick convert an entity to item - if not null, otherwise return null.\n    /// </summary>\n    /// <param name=\"entity\"></param>\n    /// <param name=\"settings\"></param>\n    /// <returns></returns>\n    [return: NotNullIfNotNull(nameof(entity))]\n    ITypedItem? AsItem(IEntity? entity, ModelSettings settings);\n\n    IEnumerable<ITypedItem> EntitiesToItems(IEnumerable<IEntity> entities, ModelSettings settings);\n    IEnumerable<ITypedItem> AsItems(object list, ModelSettings settings, NoParamOrder npo = default, IEnumerable<ITypedItem>? fallback = default);\n    void SetCompatibilityLevel(int compatibilityLevel);\n    void SetFallbacks(ISite site, int? compatibility = default, /*AdamManager*/ object? adamManagerPrepared = default);\n    object? Json2Jacket(string json, string? fallback = default);\n    ITypedStack AsStack(object[] parts);\n\n    T AsStack<T>(object[] parts)\n        where T : class, IModelFromData, new();\n\n    IDynamicStack AsDynStack(string name, List<KeyValuePair<string, IPropertyLookup>> sources);\n    ITypedStack AsTypedStack(string name, List<KeyValuePair<string, IPropertyLookup>> sources);\n    IField? Field(ITypedItem parent, bool supportOldMetadata, string? name, ModelSettings settings);\n    IEntity AsEntity(object thingToConvert);\n    IEntity FakeEntity(int appId);\n\n    TCustom? GetOne<TCustom>(Func<IEntity?> getItem, object id, bool skipTypeCheck)\n        where TCustom : class, IModelFromData;\n\n    IEntity PlaceHolderInBlock(int? appIdOrNull, IEntity? parent, string? fieldName);\n\n    /// <summary>\n    /// Creates an empty list of a specific type, with hidden information to remember what field this is etc.\n    /// </summary>\n    /// <typeparam name=\"TTypedItem\"></typeparam>\n    /// <param name=\"parent\"></param>\n    /// <param name=\"field\"></param>\n    /// <returns></returns>\n    IEnumerable<TTypedItem> CreateEmptyChildList<TTypedItem>(IEntity parent, string field)\n        where TTypedItem : class, ITypedItem;\n\n    IFile File(int id);\n    IFolder Folder(Guid entityGuid, string fieldName, IField? field = default);\n    IFolder Folder(int id);\n    IFolder Folder(ICanBeEntity item, string name, IField? field);\n\n    IFile? File(IField field);\n\n    IHtmlTag Html(object thing,\n        NoParamOrder npo = default,\n        object? container = default,\n        string? classes = default,\n        bool debug = default,\n        object? imageSettings = default,\n        bool? toolbar = default,\n        Func<ITweakInput<string>, ITweakInput<string>>? tweak = default);\n\n    IResponsivePicture Picture(\n        object? link = null,\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        string? pictureClass = default,\n        object? pictureAttributes = default,\n        object? toolbar = default,\n        object? recipe = default\n    );\n\n    IResponsiveImage Img(\n        object? link = null,\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        object? toolbar = default,\n        object? recipe = default\n    );\n\n    IEntity? GetDraft(IEntity entity);\n    IEntity? GetPublished(IEntity entity);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Factory/ICodeDataFactoryDeepWip.cs",
    "content": "﻿using ToSic.Eav.Apps;\n\nnamespace ToSic.Sxc.Data.Sys.Factory;\n\n/// <summary>\n/// Temporary interface so that `DynamicEntity` and `Field` can access specific data without\n/// needing to know the IBlockContext, which should not be available in those APIs\n/// </summary>\npublic interface ICodeDataFactoryDeepWip\n{\n    IAppReader? AppReaderOrNull { get; }\n\n    int AppIdOrZero { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Factory/SubDataFactory.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Factory;\n\n/// <summary>\n/// This helps create sub-items for a specific context, obeying the rules of the context\n/// </summary>\ninternal class SubDataFactory(ICodeDataFactory cdf, bool propsRequired, ICanDebug canDebug)\n{\n    public ICodeDataFactory Cdf { get; } = cdf;\n    public bool PropsRequired { get; } = propsRequired;\n\n    /// <summary>\n    /// Generate a dynamic entity based on an IEntity.\n    /// Used in various cases where a property would return an IEntity, and the Razor should be able to continue in dynamic syntax\n    /// </summary>\n    /// <param name=\"contents\"></param>\n    /// <returns></returns>\n    public IDynamicEntity? SubDynEntityOrNull(IEntity? contents)\n        => SubDynEntityOrNull(contents, Cdf, canDebug.Debug, propsRequired: PropsRequired);\n\n    internal static IDynamicEntity? SubDynEntityOrNull(IEntity? contents, ICodeDataFactory cdf, bool? debug, bool propsRequired)\n    {\n        if (contents == null)\n            return null;\n        var result = cdf.AsDynamic(contents, new() { ItemIsStrict = propsRequired });\n        if (debug == true) result.Debug = true;\n        return result;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Field/HasLink.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Field;\n\n/// <summary>\n/// Special helper object pass around a url when it started as a string\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HasLink: IHasLink\n{\n    internal HasLink(string url)\n        => Url = url;\n\n    public string Url { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Field/IFromField.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Field;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IFromField\n{\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IField? Field { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Field/IHasLink.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Field;\n\n[PrivateApi(\"Helper to handle generic cases where something should have a url, but it could be a string or a smarter object\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IHasLink\n{\n    string? Url { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Fields/Field.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Images.Sys;\n\nnamespace ToSic.Sxc.Data.Sys.Fields;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class Field(ITypedItem parent, string name, ICodeDataFactory cdf) : IField\n{\n    /// <inheritdoc />\n    public string Name { get; } = name;\n\n    public ITypedItem Parent { get; } = parent;\n\n    /// <inheritdoc />\n    [PrivateApi(\"Was public till 16.03, but don't think it should be surfaced...\")]\n    public object? Raw\n    {\n        get => _raw.Get(() => Parent.Get(Name, required: false));\n        // Reason is for special edge cases like in School-Sys where we must process\n        // the string before using it for Cms.Html(...)\n        set => _raw.Reset(value);\n    }\n    private readonly GetOnce<object?> _raw = new();\n\n\n    /// <inheritdoc />\n    [PrivateApi(\"Was public till 16.03, but don't think it should be surfaced...\")]\n    public object? Value\n    {\n        get => _value.Get(() => Url ?? Raw)!;\n        set => _value.Reset(value);\n    }\n    private readonly GetOnce<object?> _value = new();\n\n    /// <inheritdoc />\n    public string? Url\n    {\n        get => _url.Get(() => Parent.Url(Name))!;\n        set => _url.Reset(value);\n    }\n    private readonly GetOnce<string?> _url = new();\n\n\n    protected IMetadata? MetadataOfValue => _itemMd.Get(() =>\n    {\n        // Check if string is valid, and also a valid reference like file:742\n        if (Raw is not string rawString\n            || string.IsNullOrWhiteSpace(rawString)\n            || !ValueConverterBase.CouldBeReference(rawString))\n            return null;\n\n        // Get AppState to retrieve metadata - but exit early if we don't have it\n        if ((cdf as ICodeDataFactoryDeepWip)?.AppReaderOrNull is not { } appReader)\n            return null;\n\n        var mdOf = appReader.Metadata.GetMetadataOf(TargetTypes.CmsItem, rawString, title: \"\");\n        cdf.GetService<IImageMetadataRecommendationsService>()\n            .SetImageRecommendations(mdOf, Url); // needs the url so it can check if we use image recommendations\n        return mdOf;\n    });\n    private readonly GetOnce<IMetadata?> _itemMd = new();\n\n    [PrivateApi(\"Internal use only, may change at any time\")]\n    public ImageDecorator? ImageDecoratorOrNull =>\n        _imgDec.Get(() => ImageDecorator.GetOrNull(this, cdf.Dimensions));\n    private readonly GetOnce<ImageDecorator?> _imgDec = new();\n\n    IMetadata IHasMetadata.Metadata => MetadataOfValue!;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Fields/FieldForDynamic.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Sys.Fields;\n\n/// <summary>\n/// Older dynamic code used the Field.Metadata.Description etc. which we don't support in the new Typed system.\n/// </summary>\n/// <param name=\"parent\"></param>\n/// <param name=\"name\"></param>\n/// <param name=\"cdf\"></param>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n// Note: must be public, otherwise get RuntimeBinderException: 'ToSic.Sxc.Data.Sys.Fields.Field' does not contain a definition for 'Metadata'\n// since it would only inspect the public classes!\npublic class FieldForDynamic(ITypedItem parent, string name, ICodeDataFactory cdf) : Field(parent, name, cdf)\n{\n    private readonly ICodeDataFactory _cdf = cdf;\n\n    /// <summary>\n    /// 2025-06 2dm: It appears we reactivated it, because various older apps had code like this:\n    /// `var altText = Text.First(post.Field(\"Image\").Metadata.Description, post.Title);`\n    /// Apps include Blog v5.3.1, News 5.2.3, ImageHotspot 3.2.2\n    /// </summary>\n    /// <remarks>\n    /// test system 2dm https://2sxc-dnn961.dnndev.me/x1504a - old content app uses this\n    /// </remarks>\n    /// <remarks>\n    /// Return is an object, because it should not work with typed code.\n    /// Only dynamic code will actually inspect it and successfully use it.\n    /// </remarks>\n    public object Metadata => _dynMeta.Get(() => _cdf.MetadataDynamic(MetadataOfValue!))!;\n    private readonly GetOnce<object> _dynMeta = new();\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/InputTypes.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys;\n\npublic class InputTypes\n{\n    /// <summary>\n    /// This is the input type for a wysiwyg editor.\n    /// It should probably be in another class, as it's not just for compatibility...\n    /// </summary>\n    public const string InputTypeWysiwyg = \"string-wysiwyg\";\n\n    /// <summary>\n    /// This lists old, obsolete or never-used input types and what the new name should be\n    /// It's used because historically and for future-features, some input-types have been defined\n    /// like string-wysiwyg-tinymce, but they are actually the same as string-wysiwyg-default and\n    /// to keep things streamlined, we don't want to clutter the system with additional type definitions\n    /// even though they are the same.\n    /// </summary>\n    private static readonly Dictionary<string, string> InputTypeMap = new()\n    {\n        // This one would be used once multiple wysiwyg implementations would need\n        // to explicitly say TinyMCE. As of now, the default is the same\n        { \"string-wysiwyg-tinymce\", InputTypeWysiwyg },\n\n        // This one used to say \"use the wysiwyg of DNN\" \n        // this is currently not supported in 2sxc 10\n        { \"string-wysiwyg-dnn\", InputTypeWysiwyg },\n\n        // This one was thought to be a configurable wysiwyg\n        // ATM this feature doesn't exist yet, so just fall back to default\n        { \"string-wysiwyg-adv\", InputTypeWysiwyg },\n    };\n\n    public static string MapInputTypeV10(string original)\n        => InputTypeMap.TryGetValue(original, out var result)\n            ? result\n            : original;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Metadata/Metadata.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data.Sys.Dynamic;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.Metadata;\n\n// NOTE\n// Metadata is still a mix between dynamic and typed.\n// Reason is that certain objects such as File.Metadata are the same for both scenarios\n// and depending on the Razor version, it the code will either be working with the object\n// as dynamic or as typed.\n//\n// This is not ideal, and probably causes some \"you are using old code\" warnings after trying to serialize things.\n\n[PrivateApi(\"Hide implementation\")]\ninternal partial class Metadata(IMetadata metadata, ICodeDataFactory cdf)\n    : ITypedMetadata, IHasPropLookup, IHasJsonSource,\n        IHasMetadata // only needed so the property access work below\n{\n    #region Setup\n\n    bool IModelSetup<IEntity>.SetupModel(IEntity? source)\n        => throw new NotSupportedException($\"SetupContents is not supported for {GetType().Name}, as it requires more information.\");\n\n    #endregion\n\n    #region Additions when going TypedOnly\n\n    private readonly bool _propsRequired = false;\n\n    [field: AllowNull, MaybeNull]\n    public IEntity Entity => field ??= metadata.FirstOrDefault() ?? Cdf.PlaceHolderInBlock(KnownAppsConstants.TransientAppId, parent: null, fieldName: null);\n\n    /// <summary>\n    /// TypedItem is only internal, for use in APIs which should only have one way to handle data.\n    /// Since DynamicEntity is an old API, we don't want to surface TypedItem in the public API.\n    /// </summary>\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal ITypedItem TypedItem => field ??= new TypedItemOfEntity(Entity, Cdf, _propsRequired);\n\n    [PrivateApi] ITypedItem ICanBeItem.Item => TypedItem;\n\n    bool ITypedItem.IsPublished => Entity?.IsPublished ?? true;\n\n    /// <inheritdoc />\n    public bool Debug { get; set; }\n\n    private ICodeDataFactory Cdf { get; }= cdf;\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    internal GetAndConvertHelper GetHelper => field ??= new(this, Cdf, _propsRequired, childrenShouldBeDynamic: true, canDebug: this);\n\n    [PrivateApi]\n    public IEntity? RootContentsForEqualityCheck => field\n        ??= (Entity as IEntityWrapper)?.RootContentsForEqualityCheck ?? Entity;\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    public IEnumerable<IDecorator<IEntity>> Decorators => field ??= (Entity as IEntityWrapper)?.Decorators ?? [];\n\n    public object? Get(string name) => GetHelper.Get(name);\n\n    #endregion\n\n    IPropertyLookup IHasPropLookup.PropertyLookup => _propLookup ??= new(this, () => Debug);\n    private PropLookupMetadata? _propLookup;\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    private CodeItemHelper ItemHelper => field ??= new(GetHelper, this);\n\n    IMetadata IHasMetadata.Metadata => metadata;\n\n\n\n    public bool HasType(string type) => metadata.HasType(type);\n\n    public IEnumerable<IEntity> OfType(string type) => metadata.OfType(type);\n\n    public IEnumerable<IEntity> GetAll() => metadata.ToList();\n\n    #region Properties from the interfaces which are not really supported\n\n    public bool IsDemoItem => false;\n\n    #endregion\n\n    #region Other interfaces: JsonSource, IEquatable<ITypedItem>\n\n    object IHasJsonSource.JsonSource() => throw new NotImplementedException();\n\n    bool IEquatable<ITypedItem>.Equals(ITypedItem? other) => Equals(other);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Metadata/MetadataDynamic.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Json;\n\nnamespace ToSic.Sxc.Data.Sys.Metadata;\n\n// NOTE\n// Metadata is still a mix between dynamic and typed.\n// Reason is that certain objects such as File.Metadata are the same for both scenarios\n// and depending on the Razor version, it the code will either be working with the object\n// as dynamic or as typed.\n//\n// This is not ideal, and probably causes some \"you are using old code\" warnings after trying to serialize things.\n\n[PrivateApi(\"Hide implementation\")]\ninternal class MetadataDynamic(IMetadata metadata, ICodeDataFactory cdf)\n    : DynamicEntity(metadata, null, \"Metadata(virtual-field)\", KnownAppsConstants.TransientAppId, propsRequired: false, cdf),\n        IMetadataDynamic, IHasPropLookup, IHasJsonSource\n{\n    IPropertyLookup IHasPropLookup.PropertyLookup => _propLookup ??= new(this, () => Debug);\n    private PropLookupMetadata? _propLookup;\n\n    [PrivateApi(\"Hide this\")]\n    private readonly IMetadata _metadata = metadata;\n\n\n    IMetadata IHasMetadata.Metadata => _metadata;\n\n\n\n    public override bool HasType(string type) => _metadata.HasType(type);\n\n    public override IEnumerable<IEntity> OfType(string type) => _metadata.OfType(type);\n\n    #region Properties from the interfaces which are not really supported\n\n    public override bool IsDemoItem => false;\n\n    public new ITypedItem Presentation => throw new NotSupportedException();\n\n    #endregion\n\n    #region Other interfaces: JsonSource, IEquatable<ITypedItem>\n\n    object IHasJsonSource.JsonSource() => throw new NotImplementedException();\n\n    //bool IEquatable<ITypedItem>.Equals(ITypedItem? other) => Equals(other);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Metadata/Metadata_Typed.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Data.Options;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services.Tweaks;\nusing ToSic.Sys.Performance;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.Metadata;\n\ninternal partial class Metadata: ITypedItem\n{\n    #region Keys\n\n    [PrivateApi]\n    public bool ContainsKey(string name) =>\n        TypedHelpers.ContainsKey(name, Entity,\n            (e, k) => e.Attributes.ContainsKey(k),\n            (e, k) => e.Children(k)?.FirstOrDefault()\n        );\n\n    public bool IsEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => ItemHelper.IsEmpty(name, npo, isBlank: default, language: language);\n\n    public bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => ItemHelper.IsNotEmpty(name, npo, isBlank: default, language: language);\n\n    [PrivateApi]\n    public IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default)\n        => FilterKeysIfPossible(npo, only, Entity?.Attributes.Keys);\n\n    #endregion\n\n    #region ITyped\n\n    object? ITyped.Get(string name, NoParamOrder npo, bool? required, string? language)\n        => ItemHelper.Get(name: name, npo: npo, required: required, language: language);\n\n    TValue? ITyped.Get<TValue>(string name, NoParamOrder npo, TValue? fallback, bool? required, string? language)\n        where TValue : default\n        => ItemHelper.GetT(name, npo, fallback: fallback, required: required, language: language);\n\n    IRawHtmlString? ITyped.Attribute(string name, NoParamOrder npo, string? fallback, bool? required)\n        => ItemHelper.Attribute(name, npo, fallback, required);\n\n    DateTime ITyped.DateTime(string name, NoParamOrder npo, DateTime fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    string? ITyped.String(string name, NoParamOrder npo, string? fallback, bool? required, object? scrubHtml)\n        => ItemHelper.String(name, npo, fallback, required, scrubHtml);\n\n    int ITyped.Int(string name, NoParamOrder npo, int fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    bool ITyped.Bool(string name, NoParamOrder npo, bool fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    long ITyped.Long(string name, NoParamOrder npo, long fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    float ITyped.Float(string name, NoParamOrder npo, float fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    decimal ITyped.Decimal(string name, NoParamOrder npo, decimal fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    double ITyped.Double(string name, NoParamOrder npo, double fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    string? ITyped.Url(string name, NoParamOrder npo, string? fallback, bool? required)\n        => ItemHelper.Url(name, npo, fallback, required);\n\n    string ITyped.ToString() => \"test / debug: \" + ToString();\n\n    #endregion\n\n    #region ADAM\n\n    /// <inheritdoc />\n    [PrivateApi]\n    IFolder? ITypedItem.Folder(string name, NoParamOrder npo, bool? required) \n        => TypedItem.Folder(name, npo, required);\n\n    IFile? ITypedItem.File(string name, NoParamOrder npo, bool? required) \n        => TypedItem.File(name, npo, required);\n\n    #endregion\n\n    #region Basic Props like Id, Guid, Title, Type\n\n    //[PrivateApi]\n    //int ITypedMetadata.EntityId => Cdf.CodeInfo.GetAndWarn(V16To18(\"IMetadata.EntityId\", message: $\"Use {nameof(ITypedItem.Id)} instead of {nameof(EntityId)}\"), EntityId);\n\n    [PrivateApi]\n    int ITypedItem.Id => Entity.EntityId;\n    //int ITypedItem.Id => EntityId;\n\n    [PrivateApi]\n    Guid ITypedItem.Guid => Entity.EntityGuid;\n    //Guid ITypedItem.Guid => EntityGuid;\n\n    [PrivateApi]\n    string? ITypedItem.Title => Entity?.GetBestTitle(Cdf.Dimensions);\n    //string? ITypedItem.Title => EntityTitle;\n\n    [PrivateApi]\n    IContentType ITypedItem.Type => Entity?.Type!;\n\n    #endregion\n\n\n    #region Relationship properties Presentation, Metadata, Child, Children, Parents\n\n    /// <inheritdoc />\n    [PrivateApi]\n    [JsonIgnore]\n    ITypedItem ITypedItem.Presentation\n        => throw new NotSupportedException($\"You can't access the {nameof(ITypedItem.Presentation)} of Metadata\");\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    ITypedMetadata ITypedItem.Metadata\n        => throw new NotSupportedException($\"You can't access the {nameof(ITypedItem.Metadata)} of Metadata\");\n\n    [PrivateApi]\n    ITypedItem ITypedItem.Parent(NoParamOrder npo, bool? current, string? type, string? field, GetRelatedOptions? options)\n        => throw new NotSupportedException($\"You can't access the {nameof(ITypedItem.Parent)}() of Metadata as it usually does not make sense to do this\");\n\n    /// <inheritdoc />\n    [PrivateApi]\n    IEnumerable<ITypedItem> ITypedItem.Parents(NoParamOrder npo, string? type, string? field, GetRelatedOptions? options)\n    {\n        // Protect & no Strict (as that's not really possible, since it's not a field)\n\n        // Exit if no metadata items available to get parents from\n        var mdEntities = metadata.ToList();\n        if (!mdEntities.Any())\n            return [];\n\n        // Get children from first metadata item which matches the criteria\n        var parents = mdEntities\n            .Select(e => e.Parents(type: type, field: field).ToList())\n            .FirstOrDefault(l => l.SafeAny());\n        if (parents == null)\n            return [];\n\n        var list = Cdf.EntitiesToItems(parents, new() { ItemIsStrict = false, DropNullItems = true })\n            .ToListOpt();\n        return list.Any()\n            ? list\n            : [];\n    }\n\n    IPublishing ITypedItem.Publishing => _publishing.Get(() => new Publishing.Publishing(this, Cdf))!;\n    private readonly GetOnce<IPublishing> _publishing = new();\n\n    /// <inheritdoc />\n    [PrivateApi]\n    IEnumerable<ITypedItem> ITypedItem.Children(string? field, NoParamOrder npo, string? type, bool? required, GetRelatedOptions? options)\n    {\n        // Protect & Strict\n        if (IsErrStrictNameOptional(this, field, required, GetHelper.PropsRequired))\n            throw ErrStrict(field);\n\n        // Exit if no metadata items available to get children from\n        var mdEntities = metadata.ToList();\n        if (!mdEntities.Any())\n            return [];\n\n        // Get children from first metadata item which matches the criteria\n        var children = mdEntities\n            .Select(e => e.Children(field: field, type: type).ToList())\n            .FirstOrDefault(l => l.SafeAny());\n        if (children == null)\n            return [];\n\n        // WIP - sometimes children can contain null items, but Razor won't expect this.\n        // in future, we may add an option to preserve them, for now filter them out\n        var filtered = children\n            .Where(c => c != null)\n            .Cast<IEntity>()\n            .ToListOpt();\n\n        return Cdf.EntitiesToItems(filtered, new() { ItemIsStrict = false, DropNullItems = true })\n            .ToListOpt();\n    }\n\n    /// <inheritdoc />\n    [PrivateApi]\n    ITypedItem? ITypedItem.Child(string name, NoParamOrder npo, bool? required, GetRelatedOptions? options)\n        => (this as ITypedItem)\n            .Children(name, npo: npo, required: required, options: options)\n            .FirstOrDefault();\n\n    #endregion\n\n    #region New Child<T> / Children<T> - disabled as ATM Kit is missing\n\n    /// <inheritdoc />\n    T? ITypedItem.Child<T>(string name, NoParamOrder npo, bool? required, GetRelatedOptions? options)\n        where T : class\n        => Cdf.AsCustom<T>(source: (this as ITypedItem).Child(name, required: required, options: options), npo: npo);\n\n    /// <inheritdoc />\n    IEnumerable<T> ITypedItem.Children<T>(string? field, NoParamOrder npo, string? type, bool? required, GetRelatedOptions? options)\n        => Cdf.AsCustomList<T>(\n            source: (this as ITypedItem).Children(field: field, npo: npo, type: type, required: required, options: options),\n            npo: npo,\n            nullIfNull: false\n        );\n\n    /// <inheritdoc />\n    T? ITypedItem.Parent<T>(NoParamOrder npo, bool? current, string? type, string? field, GetRelatedOptions? options)\n        where T : class\n        => Cdf.AsCustom<T>(\n            source: (this as ITypedItem).Parent(npo: npo, current: current, type: type ?? typeof(T).Name, field: field, options: options),\n            npo: npo\n        );\n\n    /// <inheritdoc />\n    IEnumerable<T> ITypedItem.Parents<T>(NoParamOrder npo, string? type, string? field, GetRelatedOptions? options)\n        => Cdf.AsCustomList<T>(\n            source: (this as ITypedItem).Parents(npo: npo, field: field, type: type ?? typeof(T).Name, options: options),\n            npo: npo,\n            nullIfNull: false\n        );\n\n    #endregion\n\n    #region Fields, Html, Picture\n\n    [PrivateApi]\n    IField? ITypedItem.Field(string name, NoParamOrder npo, bool? required)\n        => Cdf.Field(this, supportOldMetadata: false, name, new() { EntryPropIsRequired = required ?? true, ItemIsStrict = GetHelper.PropsRequired });\n\n    IHtmlTag? ITypedItem.Html(\n        string name,\n        NoParamOrder npo,\n        object? container,\n        bool? toolbar,\n        object? imageSettings,\n        bool? required,\n        bool debug,\n        Func<ITweakInput<string>, ITweakInput<string>>? tweak\n    ) => TypedItemHelpers.Html(Cdf, this, name: name, npo: npo, container: container,\n        toolbar: toolbar, imageSettings: imageSettings, required: required, debug: debug, tweak: tweak);\n\n    /// <inheritdoc/>\n    IResponsivePicture? ITypedItem.Picture(\n        string name,\n        NoParamOrder npo,\n        Func<ITweakMedia, ITweakMedia>? tweak,\n        object? settings,\n        object? factor,\n        object? width,\n        string? imgAlt,\n        string? imgAltFallback,\n        string? imgClass,\n        object? imgAttributes,\n        string? pictureClass,\n        object? pictureAttributes,\n        object? toolbar,\n        object? recipe\n    ) => TypedItemHelpers.Picture(cdf: Cdf, item: this, name: name, npo: npo,\n        tweak: tweak,\n        settings: settings,\n        factor: factor, width: width, imgAlt: imgAlt, imgAltFallback: imgAltFallback, \n        imgClass: imgClass, imgAttributes: imgAttributes, pictureClass: pictureClass, pictureAttributes: pictureAttributes, toolbar: toolbar, recipe: recipe);\n\n    IResponsiveImage? ITypedItem.Img(\n        string name,\n        NoParamOrder npo,\n        Func<ITweakMedia, ITweakMedia>? tweak,\n        object? settings,\n        object? factor,\n        object? width,\n        string? imgAlt,\n        string? imgAltFallback,\n        string? imgClass,\n        object? imgAttributes,\n        object? toolbar,\n        object? recipe\n    ) => TypedItemHelpers.Img(cdf: Cdf, item: this, name: name, npo: npo, tweak: tweak, settings: settings,\n        factor: factor, width: width, imgAlt: imgAlt, imgAltFallback: imgAltFallback,\n        imgClass: imgClass, imgAttributes: imgAttributes,\n        toolbar: toolbar, recipe: recipe);\n\n\n    #endregion\n\n    #region GPS\n\n    GpsCoordinates ITypedItem.Gps(string name, NoParamOrder npo, bool? required)\n        => GpsCoordinates.FromJson(((ITypedItem)this).String(name, required: required));\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Metadata/PropLookupMetadata.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Data.Sys.Metadata;\n\ninternal class PropLookupMetadata(IHasMetadata parent, Func<bool> getDebug) : IPropertyLookup\n{\n    public PropReqResult FindPropertyInternal(PropReqSpecs specs, PropertyLookupPath path)\n    {\n        specs = specs.SubLog(\"Sxc.DynEnt\", getDebug());\n        var l = specs.LogOrNull.Fn<PropReqResult>(specs.Dump(), \"DynEntity\");\n        // check Entity is null (in cases where null-objects are asked for properties)\n        if (parent.Metadata == null! /* paranoid */)\n            return l.Return(PropReqResult.Null(path),\"no parent with metadata\");\n        path = path.Add(\"DynEnt\", specs.Field);\n\n        // Note: most of the following lines are copied from Metadata\n        var list = parent.Metadata;\n        var found = list.FirstOrDefault(md => md.Attributes.ContainsKey(specs.Field));\n        if (found == null)\n            return l.Return(PropReqResult.Null(path), \"no entity had attribute\");\n        var propRequest = found.FindPropertyInternal(specs, path);\n        return l.Return(propRequest, propRequest.Result == null ? \"found null\" : \"found value\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/PropLookupWithPathEntity.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.PropertyStack;\n\nnamespace ToSic.Sxc.Data.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class PropLookupWithPathEntity(IEntity entity, ICanDebug canDebug) :\n    ICanBeEntity, // This is important, to ensure that when used in a stack it can be converted to something else again\n    IPropertyLookup\n{\n    public IEntity Entity { get; } = entity;\n\n    public PropReqResult FindPropertyInternal(PropReqSpecs specs, PropertyLookupPath path)\n    {\n        specs = specs.SubLog(\"Sxc.PrpLkp\", canDebug.Debug);\n        var l = specs.LogOrNull.Fn<PropReqResult>(specs.Dump(), \"DynEntity\");\n        // check Entity is null (in cases where null-objects are asked for properties)\n        if (Entity == null!)\n            return l.Return(PropReqResult.Null(path), \"no entity\");\n        if (!specs.Field.HasValue())\n            return l.Return(PropReqResult.Null(path), \"no path\");\n\n        path = path.Add(\"DynEnt\", specs.Field);\n        var isPath = specs.Field.Contains(PropertyStack.PathSeparator.ToString());\n        var propRequest = !isPath\n            ? Entity.FindPropertyInternal(specs, path)\n            : PropertyStack.TraversePath(specs, path, Entity);\n        return l.Return(propRequest, $\"{nameof(isPath)}: {isPath}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Publishing/Publishing.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Sys.Publishing;\n\n// this can just be internal, it's only ever used as an interface\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class Publishing(ITypedItem currentItem, ICodeDataFactory cdf)\n    : HelperBase(cdf.Log, \"Pub\"), IPublishing\n{\n    // Always supported on IEntity\n    public bool IsSupported => true;\n\n    // Entity knows if it's published\n    private bool IsPublished => _isPublished ??= currentItem.Entity.IsPublished;\n    private bool? _isPublished;\n\n    // Either current is published, or the draft has a different RepositoryId\n    public bool HasPublished => IsPublished || currentItem.Entity.RepositoryId != currentItem.Entity.EntityId;\n\n    // Either current is not published, or we found a draft\n    public bool HasUnpublished => !IsPublished || UnpublishedEntity != null;\n\n    // Combination of both must be true\n    public bool HasBoth => HasUnpublished && HasPublished;\n\n    // Get published - either current, or from appState\n    public ITypedItem? GetPublished() => _published.Get(() =>\n    {\n        if (IsPublished)\n            return currentItem;\n        var pubEntity = cdf.GetPublished(currentItem.Entity);\n        return cdf.AsItem(pubEntity, new() { ItemIsStrict = true });\n    });\n    private readonly GetOnce<ITypedItem?> _published = new();\n\n    // Get draft - either current, or from appState\n    public ITypedItem? GetUnpublished() => _draft.Get(() => !IsPublished\n        ? currentItem\n        : cdf.AsItem(UnpublishedEntity, new() { ItemIsStrict = true })\n    );\n    private readonly GetOnce<ITypedItem?> _draft = new();\n\n    /// <summary>\n    /// Get draft entity - either current, or from appState.\n    /// Do this as a separate step, as we sometimes need the info without converting it to a typed item\n    /// </summary>\n    private IEntity? UnpublishedEntity => _unPubEntity.Get(() =>\n    {\n        if (!IsPublished) return currentItem.Entity;\n        var draftEntity = cdf.GetDraft(currentItem.Entity);\n        return draftEntity;\n    });\n    private readonly GetOnce<IEntity?> _unPubEntity = new();\n\n    // Get opposite - either draft or published\n    public ITypedItem? GetOpposite() => _other.Get(() => IsPublished ? GetUnpublished() : GetPublished());\n    private readonly GetOnce<ITypedItem?> _other = new();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Secret/SecureData.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Secret;\n\n[PrivateApi(\"hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SecureData<T>(T result, bool isSecure) : ISecureData<T>\n{\n    public T Value { get; internal set; } = result;\n\n    //public bool IsEncrypted { get; internal set; } = false;\n    //public bool IsSigned { get; internal set; } = false;\n    //public SecureDataAuthorities Authority { get; internal set; } = SecureDataAuthorities.None;\n    public bool IsSecured { get; internal set; } = isSecure;\n\n\n    public bool IsSecuredBy(string authorityName) \n        => IsSecured && \"preset\".EqualsInsensitive(authorityName);\n\n    public override string? ToString() => Value?.ToString();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Stack/PropLookupStack.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.PropertyStack;\n\nnamespace ToSic.Sxc.Data.Sys.Stack;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class PropLookupStack(IPropertyStack stack, Func<bool> getDebug) : IPropertyLookup\n{\n    public IPropertyStack Stack { get; } = stack;\n\n    public PropReqResult FindPropertyInternal(PropReqSpecs specs, PropertyLookupPath path)\n    {\n        specs = specs.SubLog(\"Sxc.DynStk\", getDebug());\n        path = path.Add(\"DynStack\", specs.Field);\n\n        var l = specs.LogOrNull.Fn<PropReqResult?>(specs.Dump(), nameof(PropLookupStack));\n        if (!specs.Field.HasValue())\n            return l.Return(PropReqResult.Null(path), \"no key\");\n\n        var hasPath = specs.Field.Contains(PropertyStack.PathSeparator.ToString());\n        var r = hasPath\n            ? Stack.InternalGetPath(specs, path)\n            : Stack.FindPropertyInternal(specs, path);\n\n        return l.Return(r, $\"{(r.Result == null ? \"null\" : \"ok\")} using {(hasPath ? \"Path\" : \"Property\")}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/HasKeysHelper.cs",
    "content": "﻿using System.Collections;\nusing ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Data.Sys.Typed;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HasKeysHelper\n{\n    public static bool IsEmpty(ITyped item, string name, NoParamOrder npo, bool? blankIs)\n    {\n        var value = item.Get(name, npo, required: false);\n        return IsEmpty(value, blankIs);\n    }\n\n    public static bool IsNotEmpty(ITyped item, string name, NoParamOrder npo, bool? blankIs)\n    {\n        var value = item.Get(name, npo, required: false);\n        return IsNotEmpty(value, blankIs);\n    }\n\n    public static bool IsEmpty(object? value, bool? blankIsEmpty)\n    {\n        // Since we'll reverse the final result, we must ensure that blankIs is pre-reversed as well\n        blankIsEmpty = !(blankIsEmpty ?? true);\n        return !IsNotEmpty(value, blankIsEmpty);\n    }\n\n    public static bool IsNotEmpty(object? value, bool? blankIsEmpty) =>\n        value switch\n        {\n            null => false,\n            // It's a non-null string, let's check other things\n            // null or true means blank strings (inkl. whitespace etc.) are seen as empty\n            // So Text.Has returns true if it has non-blank content\n            // old: if (blankIs is null || blankIs == false) return Text.Has(strVal);\n            string strVal when blankIsEmpty != true => Text.Has(strVal),\n            // blankIs == true, so even blank strings return true\n            string => true,\n            IEnumerable typedList => typedList.Cast<object>().Any(),\n            _ => true\n        };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/IValueOverrider.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Typed;\n\ninternal interface IValueOverrider\n{\n    #region Experiment - but decided for now that it's too much compute for something which is extremely rarely used, and can be done with an if-statement in the code\n\n    //object? OverrideRaw(string name);\n\n    //public T? OverrideRaw<T>(string name);\n\n    #endregion\n\n    /// <summary>\n    /// Replace the raw value before any parsing/conversion happens.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"originalValue\"></param>\n    /// <returns></returns>\n    string? ProcessString(string name, string? originalValue);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/ListTypedItems.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Typed;\n\n/// <summary>\n/// Special helper for marking lists which are empty, but must know about the parent entity and field they belong to,\n/// so that the toolbar can automatically create the correct sub-toolbar.\n/// </summary>\n/// <typeparam name=\"TTypedItem\"></typeparam>\n/// <param name=\"original\"></param>\n/// <param name=\"fieldInfo\"></param>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ListTypedItems<TTypedItem>(IEnumerable<TTypedItem> original, IEntity? fieldInfo)\n    : List<TTypedItem>(original), ICanBeEntity\n    where TTypedItem : class?\n{\n    [field: AllowNull, MaybeNull]\n#pragma warning disable CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes).\n    public IEntity? Entity => field ??= fieldInfo ?? (this.FirstOrDefault() as ICanBeEntity)?.Entity;\n#pragma warning restore CS8766 // Nullability of reference types in return type doesn't match implicitly implemented member (possibly because of nullability attributes).\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/TryGetResult.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Typed;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class TryGetResult(bool found, object? raw, object? result = default)\n{\n    public TryGetResult(bool found, object? result): this(found, result, result)\n    { }\n\n    public bool Found = found;\n    public object? Raw = raw;\n    public object? Result = result;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/TypedHelpers.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Sys.Code.Help;\nusing ToSic.Sys.Exceptions;\n\nnamespace ToSic.Sxc.Data.Sys.Typed;\n\n// TODO: MAKE INTERNAL AGAIN AFTER MOVING TO ToSic.Sxc.Custom\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class TypedHelpers\n{\n    public static bool ContainsKey<TNode>(string name, TNode start, Func<TNode, string, bool> checkNode, Func<TNode, string, TNode?> dig) where TNode: class\n    {\n        var parts = PropertyStack.SplitPathIntoParts(name);\n        if (!parts.Any())\n            return false;\n\n        var current = start;\n        var max = parts.Length - 1;\n        for (var i = 0; i < parts.Length; i++)\n        {\n            var key = parts[i];\n            var has = checkNode(current, key); // current.Attributes.ContainsKey(key);\n            if (i == max || !has)\n                return has;\n\n            // has = true, and we have more nodes, so we must check the children\n            //var children = current.Children(key);\n            //if (!children.Any()) return false;\n            current = dig(current, key); // children[0];\n            if (current == null) return false;\n        }\n\n        return false;\n\n    }\n\n    public static IEnumerable<string> FilterKeysIfPossible(NoParamOrder npo, IEnumerable<string>? only, IEnumerable<string>? result)\n    {\n        if (result == null)\n            return [];\n\n        if (only == default || !only.Any())\n            return result;\n        var filtered = result\n            .Where(r => only.Any(k => k.EqualsInsensitive(r)))\n            .ToArray();\n        return filtered;\n    }\n\n    public static bool IsErrStrict(bool found, bool? required, bool requiredDefault)\n        => !found && (required ?? requiredDefault);\n\n\n    public static bool IsErrStrictNameOptional(ITyped parent, string? name, bool? required, bool requiredDefault)\n    {\n        if (name == null)\n            return false; // name is optional, so no error\n        return !parent.ContainsKey(name) && (required ?? requiredDefault);\n    }\n\n    public static bool IsErrStrictNameRequired(ITyped parent, string? name, bool? required, bool requiredDefault)\n        => name == null || !parent.ContainsKey(name) && (required ?? requiredDefault);\n\n    private const int MaxKeysToUseList = 20;\n\n    public static Exception ErrStrictForTyped(ITyped? parent, string? name, [CallerMemberName] string? cName = default)\n    {\n        // Note that the parent may not fully implement som APIs, so we must try/catch everything\n        const string unknown = \"unknown\";\n        string? typeName = null;\n        var keys = new[] { \"keys can't be determined\" };\n        string? id = null;\n        //string guid = null;\n        var title = \"title can't be determined\";\n        if (parent != null)\n        {\n            try\n            {\n                keys = parent.Keys()?.ToArray() ?? keys;\n            }\n            catch { /* ignore */ }\n            try\n            {\n                var item = parent as ITypedItem;\n                typeName = item?.Type?.Name;\n                id = item?.Id.ToString();\n                //guid = item?.Guid.ToString();\n                title = item?.Title;\n            }\n            catch { /* ignore */ }\n        }\n\n        var help = new CodeHelp\n        {\n            Name = \"get-help\",\n            Detect = name,\n            UiMessage = null,\n            DetailsHtml = $\"\"\"\n                           <div>\n                           <em>You tried to use {cName}(\"{name}\") which failed. Here is more info about the object:</em>\n                           <br>\n                           Content-Type: <strong>{typeName ?? unknown}</strong>\n                           <br>\n                           Item Title: <strong>{title ?? unknown}</strong>\n                           <br>\n                           Item Id: <strong>{id ?? unknown}</strong>\n                           <br>\n                           <em>Fields of type {typeName}:</em>\n                           {(keys.Length > MaxKeysToUseList\n                               ? \"<br>\" + string.Join(\", \", keys) + \"<br>\"\n                               : $\"\"\"\n                                  <ol>\n                                      <li>\n                                      {string.Join(\"</li><li>\", keys)}\n                                      </li>\n                                  </ol>\n                                  \"\"\")}\n                           </div>\n                           \"\"\",\n        };\n        return ErrStrict(name, help, cName);\n    }\n\n\n    public static Exception ErrStrict(string? name, CodeHelp? codeHelp = default, [CallerMemberName] string? cName = default)\n    {\n        var info = $\"Either a) correct the name '{name}'; b) use {cName}(\\\"{name}\\\", required: false); or c) or use AsItem(..., propsRequired: false) or similar\";\n        var msg = cName == \".\"\n            ? $\".{name} not found and 'strict' is true, meaning that an error is thrown. {info}\"\n            : $\"{cName}('{name}', ...) not found and 'strict' is true, meaning that an error is thrown. {info}\";\n        var argEx = new ArgumentException(msg, nameof(name));\n        if (codeHelp != default)\n            return new ExceptionWithHelp(codeHelp, inner: argEx);\n        return argEx;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/TypedItemHelpers.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services.Tweaks;\n\nnamespace ToSic.Sxc.Data.Sys.Typed;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class TypedItemHelpers\n{\n    public static IHtmlTag? Html(\n        ICodeDataFactory cdf,\n        ITypedItem item,\n        string name,\n        NoParamOrder npo,\n        object? container,\n        bool? toolbar,\n        object? imageSettings,\n        bool? required,\n        bool debug,\n        Func<ITweakInput<string>, ITweakInput<string>>? tweak = default\n    )\n    {\n        var field = item.Field(name, required: required);\n        if (field == null)\n            return null;\n        return cdf.Html(field, container: container, classes: null, imageSettings: imageSettings, debug: debug, toolbar: toolbar, tweak: tweak);\n    }\n\n    public static IResponsivePicture? Picture(\n        ICodeDataFactory cdf,\n        ITypedItem item,\n        string name,\n        NoParamOrder npo,\n        Func<ITweakMedia, ITweakMedia>? tweak,\n        object? settings,\n        object? factor,\n        object? width,\n        string? imgAlt,\n        string? imgAltFallback,\n        string? imgClass,\n        object? imgAttributes,\n        string? pictureClass,\n        object? pictureAttributes,\n        object? toolbar,\n        object? recipe\n    )\n    {\n        var field = item.Field(name, required: true);\n        if (field == null || field.Url.IsEmptyOrWs())\n            return null;\n        return cdf.Picture(field, tweak: tweak, settings: settings, factor: factor, width: width,\n                imgAlt: imgAlt, imgAltFallback: imgAltFallback, \n                imgClass: imgClass, imgAttributes: imgAttributes, pictureClass: pictureClass, pictureAttributes: pictureAttributes,\n                toolbar: toolbar, recipe: recipe);\n    }\n\n    public static IResponsiveImage? Img(\n        ICodeDataFactory cdf,\n        ITypedItem item,\n        string name,\n        NoParamOrder npo,\n        Func<ITweakMedia, ITweakMedia>? tweak,\n        object? settings,\n        object? factor,\n        object? width,\n        string? imgAlt,\n        string? imgAltFallback,\n        string? imgClass,\n        object? imgAttributes,\n        object? toolbar,\n        object? recipe\n    )\n    {\n        var field = item.Field(name, required: true);\n        if (field == null || field.Url.IsEmptyOrWs())\n            return null;\n        return cdf.Img(field, tweak: tweak, settings: settings, npo: npo, factor: factor, width: width,\n                imgAlt: imgAlt, imgAltFallback: imgAltFallback,\n                imgClass: imgClass, imgAttributes: imgAttributes,\n                toolbar: toolbar, recipe: recipe);\n    }\n\n\n    public static string? MaybeScrub(string? value, object? scrubHtml, Func<IScrub> scrubSvc)\n    {\n        if (value == null)\n            return null;\n        return scrubHtml switch\n        {\n            string scrubStr => scrubStr.HasValue()\n                ? scrubSvc().Only(value, scrubStr.CsvToArrayWithoutEmpty())\n                : value,\n            bool scrubBln => scrubBln\n                ? scrubSvc().All(value)\n                : value,\n            _ => value\n        };\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/TypedItemOfEntity.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Eav.Metadata;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Data.Options;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Data.Sys.Dynamic;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services.Tweaks;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\nusing static ToSic.Sys.Wrappers.WrapperEquality;\n\n// This is for paranoid Entity? checking\n// ReSharper disable ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n\nnamespace ToSic.Sxc.Data.Sys.Typed;\n\n[JsonConverter(typeof(DynamicJsonConverter))]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class TypedItemOfEntity(IEntity entity, ICodeDataFactory cdf, bool propsRequired, IValueOverrider? overrider = default)\n    // ReSharper disable RedundantExtendsListEntry\n    : ITypedItem, IHasPropLookup, ICanDebug, ICanBeItem, ICanGetByName, IWrapper<IEntity>,\n        IEntityWrapper, IHasMetadata, IHasJsonSource\n    // ReSharper restore RedundantExtendsListEntry\n{\n    #region Setup\n\n    bool IModelSetup<IEntity>.SetupModel(IEntity? source)\n        => throw new NotSupportedException($\"SetupContents is not supported for {GetType().Name}, as it requires more information.\");\n\n    public IEntity Entity { get; } = entity;\n    private ICodeDataFactory Cdf { get; } = cdf;\n\n    #endregion\n\n    public bool Debug { get; set; }\n\n\n    public override string ToString() => $\"{GetType().Name}: '{((ITypedItem)this).Title}' ({Entity})\";\n\n    object IHasJsonSource.JsonSource() => Entity;\n\n    IEntity IWrapper<IEntity>.GetContents() => Entity;\n\n\n    #region Private Helpers / Services\n\n    [field: AllowNull, MaybeNull]\n    private GetAndConvertHelper GetHelper => field ??= new(this, Cdf, propsRequired, childrenShouldBeDynamic: false, canDebug: this, overrider: overrider);\n\n    [field: AllowNull, MaybeNull]\n    private CodeDynHelper DynHelper => field ??= new(Entity, new(Cdf, propsRequired, canDebug: this));\n\n    [field: AllowNull, MaybeNull]\n    private CodeItemHelper ItemHelper => field ??= new(GetHelper, this);\n    protected internal CodeItemHelper ItemHelperForDescendants => ItemHelper;\n\n    #endregion\n\n    #region Special Interface Implementations: IHasPropLookup, IJsonSource, ICanBeItem\n\n    IPropertyLookup IHasPropLookup.PropertyLookup => _propLookup ??= new(Entity, canDebug: this);\n    private PropLookupWithPathEntity? _propLookup;\n\n    ITypedItem ICanBeItem.Item => this;\n\n    #endregion\n\n    #region Equality\n\n    /// <summary>\n    /// This is used by various equality comparison. \n    /// Since we define two object to be equal when they host the same contents, this determines the hash based on the contents\n    /// </summary>\n    // ReSharper disable once NonReadonlyMemberInGetHashCode\n    public override int GetHashCode() => GetWrappedHashCode(this);\n\n    /// <summary>\n    /// Ensure that the equality check is done correctly.\n    /// If two objects wrap the same item, they will be considered equal.\n    /// </summary>\n    public override bool Equals(object? b) => MultiWrapperEquality.EqualsObj(this, b);\n\n    bool IEquatable<ITypedItem>.Equals(ITypedItem? other) => Equals(other);\n\n    IEnumerable<IDecorator<IEntity>> IHasDecorators<IEntity>.Decorators => (Entity as IEntityWrapper)?.Decorators ?? [];\n\n    IEntity IMultiWrapper<IEntity>.RootContentsForEqualityCheck => (Entity as IEntityWrapper)?.RootContentsForEqualityCheck ?? Entity;\n\n    #endregion\n\n    #region Keys\n\n\n    public bool ContainsKey(string name) =>\n        TypedHelpers.ContainsKey(name, Entity,\n            (e, k) => e.Attributes.ContainsKey(k),\n            (e, k) => e.Children(k)?.FirstOrDefault()\n        );\n\n    public bool IsEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => ItemHelper.IsEmpty(name, npo, isBlank: default, language: language);\n\n    public bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => ItemHelper.IsNotEmpty(name, npo, isBlank: default, language: language);\n\n\n    public IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default)\n        => FilterKeysIfPossible(npo, only, Entity?.Attributes.Keys);\n\n    #endregion\n\n    #region ITyped\n\n    object? ITyped.Get(string name, NoParamOrder npo, bool? required, string? language)\n        => ItemHelper.Get(name, npo, required, language: language);\n\n    TValue? ITyped.Get<TValue>(string name, NoParamOrder npo, TValue? fallback, bool? required, string? language)\n        where TValue : default\n        => ItemHelper.GetT(name, npo, fallback: fallback, required: required, language: language);\n\n    IRawHtmlString? ITyped.Attribute(string name, NoParamOrder npo, string? fallback, bool? required)\n        => ItemHelper.Attribute(name, npo, fallback, required);\n\n    DateTime ITyped.DateTime(string name, NoParamOrder npo, DateTime fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    string? ITyped.String(string name, NoParamOrder npo, string? fallback, bool? required, object? scrubHtml)\n        => ItemHelper.String(name, npo, fallback, required, scrubHtml);\n\n    int ITyped.Int(string name, NoParamOrder npo, int fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    bool ITyped.Bool(string name, NoParamOrder npo, bool fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    long ITyped.Long(string name, NoParamOrder npo, long fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    float ITyped.Float(string name, NoParamOrder npo, float fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    decimal ITyped.Decimal(string name, NoParamOrder npo, decimal fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    double ITyped.Double(string name, NoParamOrder npo, double fallback, bool? required)\n        => ItemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    string? ITyped.Url(string name, NoParamOrder npo, string? fallback, bool? required)\n        => ItemHelper.Url(name, npo, fallback, required);\n\n\n\n    string ITyped.ToString() => \"test / debug: \" + ToString();\n\n    /// <summary>\n    /// Get by name should never throw an error, as it's used to get null if not found.\n    /// </summary>\n    object? ICanGetByName.Get(string name) => (this as ITyped).Get(name, required: false);\n\n    #endregion\n\n    #region Basic Props like Id, Guid, Title, Type, IsDemoItem\n\n    int ITypedItem.Id => Entity?.EntityId ?? 0;\n\n    Guid ITypedItem.Guid => Entity?.EntityGuid ?? Guid.Empty;\n\n    string? ITypedItem.Title => Entity?.GetBestTitle(Cdf.Dimensions);\n\n    IContentType ITypedItem.Type => Entity?.Type!;\n    public bool IsDemoItem => _isDemoItem ??= Entity.IsDemoItemSafe();\n    private bool? _isDemoItem;\n\n    #endregion\n        \n    #region ADAM - Folder and File\n\n    IFolder ITypedItem.Folder(string name, NoParamOrder npo, bool? required)\n        => IsErrStrictNameRequired(this, name, required, GetHelper.PropsRequired)\n            ? throw ErrStrictForTyped(this, name)\n            : _adamCache.Get(name, () => Cdf.Folder(Entity, name, ((ITypedItem)this).Field(name, required: false)));\n\n    private readonly GetOnceNamed<IFolder> _adamCache = new();\n\n    IFile? ITypedItem.File(string name, NoParamOrder npo, bool? required)\n    {\n        ITypedItem typedThis = this;\n        // Case 1: The field contains a direct reference to a file\n        var field = typedThis.Field(name, required: required);\n        if (field == null)\n            return null; // if the field is not found, return null\n        var file = Cdf.File(field);\n        // Case 2: No direct reference, just get the first file in the folder of this field\n        return file ?? typedThis.Folder(name)?.Files.FirstOrDefault();\n    }\n\n    #endregion\n\n    #region Relationship properties Presentation, Metadata, Child, Children, Parents\n\n    /// <inheritdoc />\n\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    ITypedItem? ITypedItem.Presentation => (DynHelper.Presentation as ICanBeItem)?.Item;\n\n    /// <inheritdoc />\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    ITypedMetadata ITypedItem.Metadata => _md.Get(() => ItemHelper.Helper.Cdf.MetadataTyped(Entity.Metadata))!;\n    private readonly GetOnce<ITypedMetadata?> _md = new();\n\n\n    ITypedItem? ITypedItem.Parent(NoParamOrder npo, bool? current, string? type, string? field, GetRelatedOptions? options)\n    {\n        if (current != true)\n            return ((ITypedItem)this).Parents(type: type, field: field, options: options).FirstOrDefault();\n            \n        return (DynHelper.Parent as ICanBeItem)?.Item\n               ?? throw new(\n                   $\"You tried to access {nameof(ITypedItem.Parent)}({nameof(current)}: true). This should get the original Item which was used to find this one, but this item doesn't seem to have one. \" +\n                   $\"It's only set if this Item was created from another Item using {nameof(ITypedItem.Child)}(...) or {nameof(ITypedItem.Children)}(...). \" +\n                   $\"Were you trying to use {nameof(ITypedItem.Parents)}(...)?\");\n    }\n\n\n    IEnumerable<ITypedItem> ITypedItem.Parents(NoParamOrder npo, string? type, string? field, GetRelatedOptions? options)\n        => GetHelper.Converter.ParentsItems(entity: Entity, type: type, field: field, options: options ?? new());\n\n    bool ITypedItem.IsPublished => Entity.IsPublished;\n\n    IPublishing ITypedItem.Publishing => _publishing.Get(() => new Publishing.Publishing(this, Cdf))!;\n    private readonly GetOnce<IPublishing> _publishing = new();\n\n    \n    IEnumerable<ITypedItem> ITypedItem.Children(string? field, NoParamOrder npo, string? type, bool? required, GetRelatedOptions? options)\n    {\n        if (IsErrStrictNameOptional(this, field, required, GetHelper.PropsRequired))\n            throw ErrStrictForTyped(this, field);\n\n        // Ability to get child/children using path such as Child.Grandchild.GreatGrandChild\n        var dot = PropertyStack.PathSeparator.ToString();\n        if (field!.Contains(dot))\n        {\n            var first = field.Before(dot);\n            var rest = Text.After(field, dot);\n\n            // Verify it never starts / ends with a dot\n            if (first.IsEmptyOrWs() || rest.IsEmptyOrWs())\n                throw new($\"Got path '{field}' but either first or rest are empty\");\n\n            // Get first part of path without applying type filter, since that should only apply to the last returned level\n            var child = ((ITypedItem)this).Child(first, required: required);\n            \n            // if the child is null, we must return a fake list which knows about this parent\n            // so any UI interactions trying to add children know about it\n            if (child == null)\n                return Cdf.CreateEmptyChildList<ITypedItem>(Entity, field);\n\n            // On the next step, do forward the type filter, as the lowest node should check for that\n            return child.Children(rest, type: type, required: required, options: options);\n        }\n\n        // Standard case: just get the direct children\n        var list = GetHelper.Converter.ChildrenItems(entity: Entity, field: field, type: type, options ?? new());\n        \n        // Return list or special list if it's empty, as we need a special list which knows about this object being the parent\n        return list.Any()\n            ? list\n            : Cdf.CreateEmptyChildList<ITypedItem>(Entity, field);\n\n    }\n\n    /// <inheritdoc />\n\n    ITypedItem? ITypedItem.Child(string name, NoParamOrder npo, bool? required, GetRelatedOptions? options)\n        => IsErrStrictNameRequired(this, name, required, GetHelper.PropsRequired)\n            ? throw ErrStrictForTyped(this, name)\n            : ((ITypedItem)this).Children(name, options: options).FirstOrDefault();\n\n    #endregion\n\n    #region Fields, Html, Picture\n\n\n    IField? ITypedItem.Field(string name, NoParamOrder npo, bool? required)\n        => Cdf.Field(this, supportOldMetadata: false, name, new() { EntryPropIsRequired = required ?? true, ItemIsStrict = propsRequired });\n\n    IHtmlTag? ITypedItem.Html(\n        string name,\n        NoParamOrder npo,\n        object? container,\n        bool? toolbar,\n        object? imageSettings,\n        bool? required,\n        bool debug,\n        Func<ITweakInput<string>, ITweakInput<string>>? tweak\n    ) => TypedItemHelpers.Html(Cdf, this, name: name, npo: npo, container: container,\n        toolbar: toolbar, imageSettings: imageSettings, required: required, debug: debug, tweak: tweak);\n\n    /// <inheritdoc/>\n    IResponsivePicture? ITypedItem.Picture(\n        string name,\n        NoParamOrder npo,\n        Func<ITweakMedia, ITweakMedia>? tweak,\n        object? settings,\n        object? factor,\n        object? width,\n        string? imgAlt,\n        string? imgAltFallback,\n        string? imgClass,\n        object? imgAttributes,\n        string? pictureClass,\n        object? pictureAttributes,\n        object? toolbar,\n        object? recipe\n    ) => TypedItemHelpers.Picture(cdf: Cdf, item: this, name: name, npo: npo, tweak: tweak, settings: settings,\n        factor: factor, width: width, imgAlt: imgAlt, imgAltFallback: imgAltFallback, \n        imgClass: imgClass, imgAttributes: imgAttributes, pictureClass: pictureClass, pictureAttributes: pictureAttributes, \n        toolbar: toolbar, recipe: recipe);\n\n    IResponsiveImage? ITypedItem.Img(\n        string name,\n        NoParamOrder npo,\n        Func<ITweakMedia, ITweakMedia>? tweak,\n        object? settings,\n        object? factor,\n        object? width,\n        string? imgAlt,\n        string? imgAltFallback,\n        string? imgClass,\n        object? imgAttributes,\n        object? toolbar,\n        object? recipe\n    ) => TypedItemHelpers.Img(cdf: Cdf, item: this, name: name, npo: npo, tweak: tweak, settings: settings,\n        factor: factor, width: width, imgAlt: imgAlt, imgAltFallback: imgAltFallback,\n        imgClass: imgClass, imgAttributes: imgAttributes,\n        toolbar: toolbar, recipe: recipe);\n\n\n    #endregion\n\n\n    IMetadata IHasMetadata.Metadata => (((ITypedItem)this).Metadata as IHasMetadata)?.Metadata!;\n\n    #region New Child<T> / Children<T> - disabled as ATM Kit is missing\n\n    /// <inheritdoc />\n    T? ITypedItem.Child<T>(string name, NoParamOrder npo, bool? required, GetRelatedOptions? options)\n        where T : class\n        => Cdf.AsCustom<T>(\n            source: ((ITypedItem)this).Child(name, required: required, options: options)\n        );\n\n    /// <inheritdoc />\n    IEnumerable<T> ITypedItem.Children<T>(string? field, NoParamOrder npo, string? type, bool? required, GetRelatedOptions? options)\n        => Cdf.AsCustomList<T>(\n            source: ((ITypedItem)this).Children(field: field, npo: npo, type: type, required: required, options: options),\n            npo: npo,\n            nullIfNull: false\n        );\n\n    /// <inheritdoc />\n    T? ITypedItem.Parent<T>(NoParamOrder npo, bool? current, string? type, string? field, GetRelatedOptions? options)\n        where T : class\n        => Cdf.AsCustom<T>(\n            source: ((ITypedItem)this).Parent(npo: npo, current: current, type: type ?? typeof(T).Name, field: field, options: options),\n            npo: npo,\n            mock: false\n        );\n\n    /// <inheritdoc />\n    IEnumerable<T> ITypedItem.Parents<T>(NoParamOrder npo, string? type, string? field, GetRelatedOptions? options)\n        => Cdf.AsCustomList<T>(\n            source: ((ITypedItem)this).Parents(npo: npo, field: field, type: type ?? typeof(T).Name, options: options),\n            npo: npo,\n            nullIfNull: false\n        );\n\n\n    #endregion\n\n    #region GPS\n\n    GpsCoordinates ITypedItem.Gps(string name, NoParamOrder npo, bool? required) \n        => GpsCoordinates.FromJson(((ITypedItem)this).String(name, required: required));\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/TypedItemOfEntityWithOverrides.cs",
    "content": "﻿//using ToSic.Sxc.Data.Sys.Factory;\n\n//namespace ToSic.Sxc.Data.Sys.Typed;\n//internal class TypedItemOfEntityWithOverrides(IEntity entity, ICodeDataFactory cdf, bool propsRequired, IValueOverrider overrider)\n//    : TypedItemOfEntity(entity, cdf, propsRequired),\n//        ITyped\n//{\n//    string? ITyped.String(string name, NoParamOrder npo, string? fallback, bool? required, object? scrubHtml)\n//        => overrider.ProcessString(name, ItemHelperForDescendants.String(name, npo, fallback, required, scrubHtml));\n\n//    string? ITyped.Url(string name, NoParamOrder npo, string? fallback, bool? required)\n//        => ItemHelperForDescendants.Url(name, npo, fallback, required, sourceOverrider: overrider);\n\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/WrapObjectTyped.cs",
    "content": "﻿using System.Net;\nusing System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing ToSic.Sxc.Services.Sys.ConvertService;\n\nnamespace ToSic.Sxc.Data.Sys.Typed;\n\n[PrivateApi]\n[JsonConverter(typeof(DynamicJsonConverter))]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WrapObjectTyped(LazySvc<IScrub> scrubSvc, LazySvc<ConvertForCodeService> forCodeConverter)\n    : IWrapper<IPreWrap>, ITyped, IHasPropLookup, IHasJsonSource\n{\n    internal IPreWrap PreWrap { get; private set; } = null!;\n\n    internal WrapObjectTyped Setup(IPreWrap preWrap)\n    {\n        PreWrap = preWrap;\n        return this;\n    }\n\n    IPreWrap IWrapper<IPreWrap>.GetContents() => PreWrap;\n\n    IPropertyLookup IHasPropLookup.PropertyLookup => PreWrap;\n\n    #region Keys\n\n    public bool ContainsKey(string name) => TypedHelpers.ContainsKey(name, this,\n        (e, k) => e.PreWrap.ContainsKey(k),\n        (e, k) =>\n        {\n            var child = e.PreWrap.TryGetWrap(k);\n            if (!child.Found || child.Result == null)\n                return null;\n            if (child.Result is WrapObjectTyped typed)\n                return typed;\n            // Note: arrays have never been supported, so the following won't work\n            // Because the inner objects are not of the expected type.\n            // We don't want to start supporting it now.\n            // Leave this code in though, so we know that we did try it.\n            //if (child.Result is IEnumerable list)\n            //    return list.Cast<WrapObjectTyped>().FirstOrDefault(o => o != null);\n            return null;\n        }\n    );\n\n    public bool IsEmpty(string name, NoParamOrder npo = default, string? language = default /* ignore */)\n        => HasKeysHelper.IsEmpty(this, name, npo, default);\n\n    public bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default /* ignore */)\n        => HasKeysHelper.IsNotEmpty(this, name, npo, default);\n\n\n\n    public IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default)\n        => PreWrap.Keys(npo, only);\n\n    #endregion\n\n    #region ITyped Get\n\n    object? ITyped.Get(string name, NoParamOrder npo, bool? required, string? language /* ignore */)\n        => PreWrap.TryGetObject(name, npo, required);\n\n    TValue? ITyped.Get<TValue>(string name, NoParamOrder npo, TValue? fallback, bool? required, string? language /* note ignored */)\n        where TValue : default\n        => PreWrap.TryGetTyped(name, npo, fallback, required: required);\n\n    #endregion\n\n    #region ITyped Values: Bool, String, etc.\n\n    bool ITyped.Bool(string name, NoParamOrder npo, bool fallback, bool? required)\n        => PreWrap.TryGetTyped(name, npo: npo, fallback: fallback, required: required);\n\n    DateTime ITyped.DateTime(string name, NoParamOrder npo, DateTime fallback, bool? required)\n        => PreWrap.TryGetTyped(name, npo: npo, fallback: fallback, required: required);\n\n    string? ITyped.String(string name, NoParamOrder npo, string? fallback, bool? required, object? scrubHtml)\n    {\n        var value = PreWrap.TryGetTyped(name, npo: npo, fallback: fallback, required: required);\n        return TypedItemHelpers.MaybeScrub(value, scrubHtml, () => scrubSvc.Value);\n    }\n\n    int ITyped.Int(string name, NoParamOrder npo, int fallback, bool? required)\n        => PreWrap.TryGetTyped(name, npo: npo, fallback: fallback, required: required);\n\n    long ITyped.Long(string name, NoParamOrder npo, long fallback, bool? required)\n        => PreWrap.TryGetTyped(name, npo: npo, fallback: fallback, required: required);\n\n    float ITyped.Float(string name, NoParamOrder npo, float fallback, bool? required)\n        => PreWrap.TryGetTyped(name, npo: npo, fallback: fallback, required: required);\n\n    decimal ITyped.Decimal(string name, NoParamOrder npo, decimal fallback, bool? required)\n        => PreWrap.TryGetTyped(name, npo: npo, fallback: fallback, required: required);\n\n    double ITyped.Double(string name, NoParamOrder npo, double fallback, bool? required)\n        => PreWrap.TryGetTyped(name, npo: npo, fallback: fallback, required: required);\n\n    #endregion\n\n    #region ITyped Specials: Attribute, Url\n\n    string? ITyped.Url(string name, NoParamOrder npo, string? fallback, bool? required)\n    {\n        var url = PreWrap.TryGetTyped(name, npo: npo, fallback, required: required);\n        return Tags.SafeUrl(url).ToString();\n    }\n\n    IRawHtmlString? ITyped.Attribute(string name, NoParamOrder npo, string? fallback, bool? required)\n    {\n        var value = PreWrap.TryGetWrap(name, false).Result;\n        var strValue = forCodeConverter.Value.ForCode(value, fallback: fallback);\n        return strValue is null\n            ? null\n            : new RawHtmlString(WebUtility.HtmlEncode(strValue));\n    }\n\n    #endregion\n\n    #region Equality\n\n    /// <summary>\n    /// This is used by various equality comparison. \n    /// Since we define two object to be equal when they host the same contents, this determines the hash based on the contents\n    /// </summary>\n    [PrivateApi]\n    // ReSharper disable once NonReadonlyMemberInGetHashCode\n    public override int GetHashCode() => WrapperEquality.GetWrappedHashCode(PreWrap);\n\n    public override bool Equals(object? b)\n    {\n        if (b is null)\n            return false;\n        if (ReferenceEquals(this, b)) return true;\n        if (b.GetType() != GetType()) return false;\n        return WrapperEquality.EqualsWrapper(PreWrap, ((WrapObjectTyped)b).PreWrap);\n    }\n\n    #endregion\n\n    #region Explicit interfaces for Json, PropertyLookup etc.\n\n    [PrivateApi]\n    object IHasJsonSource.JsonSource() => PreWrap.JsonSource();\n\n    #endregion\n\n    #region ToString to support Json objects\n\n    public override string? ToString() => PreWrap.GetContents()?.ToString();\n\n    #endregion\n\n    /// <summary>\n    /// Get by name should never throw an error, as it's used to get null if not found.\n    /// </summary>\n    object? ICanGetByName.Get(string name) => (this as ITyped).Get(name, required: false);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Typed/WrapObjectTypedItem.cs",
    "content": "﻿using System.Collections;\nusing System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys.Entities.Sources;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Eav.Metadata.Sys;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Data.Options;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services.Sys.ConvertService;\nusing ToSic.Sxc.Services.Tweaks;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.Typed;\n\n[JsonConverter(typeof(DynamicJsonConverter))]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WrapObjectTypedItem(LazySvc<IScrub> scrubSvc, LazySvc<ConvertForCodeService> forCodeConverter)\n    : WrapObjectTyped(scrubSvc, forCodeConverter), ITypedItem\n{\n    internal WrapObjectTypedItem Setup(ILazyLike<ICodeDataFactory> cdf, ICodeDataPoCoWrapperService wrapperSvc, PreWrapObject preWrap)\n    {\n        Setup(preWrap);\n        Wrapper = wrapperSvc;\n        _cdf = cdf;\n        return this;\n    }\n\n    private ICodeDataFactory Cdf => _cdf.Value;\n    private ILazyLike<ICodeDataFactory> _cdf = null!;\n    private ICodeDataPoCoWrapperService Wrapper { get; set; } = null!;\n    public TValue? Get<TValue>(string name, NoParamOrder npo = default, TValue? fallback = default,\n        bool? required = default, string? language = default)\n        => PreWrap.TryGetTyped(name: name, npo: npo, fallback: fallback, required: required);\n\n    bool ITypedItem.IsDemoItem => PreWrap.TryGetTyped(nameof(ITypedItem.IsDemoItem), npo: default, fallback: false, required: false);\n\n    IHtmlTag? ITypedItem.Html(string name, NoParamOrder npo, object? container, bool? toolbar,\n        object? imageSettings, bool? required, bool debug, Func<ITweakInput<string>, ITweakInput<string>>? tweak\n    ) => TypedItemHelpers.Html(Cdf, this, name: name, npo: npo, container: container,\n        toolbar: toolbar, imageSettings: imageSettings, required: required, debug: debug, tweak: tweak);\n\n    IResponsivePicture? ITypedItem.Picture(string name, NoParamOrder npo, Func<ITweakMedia, ITweakMedia>? tweak, object? settings,\n        object? factor, object? width, string? imgAlt, string? imgAltFallback,\n        string? imgClass, object? imgAttributes, string? pictureClass,\n        object? pictureAttributes, object? toolbar, object? recipe\n    ) => TypedItemHelpers.Picture(cdf: Cdf, item: this, name: name, npo: npo,\n        tweak: tweak, settings: settings, factor: factor, width: width, imgAlt: imgAlt,\n        imgAltFallback: imgAltFallback, imgClass: imgClass, imgAttributes: imgAttributes, pictureClass: pictureClass, pictureAttributes: pictureAttributes, toolbar: toolbar, recipe: recipe);\n\n    IResponsiveImage? ITypedItem.Img(\n        string name,\n        NoParamOrder npo,\n        Func<ITweakMedia, ITweakMedia>? tweak,\n        object? settings,\n        object? factor,\n        object? width,\n        string? imgAlt,\n        string? imgAltFallback,\n        string? imgClass,\n        object? imgAttributes,\n        object? toolbar,\n        object? recipe\n    ) => TypedItemHelpers.Img(cdf: Cdf, item: this, name: name, npo: npo, tweak: tweak, settings: settings,\n        factor: factor, width: width, imgAlt: imgAlt, imgAltFallback: imgAltFallback,\n        imgClass: imgClass, imgAttributes: imgAttributes,\n        toolbar: toolbar, recipe: recipe);\n\n\n    public int Id => PreWrap.TryGetTyped(nameof(Id), npo: default, fallback: 0, required: false);\n\n    public Guid Guid => PreWrap.TryGetTyped(nameof(Guid), npo: default, fallback: Guid.Empty, required: false);\n\n    public string? Title => _title.Get(() => PreWrap.TryGetTyped<string>(nameof(ITypedItem.Title), npo: default, fallback: null, required: false));\n    private readonly GetOnce<string?> _title = new();\n\n    #region Properties which return null or empty\n\n    public IEntity Entity => null!;\n    public IContentType Type => null!;\n\n    #region Relationships - Child, Children, Parents, Presentation\n\n    public ITypedItem? Child(string name, NoParamOrder npo, bool? required, GetRelatedOptions? options)\n        => CreateItemFromProperty(name);\n\n    public IEnumerable<ITypedItem> Children(string? field, NoParamOrder npo, string? type, bool? required, GetRelatedOptions? options)\n    {\n        var blank = Enumerable.Empty<ITypedItem>();\n        var r = PreWrap.TryGetWrap(field);\n        if (!r.Found || r.Raw == null || r.Raw.GetType().IsValueType) return blank;\n        if (r.Raw is not IEnumerable re)\n        {\n            var rawWrapped = Wrapper.TypedItemFromObject(r.Raw, PreWrap.Settings);\n            return [rawWrapped];\n        }\n\n        var list = re.Cast<object>()\n            .Where(o => o != null && !o.GetType().IsValueType)\n            .ToList();\n            \n        var items = list\n            .Select(l => Wrapper.TypedItemFromObject(l, PreWrap.Settings));\n\n        if (type.HasValue())\n            items = items\n                .Where(i => i.String(nameof(ITypedItem.Type), required: false).EqualsInsensitive(type))\n                .ToList();\n            \n        return items;\n    }\n\n    public ITypedItem Parent(NoParamOrder npo = default, bool? current = default, string? type = default, string? field = default, GetRelatedOptions? options = default)\n        => throw new NotSupportedException($\"You can't access the {nameof(Parent)}() here\");\n\n\n    /// <summary>\n    /// The parents of Wrap-Object are \"fake\" so they behave just like children... but under the node \"Parents\".\n    /// If \"field\" is specified, then it will assume another child-level under the node parents\n    /// </summary>\n    public IEnumerable<ITypedItem> Parents(NoParamOrder npo, string? type, string? field, GetRelatedOptions? options)\n    {\n        var items = ((ITypedItem)this)\n            .Children(nameof(ITypedItem.Parents), type: type, options: options)\n            .ToList();\n\n        if (!items.SafeAny() && !field.HasValue())\n            // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract\n            return items ?? [];\n\n        if (field.HasValue())\n            items = items\n                .Where(i => i.String(\"Field\", required: false).EqualsInsensitive(field))\n                .ToList();\n        return items;\n    }\n\n    bool ITypedItem.IsPublished => true;\n\n    IPublishing ITypedItem.Publishing => _publishing.Get(() => new PublishingUnsupported(this))!;\n    private readonly GetOnce<IPublishing> _publishing = new();\n\n    [JsonIgnore]\n    public ITypedItem? Presentation => _presentation.Get(() => CreateItemFromProperty(nameof(Presentation)));\n    private readonly GetOnce<ITypedItem?> _presentation = new();\n\n    private ITypedItem? CreateItemFromProperty(string? name)\n    {\n        if (name == null)\n            return null;\n        var result = PreWrap.TryGetWrap(name);\n        if (!result.Found || result.Raw == null || result.Raw.GetType().IsValueType)\n            return null;\n        var first = result.Raw is IEnumerable re ? re.Cast<object>().FirstOrDefault() : result.Raw;\n        if (first == null || first.GetType().IsValueType)\n            return null;\n        return Wrapper.TypedItemFromObject(first, PreWrap.Settings);\n    }\n\n    #endregion\n\n\n\n\n    public IFolder Folder(string name, NoParamOrder npo, bool? required)\n    {\n        return IsErrStrictNameRequired(this, name, required, PreWrap.Settings.PropsRequired)\n            ? throw ErrStrictForTyped(this, name)\n            : Cdf.Folder(Guid, name, Field(name: name, npo: default, required: required));\n    }\n\n    public IFile? File(string name, NoParamOrder npo, bool? required)\n    {\n        if (IsErrStrictNameRequired(this, name, required, PreWrap.Settings.PropsRequired))\n            throw ErrStrictForTyped(this, name);\n        var typed = this as ITypedItem;\n        // Check if it's a direct string, or an object with a sub-property with a Value\n        var idString = typed.String(name) ?? typed.Child(name)?.String(\"Value\");\n\n        // TODO: SEE if we can also provide optional metadata\n\n        var fileId = LinkParts.CheckIdStringForId(idString);\n        return fileId == null ? null : Cdf.File(fileId.Value);\n    }\n\n    #endregion\n\n    #region New Child<T> / Children<T> - disabled as ATM Kit is missing\n\n    T? ITypedItem.Child<T>(string name, NoParamOrder npo, bool? required, GetRelatedOptions? options)\n        where T : class\n        => Cdf.AsCustom<T>(\n            source: (this as ITypedItem).Child(name, required: required, options: options)\n        );\n\n    IEnumerable<T> ITypedItem.Children<T>(string? field, NoParamOrder npo, string? type, bool? required, GetRelatedOptions? options)\n        => Cdf.AsCustomList<T>(\n            source: (this as ITypedItem).Children(field: field, npo: npo, type: type, required: required, options: options),\n            npo: npo,\n            nullIfNull: false\n        );\n\n    T? ITypedItem.Parent<T>(NoParamOrder npo, bool? current, string? type, string? field, GetRelatedOptions? options)\n        where T : class\n        => Cdf.AsCustom<T>(\n            source: (this as ITypedItem).Parent(current: current, type: type ?? typeof(T).Name, field: field, options: options)\n        );\n\n    IEnumerable<T> ITypedItem.Parents<T>(NoParamOrder npo, string? type, string? field, GetRelatedOptions? options)\n        => Cdf.AsCustomList<T>(\n            source: (this as ITypedItem).Parents(field: field, type: type ?? typeof(T).Name, options: options),\n            npo: npo,\n            nullIfNull: false\n        );\n\n    #endregion\n\n    #region Not Supported Properties such as Entity, Type, Child, Folder, Presentation, Metadata\n\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    [field: AllowNull, MaybeNull]\n    ITypedMetadata ITypedItem.Metadata => field ??= BuildMetadata(PreWrap.TryGetWrap(nameof(ITypedItem.Metadata)).Raw);\n\n    private ITypedMetadata BuildMetadata(object? raw)\n    {\n        var objList = raw != null\n            ? raw is IEnumerable rawEnum\n                ? rawEnum.Cast<object>().ToList()\n                : [raw]\n            : [];\n\n        var df = Cdf.Services.DataFactory.Value.SpawnNew(options: new()\n        {\n            AppId = ((ICodeDataFactoryDeepWip)Cdf).AppIdOrZero,\n            AutoId = false,\n        });\n        var mdEntities = objList\n            .Where(o => o != null)\n            .Select(o =>\n            {\n                var values = o.ToDicInvariantInsensitive();\n                // Note: id/guid don't really work, but it's never used in metadata context\n                //var id = values.TryGetValue(nameof(Id), out var maybeId) ? maybeId.ConvertOrFallback(0) : 0;\n                //var guid = values.TryGetValue(nameof(Guid), out var maybeGuid) ? maybeGuid.ConvertOrFallback(Guid.Empty) : Guid.Empty;\n                return df.Create(values);\n            })\n            .ToList();\n\n        var mdOf = new Metadata<int>(0, 0, \"virtual\", source: MetadataProvider.Create(mdEntities));\n        // TODO: @2dm - this probably won't work yet, without an entity (null) #todoTyped\n        var metadata = Cdf.MetadataTyped(mdOf);\n        return metadata;\n    }\n\n\n    public IField Field(string name, NoParamOrder npo, bool? required) \n        => new Fields.Field(this, name, Cdf);\n\n    /// <summary>\n    /// Override the URL, to also support checks for \"file:72\"\n    /// </summary>\n    string? ITyped.Url(string name, NoParamOrder npo, string? fallback, bool? required)\n    {\n        var url = PreWrap.TryGetTyped(name, npo: npo, fallback, required: required);\n        if (url == null)\n            return null;\n\n        // ReSharper disable once ConvertTypeCheckPatternToNullCheck\n        if (ValueConverterBase.CouldBeReference(url))\n            // ReSharper disable once ConstantNullCoalescingCondition\n            url = Cdf.Services.ValueConverter.Value.ToValue(url, Guid.Empty) ?? url;\n\n        return Tags.SafeUrl(url).ToString();\n    }\n    #endregion\n\n    #region GPS\n\n    GpsCoordinates ITypedItem.Gps(string name, NoParamOrder npo, bool? required)\n        => GpsCoordinates.FromJson(((ITypedItem)this).String(name, required: required));\n\n    #endregion\n\n\n    public ITypedItem Item => this;\n\n    /// <summary>\n    /// Get by name should never throw an error, as it's used to get null if not found.\n    /// </summary>\n    object? ICanGetByName.Get(string name)\n        => (this as ITypedItem).Get(name, required: false);\n\n    #region Equals\n\n    /// <summary>\n    /// This is used by various equality comparison. \n    /// Since we define two object to be equal when they host the same contents, this determines the hash based on the contents\n    /// </summary>\n    [PrivateApi]\n    // ReSharper disable once NonReadonlyMemberInGetHashCode\n    public override int GetHashCode()\n        => WrapperEquality.GetWrappedHashCode(this.PreWrap);\n\n    public override bool Equals(object? b)\n    {\n        if (b is null)\n            return false;\n        if (ReferenceEquals(this, b)) return true;\n        if (b.GetType() != GetType()) return false;\n        if (b is not WrapObjectTypedItem bTyped) return false;\n        if (bTyped.PreWrap.GetType() != PreWrap.GetType()) return false;\n\n        // TODO: ATM not clear how to best do this\n        // probably need to check what's inside the PreWrap...\n        return WrapperEquality.EqualsWrapper(this.PreWrap, bTyped.PreWrap);\n    }\n\n    bool IEquatable<ITypedItem>.Equals(ITypedItem? other) => Equals(other);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/TypedStack/TypedStack.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Data.Options;\nusing ToSic.Sxc.Data.Sys.Dynamic;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Stack;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.TypedStack;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal partial class TypedStack: IWrapper<IPropertyStack>, ITypedStack, IHasPropLookup\n{\n    public TypedStack(string name, ICodeDataFactory cdf, IReadOnlyCollection<KeyValuePair<string, IPropertyLookup>> sources)\n    {\n        _stack = new PropertyStack().Init(name, sources);\n        Cdf = cdf;\n        _stackPropLookup = new(_stack, () => Debug);\n        _helper = new(this, cdf, propsRequired: false, childrenShouldBeDynamic: false, canDebug: this);\n        _itemHelper = new(_helper, this);\n    }\n\n    private readonly IPropertyStack _stack;\n    IPropertyLookup IHasPropLookup.PropertyLookup => _stackPropLookup;\n    private readonly PropLookupStack _stackPropLookup;\n    private readonly GetAndConvertHelper _helper;\n    private readonly CodeItemHelper _itemHelper;\n\n    public IPropertyStack GetContents() => _stack;\n\n    public ICodeDataFactory Cdf { get; }\n\n    public bool Debug { get; set; }\n\n    #region GetByName - to allow this to be used for image settings etc.\n\n    object? ICanGetByName.Get(string name) => (this as ITyped).Get(name, required: false);\n\n    #endregion\n\n\n    #region ITyped.Keys and Dyn - both not implemented\n\n    [PrivateApi]\n    public bool ContainsKey(string name)\n        => throw new NotImplementedException($\"Not yet implemented on {nameof(ITypedStack)}\");\n\n    public bool IsEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => _itemHelper.IsEmpty(name, npo, isBlank: default, language: language);\n\n    public bool IsNotEmpty(string name, NoParamOrder npo = default, string? language = default)\n        => _itemHelper.IsNotEmpty(name, npo, isBlank: default, language: language);\n\n    // TODO: Keys()\n    public IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default)\n    {\n        //var keys = _stack.Sources;\n        throw new NotImplementedException();\n    }\n\n    #endregion\n\n    #region ITyped Value Get Methods\n\n    [PrivateApi]\n    object? ITyped.Get(string name, NoParamOrder npo, bool? required, string? language)\n        => _itemHelper.Get(name: name, npo: npo, required: required, language: language);\n\n    [PrivateApi]\n    TValue? ITyped.Get<TValue>(string name, NoParamOrder npo, TValue? fallback, bool? required, string? language)\n        where TValue : default\n        => _itemHelper.GetT(name, npo, fallback: fallback, required: required, language: language);\n\n\n    [PrivateApi]\n    IRawHtmlString? ITyped.Attribute(string name, NoParamOrder npo, string? fallback, bool? required)\n        => _itemHelper.Attribute(name, npo, fallback, required);\n\n\n    [PrivateApi]\n    DateTime ITyped.DateTime(string name, NoParamOrder npo, DateTime fallback, bool? required)\n        => _itemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    [PrivateApi]\n    string? ITyped.String(string name, NoParamOrder npo, string? fallback, bool? required, object? scrubHtml)\n        => _itemHelper.String(name, npo, fallback, required, scrubHtml);\n\n    [PrivateApi]\n    int ITyped.Int(string name, NoParamOrder npo, int fallback, bool? required)\n        => _itemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    [PrivateApi]\n    bool ITyped.Bool(string name, NoParamOrder npo, bool fallback, bool? required)\n        => _itemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    [PrivateApi]\n    long ITyped.Long(string name, NoParamOrder npo, long fallback, bool? required)\n        => _itemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    [PrivateApi]\n    float ITyped.Float(string name, NoParamOrder npo, float fallback, bool? required)\n        => _itemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    [PrivateApi]\n    decimal ITyped.Decimal(string name, NoParamOrder npo, decimal fallback, bool? required)\n        => _itemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    [PrivateApi]\n    double ITyped.Double(string name, NoParamOrder npo, double fallback, bool? required)\n        => _itemHelper.G4T(name, npo: npo, fallback: fallback, required: required);\n\n    [PrivateApi]\n    string? ITyped.Url(string name, NoParamOrder npo, string? fallback, bool? required)\n        => _itemHelper.Url(name, npo, fallback, required);\n\n    [PrivateApi]\n    string ITyped.ToString() => \"test / debug: \" + ToString();\n\n    #endregion\n\n    #region Add-Ons for ITypedStack\n\n    ITypedItem? /*ITypedStack*/ITypedItem.Child(string name, NoParamOrder npo, bool? required, GetRelatedOptions? options)\n    {\n        var findResult = _helper.TryGet(name);\n        return IsErrStrict(findResult.Found, required, _helper.PropsRequired)\n            ? throw ErrStrict(name)\n            : Cdf.AsItem(findResult.Result!, new() { EntryPropIsRequired = required ?? true, ItemIsStrict = _helper.PropsRequired });\n    }\n\n    IEnumerable<ITypedItem> /*ITypedStack*/ITypedItem.Children(string? field, NoParamOrder npo, string? type, bool? required, GetRelatedOptions? options)\n    {\n        var findResult = _helper.TryGet(field);\n        return IsErrStrict(findResult.Found, required, _helper.PropsRequired)\n            ? throw ErrStrict(field)\n            // TODO: #ConvertItemSettings - not sure if this default is correct\n            : Cdf.AsItems(findResult.Result!, new() { EntryPropIsRequired = required ?? true, ItemIsStrict = _helper.PropsRequired })\n                // Apply type filter - even if a bit \"late\"\n                .Where(i => i.Entity.Type.Is(type))\n                .ToList();\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/TypedStack/TypedStack_Item.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Data.Options;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services.Tweaks;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.TypedStack;\n\ninternal partial class TypedStack: ITypedItem\n{\n    private const string NotImplementedError = \"This is a stack. This method/property is not clearly defined on a stack of objects.\";\n\n    private const string ParentNotImplemented = \"This is a stack. There are no parents as nothing can ever point to a stack directly, only to specific objects inside it.\";\n\n    IEntity ICanBeEntity.Entity => throw new NotImplementedException(NotImplementedError);\n\n    ITypedItem ICanBeItem.Item => this;\n\n    bool IEquatable<ITypedItem>.Equals(ITypedItem? other) => ReferenceEquals(this, other);\n\n    bool ITypedItem.IsDemoItem => false;\n\n    IHtmlTag? ITypedItem.Html(string name, NoParamOrder npo, object? container, bool? toolbar,\n        object? imageSettings, bool? required, bool debug, Func<ITweakInput<string>, ITweakInput<string>>? tweak)\n        => TypedItemHelpers.Html(Cdf, this, name, npo, container, toolbar, imageSettings, required, debug, tweak);\n\n    IResponsivePicture? ITypedItem.Picture(string name, NoParamOrder npo,\n        Func<ITweakMedia, ITweakMedia>? tweak,\n        object? settings,\n        object? factor, object? width, string? imgAlt, string? imgAltFallback,\n        string? imgClass, object? imgAttributes, string? pictureClass,\n        object? pictureAttributes, object? toolbar, object? recipe\n    ) => TypedItemHelpers.Picture(cdf: Cdf, item: this, name: name, npo: npo, tweak: tweak, settings: settings,\n        factor: factor, width: width, imgAlt: imgAlt, imgAltFallback: imgAltFallback,\n        imgClass: imgClass, imgAttributes: imgAttributes, pictureClass: pictureClass,\n        pictureAttributes: pictureAttributes,\n        toolbar: toolbar, recipe: recipe);\n\n    IResponsiveImage? ITypedItem.Img(string name, NoParamOrder npo, Func<ITweakMedia, ITweakMedia>? tweak, object? settings, object? factor,\n        object? width, string? imgAlt, string? imgAltFallback, string? imgClass, object? imgAttributes, object? toolbar, object? recipe\n    ) => TypedItemHelpers.Img(cdf: Cdf, item: this, name: name, npo: npo, tweak: tweak, settings: settings,\n        factor: factor, width: width, imgAlt: imgAlt, imgAltFallback: imgAltFallback,\n        imgClass: imgClass, imgAttributes: imgAttributes,\n        toolbar: toolbar, recipe: recipe);\n\n\n    GpsCoordinates ITypedItem.Gps(string name, NoParamOrder npo, bool? required)\n        => GpsCoordinates.FromJson(((ITypedItem)this).String(name, required: required));\n\n    #region ADAM\n\n    IField? ITypedItem.Field(string name, NoParamOrder npo, bool? required)\n    {\n        // Try to find the object which has that field with a valid value etc.\n        var sourceItem = FindSubItemHavingField(name);\n        return sourceItem?.Field(name, required: required)\n               ?? (IsErrStrict(false, required, _helper.PropsRequired)\n                   ? throw ErrStrict(name)\n                   : null);\n    }\n\n    /// <summary>\n    /// Find the first source having the specified field with a real value...\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <returns></returns>\n    private ITypedItem? FindSubItemHavingField(string name)\n    {\n        // Try to find the object which has that field with a valid value etc.\n        var logOrNull = _helper.LogOrNull.SubLogOrNull(\"Stk.Field\", Debug);\n        var specs = new PropReqSpecs(name, Cdf.Dimensions, true, logOrNull);\n        var path = new PropertyLookupPath().Add(\"DynEntStart\", name);\n\n        var findResult = _stackPropLookup.FindPropertyInternal(specs, path);\n        if (findResult == null! /* paranoid */ || findResult.ValueType == ValueTypesWithState.NotFound)\n            return null;\n\n        var sourceItem = findResult.Source as ITypedItem\n                         ?? (findResult.Source as ICanBeItem)?.Item\n                         // TODO: #ConvertItemSettings\n                         ?? (findResult.Source as ICanBeEntity)\n                         .NullOrGetWith(e => Cdf.AsItem(e, new() { ItemIsStrict = false }));\n\n        return sourceItem;\n    }\n\n    IFolder? ITypedItem.Folder(string name, NoParamOrder npo, bool? required)\n    {\n        // Try to find the object which has that field with a valid value etc.\n        var sourceItem = FindSubItemHavingField(name);\n        return sourceItem?.Folder(name, required: required)\n               ?? (IsErrStrict(false, required, _helper.PropsRequired)\n                   ? throw ErrStrict(name)\n                   : null);\n    }\n\n    IFile? ITypedItem.File(string name, NoParamOrder npo, bool? required)\n    {\n        // Try to find the object which has that field with a valid value etc.\n        var sourceItem = FindSubItemHavingField(name);\n        return sourceItem?.File(name, required: required)\n               ?? (IsErrStrict(false, required, _helper.PropsRequired)\n                   ? throw ErrStrict(name)\n                   : null);\n    }\n\n    #endregion\n\n    //ITypedItem ITypedItem.Child(string name, NoParamOrder npo, bool? required)\n    //    => (this as ITypedStack).Child(name, npo, required);\n\n    //IEnumerable<ITypedItem> ITypedItem.Children(string field, NoParamOrder npo, string type, bool? required)\n    //    => (this as ITypedStack).Children(field, npo, type, required);\n\n    T? ITypedItem.Child<T>(string name, NoParamOrder npo, bool? required, GetRelatedOptions? options)\n        where T : class\n        => Cdf.AsCustom<T>(\n            source: ((ITypedItem)this).Child(name, required: required, options: options)\n        );\n\n    IEnumerable<T> ITypedItem.Children<T>(string? field, NoParamOrder npo, string? type, bool? required, GetRelatedOptions? options)\n        => Cdf.AsCustomList<T>(\n            source: ((ITypedItem)this).Children(field: field, npo: npo, type: type, required: required, options: options),\n            npo: npo,\n            nullIfNull: false\n        );\n\n    #region Not implemented: Parents, Publishing, Dyn, Presentation, Metadata\n\n    ITypedItem ITypedItem.Parent(NoParamOrder npo, bool? current, string? type, string? field, GetRelatedOptions? options)\n        => throw new NotImplementedException(ParentNotImplemented);\n\n    IEnumerable<ITypedItem> ITypedItem.Parents(NoParamOrder npo, string? type, string? field, GetRelatedOptions? options)\n        => throw new NotImplementedException(ParentNotImplemented);\n\n    T? ITypedItem.Parent<T>(NoParamOrder npo, bool? current, string? type, string? field, GetRelatedOptions? options)\n        where T : class\n        => throw new NotImplementedException(ParentNotImplemented);\n\n    IEnumerable<T> ITypedItem.Parents<T>(NoParamOrder npo, string? type, string? field, GetRelatedOptions? options)\n        => throw new NotImplementedException(ParentNotImplemented);\n\n    bool ITypedItem.IsPublished => throw new NotImplementedException(NotImplementedError);\n\n    IPublishing ITypedItem.Publishing => throw new NotImplementedException(NotImplementedError);\n\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    ITypedItem ITypedItem.Presentation => throw new NotImplementedException(NotImplementedError);\n\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    ITypedMetadata ITypedItem.Metadata => throw new NotImplementedException(NotImplementedError);\n\n    #endregion\n\n    int ITypedItem.Id => 0;\n\n    Guid ITypedItem.Guid => Guid.Empty;\n\n    string ITypedItem.Title => \"\";\n\n    IContentType ITypedItem.Type => throw new NotImplementedException();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/CodeDataPoCoWrapperService.cs",
    "content": "﻿using System.Dynamic;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Sxc.Data.Sys.Dynamic;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.Wrappers;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeDataPoCoWrapperService(\n    LazySvc<ICodeDataFactory> cdf,\n    Generator<WrapObjectTyped> wrapTypeGenerator,\n    Generator<WrapObjectTypedItem> wrapItemGenerator)\n    : ServiceBase(\"Sxc.DWrpFk\", connect: [wrapTypeGenerator, wrapItemGenerator, cdf]), ICodeDataPoCoWrapperService\n{\n    /*DynamicFromDictionary<TKey, TValue>*/object ICodeDataPoCoWrapperService.FromDictionary<TKey, TValue>(IDictionary<TKey, TValue> original)\n        => new DynamicFromDictionary<TKey, TValue>(original, this);\n\n    public object DynamicFromObject(object? data, WrapperSettings settings)\n    {\n        var preWrap = new PreWrapObject(data, settings, this);\n        return new WrapObjectDynamic(preWrap, this);\n    }\n\n    public ITyped TypedFromObject(object data, WrapperSettings settings)\n    {\n        var preWrap = new PreWrapObject(data, settings, this);\n        return wrapTypeGenerator.New().Setup(preWrap);\n    }\n\n    public ITypedItem TypedItemFromObject(object? data, WrapperSettings settings, ILazyLike<ICodeDataFactory>? cdf1 = default)\n    {\n        var preWrap = new PreWrapObject(data, settings, this);\n        return wrapItemGenerator.New().Setup(cdf1 ?? cdf, this, preWrap);\n    }\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"data\"></param>\n    /// <param name=\"wrapNonAnon\">if true and the contents isn't already a dynamic object, it will also wrap real objects; otherwise only anonymous</param>\n    /// <param name=\"settings\"></param>\n    /// <returns></returns>\n    [PrivateApi]\n    object? ICodeDataPoCoWrapperService.ChildNonJsonWrapIfPossible(object? data, bool wrapNonAnon, WrapperSettings settings)\n    {\n        // If null or simple value, use that\n        if (data is null)\n            return null;\n\n        if (data is string || data.GetType().IsValueType)\n            return data;\n\n        // Guids & DateTimes are objects, but very simple, and should be returned for normal use\n        if (data is Guid or DateTime)\n            return data;\n\n        // 2023-08-18 2dm DISABLED - I'm pretty sure that json should never be a source of this\n        // as I believe it's only used in non-json wrappers\n        // Check if the result is a JSON object which should support navigation again\n        //var result = new CodeJsonWrapper(this, settings).IfJsonGetValueOrJacket(data);\n        var result = data;\n\n        // Check if the original or result already supports navigation... - which is the case if it's a DynamicJacket now\n        switch (result)\n        {\n            case IPropertyLookup:\n            case ISxcDynamicObject:\n            case DynamicObject:\n                return result;\n        }\n\n        // if (result is IDictionary dicResult) return DynamicReadDictionary(dicResult);\n\n        // Simple arrays don't benefit from re-wrapping. \n        // If the calling code needs to do something with them, it should iterate it and then rewrap with AsDynamic\n        if (result.GetType().IsArray)\n            return result;\n\n        // Otherwise it's a complex object, which should be re-wrapped for navigation\n        var wrap = wrapNonAnon || data.IsAnonymous();\n        return wrap\n            ? settings.WrapToDynamic \n                ? DynamicFromObject(data, settings)\n                : TypedFromObject(data, settings)\n            : data;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/ICodeDataPoCoWrapperService.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Data.Sys.Wrappers;\n\n/// <summary>\n/// Service to create dynamic or typed objects from non Entity objects.\n/// </summary>\npublic interface ICodeDataPoCoWrapperService\n{\n    /// <summary>\n    /// Note: returns a WrapObjectDynamic, but not typed to make it easier to move objects in code.\n    /// It's mainly used in production code as `dynamic` so the internal type doesn't matter.\n    /// </summary>\n    /// <param name=\"data\"></param>\n    /// <param name=\"settings\"></param>\n    /// <returns></returns>\n    /*WrapObjectDynamic*/\n    object DynamicFromObject(object? data, WrapperSettings settings);\n    ITyped TypedFromObject(object data, WrapperSettings settings);\n    ITypedItem TypedItemFromObject(object? data, WrapperSettings settings, ILazyLike<ICodeDataFactory>? cdf1 = default);\n\n    public /*DynamicFromDictionary<TKey, TValue>*/object FromDictionary<TKey, TValue>(IDictionary<TKey, TValue> original);\n\n    internal object? ChildNonJsonWrapIfPossible(object? data, bool wrapNonAnon, WrapperSettings settings);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/IPreWrap.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.Data.Sys.Wrappers;\n\n[PrivateApi]\n[JsonConverter(typeof(DynamicJsonConverter))]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal interface IPreWrap : IHasJsonSource, IPropertyLookup, IWrapper<object>\n{\n    TryGetResult TryGetWrap(string? name, bool wrapDefault = true);\n\n    object TryGetObject(string name, NoParamOrder npo, bool? required, [CallerMemberName] string? cName = default);\n\n    [return: NotNullIfNotNull(nameof(fallback))]\n    TValue? TryGetTyped<TValue>(string name, NoParamOrder npo, TValue? fallback, bool? required, [CallerMemberName] string? cName = default);\n\n    WrapperSettings Settings { get; }\n\n    bool ContainsKey(string name);\n\n    IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/JsonProcessingHelpers.cs",
    "content": "﻿using System.Text.Json;\nusing System.Text.Json.Nodes;\nusing static ToSic.Eav.Serialization.Sys.Json.JsonOptions;\nusing static ToSic.Sxc.Data.Sys.Wrappers.WrapperConstants;\n\nnamespace ToSic.Sxc.Data.Sys.Wrappers;\n\ninternal class JsonProcessingHelpers\n{\n    internal static JsonNode? AsJsonNode(string? json, string? fallback = EmptyJson)\n    {\n        if (!json.HasValue())\n            return fallback == null\n                ? null\n                : StandardParse(fallback);\n\n        try\n        {\n            var (isComplex, _) = AnalyzeJson(json);\n            if (isComplex)\n            {\n                var node = StandardParse(json);\n                if (node != null) return node;\n            }\n        }\n        catch\n        {\n            if (fallback == JsonErrorCode) throw;\n        }\n\n        // fallback\n        return fallback == null ? null : StandardParse(fallback);\n\n        JsonNode? StandardParse(string jsonToParse)\n            => JsonNode.Parse(jsonToParse, JsonNodeDefaultOptions, JsonDocumentDefaultOptions);\n    }\n\n    /// <summary>\n    /// Make sure a JsonNode which is a JValue containing an Array or Object is correctly packages\n    /// </summary>\n    /// <param name=\"node\"></param>\n    /// <returns></returns>\n    public static (JsonNode? Node, bool Repackaged) NeutralizeValueToObjectOrArray(JsonNode node)\n    {\n        if (node is not JsonValue jValue)\n            return (node, false);\n        var je = jValue.GetValue<JsonElement>();\n        switch (je.ValueKind)\n        {\n            case JsonValueKind.Array: return (JsonArray.Create(je), true);\n            case JsonValueKind.Object: return (JsonObject.Create(je), true);\n            default: return (node, false);\n        }\n    }\n\n    /// <summary>\n    /// Find out if a string is a complex object (obj/array) and if it's an array.\n    /// </summary>\n    /// <param name=\"json\"></param>\n    /// <returns></returns>\n    public static (bool IsComplex, bool IsArray) AnalyzeJson(string json)\n    {\n        // find first possible opening character\n        var firstCharPos = json.IndexOfAny([JObjStart, JArrayStart]);\n        return firstCharPos <= -1\n            ? (false, false)\n            : (true, json[firstCharPos] == JArrayStart);\n    }\n\n\n    public static object? JsonValueGetContents(JsonNode? jValue)\n    {\n        if (jValue == null)\n            return null;\n\n        var je = jValue.GetValue<JsonElement>();\n        return je.ValueKind switch\n        {\n            JsonValueKind.True => true,\n            JsonValueKind.False => false,\n            JsonValueKind.Number when je.TryGetInt32(out var intValue) => intValue,\n            JsonValueKind.Number when je.TryGetInt64(out var longValue) => longValue,\n            JsonValueKind.Number => je.GetDouble(),\n            JsonValueKind.String when je.TryGetDateTime(out var dateTime) => dateTime,\n            JsonValueKind.String => je.GetString(),\n            JsonValueKind.Null or JsonValueKind.Undefined => null,\n            //case JsonValueKind.Object: return new DynamicJacket(JsonObject.Create(je));\n            //case JsonValueKind.Array: return new DynamicJacketList(JsonArray.Create(je));\n            _ => jValue.AsValue()\n        };\n    }\n\n    //private (object Final, bool Ok, JsonValueKind ValueKind) IfJsonTryConvertToExpected(object original) =>\n    //    Settings.WrapToDynamic\n    //        ? ((object Final, bool Ok, JsonValueKind ValueKind))IfJsonTryConvertToJacket(original)\n    //        : IfJsonTryConvertToJacket<ITyped>(original, CreateTypedObject, CreateTypedList);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/PreWrapBase.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.Wrappers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class PreWrapBase(object? data) : IWrapper<object>, IHasJsonSource\n{\n    #region IWrapper\n\n    object? IWrapper<object>.GetContents() => data;\n\n    #endregion\n\n    public abstract WrapperSettings Settings { get; }\n\n    #region Abstract things which must be implemented like TryGetWrap\n\n    public abstract object JsonSource();\n\n    public abstract TryGetResult TryGetWrap(string? name, bool wrapDefault = true);\n\n    #endregion\n\n    #region Abstract: Keys\n\n    public abstract IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default);\n\n    public abstract bool ContainsKey(string name);\n\n    #endregion\n\n    #region TryGet and FindPropertyInternals\n\n    public object TryGetObject(string name, NoParamOrder npo, bool? required, [CallerMemberName] string? cName = default)\n    {\n        var result = TryGetWrap(name, wrapDefault: true);\n        return IsErrStrict(result.Found, required, Settings.PropsRequired)\n            ? throw ErrStrict(name, cName: cName)\n            : result.Result!;\n    }\n\n    public TValue? TryGetTyped<TValue>(string name, NoParamOrder npo, TValue? fallback, bool? required, [CallerMemberName] string? cName = default)\n    {\n        var result = TryGetWrap(name, false);\n        return IsErrStrict(result.Found, required, Settings.PropsRequired)\n            ? throw ErrStrict(name, cName: cName)\n            : result.Result.ConvertOrFallback(fallback);\n    }\n\n    [PrivateApi(\"Internal\")]\n    public PropReqResult FindPropertyInternal(PropReqSpecs specs, PropertyLookupPath path)\n    {\n        path = path.KeepOrNew().Add($\"PreWrap.{GetType()}\", specs.Field);\n        var result = TryGetWrap(specs.Field, wrapDefault: true).Result;\n        return new(result: result, valueType: ValueTypesWithState.Dynamic, path: path) { Source = this, Name = \"dynamic\" };\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/PreWrapObject.cs",
    "content": "﻿using System.Reflection;\nusing System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Sxc.Data.Sys.Json;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing static ToSic.Sxc.Data.Sys.Typed.TypedHelpers;\n\nnamespace ToSic.Sxc.Data.Sys.Wrappers;\n\n// WIP\n// Inspired by https://stackoverflow.com/questions/46948289/how-do-you-convert-any-c-sharp-object-to-an-expandoobject\n// That was more complex with ability so set new values and switch between case-insensitive or not but that's not the purpose of this\n/// <summary>\n/// \n/// </summary>\n/// <remarks>\n/// Will always return a value even if the property doesn't exist, in which case it resolves to null.\n/// </remarks>\n[JsonConverter(typeof(DynamicJsonConverter))]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal partial class PreWrapObject: PreWrapBase, IPropertyLookup, IHasJsonSource, IPreWrap\n{\n    #region Constructor / Setup\n\n    /// <summary>\n    /// Case-insensitive property dictionary\n    /// </summary>\n    private Dictionary<string, PropertyInfo> PropDic { get; }\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"data\"></param>\n    /// <param name=\"settings\">\n    /// Determines if properties which are objects should again be wrapped.\n    /// When using this for DynamicModel it should be false, otherwise usually true.\n    /// </param>\n    /// <param name=\"wrapperSvc\"></param>\n    [PrivateApi]\n    internal PreWrapObject(object? data, WrapperSettings settings, ICodeDataPoCoWrapperService wrapperSvc): base(data)\n    {\n        WrapperSvc = wrapperSvc;\n        _innerObject = data;\n        Settings = settings;\n        PropDic = CreatePropertyInfoDictionary(data);\n    }\n\n    private ICodeDataPoCoWrapperService WrapperSvc { get; }\n    private readonly object? _innerObject;\n    public override WrapperSettings Settings { get; }\n\n    internal static Dictionary<string, PropertyInfo> CreatePropertyInfoDictionary(object? original)\n    {\n        var dic = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCultureIgnoreCase);\n        if (original is null)\n            return dic;\n        var itemType = original.GetType();\n        foreach (var propertyInfo in itemType.GetProperties())\n            dic[propertyInfo.Name] = propertyInfo;\n        return dic;\n    }\n\n    #endregion\n\n    #region Keys\n\n    public override bool ContainsKey(string name) => PropDic.ContainsKey(name);\n\n    public override IEnumerable<string> Keys(NoParamOrder npo = default, IEnumerable<string>? only = default)\n        => FilterKeysIfPossible(npo, only, PropDic.Keys);\n\n    #endregion\n\n\n    public override TryGetResult TryGetWrap(string? name, bool wrapDefault = true)\n    {\n        if (name.IsEmptyOrWs() || _innerObject == null)\n            return new(false, null, null);\n\n        var isPath = name.Contains(PropertyStack.PathSeparator.ToString());\n\n        if (!isPath)\n            return TryGetFromNode(name, this, wrapDefault);\n\n        var pathParts = PropertyStack.SplitPathIntoParts(name);\n        var node = this;\n        for (var i = 0; i < pathParts.Length; i++)\n        {\n            var part = pathParts[i];\n            var result = TryGetFromNode(part, node, true);\n            // last one or not found - return a not-found\n            if (i == pathParts.Length - 1 || !result.Found) return result;\n\n            node = (result.Result as IHasPropLookup)?.PropertyLookup as PreWrapObject;\n            if (node == null) return new(false, null, null);\n        }\n        return new(false, null, null);\n\n    }\n\n    private TryGetResult TryGetFromNode(string name, PreWrapObject preWrap, bool wrapDefault)\n    {\n        if (!preWrap.PropDic.TryGetValue(name, out var lookup))\n            return new(false, null, null);\n\n        var result = lookup.GetValue(preWrap._innerObject);\n\n        // Probably re-wrap for further dynamic navigation!\n        return new(true, result,\n            Settings.WrapChildren && wrapDefault\n                ? WrapperSvc.ChildNonJsonWrapIfPossible(result, Settings.WrapRealObjects, Settings)\n                : result);\n\n    }\n\n\n\n    public override object JsonSource() => _innerObject!;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/PreWrapObjectDumpHelper.cs",
    "content": "﻿using System.Reflection;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.PropertyDump;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\n\nnamespace ToSic.Sxc.Data.Sys.Wrappers;\ninternal class PreWrapObjectDumpHelper\n{\n    public const string DumpSourceName = \"DynamicRead\";\n\n\n    public List<PropertyDumpItem> _Dump(PreWrapObject preWrap, Dictionary<string, PropertyInfo> propDic,\n        ICodeDataPoCoWrapperService wrapperSvc, PropReqSpecs specs, string path, IPropertyDumpService dumpService)\n    {\n        if (string.IsNullOrEmpty(path))\n            path = DumpSourceName;\n\n        var allProperties = propDic.ToList();\n\n        var simpleProps = allProperties;\n        var resultDynChildren = simpleProps\n            .Select(p => new\n            {\n                Field = p.Key,\n                Pdi = new PropertyDumpItem\n                {\n                    Path = path + PropertyDumpItem.Separator + p.Key,\n                    Property = preWrap.FindPropertyInternal(specs.ForOtherField(p.Key),\n                        new PropertyLookupPath().Add(\"DynReadObject\", p.Key)),\n                    SourceName = DumpSourceName\n                }\n            })\n            .ToList();\n\n        var deeperProperties = resultDynChildren\n            .Where(r =>\n            {\n                var result = r.Pdi.Property?.Result;\n                return result != null && result is not string && !result.GetType().IsValueType;\n            })\n            .Select(p =>\n            {\n                var maybeDump = wrapperSvc.ChildNonJsonWrapIfPossible(data: p.Pdi.Property!.Result, wrapNonAnon: false,\n                    WrapperSettings.Dyn(children: true, realObjectsToo: true));\n                return new\n                {\n                    p.Field,\n                    CanDump = maybeDump as IPropertyLookup ?? (maybeDump as IHasPropLookup)?.PropertyLookup,\n                };\n            })\n            .Where(p => p.CanDump is not null)\n            .ToList();\n        var deeperLookups = deeperProperties\n            .SelectMany(p => (p.CanDump as IPropertyDumpCustom)?._DumpProperties(specs, path + PropertyDumpItem.Separator + p.Field, dumpService) ?? []);\n\n        var final = resultDynChildren\n            .Where(r => deeperProperties.All(dp => dp.Field != r.Field))\n            .Select(r => r.Pdi)\n            .ToList();\n\n        final.AddRange(deeperLookups);\n\n        return final\n            .OrderBy(p => p.Path)\n            .ToList();\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/PreWrapObject_Debug.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyDump;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\n\nnamespace ToSic.Sxc.Data.Sys.Wrappers;\n\npartial class PreWrapObject: IPropertyDumpCustom\n{\n    [PrivateApi]\n    public List<PropertyDumpItem> _DumpProperties(PropReqSpecs specs, string path, IPropertyDumpService dumpService)\n        => _innerObject == null\n            ? []\n            : new PreWrapObjectDumpHelper()._Dump(this, PropDic, WrapperSvc, specs, path, dumpService);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/WrapperConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Wrappers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class WrapperConstants\n{\n    public const string EmptyJson = \"{}\";\n    public const char JObjStart = '{';\n    public const char JArrayStart = '[';\n    public const string JsonErrorCode = \"error\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/Sys/Wrappers/WrapperSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Data.Sys.Wrappers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic readonly struct WrapperSettings\n{\n    private WrapperSettings(bool wrapChildren, bool wrapRealObjects, bool wrapToDynamic, bool propsRequired = false)\n    {\n        WrapChildren = wrapChildren;\n        WrapRealObjects = wrapRealObjects;\n        WrapToDynamic = wrapToDynamic;\n        PropsRequired = propsRequired;\n    }\n\n    public static WrapperSettings Dyn(bool children, bool realObjectsToo, bool propsRequired = false)\n        => new(wrapChildren: children, wrapRealObjects: realObjectsToo, wrapToDynamic: true, propsRequired: propsRequired);\n\n    public static WrapperSettings Typed(bool children, bool realObjectsToo, bool propsRequired = true)\n        => new(wrapChildren: children, wrapRealObjects: realObjectsToo, wrapToDynamic: false, propsRequired: propsRequired);\n\n    /// <summary>\n    /// Determine if children of this object should be re wrapped into special objects,\n    /// IF they are themselves richer objects (classes, anonymous); but not values.\n    /// </summary>\n    public bool WrapChildren { get; }\n\n    /// <summary>\n    /// Determine if real objects (with an existing class, like non-Anonymous) should also be wrapped.\n    /// </summary>\n    public bool WrapRealObjects { get; }\n\n    /// <summary>\n    /// Determines if wrapping should result in a Dynamic or typed object.\n    /// </summary>\n    public bool WrapToDynamic { get; }\n\n    /// <summary>\n    /// Determine if Get will be strict\n    /// </summary>\n    public bool PropsRequired { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/TypedItem (no namespace)/ITypedItem.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Sxc.Data.Sys.Json;\n\nnamespace ToSic.Sxc.Data;\n\n/// <summary>\n/// A typed item to access <see cref=\"IEntity\"/> data in a strongly typed way.\n/// </summary>\n/// <remarks>\n/// Previously Razor code always used `dynamic` <see cref=\"IDynamicEntity\"/> objects.\n/// This had some disadvantages when working with LINQ or advanced toolbars.\n/// \n/// History: Introduced in 2sxc 16.01\n/// </remarks>\n[PublicApi]\n[JsonConverter(typeof(DynamicJsonConverter))]\npublic partial interface ITypedItem: ITyped, ICanBeEntity, ICanBeItem, IEquatable<ITypedItem>\n{\n    /// <summary>\n    /// The presentation item or `null` if it doesn't exist.\n    /// </summary>\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    ITypedItem? Presentation { get; }\n\n    /// <summary>\n    /// Metadata of the current item, with special features.\n    /// </summary>\n    /// <remarks>\n    /// Added in 16.02\n    /// </remarks>\n    [JsonIgnore] // prevent serialization as it's not a normal property\n    ITypedMetadata Metadata { get; }\n\n    /// <summary>\n    /// Get a special info-object describing a specific field in this item.\n    /// This is a rich object used by other operations which need a lot of context about the item and the field.\n    /// </summary>\n    /// <param name=\"name\">Name of the property</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns></returns>\n    IField? Field(string name,\n        NoParamOrder npo = default,\n        bool? required = default);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/TypedItem (no namespace)/ITypedItem_Adam.cs",
    "content": "﻿using ToSic.Sxc.Adam;\n\nnamespace ToSic.Sxc.Data;\n\npartial interface ITypedItem\n{\n    /// <summary>\n    /// Get the ADAM (Automatic Digital Asset Manager) for this field.\n    /// This is a folder which contains all the files and possibly folders which are uploaded on exactly this field.\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns>The Folder object</returns>\n    /// <remarks>Added in 16.02</remarks>\n    IFolder? Folder(string name,\n        NoParamOrder npo = default,\n        bool? required = default);\n\n    /// <summary>\n    /// Get the file of the current field.\n    /// There are a few scenarios:\n    /// \n    /// 1. If it's a file/hyperlink field pointing to a file such as `file:27` it will retrieve the file itself.\n    /// 1. If it's a file/hyperlink field pointing to a url such as `http://xyz` it will return `null`.\n    /// 1. If it's a library field, it will just take the first file, as there is no value referencing a specific field\n    /// 1. If it's any other field, will return `null`\n    /// </summary>\n    /// <param name=\"name\">property name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <remarks>Added in 16.02</remarks>\n    /// <returns></returns>\n    IFile? File(string name,\n        NoParamOrder npo = default,\n        bool? required = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/TypedItem (no namespace)/ITypedItem_Relationships.cs",
    "content": "﻿using ToSic.Sxc.Data.Options;\nusing ToSic.Sxc.Data.Sys.Docs;\n\nnamespace ToSic.Sxc.Data;\n\npartial interface ITypedItem\n{\n    #region parents / children\n\n    /// <inheritdoc cref=\"ITypedRelationshipsDocs.Child\"/>\n    ITypedItem? Child(string name, NoParamOrder npo = default, bool? required = default, GetRelatedOptions? options = default);\n\n    /// <inheritdoc cref=\"ITypedRelationshipsDocs.Children\"/>\n    IEnumerable<ITypedItem> Children(string? field = default, NoParamOrder npo = default, string? type = default, bool? required = default, GetRelatedOptions? options = default);\n\n    /// <inheritdoc cref=\"ITypedRelationshipsDocs.Parent\"/>\n    ITypedItem? Parent(NoParamOrder npo = default, bool? current = default, string? type = default, string? field = default, GetRelatedOptions? options = default);\n\n    /// <inheritdoc cref=\"ITypedRelationshipsDocs.Parents\"/>\n    IEnumerable<ITypedItem> Parents(NoParamOrder npo = default, string? type = default, string? field = default, GetRelatedOptions? options = default);\n\n    #endregion\n\n    #region New Child<T> / Children<T>\n\n    /// <summary>\n    /// Get a child and return with specified custom type.\n    /// </summary>\n    /// <param name=\"name\">Name of the field</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New v17.05\n    /// </remarks>\n    public T? Child<T>(string name, NoParamOrder npo = default, bool? required = default, GetRelatedOptions? options = default)\n        where T : class, IModelFromData, new();\n\n    /// <summary>\n    /// A **strongly typed** list of sub-items. Important for LINQ style querying or just\n    /// working with various lists. Note that for getting child items of this item you\n    /// can just use the properties, like content.Authors. <br/>\n    /// But using Children(\"Authors\", type: typeName) gives you the ability to restrict to a type.  <br/>\n    /// Please check the tutorials on 2sxc.org/dnn-tutorials/ for more info. \n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"field\">Name of the field</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"type\">Optional type filter - would only return items of this type. </param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New v17.05\n    /// Never null, unless explicitly requested with `nullIfNull`, otherwise it would return an empty list.\n    /// </remarks>\n    public IEnumerable<T> Children<T>(string? field = default, NoParamOrder npo = default,\n        string? type = default, bool? required = default, GetRelatedOptions? options = default)\n        where T : class, IModelFromData, new();\n\n    /// <summary>\n    /// Get either the _current_ parent or the first parent which would be found on `.Parents(...)` as **strongly typed**.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"current\">if set to `true`, will get the Item which created the current item (the parent) which called `.Child(...)` or `.Children(...)`</param>\n    /// <param name=\"type\">Optional type filter - would only return items of this type. </param>\n    /// <param name=\"field\">Optional field filter - would only return items that point to the current item in a specific field name.</param>\n    /// <returns>_either_ the current parent _or_ the first parent returned by the same `.Parents(...)` call.</returns>\n    /// <returns></returns>\n    /// <remarks>\n    /// New v17.06\n    /// </remarks>\n    public T? Parent<T>(NoParamOrder npo = default, bool? current = default, string? type = default,\n        string? field = default, GetRelatedOptions? options = default)\n        where T : class, IModelFromData, new();\n\n    /// <summary>\n    /// A **typed** list of entities which point to this item. Important for LINQ style querying or just\n    /// working with various lists. Note that for getting child items of this item you\n    /// can just use the properties, like content.Authors. <br/>\n    /// Please check the tutorials on 2sxc.org/dnn-tutorials/ for more info. \n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"type\">Optional type filter - would only return items of this type. If not specified (null) will use the name of T.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"field\">Optional field filter - would only return items that point to the current item in a specific field name.</param>\n    /// <returns>A list of all items pointing here (filtered), converted to DynamicEntity for convenience.</returns>\n    /// <remarks>Note that the parameter-order is reversed to the Children()</remarks>\n    /// <returns></returns>\n    /// <remarks>\n    /// New v17.06\n    /// Never null. If not found, will return an empty list.\n    /// </remarks>\n    public IEnumerable<T> Parents<T>(NoParamOrder npo = default,\n        string? type = default, string? field = default, GetRelatedOptions? options = default)\n        where T : class, IModelFromData, new();\n\n    #endregion\n\n    /// <summary>\n    /// True if this item version is published.\n    /// This means that the item can exist as published, or published-with-draft, showing the published version.\n    /// \n    /// _Note that by default, end-users only see the published version and don't see any draft version._\n    /// </summary>\n    /// <remarks>New in v17, see also <see cref=\"Publishing\"/></remarks>\n    bool IsPublished { get; }\n\n    IPublishing Publishing { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/TypedItem (no namespace)/ITypedItem_SharedCms.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Cms.Data;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Tweaks;\n\nnamespace ToSic.Sxc.Data;\n\npartial interface ITypedItem\n{\n    /// <summary>\n    /// Many templates show demo data.\n    /// If the template code must know if it's the demo item or\n    /// real data, use `.IsDemoItem`.\n    /// </summary>\n    /// <returns>\n    /// True if this is the item configured in the view-settings, false if not.\n    /// </returns>\n    bool IsDemoItem { get; }\n\n    /// <summary>\n    /// Show a field in the expected / best possible way.\n    /// As of now it's meant for WYSIWYG fields with Very-Rich Text.\n    /// See [](xref:NetCode.DynamicData.DynamicEntityHtml)\n    /// </summary>\n    /// <param name=\"name\">the field name</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"container\">\n    /// A wrapper tag for the result.\n    /// It's either a RazorBlade tag such as `Kit.HtmlTag.Div()`, a string such as `span` or an empty string `` to indicate no container.\n    /// If not set it will default to to a div-tag.\n    /// See [docs](xref:NetCode.DynamicData.DynamicEntityHtml)\n    /// </param>\n    /// <param name=\"toolbar\">Override default toolbar behavior on this field. See [docs](xref:NetCode.DynamicData.DynamicEntityHtml)</param>\n    /// <param name=\"imageSettings\">Settings for resizing. Default is `Wysiwyg` but it can also be `Content` or a settings object.</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <param name=\"debug\">Activate debug visualization to better see alignments and such.</param>\n    /// <param name=\"tweak\">tweak behavior - ATM modify the input before it's processed new in v17</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Added in 2sxc 16.01\n    /// * Added `tweak` in v17\n    /// * Only works on Razor files inheriting from Hybrid14 or newer\n    /// </remarks>\n    IHtmlTag? Html(\n        string name,\n        NoParamOrder npo = default,\n        object? container = default,\n        bool? toolbar = default,\n        object? imageSettings = default,\n        bool? required = default,\n        bool debug = default,\n        Func<ITweakInput<string>, ITweakInput<string>>? tweak = default\n    );\n\n\n    /// <summary>\n    /// Get a Responsive Picture object which you can then either just show, or use to construct a more customized output as you need it.\n    /// \n    /// The resulting object can just be added to the html, like `@pic` or you can work with sub-properties as specified in the <see cref=\"IResponsivePicture\"/>.\n    /// \n    /// **Important:** This call only allows you to set the most common parameters `factor` and `width`.\n    /// For other parameters like `height`, `aspectRatio`, `quality` etc. create typed Settings <see cref=\"IImageService.Settings\"/> and pass them in.\n    ///\n    /// > [!NOTE]\n    /// > This is the similar as using the <see cref=\"IImageService.Picture\"/> just a bit simpler.\n    /// >\n    /// > An important difference is that it returns `null` if the field does not exist or is empty, allowing you to just show nothing or use `...Picture(...) ?? someFallback;`\n    /// </summary>\n    /// <param name=\"name\">Name of a field</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">\n    /// Tweak API to configure everything (new v18.03).\n    /// This is recommended above using parameter names and all newer parameters will only be available on this.\n    /// </param>\n    /// <param name=\"settings\">\n    /// - The name of a settings configuration, like \"Content\", \"Screen\", \"Square\", etc.\n    /// - A standardized Image-Settings object like Settings.Child(\"Images.Content\") - see https://go.2sxc.org/settings\n    /// - A dynamic object containing settings properties (this can also be a merged custom + standard settings)\n    /// - A strictly typed <see cref=\"IResizeSettings\"/> object containing all settings created using <see cref=\"ToSic.Sxc.Services.IImageService.Settings\">ResizeSettings</see> \n    /// </param>\n    /// <param name=\"factor\">An optional multiplier, usually used to create urls which resize to a part of the default content-size. Like 0.5. </param>\n    /// <param name=\"width\">An optional, fixed width of the image</param>\n    /// <param name=\"imgAlt\">\n    /// Optional `alt` attribute on the created `img` tag for SEO etc.\n    /// If supplied, it takes precedence to the alt-description in the image metadata which the editor added themselves.\n    /// If you want to provide a fallback value (in case the metadata has no alt), use `imgAltFallback`\n    /// </param>\n    /// <param name=\"imgAltFallback\">\n    /// Optional `alt` attribute which is only used if the `imgAlt` or the alt-text in the metadata are empty.\n    /// </param>\n    /// <param name=\"imgClass\">Optional `class` attribute on the created `img` tag</param>\n    /// <param name=\"toolbar\">Provide a custom toolbar or `false` to not show a toolbar</param>\n    /// <param name=\"imgAttributes\">Optional additional attributes - as anonymous object like `new { style = \"padding: 10px\" }` or Dictionary (new 16.07)</param>\n    /// <param name=\"pictureClass\">Optional `class` attribute on the created `picture` tag</param>\n    /// <param name=\"pictureAttributes\">Optional additional attributes - as anonymous object like `new { style = \"padding: 10px\" }` or Dictionary (new 16.07)</param>\n    /// <param name=\"recipe\">\n    /// Optional recipe = instructions how to create the various variants of this link.\n    /// Can be any one of these:\n    /// \n    /// - string containing variants\n    /// - Rule object\n    /// \n    /// TO DO: DOCS for this not quite ready\n    /// </param>\n    /// <returns>\n    /// * A <see cref=\"IResponsivePicture\"/> object which can be rendered directly. See [](xref:NetCode.Images.Index)\n    /// * If the field does not exist, it will return `null`\n    /// * If the field exists, but is empty, it will return `null`\n    /// </returns>\n    /// <remarks>\n    /// * Added to ITypedItem in v16.03\n    /// * `imgAttributes`, `picClass` and `picAttributes` added in 16.07\n    /// * `tweak` added in 18.03\n    /// </remarks>\n    IResponsivePicture? Picture(\n        string name,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? settings = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        string? pictureClass = default,\n        object? pictureAttributes = default,\n        object? toolbar = default,\n        object? recipe = default\n    );\n\n    /// <summary>\n    /// Get a Responsive Picture object which you can then either just show, or use to construct a more customized output as you need it.\n    /// \n    /// The resulting object can just be added to the html, like `@pic` or you can work with sub-properties as specified in the <see cref=\"IResponsivePicture\"/>.\n    /// \n    /// **Important:** This call only allows you to set the most common parameters `factor` and `width`.\n    /// For other parameters like `height`, `aspectRatio`, `quality` etc. create typed Settings <see cref=\"IImageService.Settings\"/> and pass them in.\n    ///\n    /// > [!NOTE]\n    /// > This is the similar as using the <see cref=\"IImageService.Picture\"/> just a bit simpler.\n    /// >\n    /// > An important difference is that it returns `null` if the field does not exist or is empty, allowing you to just show nothing or use `...Picture(...) ?? someFallback;`\n    /// </summary>\n    /// <param name=\"name\">Name of a field</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">\n    /// Tweak API to configure everything (new v18.03).\n    /// This is recommended above using parameter names and all newer parameters will only be available on this.\n    /// </param>\n    /// <param name=\"settings\">\n    /// - The name of a settings configuration, like \"Content\", \"Screen\", \"Square\", etc.\n    /// - A standardized Image-Settings object like Settings.Child(\"Images.Content\") - see https://go.2sxc.org/settings\n    /// - A dynamic object containing settings properties (this can also be a merged custom + standard settings)\n    /// - A strictly typed <see cref=\"IResizeSettings\"/> object containing all settings created using <see cref=\"ToSic.Sxc.Services.IImageService.Settings\">ResizeSettings</see> \n    /// </param>\n    /// <param name=\"factor\">An optional multiplier, usually used to create urls which resize to a part of the default content-size. Like 0.5. </param>\n    /// <param name=\"width\">An optional, fixed width of the image</param>\n    /// <param name=\"imgAlt\">\n    /// Optional `alt` attribute on the created `img` tag for SEO etc.\n    /// If supplied, it takes precedence to the alt-description in the image metadata which the editor added themselves.\n    /// If you want to provide a fallback value (in case the metadata has no alt), use `imgAltFallback`\n    /// </param>\n    /// <param name=\"imgAltFallback\">\n    /// Optional `alt` attribute which is only used if the `imgAlt` or the alt-text in the metadata are empty.\n    /// </param>\n    /// <param name=\"imgClass\">Optional `class` attribute on the created `img` tag</param>\n    /// <param name=\"toolbar\">Provide a custom toolbar or `false` to not show a toolbar</param>\n    /// <param name=\"imgAttributes\">Optional additional attributes - as anonymous object like `new { style = \"padding: 10px\" }` or Dictionary (new 16.07)</param>\n    /// <param name=\"recipe\">\n    /// Optional recipe = instructions how to create the various variants of this link.\n    /// Can be any one of these:\n    /// \n    /// - string containing variants\n    /// - Rule object\n    /// \n    /// TODO: DOCS not quite ready\n    /// </param>\n    /// <returns>\n    /// * A <see cref=\"IResponsivePicture\"/> object which can be rendered directly. See [](xref:NetCode.Images.Index)\n    /// * If the field does not exist, it will return `null`\n    /// * If the field exists, but is empty, it will return `null`\n    /// </returns>\n    /// <remarks>\n    /// * Added to ITypedItem in v17.04 (previously only Picture was available)\n    /// * `tweak` added in 18.03\n    /// </remarks>\n    IResponsiveImage? Img(\n        string name,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? settings = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        object? toolbar = default,\n        object? recipe = default\n    );\n\n    /// <summary>\n    /// Get the GPS coordinates of a GPS field as a typed object.\n    /// </summary>\n    /// <param name=\"name\">Name of a field</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"required\">throw error if `name` doesn't exist, see [](xref:NetCode.Conventions.PropertiesRequired)</param>\n    /// <returns></returns>\n    /// <remarks>New in v17.03</remarks>\n    GpsCoordinates Gps(string name, NoParamOrder npo = default, bool? required = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Data/TypedItem (no namespace)/ITypedItem_ShortEntityProperties.cs",
    "content": "﻿namespace ToSic.Sxc.Data;\n\npartial interface ITypedItem\n{\n    /// <summary>\n    /// The ID of the underlying entity.\n    /// Use it for edit-functionality or just to have a unique number for this item.\n    /// </summary>\n    /// <remarks>If the entity doesn't exist, it will return 0</remarks>\n    int Id { get; }\n\n    /// <summary>\n    /// The guid of the underlying entity.\n    /// </summary>\n    /// <remarks>If the entity doesn't exist, it will return an empty guid</remarks>\n    Guid Guid { get; }\n\n    /// <summary>\n    /// The title of this item. This is always available no matter what the underlying field for the title is. \n    /// </summary>\n    /// <returns>\n    /// The title of the underlying entity.\n    /// In rare cases where no title-field is known, it can be null.\n    /// It can also be null if there is no underlying entity. \n    /// </returns>\n    /// <remarks>This returns a string which is usually what's expected. In previous versions (before v15) 2sxc it returned an object.</remarks>\n    string? Title { get; }\n\n    /// <summary>\n    /// The Content-Type of the current entity.\n    /// </summary>\n    IContentType Type { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder.cs",
    "content": "﻿using ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Edit.Toolbar;\n\n/// <summary>\n/// The toolbar builder helps you create Toolbar configurations for the UI.\n/// Note that it has a fluid API, and each method/use returns a fresh object with the updated configuration.\n/// </summary>\n/// <remarks>\n/// Your code cannot construct this object by itself, as it usually needs additional information.\n/// To get a `ToolbarBuilder`, use the [](xref:ToSic.Sxc.Services.IToolbarService).\n///\n/// * uses the [](xref:NetCode.Conventions.Functional)\n/// \n/// History\n/// * Added in 2sxc 13, just minimal API\n/// * massively enhanced in v14.04\n/// * most commands extended with [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) in v15.07\n/// </remarks>\n[PublicApi]\npublic partial interface IToolbarBuilder: IRawHtmlString, IHasLog;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_Buttons.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Add a custom button / command.\n    /// Can also be used to do advanced remove operations or modify a button on a toolbar which would have it by default. \n    /// </summary>\n    /// <param name=\"name\">\n    /// 1. The _required_ name of the command.\n    /// See [](xref:Api.Js.SxcJs.CommandNames).\n    /// \n    /// 2. Can also be a full rule-string containing parameters and more\n    /// according to the conventions of the [js toolbar](xref:JsCode.Toolbars.Simple)\n    /// </param>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <param name=\"context\"></param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Button(\n        string name,\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null,\n        string? context = null\n    );\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_CommandsAdmin.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Create button to **admin the app**.\n    /// Can also be used to remove the same button on a toolbar which would have it by default. \n    /// </summary>\n    /// <param name=\"target\">_not used ATM_ just here for API consistency</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"operation\">\n    /// _optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation).\n    /// By default, the button will show based on conditions like permissions.\n    /// </param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder App(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to open the **import-app** dialog.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">_not used ATM_ just here for API consistency</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"operation\">\n    /// _optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation).\n    /// By default, the button will show based on conditions like permissions.\n    /// </param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder AppImport(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **edit the app resources** if there are any.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">_not used ATM_ just here for API consistency</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"operation\">\n    /// _optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation).\n    /// By default, the button will show based on conditions like permissions.\n    /// </param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder AppResources(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **edit the custom app settings** if there are any.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">_not used ATM_ just here for API consistency</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"operation\">\n    /// _optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation).\n    /// By default, the button will show based on conditions like permissions.\n    /// </param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder AppSettings(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to open the **apps management** of the current site.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">_not used ATM_ just here for API consistency</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"operation\">\n    /// _optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation).\n    /// By default, the button will show based on conditions like permissions.\n    /// </param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Apps(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to open the **system admin** dialog.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">_not used ATM_ just here for API consistency</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"operation\">\n    /// _optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation).\n    /// By default, the button will show based on conditions like permissions.\n    /// </param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder System(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to open the **insights** for debugging.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">_not used ATM_ just here for API consistency</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"operation\">\n    /// _optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation).\n    /// By default, the button will show based on conditions like permissions.\n    /// </param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Insights(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_CommandsForLists.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Create button to **add a new entity** to a list of entities.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// _optional_ entity-like target which is in a list of items in on a content-block,\n    /// see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"contentType\"></param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Add(\n        object? target = null,\n        NoParamOrder npo = default,\n        string? contentType = null,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **add an existing** entity to the list.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// _optional_ entity-like target which is in a list of items in on a content-block,\n    /// see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"contentType\"></param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder AddExisting(\n        object? target = null,\n        NoParamOrder npo = default,\n        string? contentType = null,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **manage the list** of entities shown here.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// _optional_ entity-like target which is in a list of items in on a content-block,\n    /// see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder List(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **move an item down** in a list.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// _optional_ entity-like target which is in a list of items in on a content-block,\n    /// see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder MoveDown(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **move an item up** in a list.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// _optional_ entity-like target which is in a list of items in on a content-block,\n    /// see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder MoveUp(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **remove an item** from a list.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// This will not delete the item, just remove. \n    /// </summary>\n    /// <param name=\"target\">\n    /// _optional_ entity-like target which is in a list of items in on a content-block,\n    /// see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Remove(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **replace the current item** in the list with another existing item.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// _optional_ entity-like target which is in a list of items in on a content-block,\n    /// see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Replace(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_CommandsItems.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Create (or reconfigure) the button to **delete an item**.\n    /// \n    /// This has a special behavior.\n    /// The `default` toolbar already includes a delete-button in the third group.\n    /// So if the toolbar is is a `default` this will just modify it to force-show.\n    /// But it will still be in the third group of buttons.\n    /// \n    /// For the `empty` toolbar it will just add the button in the normal way.\n    ///\n    /// To change this automatic behavior, use a `operation` = `modify` or `add`\n    /// </summary>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Delete(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **edit an item**.\n    /// Can also be used to remove the same button on a toolbar which would have it by default. \n    /// </summary>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"prefill\">_optional_ prefill for the edit-UI, see [prefill guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Prefill)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Edit(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = default,\n        object? parameters = default, \n        object? prefill = default,\n        string? operation = default\n    );\n\n    /// <summary>\n    /// Create button to **create a new item**.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// X Options\n    /// * an entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// * a string with the content-type name\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"prefill\">_optional_ prefill for the edit-UI, see [prefill guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Prefill)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder New(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create button to **show a data-admin dialog** with all the data-items / entities of a specific content type.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// 3 Options: \n    /// * an entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// * a `string` containing the type name\n    /// * a modifier keyword such as `remove` or `-` to remove the button\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"filter\">object or string with the filters for the data view see [filter](xref:ToSic.Sxc.Services.ToolbarBuilder.DataFilter)</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Data(\n        object? target = null, // entity-like or content-type name\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? filter = null,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n\n    /// <summary>\n    /// Create button to **add or edit metadata** to the specified object and using the content-type specified here.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">\n    /// The target object which should receive metadata.\n    /// Must support <see cref=\"ToSic.Eav.Metadata.IHasMetadata\"/>.\n    /// Often an entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target),\n    /// but can also other metadata supporting objects, like an Asset, Page, Site, etc.\n    /// </param>\n    /// <param name=\"contentTypes\">Name of one or more content-types for which to generate the button(s). For many, use comma `,` to separate. If not specified, will try to lookup config (v14)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <param name=\"context\">EXPERIMENTAL - not final</param>\n    /// <param name=\"prefill\">_optional_ prefill for the edit-UI, see [prefill guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Prefill)</param>\n    /// <returns>A new toolbar builder which has been extended with this button</returns>\n    /// <remarks>\n    /// History\n    /// * Added in 2sxc 13\n    /// * contentTypes changed from one to many in v14\n    /// * contentTypes can also have `*` or `SomeType,*` in v14\n    /// * contentTypes can also be optional, in which case it behaves as if it was `*` in v14 - if no config is found, it will not add a metadata-button\n    /// * parameter context added in 2sxc 14 - still WIP/experimental\n    /// * changed ui and parameters to support object in v14.04\n    /// </remarks>\n    IToolbarBuilder Metadata(\n        object target,\n        string? contentTypes = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? operation = null,\n        string? context = null\n    );\n\n    /// <summary>\n    /// Create button to publish the current item.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// By default it will only appear if the current item is draft/unpublished.\n    /// You can change this (but probably shouldn't) by setting an `operation`. \n    /// </summary>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Publish(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n\n    /// <summary>\n    /// Create button to **copy an item**.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// It needs the item which it will copy as a parameter.\n    /// </summary>\n    /// <param name=\"target\">\n    /// * an entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)\n    /// * can also be a int (number) entityId. If you only supply the entity ID, you must also supply the `contentType`.\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"contentType\"></param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <param name=\"context\">EXPERIMENTAL - not final</param>\n    /// <param name=\"prefill\">_optional_ prefill for the edit-UI, see [prefill guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Prefill)</param>\n    /// <returns>A new toolbar builder which has been extended with this button</returns>\n    /// <remarks>\n    /// Added in v14.02\n    /// </remarks>\n    IToolbarBuilder Copy(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        string? contentType = null,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? operation = null,\n        string? context = null\n    );\n\n        \n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_CommandsView.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Create Button to **change the view/layout** of the data shown on the page.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\">_not used ATM_ just here for API consistency</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Layout(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create Button to **run JS code**.\n    /// Can also be used to remove the same button on a toolbar which would have it by default. \n    /// </summary>\n    /// <param name=\"target\">Name of the function to call, without parameters. </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Code(\n        object target,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create Button to open a dialog to **manage the fields/attributes** of the content type.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Fields(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create Button to **open the edit-template** (source-code) dialog.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Template(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create Button to **open the design/edit query** dialog.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Query(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create Button to open the **edit view settings** dialog.\n    /// Can also be used to remove the same button on a toolbar which would have it by default.\n    /// </summary>\n    /// <param name=\"target\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"operation\">_optional_ change [what should happen](xref:ToSic.Sxc.Services.ToolbarBuilder.Operation)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder View(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    );\n\n    /// <summary>\n    /// Create Button to let the user switch to other app editions.\n    ///\n    /// Note that by default, this functionality is also on the `Layout` button, but there are cases\n    /// where a user won't see that (like a non-admin) and you may still want to provide them this feature.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"editions\">Optional list of editions, like `staging,live`. By default, it would take the editions in the `app.json`.</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    /// <remarks>new v17.08, should be considered experimental ATM</remarks>\n    IToolbarBuilder Edition(\n        NoParamOrder npo = default,\n        string? editions = default,\n        Func<ITweakButton, ITweakButton>? tweak = default\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_Context.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\ninternal interface IToolbarBuilderInternal\n{\n    [PrivateApi(\"WIP / Debugging\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    ToolbarContext? GetContext();\n\n    [PrivateApi(\"WIP 14.07.04\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IToolbarBuilder Context(\n        object target\n    );\n}\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Set the main target of this toolbar.\n    /// </summary>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    /// <remarks>\n    /// New in v14.04\n    /// </remarks>\n    IToolbarBuilder For(object target);\n\n    /// <summary>\n    /// Detect if the toolbar should go into demo-mode.\n    /// \n    /// </summary>\n    /// <param name=\"root\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"message\">Optional message or a resources key such as `Resources.ToolbarShowingDemo`</param>\n    /// <returns></returns>\n    [InternalApi_DoNotUse_MayChangeWithoutNotice(\"WIP 16.02\")]\n    IToolbarBuilder DetectDemo(\n        ICanBeEntity root,\n        NoParamOrder npo = default,\n        string? message = default);\n\n    /// <summary>\n    /// Condition to apply if the toolbar would show, but maybe shouldn't.\n    /// For example, you can prevent the toolbar from appearing if it's the Demo-Item.\n    ///\n    /// For expensive conditions, use the overload which accepts a function. \n    /// </summary>\n    /// <param name=\"condition\">true/false</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    /// <remarks>\n    /// New in v14.04\n    /// </remarks>\n    IToolbarBuilder Condition(bool condition);\n\n    /// <summary>\n    /// Condition to apply if the toolbar would show, but maybe shouldn't.\n    /// For example, you can prevent the toolbar from appearing if it's the Demo-Item.\n    ///\n    /// This accepts a function to check the condition.\n    /// It will only run if the toolbar would already show. \n    /// </summary>\n    /// <param name=\"condition\">function such as `() => true`</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    /// <remarks>\n    /// New in v14.04\n    /// </remarks>\n    IToolbarBuilder Condition(Func<bool> condition);\n\n    /// <summary>\n    /// Specify an audience for the toolbar - to activate even if the user wouldn't normally see it.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"everyone\">default is `null`, set to true to make everybody see this.</param>\n    /// <param name=\"roleNames\">list/array of role names which should _also_ see the toolbar (new v20)</param>\n    /// <param name=\"denyRoleNames\">list/array of role names which should _never_ see the toolbar - has precedence over allow (new v20)</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Normally only people with admin permissions would see a toolbar.\n    /// Specifying the audience will make it appear even if you are not an admin.\n    /// \n    /// Reasons for this would be to have some special buttons for a certain group of users.\n    ///\n    /// * New in v17.08, experimental\n    /// * released v19\n    /// * updated with roleNames/denyRoleNames v20\n    /// </remarks>\n    IToolbarBuilder Audience(\n        NoParamOrder npo = default,\n        bool? everyone = default,\n        IEnumerable<string>? roleNames = default,\n        IEnumerable<string>? denyRoleNames = default);\n\n    /// <summary>\n    /// Adds a button group to the toolbar.\n    /// All following buttons will be in this group automatically.\n    ///\n    /// Can also be used to remove a group of buttons on the `default` toolbar, such as the group `view`.\n    /// See [list of groups on default](xref:Basics.Browser.EditUx.Toolbars.ButtonGroups)\n    /// </summary>\n    /// <param name=\"name\">_optional_ - name of new group or `-name` to remove an existing group.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New in v14.08\n    /// </remarks>\n    IToolbarBuilder Group(string? name = null);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_InfoNote.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Create an info, warning, help or link-button to assist the user.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"target\">the target window, like `_blank` - new in v17; defaults to `null` so that ctrl-click etc. work as expected</param>\n    /// <param name=\"tweak\">Optional function call to tweak the button.</param>\n    /// <param name=\"link\">If provided, will make the button open the link in a new window.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Added in v15.07\n    /// * `target` added in v17 - defaults to nothing, so if you explicitly want a new window, you must set it to `_blank`\n    /// </remarks>\n    IToolbarBuilder Info(\n        NoParamOrder npo = default,\n        string? link = default,\n        string? target = default,\n        Func<ITweakButton, ITweakButton>? tweak = default\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_Output.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Get a toolbar builder which would render to HTML as a standalone tag.\n    ///\n    /// **Important:** Toolbars created using this will behave differently from previous standalone toolbars.\n    /// These standalone toolbars will _not_ float automatically as previous ones did.\n    /// You can still get them to float by adjusting the Settings as you need them.\n    /// \n    /// This is because many years ago, standalone toolbars were configured floated automatically.\n    /// As the APIs got better, this wasn't a great default any more, but we couldn't introduce a breaking change.\n    /// Anything created now with this new API will be new, so this will behave more in line with expectations.\n    /// See also [issue](https://github.com/2sic/2sxc/issues/2838)\n    /// </summary>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder AsTag(\n        object? target = null\n    );\n\n    /// <summary>\n    /// Get a toolbar builder which would render to HTML as attributes on an existing tag.\n    /// Note that this is the default, so you will usually not need this. \n    /// </summary>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder AsAttributes(\n        object? target = null\n    );\n\n\n    /// <summary>\n    /// Test code\n    /// </summary>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    [PrivateApi(\"wip\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IToolbarBuilder AsJson(\n        object? target = null\n    );\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/Builder/IToolbarBuilder_SettingsAndParams.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\npublic partial interface IToolbarBuilder\n{\n    /// <summary>\n    /// Add a `more` button. Not really useful to do, but included for completeness\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder More(\n        NoParamOrder npo = default,\n        object? ui = default\n    );\n\n    /// <summary>\n    /// Add a `settings` rule to configure what the toolbar should look like. See [](xref:JsCode.Toolbars.Settings)\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"show\">`hover` (default), `always`</param>\n    /// <param name=\"hover\">`right` (default), `left`</param>\n    /// <param name=\"follow\"></param>\n    /// <param name=\"classes\">css class names to add to the entire toolbar</param>\n    /// <param name=\"autoAddMore\">placement of the _more_ ellipsis button, `auto` (default), `end`, `start`, `never`</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">Parameters for the command - doesn't really have an effect on Settings, but included for consistency</param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    /// <remarks>\n    /// History\n    /// * Added in 2sxc 13\n    /// * options `auto` and `never` on autoAddMore added in 14.08\n    /// </remarks>\n    IToolbarBuilder Settings(\n        NoParamOrder npo = default,\n        string? show = default,\n        string? hover = default,\n        string? follow = default,\n        string? classes = default,\n        string? autoAddMore = default,\n        object? ui = default,\n        object? parameters = default\n    );\n\n    /// <summary>\n    /// Adds / updates the `params` rule on the toolbar which contains information for all the buttons\n    /// </summary>\n    /// <param name=\"target\">\n    /// Many options\n    /// 1. An Entity-like thing which would be used to prepare default params like `entityId`\n    /// 1. A string, which would be the same as using the term on the `parameters`\n    /// 1. An object - especially an anonymous object like `new { id = 7, show = true }`\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters (new v16.02)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"prefill\">_optional_ prefill for the edit-UI, see [prefill guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Prefill)</param>\n    /// <param name=\"context\"></param>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    IToolbarBuilder Parameters(\n        object? target = default,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = default,\n        object? parameters = default,\n        object? prefill = default,\n        string? context = default\n    );\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/ToolbarContext.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Apps;\n\nnamespace ToSic.Sxc.Edit.Toolbar;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ToolbarContext: IAppIdentity\n{\n    internal const string CtxZone = \"context:zoneId\";\n    internal const string CtxApp = \"context:appId\";\n    internal const int NotInitialized = -7007;\n\n    internal ToolbarContext(IAppIdentity parent): this(parent.ZoneId, parent.AppId) { }\n\n    public ToolbarContext(int zoneId, int appId)\n    {\n        ZoneId = zoneId;\n        AppId = appId;\n    }\n\n    internal ToolbarContext(string custom)\n        => Custom = custom;\n\n\n    [JsonPropertyName(\"zoneId\")]\n    public int ZoneId { get; } = NotInitialized;\n\n    [JsonPropertyName(\"appId\")]\n    public int AppId { get; } = NotInitialized;\n\n    [JsonPropertyName(\"custom\")][JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Custom { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Edit.Toolbar/TweakButton/ITweakButton.cs",
    "content": "﻿using System.Collections.Immutable;\n\nnamespace ToSic.Sxc.Edit.Toolbar;\n\n/// <summary>\n/// Experimental new API in v15.07 to improve how to configure the Ui of a button.\n///\n/// > [!TIP]\n/// > Read more about this in [](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons)\n/// </summary>\n/// <remarks>\n/// Added in v15.07\n/// </remarks>\n[PublicApi]\npublic interface ITweakButton\n{\n    #region UI\n\n    /// <summary>\n    /// Add a floating note to the button.\n    /// </summary>\n    /// <param name=\"note\">The note/message</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"type\">Optional type, like `info` (default), `warning`, `help`</param>\n    /// <param name=\"background\">Background color.</param>\n    /// <param name=\"delay\">Delay show by this duration in ms. If mouse leaves before, it won't appear (new v17).</param>\n    /// <param name=\"linger\">Linger by this duration in ms after the mouse leaves - new v17.</param>\n    /// <param name=\"format\">`html` or `text` (default) - new v17</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Added in v15.07\n    /// * `delay` and `linger` added in v17\n    /// * `format` added in v17\n    /// </remarks>\n    ITweakButton Note(\n        string? note = default,\n        NoParamOrder npo = default,\n        string? type = default,\n        string? background = default,\n        int delay = default,\n        int linger = default,\n        string? format = default\n    );\n\n    /// <summary>\n    /// Set the show of this button.\n    /// </summary>\n    /// <param name=\"show\">Optional show value, default is `true`</param>\n    /// <returns></returns>\n    ITweakButton Show(bool show = true);\n\n    /// <summary>\n    /// Set the color of this button.\n    /// A color can be `red`, `green` or `#FFCC66` as well as transparent colors such as `#FFCC6699`\n    /// </summary>\n    /// <param name=\"color\">The main color parameter. Can contain two values, comma separated.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"background\">Background color - will only take effect if the `color` was not set.</param>\n    /// <param name=\"foreground\">Foreground color - will only take effect if the `color` was not set.</param>\n    /// <returns></returns>\n    ITweakButton Color(\n        string? color = default,\n        NoParamOrder npo = default,\n        string? background = default,\n        string? foreground = default\n    );\n\n    /// <summary>\n    /// Set the title / Tooltip of the button.\n    /// </summary>\n    /// <param name=\"value\">The title/tooltip to show</param>\n    /// <returns></returns>\n    ITweakButton Tooltip(string value);\n\n    /// <summary>\n    /// Set what group the button is in.\n    /// This is rarely used.\n    /// </summary>\n    /// <param name=\"value\">the group name</param>\n    /// <returns></returns>\n    ITweakButton Group(string value);\n\n    /// <summary>\n    /// Set the icon for this button.\n    /// </summary>\n    /// <param name=\"value\">One of a few predefined names, or a SVG string.</param>\n    /// <returns></returns>\n    ITweakButton Icon(string value);\n\n    /// <summary>\n    /// Set one or more classes on the button.\n    /// </summary>\n    /// <param name=\"value\">a string containing one or more CSS class names</param>\n    /// <returns></returns>\n    ITweakButton Classes(string value);\n\n    /// <summary>\n    /// Specify the position of the button.\n    /// `0` means in the very front, `1` is right after the first button, etc.\n    /// `-1` means the last button, `-2` is the second last, etc.\n    /// </summary>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    ITweakButton Position(int value);\n\n    /// <summary>\n    /// Add a general ui-rule for things which are not in the standard API.\n    /// </summary>\n    /// <param name=\"value\">a string such as `this=that` or an object which will be parsed/serialized such as `new { this = 27 }`</param>\n    /// <returns></returns>\n    ITweakButton Ui(object value);\n\n    /// <summary>\n    /// Add a general UI rule for things which are not in the standard API.\n    /// </summary>\n    /// <param name=\"name\">The name/key which comes before the `=`</param>\n    /// <param name=\"value\">The value which comes after the `=`</param>\n    /// <returns></returns>\n    ITweakButton Ui(string name, object value);\n\n    #endregion\n\n    #region Params\n\n    /// <summary>\n    /// Add form-parameters to the button - which are available in the `data.parameters` in formulas.\n    /// </summary>\n    /// <param name=\"value\">A string such as `name=value` or an anonymous object such as `new { name = 27 }`</param>\n    /// <returns></returns>\n    /// <remarks>Added in 16.02</remarks>\n    ITweakButton FormParameters(object value);\n\n    /// <summary>\n    /// Add form-parameters to the button - which are available in the `data.parameters` in formulas.\n    /// </summary>\n    /// <param name=\"name\">The name/key which comes before the `=`</param>\n    /// <param name=\"value\">The value which comes after the `=`</param>\n    /// <returns></returns>\n    /// <remarks>Added in 16.02</remarks>\n    ITweakButton FormParameters(string name, object value);\n\n\n    /// <summary>\n    /// Add parameters to the button - which are usually used when executing the command.\n    ///\n    /// > [!TIP]\n    /// > These parameters are used in the page itself and not forwarded to the form.\n    /// > Use <see cref=\"FormParameters(object)\"/> for that purpose.\n    /// </summary>\n    /// <param name=\"value\">A string such as `name=value` or an anonymous object such as `new { name = 27 }`</param>\n    /// <returns></returns>\n    ITweakButton Parameters(object value);\n\n    /// <summary>\n    /// Add parameters to the button - which are usually used when executing the command.\n    ///\n    /// > [!TIP]\n    /// > These parameters are used in the page itself and not forwarded to the form.\n    /// > Use <see cref=\"FormParameters(object)\"/> for that purpose.\n    /// </summary>\n    /// <param name=\"name\">The name/key which comes before the `=`</param>\n    /// <param name=\"value\">The value which comes after the `=`</param>\n    /// <returns></returns>\n    ITweakButton Parameters(string name, object value);\n\n    /// <summary>\n    /// Add prefill information to the button, usually for creating new Entities.\n    /// </summary>\n    /// <param name=\"value\">A string such as `name=value` or an anonymous object such as `new { name = 27 }`</param>\n    /// <returns></returns>\n    ITweakButton Prefill(object value);\n\n    /// <summary>\n    /// Add prefill information to the button, usually for creating new Entities.\n    /// </summary>\n    /// <param name=\"name\">The name/key which comes before the `=`</param>\n    /// <param name=\"value\">The value which comes after the `=`</param>\n    /// <returns></returns>\n    ITweakButton Prefill(string name, object value);\n\n    /// <summary>\n    /// Add filter information to the button - usually when opening Data dialogs.\n    /// </summary>\n    /// <param name=\"value\">A string such as `name=value` or an anonymous object such as `new { name = 27 }`</param>\n    /// <returns></returns>\n    ITweakButton Filter(object value);\n\n    /// <summary>\n    /// Add filter information to the button - usually when opening Data dialogs.\n    /// </summary>\n    /// <param name=\"name\">The name/key which comes before the `=`</param>\n    /// <param name=\"value\">The value which comes after the `=`</param>\n    /// <returns></returns>\n    ITweakButton Filter(string name, object value);\n\n    /// <summary>\n    /// Tell the Edit-UI which fields to show / edit, so the user sees a smaller focused form.\n    /// </summary>\n    /// <param name=\"value\">A string such as `FirstName,SecondName` listing a CSV of fields to show</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Introduced as a hidden feature in v16\n    /// * released in v20.09\n    /// </remarks>\n    public ITweakButton UiFields(string value);\n\n    #endregion\n\n    /// <summary>\n    /// Optional parameter to skip adding this button-rule.\n    /// </summary>\n    /// <param name=\"value\">if `false`, this button will not be added.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// This may sometimes be confusing:\n    ///\n    /// - most rules are add rules, so if this is false, it will not add the button\n    /// - but if you have a remove rule, it will _not_ remove the button\n    /// </remarks>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    ITweakButton Condition(bool value);\n\n\n    /// <summary>\n    /// Experimental add custom rule. For internal development only. May change at any time.\n    /// </summary>\n    /// <param name=\"prefix\">prefix like `dialog` etc.</param>\n    /// <param name=\"name\"></param>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public ITweakButton XCustom(string prefix, string name, object value);\n\n\n    #region Internal Properties, not part of the public API\n\n    /// <summary>\n    /// List of changes to apply to the UI parameter\n    /// </summary>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    internal IImmutableList<object?> UiMerge { get; }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    internal IImmutableList<object?> ParamsMerge { get; }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    internal bool? ConditionValue { get; }\n\n    /// <summary>\n    /// Named tweaks for situations where the tweak may be needed for multiple buttons,\n    /// each with a different tweak.\n    /// </summary>\n    internal IImmutableDictionary<string, Func<ITweakButton, ITweakButton>> Named { get; }\n\n    /// <summary>\n    /// Special internal add-rule, which is typically on the main toolbar,\n    /// but will then only be applied to buttons with exactly this name...?\n    ///\n    /// Used in image responsive to add notes to the buttons,\n    /// but different notes for e.g. Copyright etc.\n    ///\n    /// Not fully documented or standardized.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"tweak\"></param>\n    /// <returns></returns>\n    internal ITweakButton AddNamed(string name, Func<ITweakButton, ITweakButton> tweak);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Eav.Models;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Wrappers;\nglobal using ToSic.Sys.GetByName;\nglobal using ToSic.Sys.Utils;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/IResizeSettings.cs",
    "content": "﻿using System.Collections.Specialized;\n\nnamespace ToSic.Sxc.Images;\n\n/// <summary>\n/// Settings how to resize an image for the `src` or `srcset` attributes.\n///\n/// It's read only, to create it, use the <see cref=\"ToSic.Sxc.Services.IImageService\"/>\n/// </summary>\n/// <remarks>\n/// History: Released 2sxc 13.10\n/// </remarks>\n[PublicApi(\"Still WIP\")]\npublic interface IResizeSettings\n{\n    /// <summary>\n    /// Name of the original settings it was based on - can be null/empty.\n    /// </summary>\n    /// <remarks>New v17.03</remarks>\n    string? BasedOn { get; }\n\n    /// <summary>\n    /// Width to resize to.\n    /// If 0, width will not be changed\n    /// </summary>\n    int Width { get; }\n\n    /// <summary>\n    /// Height to resize to.\n    /// If 0, height will not be changed\n    /// </summary>\n    int Height { get; }\n\n    /// <summary>\n    /// Quality factor for image formats which support quality.\n    /// Usually a value between 0 and 100.\n    /// If 0, quality will not be changed.\n    /// </summary>\n    int Quality { get; }\n\n    /// <summary>\n    /// Resize mode.\n    /// If empty or \"(none)\" will not be used. \n    /// </summary>\n    string? ResizeMode { get; }\n\n    /// <summary>\n    /// Scale Mode.\n    /// If empty or \"(none)\" will not be used. \n    /// </summary>\n    string? ScaleMode { get; }\n\n    /// <summary>\n    /// Target format like 'jpg' or 'png'.\n    /// If empty will not be used. \n    /// </summary>\n    string? Format { get; }\n\n    /// <summary>\n    /// The resize factor by which the original value (width/height) is scaled\n    /// </summary>\n    double Factor { get; }\n\n    /// <summary>\n    /// The aspect ratio to determine the height, in case no height was specified. \n    /// </summary>\n    double AspectRatio { get; }\n\n    /// <summary>\n    /// Additional url parameters in case the final link would need this.\n    /// Rarely used, but can be used for resize parameters which are not standard. \n    /// </summary>\n    NameValueCollection? Parameters { get; }\n\n    //[PrivateApi(\"WIP\")] \n    //bool UseFactorMap { get; }\n\n    //[PrivateApi(\"WIP\")]\n    //bool UseAspectRatio { get; }\n\n    ///// <summary>\n    ///// Settings which are used when img/picture tags are generated with multiple resizes\n    ///// </summary>\n    //[InternalApi_DoNotUse_MayChangeWithoutNotice(\"Still WIP\")]\n    //AdvancedSettings Advanced { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/IResponsiveImage.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Razor.Html5;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Edit.Toolbar;\n\nnamespace ToSic.Sxc.Images;\n\n/// <summary>\n/// A object which contains everything to create HTML for responsive `img` tags with optimal `srcset` offering all the sizes you may need.\n///\n/// You can simply add this object to the source, like `@image` to render the image - which is the same as `@image.ImgTag`\n/// </summary>\n/// <remarks>\n/// History: Released 2sxc 13.10\n/// </remarks>\n[PublicApi]\npublic interface IResponsiveImage: IRawHtmlString\n{\n    /// <summary>\n    /// An Alt-description on the image which is retrieved from (in order of priority):\n    /// \n    /// 1. the Razor code creating this object using the parameter `imgAlt`\n    /// 2. or from image metadata - see <see cref=\"Description\"/>\n    /// 3. or from the Razor code using the parameter `imgAltFallback` _new v15_\n    /// </summary>\n    string? Alt { get; }\n\n    /// <summary>\n    /// The Class of the image. Usually created from these sources\n    /// - The initial call creating this image tag\n    /// - Resize-Settings which may add classes\n    /// - Rule which determines if the image should crop or not, which may add a class\n    /// </summary>\n    string? Class { get; }\n\n    /// <summary>\n    /// Image description from the image Metadata.\n    /// See also <see cref=\"Alt\"/>.\n    /// </summary>\n    /// <returns>\n    /// * `null` if no metadata exists\n    /// * `\"\"` empty string if metadata exists but no description was given\n    /// * a string containing the added description\n    /// </returns>\n    /// <remarks>Added in v15</remarks>\n    string? Description { get; }\n\n    /// <summary>\n    /// Extended description, typically used in galleries.\n    /// </summary>\n    /// <remarks>Added in v16.04</remarks>\n    string? DescriptionExtended { get; }\n\n    /// <summary>\n    /// The `img` tag which would normally be added to the page automatically.\n    /// You can also use the normal RazorBlade API and do things like `.Alt(\"description\")` etc.\n    /// See also the [RazorBlade Img docs](https://razor-blade.net/api/ToSic.Razor.Html5.Img.html)\n    /// </summary>\n    Img Img { get; }\n\n    /// <summary>\n    /// The outermost tag - name not yet final\n    /// </summary>\n    [PrivateApi(\"Name not yet final\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IHtmlTag Tag { get; }\n\n    /// <summary>\n    /// Determines if the image should be shown entirely.\n    /// This usually means that the image is a logo or something, so cropping was not an option.\n    /// This also usually means that the aspect ratio / height may be different than expected\n    /// </summary>\n    bool ShowAll { get; }\n\n    /// <summary>\n    /// The image height, if it should be set at all. Will be null otherwise. \n    /// </summary>\n    string? Height { get; }\n\n    /// <summary>\n    /// The image width, if it should be set at all. Will be null otherwise. \n    /// </summary>\n    string? Width { get; }\n\n    /// <summary>\n    /// The SrcSet in case you need to use it in your own custom img-tag.\n    /// Note that it will be null if the image has no reason to have a srcset.\n    ///\n    /// It will only be used for normal `img` tags, but not for `img` tags inside `picture` tags.\n    /// </summary>\n    string? SrcSet { get; }\n\n    /// <summary>\n    /// The sizes in case you need it in your custom img-tag.\n    /// It will only be used for normal `img` tags, but not for `img` tags inside `picture` tags.\n    /// </summary>\n    string? Sizes { get; }\n\n    /// <summary>\n    /// Get the toolbar to show it on another tag (typically a `figure` around the `picture`)\n    /// or set another toolbar instead.\n    /// </summary>\n    /// <remarks>Added in v16.04</remarks>\n    [InternalApi_DoNotUse_MayChangeWithoutNotice(\"WIP 16.04, may still change\")]\n    IToolbarBuilder? Toolbar();\n\n    /// <summary>\n    /// The main url, used for main `src` property\n    /// </summary>\n    /// <remarks>Added in v13.11</remarks>\n    string Src { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/IResponsivePicture.cs",
    "content": "﻿using ToSic.Razor.Html5;\nusing ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Images;\n\n/// <summary>\n/// A object which contains everything to create HTML for responsive `picture` tags with optimal `srcset` offering all the sizes you may need\n/// </summary>\n/// <remarks>\n/// History: Released 2sxc 13.10\n/// </remarks>\n[PublicApi]\npublic interface IResponsivePicture: IRawHtmlString, IResponsiveImage\n{\n    /// <summary>\n    /// The `picture` tag with everything automatically included.\n    /// See also the [RazorBlade Picture docs](https://razor-blade.net/api/ToSic.Razor.Html5.Picture.html)\n    /// </summary>\n    Picture Picture { get; }\n\n\n    /// <summary>\n    /// The `source` tags as they were auto-generated, in case you want to build the picture tag manually.\n    /// Contains many `source` tags - see [RazorBlade Source docs](https://razor-blade.net/api/ToSic.Razor.Html5.Source.html)\n    /// </summary>\n    TagList Sources { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/ITweakMedia.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\n\nnamespace ToSic.Sxc.Images;\n\n/// <summary>\n/// Tweak API for various media settings.\n/// Specifically meant for images and pictures.\n///\n/// Some methods such as PictureClass will only have an effect if used on Picture(...) methods. \n/// </summary>\n/// <remarks>\n/// - Added v18.03\n/// - All methods return a <see cref=\"ITweakMedia\"/> to allow chaining.\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"New v18.03, still WIP, especially the name could still change\")]\npublic interface ITweakMedia\n{\n    #region Resize Settings\n\n    /// <summary>\n    /// Configure the Resize Settings.\n    /// </summary>\n    /// <param name=\"tweak\">Tweak API to customize further settings</param>\n    ITweakMedia Resize(Func<ITweakResize, ITweakResize>? tweak = default);\n\n    /// <summary>\n    /// Configure the Resize Settings.\n    /// </summary>\n    /// <param name=\"name\">\n    /// Name of an existing configuration, such as \"Lightbox\".\n    /// If not specified (null) will default to \"Content\".\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Tweak API to customize further settings</param>\n    public ITweakMedia Resize(\n        string? name,\n        NoParamOrder npo = default,\n        Func<ITweakResize, ITweakResize>? tweak = default\n    );\n\n    ITweakMedia Resize(\n        IResizeSettings settings,\n        NoParamOrder npo = default,\n        Func<ITweakResize, ITweakResize>? tweak = default\n    );\n    // Note: Recipe is missing\n\n    #endregion\n\n    #region Lightbox\n\n    /// <summary>\n    /// Force Lightbox to be enabled (or disabled)\n    /// </summary>\n    /// <param name=\"isEnabled\">Optional enabled state, defaults to true</param>\n    ITweakMedia LightboxEnable(bool isEnabled = true);\n\n    /// <summary>\n    /// Group name for lightbox.\n    /// All images with the same group-name will be treated as an album.\n    /// </summary>\n    /// <param name=\"group\"></param>\n    ITweakMedia LightboxGroup(string group);\n\n\n    ITweakMedia LightboxDescription(string description);\n\n    #endregion\n\n    #region Img\n\n    ITweakMedia ImgClass(string imgClass);\n\n    ITweakMedia ImgAlt(string alt);\n\n    ITweakMedia ImgAltFallback(string imgAltFallback);\n\n    ITweakMedia ImgAttributes(IDictionary<string, string> attributes);\n\n    ITweakMedia ImgAttributes(IDictionary<string, object> attributes);\n\n    ITweakMedia ImgAttributes(object attributes);\n\n    #endregion\n\n    #region Picture\n\n    ITweakMedia PictureClass(string pictureClass);\n\n    ITweakMedia PictureAttributes(IDictionary<string, string> attributes);\n\n    ITweakMedia PictureAttributes(IDictionary<string, object> attributes);\n\n    ITweakMedia PictureAttributes(object attributes);\n\n    #endregion\n\n    #region Toolbar\n\n    ITweakMedia Toolbar(bool enabled);\n\n    ITweakMedia Toolbar(IToolbarBuilder toolbar);\n\n    #endregion\n\n    #region TweakInput - attempted in v20.09 but doesn't work - reason is we would have to pass the tweak very, very deep into the system which we stopped\n\n    ///// <inheritdoc cref=\"ITweakInput{IInput}.Input(IInput, NoParamOrder)\"/>\n    //ITweakMedia Input(string replace, NoParamOrder npo = default);\n\n    ///// <inheritdoc cref=\"ITweakInput{IInput}.Input(Func{IInput}, NoParamOrder)\"/>\n    //ITweakMedia Input(Func<string> func, NoParamOrder npo = default);\n\n    ///// <inheritdoc cref=\"ITweakInput{IInput}.Input(Func{IInput, IInput}, NoParamOrder)\"/>\n    //ITweakMedia Input(Func<string, string> func, NoParamOrder npo = default);\n\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/ITweakResize.cs",
    "content": "﻿namespace ToSic.Sxc.Images;\n\n/// <summary>\n/// WIP - ATM just the properties which are needed for the ImageService\n/// </summary>\n/// <remarks>\n/// Introduced v18.03, still WIP\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"New v18.03, still WIP\")]\npublic interface ITweakResize\n{\n    /// <summary>\n    /// Optional width parameter.\n    /// Cannot be used if `factor` is set (will take precedence).\n    /// Usually takes the default from the `settings`.\n    /// </summary>\n    public ITweakResize Width(int width);\n\n    /// <summary>\n    /// Set an explicit height.\n    /// </summary>\n    public ITweakResize Height(int height);\n\n    /// <summary>\n    /// A multiplier, usually used to create urls which resize to a part of the default content-size. Like 0.5.\n    /// </summary>\n    public ITweakResize Factor(double factor);\n\n    /// <summary>\n    /// A multiplier, as string usually used to create urls which resize to a part of the default content-size. Like 0.5.\n    /// Can also be a ratio or formula, like \"1/2\" or \"1:2\" so it can accept CSS-like values.\n    /// </summary>\n    public ITweakResize Factor(string factor);\n\n    /// <summary>\n    /// The aspect ratio to use for resizing - for width to height.\n    /// </summary>\n    public ITweakResize AspectRatio(double aspectRatio);\n\n    /// <summary>\n    /// The aspect ratio to use for resizing - for width to height.\n    /// Can also be a ratio or formula, like \"1/2\" or \"1:2\" so it can accept CSS-like values.\n    /// </summary>\n    public ITweakResize AspectRatio(string aspectRatio);\n\n    /// <summary>\n    /// Set the compression quality\n    /// </summary>\n    public ITweakResize Quality(double quality);\n\n    /// <summary>\n    /// Set the resize mode, like 'crop', 'max', etc.\n    /// </summary>\n    public ITweakResize ResizeMode(string resizeMode);\n\n    /// <summary>\n    /// Set scale-mode to allow up-scaling images like `up` or `both`.\n    /// </summary>\n    public ITweakResize ScaleMode(string scaleMode);\n\n    /// <summary>\n    /// Set the format of the image, like 'jpg', 'png', etc.\n    /// Will only accept known formats, otherwise will ignore the value.\n    /// </summary>\n    public ITweakResize Format(string format);\n\n    /// <summary>\n    /// Specify custom url parameters for the image, like 'cachebreak=42'\n    /// </summary>\n    public ITweakResize Parameters(string parameters);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Recipes/Recipe.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Sxc.Sys.Plumbing;\n\n\nnamespace ToSic.Sxc.Images;\n\n/// <summary>\n/// A recipe contains instructions how to generate tags etc. which can contain multiple resized images\n/// </summary>\n/// <remarks>\n/// All the properties are read-only. If you need to override anything, copy it and set the modified values, then use the copy. \n/// </remarks>\n/// <remarks>\n/// History: Released 2sxc 13.10\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice(\"Still Beta / WIP\")]   // note: was marked as PublicApi(Beta/WIP) till v17\npublic class Recipe: ICanDump\n{\n    internal const string RuleForDefault = \"default\";\n\n    // Special properties which are only added to the tag if activated in settings\n    internal const string SpecialPropertySizes = \"sizes\";\n    internal const string SpecialPropertyMedia = \"media\";\n    internal const string SpecialPropertyClass = \"class\";\n    internal const string SpecialPropertyStyle = \"style\";\n    internal static string[] SpecialProperties = [SpecialPropertySizes, SpecialPropertyMedia, SpecialPropertyClass, SpecialPropertyStyle];\n\n\n    /// <summary>\n    /// **Important**\n    ///\n    /// If you call this from your code, always use named parameters, as the parameter order can change in future.\n    /// </summary>\n    /// <param name=\"original\">An original recipe to copy if we want to get a modified recipe based on one which already existed.</param>\n    /// <param name=\"name\">An optional name </param>\n    /// <param name=\"forTag\">Restricts the rule to only apply to specific tags - ATM `img` and `source`</param>\n    /// <param name=\"forFactor\">Restricts the rule to only apply to resizes for a specified factor</param>\n    /// <param name=\"forCss\">Restricts the rule to only apply to pages which have the specified CSS Framework</param>\n    /// <param name=\"width\">Initial width to use when resizing</param>\n    /// <param name=\"setWidth\">Set the `width` attribute if the img width is known</param>\n    /// <param name=\"setHeight\">Set the `height` attribute if the img-height is known</param>\n    /// <param name=\"variants\">Special string containing variants to generate</param>\n    /// <param name=\"attributes\">List of attributes to set on the `img` tag</param>\n    /// <param name=\"recipes\">List of additional recipes which will all inherit values from this master after creation</param>\n    public Recipe(\n        Recipe? original,\n        // IMPORTANT: the names of these parameters may never change, as they match the names in the JSON\n        string? name = default,\n        string? forTag = default,\n        string? forFactor = default,\n        string? forCss = default,\n        int width = default,\n        bool? setWidth = default,\n        bool? setHeight = default,\n        string? variants = default,\n        IDictionary<string, object?>? attributes = null,\n        IEnumerable<Recipe>? recipes = default\n    )\n    {\n        Name = name;\n        ForTag = forTag ?? original?.ForFactor ?? RuleForDefault;\n        ForFactor = forFactor ?? original?.ForFactor;\n        ForCss = forCss;\n        Width = width != 0 ? width : original?.Width ?? 0;\n        SetWidth = setWidth ?? original?.SetWidth;\n        SetHeight = setHeight ?? original?.SetHeight;\n        Variants = variants ?? original?.Variants;\n        Recipes = recipes != null ? Array.AsReadOnly(recipes.ToArray()) : original?.Recipes ?? Array.AsReadOnly(Array.Empty<Recipe>());\n        Attributes = RecipeHelpers.MergeDics(original?.Attributes, attributes);\n    }\n\n    /// <summary>\n    /// Lighter constructor for json, without parameter Recipe.\n    /// \n    /// **Important**\n    /// If you call this from your code, always use named parameters, as the parameter order can change in future.\n    /// </summary>\n    /// <param name=\"name\">An optional name </param>\n    /// <param name=\"forTag\">Restricts the rule to only apply to specific tags - ATM `img` and `source`</param>\n    /// <param name=\"forFactor\">Restricts the rule to only apply to resizes for a specified factor</param>\n    /// <param name=\"forCss\">Restricts the rule to only apply to pages which have the specified CSS Framework</param>\n    /// <param name=\"width\">Initial width to use when resizing</param>\n    /// <param name=\"setWidth\">Set the `width` attribute if the img width is known</param>\n    /// <param name=\"setHeight\">Set the `height` attribute if the img-height is known</param>\n    /// <param name=\"variants\">Special string containing variants to generate</param>\n    /// <param name=\"attributes\">List of attributes to set on the `img` tag</param>\n    /// <param name=\"recipes\">List of additional recipes which will all inherit values from this master after creation</param>\n    [JsonConstructor]   // This is important for deserialization from json\n    public Recipe(\n        // IMPORTANT: the names of these parameters may never change, as they match the names in the JSON\n        string? name = default,\n        string? forTag = default,\n        string? forFactor = default,\n        string? forCss = default,\n        int width = default,\n        bool? setWidth = default,\n        bool? setHeight = default,\n        string? variants = default,\n        IDictionary<string, object?>? attributes = null,\n        IEnumerable<Recipe>? recipes = default\n    ) : this(original: null, name: name, forTag: forTag, forFactor: forFactor, forCss: forCss, width: width, setWidth: setWidth, setHeight: setHeight, variants: variants, attributes: attributes, recipes: recipes)\n    { }\n\n\n    /// <summary>\n    /// Just an identifier - no technical use\n    /// </summary>\n    public string? Name { get; private set; }\n\n    /// <summary>\n    /// TODO: DOC\n    /// - `img`, `source`\n    /// </summary>\n    public string? ForTag { get; private set; }\n\n    /// <summary>\n    /// Determines which factors this recipe should be applied to.\n    /// Null means any factor.\n    /// </summary>\n    public string? ForFactor { get; private set; }\n\n\n    /// <summary>\n    /// WIP, not implemented yet\n    /// </summary>\n    public string? ForCss { get; set; }\n\n\n    /// <summary>\n    /// The resize factor for which this rules is meant.\n    /// Used in cases where there are many such rules and the one will be picked that matches this factor.\n    /// </summary>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public double FactorParsed { get; private set; }\n\n    /// <summary>\n    /// The initial width to assume in this resize, from which other sizes would be calculated.\n    /// \n    /// If set to 0, it will be ignored. \n    /// </summary>\n    public int Width { get; private set; }\n\n    /// <summary>\n    /// Determines if the img tag will receive a width-attribute\n    /// </summary>\n    public bool? SetWidth { get; private set; }\n\n    /// <summary>\n    /// Determines if the img tag will receive a height-attribute\n    /// </summary>\n    public bool? SetHeight { get; private set; }\n\n    /// <summary>\n    /// Source-Set rules (comma separated) which will determine what will be generated.\n    ///\n    /// Examples:\n    /// - `1x,1.5x,2x` - screen resolutions\n    /// - `200w,400w,600w,800w,1000w` - pixel sizes\n    /// - `0.5*,1*,1.5*,2*` - multipliers of the originally specified pixel size\n    ///\n    /// _Important: According to the HTML standard you can mix pixel-sizes and multipliers, but not resolutions with any of the other types._\n    /// </summary>\n    public string? Variants { get; private set; }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public string? Sizes => Attributes?.TryGetValue(SpecialPropertySizes, out var strSizes) == true\n        ? strSizes?.ToString()\n        : null;\n\n\n    /// <summary>\n    /// Attributes to add to the img tag \n    /// </summary>\n    /// <remarks>\n    /// System.Text.Json requires that the case-insensitive property name and type match the parameter in the constructor.\n    /// We are using string/object because a value could also be { \"name\": true, \"other-name\": 5 } in the json configuration\n    /// </remarks>\n    public IDictionary<string, object?> Attributes { get; private set; }\n\n    /// <summary>\n    /// wip TODO: DOC\n    /// </summary>\n    /// <remarks>\n    /// System.Text.Json requires that the case-insensitive property name and type match the parameter in the constructor.\n    /// </remarks>\n    public IEnumerable<Recipe> Recipes { get; } \n\n\n    [PrivateApi(\"Important for using these settings, but not relevant outside of this\")]\n    internal RecipeVariant[]? VariantsParsed { get; private set; }\n\n    [PrivateApi]\n    internal Recipe InitAfterLoad()\n    {\n        if (_alreadyInit) return this;\n        _alreadyInit = true;\n        InitAfterLoad(null);\n        return this;\n    }\n    private bool _alreadyInit;\n\n\n\n    [PrivateApi]\n    internal virtual Recipe InitAfterLoad(Recipe? parent)\n    {\n        ForFactor ??= parent?.ForFactor;\n        FactorParsed = ParseObject.DoubleOrNullWithCalculation(ForFactor) ?? parent?.FactorParsed ?? 0;\n        if (Width == 0) Width = parent?.Width ?? 0;\n        ForTag ??= parent?.ForTag;\n        var hasVariants = Variants != null;\n        Variants ??= parent?.Variants;\n        SetWidth ??= parent?.SetWidth;\n        SetHeight ??= parent?.SetHeight;\n        Attributes = RecipeHelpers.MergeDics(parent?.Attributes, Attributes);\n        Name ??= parent?.Name;\n        ForCss ??= parent?.ForCss;\n        VariantsParsed = hasVariants ? RecipeVariantsParser.ParseSet(Variants) : parent?.VariantsParsed;\n\n        foreach (var s in Recipes)\n            s?.InitAfterLoad(this);\n\n        return this;\n    }\n\n    public string Dump() => \"Recipe \" +\n        $\"{nameof(Name)}: '{Name}', {nameof(ForCss)}: {ForCss}, \" +\n        $\"{nameof(ForFactor)}: {ForFactor}, {nameof(FactorParsed)}: {FactorParsed}, \" +\n        $\"{nameof(Variants)}: '{Variants}', {nameof(VariantsParsed)}: {VariantsParsed}, \" +\n        $\"{nameof(SetWidth)}: {SetWidth}, {nameof(SetHeight)}: {SetHeight}, \" +\n        $\"{nameof(Attributes)}: {Attributes?.Count}\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys/CopyrightDecorator.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys;\n\n// TODO: LOCATION / NAMESPACE not final\n[PrivateApi(\"WIP v16.08\")]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record CopyrightDecorator : ModelFromEntity\n{\n    public const string ContentTypeNameId = \"077835ec-889e-433f-8acf-a4715acb3503\";\n    public const string ContentTypeName = \"CopyrightDecorator\";\n\n    /// <summary>\n    /// Specifies what kind of information is used. `` (blank), `simple` (text only),`advanced` - selecting the data from Copyright entities.\n    /// </summary>\n    public string? CopyrightInfoType => GetThis<string>(null);\n\n    /// <summary>\n    /// Simple Copyright Message such as \"© 2027 My Company\".\n    /// </summary>\n    public string? CopyrightMessage => GetThis<string>(null);\n\n    // TODO: THIS will probably not work yet\n    /// <summary>\n    /// Copyright Entities of type <see cref=\"CopyrightPreset\"/>.\n    /// </summary>\n    public IEnumerable<IEntity>? Copyrights => GetThis<object>(null) as IEnumerable<IEntity>;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys/CopyrightSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys;\n\n/// <summary>\n/// System Settings regarding Copyright Configuration of an App/Site\n/// </summary>\n/// <remarks>\n/// * Created ca. v16.08\n/// * As of v21 not actively used in code, but in this structure to ensure consistency\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record CopyrightSettings : ModelFromEntity\n{\n    /// <summary>\n    /// Where these settings are placed in the Settings structure - for use as prefix when accessing settings.\n    /// </summary>\n    /// <remarks>\n    /// To be used like `SettingsPath + \".\" + KeyName`\n    /// </remarks>\n    public const string SettingsPath = \"Copyright\";\n\n    public const string ContentTypeNameId = \"aed871cf-220b-4330-b368-f1259981c9c8\";\n    public const string ContentTypeName = \"⚙️CopyrightSettings\";\n\n    // todo: unclear if nullable booleans work, probably never tested before\n    public bool? ImagesInputEnabled => GetThis(null as bool?);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys/IImageDecorator.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys;\n\n/// <summary>\n/// Interface for ImageDecorator,\n/// so we can also use it when not created from an IEntity.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IImageDecorator\n{\n    bool? LightboxIsEnabled { get; }\n    string? LightboxGroup { get; }\n    string? DescriptionExtended { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys/IImageFormat.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys;\n\n/// <summary>\n/// Describes everything to be known about an image format for resizing or generating source-tags.\n/// </summary>\n[PrivateApi(\"ATM no good reason to show this information\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IImageFormat\n{\n    /// <summary>\n    /// The format name, like 'jpg' or 'png'\n    /// </summary>\n    string Format { get; }\n\n    /// <summary>\n    /// The Mime Type - if known\n    /// </summary>\n    string MimeType { get; }\n\n    /// <summary>\n    /// Information if this type can be resized\n    /// </summary>\n    bool CanResize { get; }\n\n    /// <summary>\n    /// Other formats this can be resized to, order by best to least good.\n    /// \n    /// Usually used for creating source-tags in HTML\n    /// </summary>\n    IList<IImageFormat> ResizeFormats { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys/IImageMetadataRecommendationsService.cs",
    "content": "﻿using ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Images.Sys;\n\npublic interface IImageMetadataRecommendationsService\n{\n    /// <summary>\n    /// Optionally add image-metadata recommendations\n    /// </summary>\n    void SetImageRecommendations(IMetadata? mdOf, string? path);\n\n    string[] GetImageRecommendations();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys/ImageDecorator.cs",
    "content": "﻿using ToSic.Eav.Metadata;\n\nnamespace ToSic.Sxc.Images.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record ImageDecorator : ModelFromEntity, IImageDecorator\n{\n    public ImageDecorator(IEntity entity, string?[] languageCodes) : base(entity)\n    {\n        LookupLanguages = languageCodes;\n    }\n\n    #region Constants and Type Names\n\n    public static string TypeNameId = \"cb27a0f2-f921-48d0-a3bc-37c0e77b1d0c\";\n    public static string NiceTypeName = \"ImageDecorator\";\n\n    public const string NoCrop = \"none\";\n    public const string ToCrop = \"to\";\n    public const string DefaultCropCenter = \"Middle Center\";\n\n    private static readonly Dictionary<string, string> ToCropNiceNames = new()\n    {\n        { \"tl\", \"Top Left\" },\n        { \"tc\", \"Top Center\" },\n        { \"tr\", \"Top Right\" },\n        { \"ml\", \"Middle Left\" },\n        { \"mc\", \"Middle Center\" },\n        { \"mr\", \"Middle Right\" },\n        { \"bl\", \"Bottom Left\" },\n        { \"bc\", \"Bottom Center\" },\n        { \"br\", \"Bottom Right\" }\n    };\n\n    /// <summary>\n    /// Parameter to give the UI when it should show a warning for a global file\n    /// </summary>\n    public const string ShowWarningGlobalFile = \"showWarningGlobalFile\";\n\n    #endregion\n\n\n    public static ImageDecorator? GetOrNull(IHasMetadata? source, string?[] dimensions)\n    {\n        var decItem = source?.Metadata?.First(typeName: TypeNameId);\n        return decItem != null\n            ? new ImageDecorator(decItem, dimensions)\n            : null;\n    }\n\n    #region Cropping\n\n    public string CropBehavior => GetThis(\"\");\n\n    public string CropTo => GetThis(\"\");\n\n    internal string CropToNiceName => ToCropNiceNames.TryGetValue(CropTo, out var name) ? name : DefaultCropCenter;\n\n    #endregion\n\n    #region Descriptions / Titles\n\n    public string Description => GetThis(\"\");\n\n    /// <summary>\n    /// Disable falling back to the default/alternate title\n    /// </summary>\n    public bool SkipFallbackTitle => GetThis(false);\n\n    /// <summary>\n    /// Detailed description of an image\n    /// </summary>\n    public string? DescriptionExtended => GetThis<string>(null);\n\n    #endregion\n\n    /// <summary>\n    /// EXPERIMENTAL V18 not implemented yet\n    /// </summary>\n    public string ResizeSettings => GetThis(\"\");\n\n    #region Lightbox - new v18\n\n    /// <summary>\n    /// Important: Triple-State: can be null even if the entity exists, \n    /// </summary>\n    public bool? LightboxIsEnabled => GetThis<bool?>(null);\n\n    public string LightboxGroup => GetThis(\"\");\n\n    #endregion\n\n\n    internal (string? Param, string? Value) GetAnchorOrNull()\n    {\n        var b = CropBehavior;\n        if (b != ToCrop)\n            return (null, null);\n        \n        var direction = CropTo;\n        if (string.IsNullOrWhiteSpace(direction))\n            return (null, null);\n\n        var dirLong = ResolveCompass(direction);\n        if (string.IsNullOrWhiteSpace(dirLong))\n            return (null, null);\n\n        return (\"anchor\", dirLong);\n    }\n\n    #region Private Gets\n\n\n    private string? ResolveCompass(string code)\n    {\n        if (string.IsNullOrEmpty(code) || code.Length != 2)\n            return null;\n        return GetRow(code[0]) + GetCol(code[1]);\n    }\n\n    private static string? GetRow(char code)\n    {\n        switch (code)\n        {\n            case 't': return \"top\";\n            case 'm': return \"middle\";\n            case 'b': return \"bottom\";\n            default: return null;\n        }\n    }\n    private static string? GetCol(char code)\n    {\n        switch (code)\n        {\n            case 'c': return \"center\";\n            case 'l': return \"left\";\n            case 'r': return \"right\";\n            default: return null;\n        }\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys.ResizeSettings/AdvancedSettings.cs",
    "content": "﻿using System.Collections.ObjectModel;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sys.Caching.PiggyBack;\n\nnamespace ToSic.Sxc.Images;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdvancedSettings : IHasPiggyBack\n{\n    [JsonConstructor]\n    public AdvancedSettings(Recipe? recipe = default)\n    {\n        Recipe = recipe;\n\n        // Initialize the recipe and all sub-recipes\n        Recipe?.InitAfterLoad();\n    }\n\n    /// <summary>\n    /// Default Resize rules for everything which isn't specified more closely in the factors\n    /// </summary>\n    /// <remarks>\n    /// System.Text.Json requires that the case-insensitive property name and type match the parameter in the constructor.\n    /// </remarks>\n    public Recipe? Recipe { get; }\n\n    [PrivateApi]\n    public static AdvancedSettings? Parse(object? value)\n        => InnerParse(value);\n\n    private static AdvancedSettings? InnerParse(object? value)\n    {\n        if (value == null)\n            return null;\n\n        // It's already what's expected\n        if (value is AdvancedSettings mrsValue)\n            return mrsValue;\n\n        // Parse any string which would be a typical MRS - convert to single rule\n        if (value is string strValue && !string.IsNullOrWhiteSpace(strValue))\n            value = new Recipe(variants: strValue);\n\n        // Parse any single rule It's just one rule which should be used\n        if (value is Recipe mrrValue)\n            return new(mrrValue);\n\n        return null;\n    }\n\n    [PrivateApi]\n    public static AdvancedSettings FromJson(object? value, ILog? log = null)\n    {\n        var l = log.Fn<AdvancedSettings>();\n        try\n        {\n            if (value is string advString && !string.IsNullOrWhiteSpace(advString))\n                return l.Return(\n                    JsonSerializer.Deserialize<AdvancedSettings>(advString,\n                        JsonOptions.UnsafeJsonWithoutEncodingHtml)!, \"create\");\n        }\n        catch (Exception ex)\n        {\n            l.A($\"error converting json to AdvancedSettings. Json: {value}\");\n            l.Ex(ex);\n        }\n\n        return l.Return(new(), \"new\");\n    }\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    public ReadOnlyCollection<Recipe> AllSubRecipes\n        => field ??= GetAllRecipesRecursive(Recipe?.Recipes).AsReadOnly();\n\n    private static List<Recipe> GetAllRecipesRecursive(IEnumerable<Recipe>? recipes)\n    {\n        if (recipes.SafeNone())\n            return [];\n\n        var list = new List<Recipe>();\n        foreach (var r in recipes)\n        {\n            list.Add(r);\n            list.AddRange(GetAllRecipesRecursive(r.Recipes));\n        }\n\n        return list;\n    }\n\n\n    /// <summary>\n    /// Piggyback cache to remember previous LINQ queries which already filtered certain combinations\n    /// </summary>\n    [PrivateApi(\"internal use only\")]\n    [JsonIgnore]\n    [field: AllowNull, MaybeNull]\n    public PiggyBack PiggyBack => field ??= new();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys.ResizeSettings/IResizeSettingsInternal.cs",
    "content": "﻿namespace ToSic.Sxc.Images;\n\npublic interface IResizeSettingsInternal\n{\n    /// <summary>\n    /// Settings which are used when img/picture tags are generated with multiple resizes\n    /// </summary>\n    [InternalApi_DoNotUse_MayChangeWithoutNotice(\"Still WIP - will move to public once official, and then probably an IAdvancedSettings\")]\n    AdvancedSettings? Advanced { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys.ResizeSettings/RecipeHelpers.cs",
    "content": "﻿using System.Collections.ObjectModel;\n\nnamespace ToSic.Sxc.Images;\n\npublic class RecipeHelpers\n{\n    internal static ReadOnlyDictionary<string, object?> MergeDics(IDictionary<string, object?>? parentOrNull, IDictionary<string, object?>? myOrNull)\n    {\n        if (myOrNull == null)\n            return new(parentOrNull ?? new Dictionary<string, object?>());\n        if (parentOrNull == null || !parentOrNull.Any())\n            return new(myOrNull);\n\n        var newMaster = new Dictionary<string, object?>(parentOrNull);\n\n        foreach (var pair in myOrNull)\n            if (pair.Value == null) newMaster.Remove(pair.Key);\n            else newMaster[pair.Key] = pair.Value;\n\n        return new(newMaster);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys.ResizeSettings/RecipeVariant.cs",
    "content": "﻿using System.Globalization;\n\nnamespace ToSic.Sxc.Images;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class RecipeVariant\n{\n    public const char SizeDefault = 'd';\n    public const char SizeWidth = 'w';\n    public const char SizePixelDensity = 'x';\n    public const char SizeFactorOf = '*';\n    public static readonly char[] SizeTypes = [SizeWidth, SizePixelDensity, SizeDefault, SizeFactorOf];\n\n    /// <summary>\n    /// The size - usually 1000 or something in case of 'w', and 1.5 or something in case of 'x'\n    /// </summary>\n    public double Size;\n\n\n    public double AdditionalFactor = 1;\n\n    /// <summary>\n    /// Type of size - width or pixel density\n    /// </summary>\n    public char SizeType = SizeDefault;\n\n    /// <summary>\n    /// Image width if specified, in pixels\n    /// </summary>\n    public int Width;\n\n    /// <summary>\n    /// Image height if specified in pixels\n    /// </summary>\n    public int Height;\n\n    public string SrcSetSuffix(int finalWidth)\n    {\n        var srcSetSize = Size;\n        var srcSetSizeTypeCode = SizeType;\n        if (srcSetSizeTypeCode == SizeFactorOf)\n        {\n            srcSetSize = finalWidth;\n            srcSetSizeTypeCode = SizeWidth;\n        }\n\n        var suffix = $\" {srcSetSize.ToString(CultureInfo.InvariantCulture)}{srcSetSizeTypeCode}\";\n        return suffix;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Images/Sys.ResizeSettings/RecipeVariantsParser.cs",
    "content": "﻿using static ToSic.Sxc.Sys.Plumbing.ParseObject;\n\nnamespace ToSic.Sxc.Images;\n\n[PrivateApi(\"Hide implementation\")]\ninternal class RecipeVariantsParser\n{\n    public const char KeyValueSeparator = '=';\n    public const char PartSeparator = ',';\n    public const char WidthSeparator = ':';\n\n\n    public static RecipeVariant[] ParseSet(string? srcSet)\n    {\n        if (string.IsNullOrWhiteSpace(srcSet))\n            return [];\n\n        var partStrings = srcSet!\n            .Split(PartSeparator)\n            .Select(s => s.Trim())\n            .Select(ParsePart);\n\n        return partStrings.ToArray();\n    }\n\n    public static RecipeVariant ParsePart(string? partString)\n    {\n        var withMore = (partString ?? string.Empty)\n            .Split(KeyValueSeparator)\n            .Select(more => more.Trim())\n            .ToArray();\n\n        var part = new RecipeVariant();\n\n        // A 0 index must always exist if the previous string was non-null, which is guaranteed\n        var mainPart = withMore[0];\n        if (!string.IsNullOrEmpty(mainPart))\n        {\n            var lastChar = mainPart.ToLowerInvariant().Last();\n            if (RecipeVariant.SizeTypes.Contains(lastChar)) part.SizeType = lastChar;\n            mainPart = mainPart.TrimEnd(RecipeVariant.SizeTypes);\n\n            var sizeAsNumber = DoubleOrNull(mainPart);\n            if (sizeAsNumber == null)\n            {\n                // Try calculating - if it is a calculation, we always assume factor-mode '*'\n                sizeAsNumber = DoubleOrNullWithCalculation(mainPart);\n                if (sizeAsNumber != null && part.SizeType == RecipeVariant.SizeDefault)\n                    part.SizeType = RecipeVariant.SizeFactorOf;\n            }\n            part.Size = Math.Round(sizeAsNumber ?? 0, 2);\n\n            // If it's a real size and we didn't already set the Type, set it based on the value range\n            if (part.SizeType == RecipeVariant.SizeDefault && !DNearZero(part.Size))\n                part.SizeType = part.Size < 1 \n                    ? RecipeVariant.SizeFactorOf // Less than 1 - can't be pixel density, must be factor\n                    : part.Size < 10 ? RecipeVariant.SizePixelDensity : RecipeVariant.SizeWidth;\n\n            // Set the factor for later calculations\n            if (part.SizeType == RecipeVariant.SizeFactorOf || part.SizeType == RecipeVariant.SizePixelDensity)\n                part.AdditionalFactor = part.Size;\n        }\n\n        // If size type is width, then we must round to int and the width must have the same value\n        if (part.SizeType == RecipeVariant.SizeWidth) \n            part.Size = part.Width = (int)part.Size;\n\n        if (withMore.Length > 1)\n        {\n            var moreParts = withMore[1].Split(WidthSeparator).Select(s => s.Trim()).ToArray();\n            if (!string.IsNullOrEmpty(moreParts[0]))\n                part.Width = IntOrNull(moreParts[0]) ?? 0;\n            if (moreParts.Length > 1 && !string.IsNullOrEmpty(moreParts[1]))\n                part.Height = IntOrNull(moreParts[1]) ?? 0;\n        }\n\n        return part;\n    }\n\n    //public static string SrcSetSuffix(SrcSetPart ssConfig, int finalWidth)\n    //{\n    //    var srcSetSize = ssConfig.Size;\n    //    var srcSetSizeTypeCode = ssConfig.SizeType;\n    //    if (srcSetSizeTypeCode == SizeFactorOf)\n    //    {\n    //        srcSetSize = finalWidth;\n    //        srcSetSizeTypeCode = SizeWidth;\n    //    }\n\n    //    var suffix = $\" {srcSetSize.ToString(CultureInfo.InvariantCulture)}{srcSetSizeTypeCode}\";\n    //    return suffix;\n    //}\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Properties/SxcDataInternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n// Edit needs some internal Toolbar APIs\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Edit\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Images\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Services\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Code\")]\n\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Core\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.UnitTests\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.SystemTests\")]"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Services/IImageService.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Images.Sys;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Image`](xref:ToSic.Sxc.Services.ServiceKit16.Image) to help create responsive `img` and `picture` tags the best possible way.\n/// </summary>\n/// <remarks>\n/// History: Released 2sxc 13.10\n/// </remarks>\n[PublicApi]\npublic interface IImageService: ICanDebug\n{\n    /// <summary>\n    /// Get the format information for a specific extension.\n    /// Mostly used internally, you will usually not need this. \n    /// </summary>\n    /// <param name=\"path\">Path or extension</param>\n    /// <returns></returns>\n    /// <remarks>Only works for the basic, known image types</remarks>\n    [PrivateApi(\"Not sure if this is needed outside...\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IImageFormat GetFormat(string path);\n\n\n    // TODO - SETTINGS CAN'T BE AN IResizeSettings, because that will throw an error in the merge call\n    // We should reconsider this and make it possible to also rebuild a resize-settings\n    // - Or a specially prepared <see cref=\"ToSic.Sxc.Images.IResizeSettings\"/> object containing all settings.\n\n\n    /// <summary>\n    /// Construct custom Resize-Settings as needed, either based on existing settings or starting from scratch\n    /// </summary>\n    /// <param name=\"settings\">\n    /// - A standardized Image-Settings object like `Settings.Images.Content` used as a template - see https://go.2sxc.org/settings\n    /// - The `string` name of a template settings , like \"Content\" or \"Screen\"\n    /// - a `bool` true/false - if true, the normal \"Content\" configuration is used as a template, if false, no initial configuration is used\n    /// - Or a dynamic object containing settings properties (this can also be a merged custom + standard settings)\n    /// - Or a specially prepared <see cref=\"ToSic.Sxc.Images.IResizeSettings\"/> object containing all settings.\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">\n    /// Tweak API to configure everything (new v18.03).\n    /// This is recommended above using parameter names and all newer parameters will only be available on this.\n    /// Note that tweak will be executed after applying other parameters.\n    /// </param>\n    /// <param name=\"factor\">A multiplier, usually used to create urls which resize to a part of the default content-size. Like 0.5. </param>\n    /// <param name=\"width\">Optional width parameter. Cannot be used if `factor` is set. Usually takes the default from the `settings`.</param>\n    /// <param name=\"height\">Optional height parameter. Can only be 0 if `factor` is set, no not specify a height. Usually takes the default from the `settings`.</param>\n    /// <param name=\"quality\">Optional quality parameter. Usually takes the default from the `settings`.</param>\n    /// <param name=\"resizeMode\">Optional resize-mode, like `crop` or `max`. Usually takes the default from the `settings`.</param>\n    /// <param name=\"scaleMode\">Optional scale-mode to allow up-scaling images like `up` or `both`. Usually takes the default from the `settings`.</param>\n    /// <param name=\"format\">Optional file format like `jpg` or `png`</param>\n    /// <param name=\"aspectRatio\">Aspect Ratio width/height, only relevant if a `factor` is supplied. Usually takes default from the `settings` or is ignored. </param>\n    /// <param name=\"parameters\">\n    ///     - the parameters either as `id=47&amp;name=daniel` (Dnn also supports `/id/47/name/daniel`)\n    ///     - it can also be an <see cref=\"Context.IParameters\"/>\n    /// </param>\n    /// <param name=\"recipe\">WIP - not ready yet</param>\n    /// <returns>A settings object which has all the parameters as configured</returns>\n    /// <remarks>\n    /// * Added in v13.03\n    /// * Tweak added in v18.03\n    /// </remarks>\n    IResizeSettings Settings(\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakResize, ITweakResize>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        object? height = default,\n        object? quality = default,\n        string? resizeMode = default,\n        string? scaleMode = default,\n        string? format = default,\n        object? aspectRatio = default,\n        string? parameters = default,\n        object? recipe = default\n    );\n\n    Recipe Recipe(string variants);\n\n    Recipe Recipe(\n        Recipe recipe,\n        NoParamOrder npo = default,\n        string? name = default,\n        int width = default,\n        string? variants = default,\n        IDictionary<string, object?>? attributes = default,\n        IEnumerable<Recipe>? recipes = default,\n        bool? setWidth = default,\n        bool? setHeight = default,\n        string? forTag = default,\n        string? forFactor = default,\n        string? forCss = default\n    );\n\n    // 2022-03-19 2dm - not ready yet\n    ///// <summary>\n    ///// Generate a `srcset` attribute for an image, containing various sizes as specified by the image itself\n    ///// </summary>\n    ///// <param name=\"url\">The image url</param>\n    ///// <param name=\"settings\">\n    /////     - A standardized Image-Settings object like Settings.Images.Content - see https://go.2sxc.org/settings\n    /////     - Or a dynamic object containing settings properties (this can also be a merged custom + standard settings)\n    /////     - Or a specially prepared <see cref=\"IResizeSettings\"/> object containing all settings.\n    /////     Note: If you need to construct very custom settings, use <see cref=\"ResizeSettings\">ResizeSettings</see> to create them\n    ///// </param>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    ///// <param name=\"factor\">A multiplier, usually used to create urls which resize to a part of the default content-size. Like 0.5. </param>\n    ///// <param name=\"recipe\">Optional string to configure what `srcset`s to generate - see [](xref:NetCode.Images.SrcSet) (note it's `srcset`, not `srcSet`)</param>\n    ///// <returns></returns>\n    ///// <remarks>\n    ///// History: Added in 2sxc 13.03\n    ///// </remarks>\n    //IHybridHtmlString SrcSet(\n    //    string url,\n    //    object settings = default,\n    //    string noParamOrder = Eav.Parameters.Protector,\n    //    object factor = default,\n    //    object recipe = default\n    //);\n\n    /// <summary>\n    /// Get a Responsive Picture object which you can then either just show, or use to construct a more customized output as you need it.\n    /// \n    /// The resulting object can just be added to the html, like `@pic` or you can work with sub-properties as specified in the <see cref=\"IResponsivePicture\"/>.\n    /// \n    /// **Important:** This call only allows you to set the most common parameters `factor` and `width`.\n    /// For other parameters like `height`, `aspectRatio`, `quality` etc. create Settings <see cref=\"Settings\"/> and pass them in.\n    /// </summary>\n    /// <param name=\"link\">\n    /// What should be in this, can be:\n    /// \n    /// - a string url, in which case it would be used if `url` is not specified\n    /// - a <see cref=\"IField\"/> in which case it would be used if `field` is not specified\n    /// - a <see cref=\"IFile\"/> (new 16.03)\n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"settings\">\n    /// - The name of a settings configuration, like \"Content\", \"Screen\", \"Square\", etc.\n    /// - A standardized Image-Settings object like Settings.Images.Content - see https://go.2sxc.org/settings\n    /// - Or a dynamic object containing settings properties (this can also be a merged custom + standard settings)\n    /// - A <see cref=\"IResizeSettings\"/> object containing all settings created using <see cref=\"ToSic.Sxc.Services.IImageService.Settings\">ResizeSettings</see> \n    /// </param>\n    /// <param name=\"tweak\">\n    /// Tweak API to configure everything (new v18.03).\n    /// This is recommended above using parameter names and all newer parameters will only be available on this.\n    /// Note that tweak will be executed after applying other parameters.\n    /// </param>\n    /// <param name=\"factor\">An optional multiplier, usually used to create urls which resize to a part of the default content-size. Like 0.5. </param>\n    /// <param name=\"width\">An optional, fixed width of the image</param>\n    /// <param name=\"imgAlt\">\n    /// Optional `alt` attribute on the created `img` tag for SEO etc.\n    /// If supplied, it takes precedence to the alt-description in the image metadata which the editor added themselves.\n    /// If you want to provide a fallback value (in case the metadata has no alt), use `imgAltFallback`\n    /// </param>\n    /// <param name=\"imgAltFallback\">\n    /// Optional `alt` attribute which is only used if the `imgAlt` or the alt-text in the metadata are empty.\n    /// _new in v15_\n    /// </param>\n    /// <param name=\"imgClass\">Optional `class` attribute on the created `img` tag</param>\n    /// <param name=\"imgAttributes\">Optional additional attributes - as anonymous object like `new { style = \"padding: 10px\" }` or Dictionary (new 16.07)</param>\n    /// <param name=\"pictureClass\">Optional `class` attribute on the created `picture` tag</param>\n    /// <param name=\"pictureAttributes\">Optional additional attributes - as anonymous object like `new { style = \"padding: 10px\" }` or Dictionary (new 16.07)</param>\n    /// <param name=\"toolbar\">Provide a custom toolbar or `false` to not show a toolbar</param>\n    /// <param name=\"recipe\">\n    /// Optional recipe = instructions how to create the various variants of this link.\n    /// Can be any one of these:\n    /// \n    /// - string containing variants\n    /// - Rule object\n    /// \n    /// TODO: DOCS not quite ready\n    /// </param>\n    /// <returns>A ResponsivePicture object which can be rendered directly. See [](xref:NetCode.Images.Index)</returns>\n    /// <remarks>\n    /// * Added in v13.03\n    /// * Extended in v16.03 to also support IFile\n    /// * `toolbar` added in v16.04\n    /// * `imgAttributes`, `picClass` and `picAttributes` added in 16.07\n    /// * `tweak` added in 18.03\n    /// </remarks>\n    IResponsivePicture Picture(\n        object? link = null,\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        string? pictureClass = default,\n        object? pictureAttributes = default,\n        object? toolbar = default,\n        object? recipe = default\n    );\n\n    /// <summary>\n    /// Get a Responsive Image object which you can then either just show, or use to construct a more customized output as you need it.\n    /// \n    /// The resulting object can just be added to the html, like `@img` or you can work with sub-properties as specified in the <see cref=\"IResponsiveImage\"/>\n    /// </summary>\n    /// <param name=\"link\">\n    ///     What should be in this, can be:\n    /// \n    ///     - a string url, in which case it would be used if `url` is not specified\n    ///     - a <see cref=\"IField\"/> in which case it would be used if `field` is not specified\n    /// </param>\n    /// <param name=\"settings\">\n    ///     - The name of a settings configuration, like \"Content\", \"Screen\", \"Square\", etc.\n    ///     - A standardized Image-Settings object like Settings.Images.Content - see https://go.2sxc.org/settings\n    ///     - Or a dynamic object containing settings properties (this can also be a merged custom + standard settings)\n    ///     - A <see cref=\"IResizeSettings\"/> object containing all settings created using <see cref=\"ToSic.Sxc.Services.IImageService.Settings\">ResizeSettings</see> \n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">\n    /// Tweak API to configure everything (new v18.03).\n    /// This is recommended above using parameter names and all newer parameters will only be available on this.\n    /// Note that tweak will be executed after applying other parameters.\n    /// </param>\n    /// <param name=\"factor\">An optional multiplier, usually used to create urls which resize to a part of the default content-size. Like 0.5. </param>\n    /// <param name=\"width\">An optional, fixed width of the image</param>\n    /// <param name=\"imgAlt\">\n    /// Optional `alt` attribute on the created `img` tag for SEO etc.\n    /// If supplied, it takes precedence to the alt-description in the image metadata which the editor added themselves.\n    /// If you want to provide a fallback value (in case the metadata has no alt), use `imgAltFallback`.\n    /// </param>\n    /// <param name=\"imgAltFallback\">\n    /// Optional `alt` attribute which is only used if the `imgAlt` or the alt-text in the metadata are empty.\n    /// _new in v15_\n    /// </param>\n    /// <param name=\"imgClass\">Optional `class` attribute on the created `img` tag</param>\n    /// <param name=\"imgAttributes\">Optional additional attributes - as anonymous object like `new { style = \"padding: 10px\" }` or Dictionary (new 16.07)</param>\n    /// <param name=\"toolbar\">Provide a custom toolbar or `false` to not show a toolbar</param>\n    /// <param name=\"recipe\">\n    ///     Optional recipe = instructions how to create the various variants of this link.\n    ///     Can be any one of these:\n    /// \n    ///     - string containing variants\n    ///     - Rule object\n    /// \n    ///     TODO: DOCS not quite ready\n    /// </param>\n    /// <returns>A ResponsiveImage object which can be rendered directly. See [](xref:NetCode.Images.Index)</returns>\n    /// <remarks>\n    /// * Added in 2sxc 13.03\n    /// * `toolbar` added in v16.04\n    /// * `tweak` added in 18.03\n    /// </remarks>\n    IResponsiveImage Img(\n        object? link = null,\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        object? toolbar = default,\n        object? recipe = default\n    );\n        \n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Services/Sys/ServiceWithContext.cs",
    "content": "﻿using ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Services.Sys;\n\n/// <summary>\n/// Internal special base class for services which link to the dynamic code root\n/// </summary>\n[PrivateApi]\n// #NoEditorBrowsableBecauseOfInheritance\n//[ShowApiWhenReleased(ShowApiMode.Never)]\n[method: PrivateApi]\npublic abstract class ServiceWithContext(string logName, NoParamOrder npo = default, object[]? connect = default)\n    : ServiceBase(logName, npo: npo, connect: connect), INeedsExecutionContext, ICanDebug\n{\n    /// <summary>\n    /// Connect to CodeRoot and it's log\n    /// </summary>\n    /// <param name=\"exCtx\"></param>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public virtual void ConnectToRoot(IExecutionContext exCtx)\n        => ConnectToRoot(exCtx, null);\n\n    /// <summary>\n    /// Connect to CodeRoot and a custom log\n    /// </summary>\n    /// <param name=\"exCtx\"></param>\n    /// <param name=\"parentLog\"></param>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public void ConnectToRoot(IExecutionContext? exCtx, ILog? parentLog)\n    {\n        // Avoid unnecessary reconnects\n        if (_alreadyConnected)\n            return;\n        _alreadyConnected = true;\n\n        // Remember the parent\n        ExCtxOrNull = exCtx;\n        // Link the logs\n        this.LinkLog(parentLog ?? exCtx?.Log);\n        // report connection in log\n        Log.Fn(message: \"Linked to Root\").Done();\n    }\n    private bool _alreadyConnected;\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n\n    protected IExecutionContext ExCtx => ExCtxOrNull\n                                         ?? throw new($\"{nameof(ExCtxOrNull)} is null - this is a bug, please report it.\");\n\n    protected IExecutionContext? ExCtxOrNull { get; private set; }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public virtual bool Debug { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Services/Sys.Cms/ICmsService.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Services.Tweaks;\n\nnamespace ToSic.Sxc.Services.Sys.Cms;\n\n[PrivateApi(\"not published, use Item.Html() instead\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ICmsService\n{\n    IHtmlTag Html(object thing,\n        NoParamOrder npo = default,\n        object? container = default,\n        string? classes = default,\n        bool debug = default,\n        object? imageSettings = default,\n        bool? toolbar = default,\n        Func<ITweakInput<string>, ITweakInput<string>>? tweak = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Services/Sys.ConvertService/ConvertForCodeService.cs",
    "content": "﻿\n// ReSharper disable MethodOverloadWithOptionalParameter\n\nnamespace ToSic.Sxc.Services.Sys.ConvertService;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ConvertForCodeService(ConvertValueService cnvSvc) : ServiceBase(\"Sxc.CnvSrv\", connect: [cnvSvc])\n{\n    public string? ForCode(object? value, NoParamOrder npo = default, string? fallback = default)\n    {\n        if (value == null)\n            return fallback;\n\n        // Pre-check special case of date-time which needs ISO encoding without time zone\n        if (value.GetType().UnboxIfNullable() == typeof(DateTime))\n        {\n            var dt = ((DateTime)value).ToString(\"O\").Substring(0, 23) + \"z\";\n            return dt;\n        }\n\n        var result = cnvSvc.To(value, fallback: fallback);\n        if (result is null)\n            return null;\n\n        // If the original value was a boolean, we will do case changing as js expects \"true\" or \"false\" and not \"True\" or \"False\"\n        if (value.GetType().UnboxIfNullable() == typeof(bool)) result = result.ToLowerInvariant();\n\n        return result;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Services/Sys.ConvertService/ConvertValueService.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Sys.ConvertService;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ConvertValueService() : ServiceBase(\"Sxc.CnvSrv\")\n{\n    public bool OptimizeNumbers => true;\n\n    public bool OptimizeBoolean => true;\n\n    public T? To<T>(object value) => value.ConvertOrDefault<T>(numeric: OptimizeNumbers, truthy: OptimizeBoolean);\n\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    [return: NotNullIfNotNull(nameof(fallback))]\n    public T? To<T>(object value, NoParamOrder npo = default, T? fallback = default)\n        => value.ConvertOrFallback(fallback, numeric: OptimizeNumbers, truthy: OptimizeBoolean, fallbackOnDefault: false);\n\n    public string? ToString(object value, NoParamOrder npo = default, string? fallback = null, bool fallbackOnNull = true)\n    {\n        var result = To(value, fallback: fallback);\n        return result is null && fallbackOnNull ? fallback: result;\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Services/Tweaks/ITweakInput.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks;\n\n/// <summary>\n/// Tweak API to reconfigure a value pre-processing in a service / method call.\n///\n/// Whatever code you write, always assume that this interface can be replaced with another name\n/// which will then provide more tweaks. So never use the interface-name in your code.\n/// </summary>\n/// <remarks>Added in v17</remarks>\n[PublicApi]\npublic interface ITweakInput<TInput>\n{\n    /// <summary>\n    /// Simple value tweak, to inject a different value for use instead of the original.\n    /// </summary>\n    /// <param name=\"replace\">replacement value to use instead</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <returns></returns>\n    ITweakInput<TInput> Input(TInput replace, NoParamOrder npo = default);\n    ///// <param name=\"step\">optional step, such as 'before' or 'after' - default is 'before'</param>\n    \n\n    /// <summary>\n    /// Simple value tweak, to inject a different value for use instead of the original.\n    /// </summary>\n    /// <param name=\"func\">function to generate a replacement value</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <returns></returns>\n    ITweakInput<TInput> Input(Func<TInput> func, NoParamOrder npo = default);\n    ///// <param name=\"step\">optional step, such as 'before' or 'after' - default is 'before'</param>\n\n\n    /// <summary>\n    /// Simple value tweak, to inject a different value for use instead of the original.\n    /// </summary>\n    /// <param name=\"func\">function to generate a replacement value, but first providing the initial value</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <returns></returns>\n    ITweakInput<TInput> Input(Func<TInput, TInput> func, NoParamOrder npo = default);\n    ///// <param name=\"step\">optional step, such as 'before' or 'after' - default is 'before'</param>\n\n\n    ///// <summary>\n    ///// DO NOT USE YET - BETA\n    ///// Simple value tweak, to inject a different value for use instead of the original.\n    ///// </summary>\n    ///// <param name=\"func\">function to generate a replacement value, receiving the previous value inside a <see cref=\"ITweakValue{TValue}\"/> </param>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    ///// <param name=\"step\">optional step, such as 'before' or 'after' - default is 'before'</param>\n    ///// <returns></returns>\n    //[PrivateApi(\"not yet final\")]\n    //ITweakHtml Process(Func<ITweakValue<string>, string> func, NoParamOrder npo = default);//, string step = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/StartupSxcData.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Data.Sys.DynamicJacket;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcData\n{\n    public static IServiceCollection AddSxcData(this IServiceCollection services)\n    {\n\n        // v16 DynamicJacket and DynamicRead factories\n        services.TryAddTransient<ICodeDataPoCoWrapperService, CodeDataPoCoWrapperService>();\n        services.TryAddTransient<CodeJsonWrapper>();\n        services.TryAddTransient<WrapObjectTyped>();\n        services.TryAddTransient<WrapObjectTypedItem>();\n\n        return services;\n    }\n\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Sys.ExecutionContext/ExecutionContextStateNames.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// Just a helper to ensure that only known state names are used.\n/// </summary>\n/// <remarks>\n/// This is for the <see cref=\"IExecutionContext.GetDataStack{TState}\"/>\n/// </remarks>\npublic class ExecutionContextStateNames\n{\n    /// <summary>\n    /// Settings must be a <see cref=\"IDynamicStack\"/>\n    /// </summary>\n    public const string Settings = \"Settings\";\n\n    /// <summary>\n    /// AllSettings must be a <see cref=\"ITypedStack\"/>\n    /// </summary>\n    public const string AllSettings = \"AllSettings\";\n\n    /// <summary>\n    /// AllResources must be a <see cref=\"ITypedStack\"/>\n    /// </summary>\n    public const string AllResources = \"AllResources\";\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Sys.ExecutionContext/ICanGetService.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// Interface to mark objects which can get a service.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ICanGetService\n{\n    /// <summary>\n    /// Get a service from the Dependency Injection.\n    /// The service can come from 2sxc, EAV or the underlying platform (Dnn, Oqtane).\n    /// </summary>\n    /// <typeparam name=\"TService\">Interface (preferred) or Class which is needed</typeparam>\n    /// <returns>An object of the type or interface requested, or null if not found in the DI.</returns>\n    TService GetService<TService>() where TService : class;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Sys.ExecutionContext/IExecutionContext.cs",
    "content": "﻿using ToSic.Sys.Caching.PiggyBack;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// Internal context information about the current execution.\n/// </summary>\n/// <remarks>\n/// It contains:\n/// 1. state\n/// 2. services\n/// 3. ...and more\n///\n/// The initial interface has none or few properties, so that we can pass it around without all projects being tied to each other.\n/// </remarks>\npublic interface IExecutionContext: ICanGetService, IHasPiggyBack, IHasLog\n{\n    /// <summary>\n    /// Get the current state of the execution context. Only works for a few types.\n    /// </summary>\n    /// <typeparam name=\"TState\">The data type of known states: `IApp`, `ICmsContext` or `IDataSource` and a few more.\n    /// Any other type will throw an error.</typeparam>\n    /// <returns></returns>\n    public TState GetState<TState>() where TState : class;\n\n    /// <summary>\n    /// Special accessor - currently only for\n    /// * `IDynamicStack` and name \"Settings\"\n    /// * `ITypedStack` and name `AllSettings`\n    /// </summary>\n    /// <typeparam name=\"TState\"></typeparam>\n    /// <param name=\"name\"></param>\n    /// <returns></returns>\n    public TState GetDataStack<TState>(string name) where TState : class;\n\n    /// <summary>\n    /// Special GetService which can cache the found service so any other use could get the same instance.\n    /// This should ensure that an Edit service requested through Kit14 and Kit16 are both the same, etc.\n    /// </summary>\n    /// <typeparam name=\"TService\"></typeparam>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"reuse\">if true, then a service requested multiple times will return the same instance</param>\n    /// <param name=\"type\">rare option: type name of the service to create; probably not relevant any more today</param>\n    /// <returns></returns>\n    [PrivateApi]\n    TService GetService<TService>(NoParamOrder npo = default, bool reuse = false, Type? type = default) where TService : class;\n\n    /// <summary>\n    /// Get special services which data need to initialize.\n    /// This is a select list, ATM just the `AdamManager`\n    /// </summary>\n    /// <typeparam name=\"TService\"></typeparam>\n    /// <returns></returns>\n    TService GetServiceForData<TService>() where TService : class;\n}\n\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Sys.ExecutionContext/IExecutionContextCdf.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\npublic static class IExecutionContextCdf\n{\n    public static ICodeDataFactory GetCdf(this IExecutionContext exCtx)\n        => ((IWrapper<ICodeDataFactory>)exCtx).GetContents()!;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Sys.ExecutionContext/INeedsExecutionContext.cs",
    "content": "﻿namespace ToSic.Sxc.Sys.ExecutionContext;\n\n/// <summary>\n/// Interface for components that require access to the execution context.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface INeedsExecutionContext\n{\n    /// <summary>\n    /// Internal call to connect to the execution context.\n    /// </summary>\n    /// <param name=\"exCtx\"></param>\n    [ShowApiWhenReleased(ShowApiMode.Never)] \n    void ConnectToRoot(IExecutionContext exCtx);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/Sys.ExecutionContext/readme.md",
    "content": "# Execution Context (Experimental)\n\nMany services etc. need to know about the current context.\n\nThis to get the latest Block, Settings, Resources etc.\n\nATM we have the CodeApiService which originally was meant to provide all the APIs\nneeded by Razor, WebApi etc. \n...but has since been used by all services to get their context.\n\nThese interfaces here MUST be implemented by the CodeApiService,\nbut to use them will require an explicit cast. "
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/ToSic.Sxc.Data.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Data</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"Data\\DataWrapper %28no namespace%29\\\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Data/ToSic.Sxc.Data.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data2_005Cdatawrapper/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data2_005Cdatawrapper_0020_0028no_0020namespace_0029/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data2_005Cdynamicentity/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data2_005Cpublishing/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data2_005Ctypedinterfaces/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data2_005Ctypeditem_0020_0028no_0020namespace_0029/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Cdatawrapper_0020_0028no_0020namespace_0029/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Cdynamicentity/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Cdynamicentity_0020_0028no_0020namespace_0029/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Cmodels_005Cattributes/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Cmodels_005Cattributes_0020_0028no_0020namespace_0029/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Cpublishing/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Cpublishing_0020_0028no_0020namespace_0029/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Csecret/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Csecret_0020_0028no_0020namespace_0029/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Csys_005Cdynamicentity/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=data_005Ctypeditem_0020_0028no_0020namespace_0029/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=edit_002Etoolbar_005Cbuilder/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=edit_002Etoolbar_005Ctweakbutton/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Crecipes/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Cresizesettings/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/EditService/EditService.cs",
    "content": "﻿using ToSic.Razor.Markup;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Web.Sys.Html;\n\nnamespace ToSic.Sxc.Edit.EditService;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal partial class EditService(IJsonService jsonService)\n    : ServiceWithContext(\"Sxc.Edit\", connect: [jsonService]), IEditService, IEditServiceSetup\n{\n    public override void ConnectToRoot(IExecutionContext exCtx)\n    {\n        base.ConnectToRoot(exCtx);\n        ((IEditServiceSetup)this).SetBlock(exCtx, exCtx.GetBlock());\n    }\n\n    IEditService IEditServiceSetup.SetBlock(IExecutionContext? exCtxOrNull, IBlock block)\n    {\n        var user = exCtxOrNull?.GetCmsContext()?.User;\n        Enabled = block?.Context.Permissions.IsContentAdmin ?? (user?.IsSiteAdmin ?? false);\n        return this;\n    }\n\n    #region Attribute-helper\n\n    /// <inheritdoc/>\n    public IRawHtmlString? Attribute(string name, string value)\n        => !Enabled ? null : HtmlAttribute.Create(name, value);\n\n    /// <inheritdoc/>\n    public IRawHtmlString? Attribute(string name, object value)\n        => !Enabled ? null : HtmlAttribute.Create(name, jsonService.ToJson(value));\n\n    #endregion Attribute Helper\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/EditService/EditService_Context.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Web.Sys.Html;\n\nnamespace ToSic.Sxc.Edit.EditService;\n\npartial class EditService\n{\n    #region Context Attributes\n\n    /// <inheritdoc/>\n    public IRawHtmlString? ContextAttributes(ICanBeEntity target,\n        NoParamOrder npo = default,\n        string? field = null,\n        string? contentType = null,\n        Guid? newGuid = null,\n        string? apps = null,\n        int max = 100)\n    {\n        var l = Log.Fn<IRawHtmlString>(\"ctx attribs - enabled:{Enabled}\");\n        if (!Enabled)\n            return null;\n\n        if (field == null)\n            throw new(\"need parameter 'field'\");\n\n        var serialized = JsonSerializer.Serialize(new\n        {\n            apps,\n            field,\n            guid = newGuid.ToString(),\n            max,\n            parent = target.Entity.EntityId,\n            parentGuid = target.Entity.EntityGuid,\n            type = contentType ?? AppConstants.ContentGroupRefTypeName,\n        }, JsonOptions.SafeJsonForHtmlAttributes);\n\n        return l.Return(HtmlAttribute.Create(InnerContentAttribute, serialized));\n    }\n\n    #endregion Context Attributes\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/EditService/EditService_Enable.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\n\nnamespace ToSic.Sxc.Edit.EditService;\n\npartial class EditService\n{\n    /// <inheritdoc />\n    public bool Enabled { \n        get; \n        [PrivateApi(\"hide, only used for demos\")]\n        set;\n    }\n\n    #region Scripts and CSS includes\n\n    /// <inheritdoc/>\n    public string? Enable(NoParamOrder npo = default, bool? js = null, bool? api = null,\n        bool? forms = null, bool? context = null, bool? autoToolbar = null, bool? styles = null)\n    {\n        var l = Log.Fn<string>();\n\n        var ps = ExCtx.GetService<IPageService>(reuse: true);\n        if (ps == null! /* paranoid */)\n            return l.ReturnNull(\"page service not found\");\n\n        if (js == true || api == true || forms == true) ps.Activate(SxcPageFeatures.JsCore.NameId);\n\n        // only update the values if true, otherwise leave untouched\n        // Must activate the \"public\" one JsCms, not internal, so feature-tests will run\n        if (api == true || forms == true) ps.Activate(SxcPageFeatures.JsCms.NameId);\n\n        if (styles == true) ps.Activate(SxcPageFeatures.Toolbars.NameId);\n\n        if (context == true) ps.Activate(SxcPageFeatures.ContextModule.NameId);\n\n        if (autoToolbar == true) ps.Activate(SxcPageFeatures.ToolbarsAuto.NameId);\n\n        return l.ReturnNull(\"ok\");\n    }\n\n    #endregion Scripts and CSS includes\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/EditService/EditService_Toolbar.cs",
    "content": "﻿using ToSic.Razor.Markup;\nusing ToSic.Sxc.Edit.Toolbar.Sys;\n\n\nnamespace ToSic.Sxc.Edit.EditService;\n\npartial class EditService\n{\n    private const string InnerContentAttribute = \"data-list-context\";\n\n    /// <inheritdoc />\n    public IRawHtmlString? Toolbar(\n        object? target = null,\n        NoParamOrder npo = default,\n        string? actions = null,\n        string? contentType = null,\n        object? condition = null,\n        object? prefill = null,\n        object? settings = null,\n        object? toolbar = null)\n        => ToolbarInternal(false, target, npo, actions, contentType, condition, prefill, settings, toolbar)\n            ?.Render(false);\n\n    /// <inheritdoc/>\n    public IRawHtmlString? TagToolbar(\n        object? target = null,\n        NoParamOrder npo = default,\n        string? actions = null,\n        string? contentType = null,\n        object? condition = null,\n        object? prefill = null,\n        object? settings = null,\n        object? toolbar = null)\n        => ToolbarInternal(true, target, npo, actions, contentType, condition, prefill, settings, toolbar)\n            ?.Render(true);\n\n    private ItemToolbarBase? ToolbarInternal(\n        bool inTag,\n        object? target,\n        // ReSharper disable once UnusedParameter.Local\n        NoParamOrder npo,\n        string? actions,\n        string? contentType,\n        object? condition,\n        object? prefill,\n        object? settings,\n        object? toolbar)\n    {\n        var l = Log.Fn<ItemToolbarBase?>($\"enabled:{Enabled}; inline{inTag}\");\n\n        // #DropRoutingToolbarBuilderThroughEditService v20\n        //// new v17.08 - force-show for everyone\n        //var tlbConfig = (target as ToolbarBuilder)?.Configuration;\n        //var forceShow = tlbConfig?.ShowForce == true;\n\n        // #DropRoutingToolbarBuilderThroughEditService v20\n        //if (!Enabled && !forceShow)\n        if (!Enabled)\n            return l.ReturnNull(\"not enabled\");\n\n        if (!IsConditionOk(condition))\n            return l.ReturnNull(\"condition false\");\n\n        // #DropRoutingToolbarBuilderThroughEditService v20\n        //// New in v13: The first parameter can also be a ToolbarBuilder, in which case all other params are ignored\n        //if (target is IToolbarBuilder tlbBuilder)\n        //    return l.Return(new ItemToolbarV14(tlbBuilder),\n        //        \"Using new modern Item-Toolbar, will ignore all other parameters.\");\n        \n        // ensure that internally we always process it as an entity\n        var eTarget = target as IEntity\n                      ?? (target as ICanBeEntity)?.Entity;\n        \n        if (target != null && eTarget == null)\n            l.W(\"Creating toolbar - it seems the object provided was neither null, IEntity nor DynamicEntity\");\n\n        // #DropRoutingToolbarBuilderThroughEditService v20\n        //if (toolbar is IToolbarBuilder tlbBuilder2)\n        //    return l.Return(new ItemToolbarV14(tlbBuilder2, eTarget),\n        //        \"Using new modern Item-Toolbar with an entity, will ignore all other parameters.\");\n        \n        return l.Return(ItemToolbarPicker.ItemToolbar(eTarget, actions, contentType,\n            prefill: prefill, settings: settings, toolbar: toolbar), \"Using classic mode, with all parameters.\");\n    }\n\n    private bool IsConditionOk(object? condition)\n    {\n        var l = Log.Fn<bool>();\n        // Null = no condition and certainly not false, say ok\n        if (condition == null)\n            return l.ReturnTrue(\"null,true\");\n\n        // Bool (non-null) and nullable\n        if (condition is false)\n            return l.ReturnFalse(\"bool false\");\n        if (condition as bool? == false)\n            return l.ReturnFalse(\"null false\");\n\n        // Int are only false if exactly 0\n        if (condition is 0)\n            return l.ReturnFalse(\"int 0\");\n        if (condition as int? == 0)\n            return l.ReturnFalse(\"int nullable 0\");\n\n        // String\n        if (condition is string s &&\n            string.Equals(s, false.ToString(), StringComparison.InvariantCultureIgnoreCase))\n            return l.ReturnFalse(\"string false\");\n\n        // Anything else: true\n        return l.ReturnTrue(\"default,true\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/EditService/IEditServiceSetup.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Edit.EditService;\n\npublic interface IEditServiceSetup\n{\n    internal IEditService SetBlock(IExecutionContext? exCtxOrNull, IBlock block);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Sys/SxcUiConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcUiConstants\n{\n    /// <summary>\n    /// Wrapper tag which contains the context information.\n    /// Usually just used in edit mode, but in rare cases also at runtime\n    /// </summary>\n    internal const string DefaultContextTag = \"div\";\n\n    /// <summary>\n    /// Decorator crass to mark a content-block in the HTML\n    /// </summary>\n    internal const string ClassToMarkContentBlock = \"sc-content-block\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/ActionNames.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar;\n\n/// <summary>\n/// Action names of buttons in toolbars, mainly for internal use - only publicly documented FYI.\n/// </summary>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\ninternal class ActionNames\n{\n    public const string App = \"app\";\n    public const string AppImport = \"app-import\";\n    public const string AppSettings = \"app-settings\";\n    public const string AppResources = \"app-resources\";\n    public const string Apps = \"apps\";\n    public const string System = \"system\";\n    public const string Insights = \"insights\";\n\n    public const string Add = \"add\";\n    public const string AddExisting = \"add-existing\";\n    public const string List = \"list\";\n    public const string MoveDown = \"movedown\";\n    public const string MoveUp = \"moveup\";\n    public const string Remove = \"remove\";\n    public const string Replace = \"replace\";\n\n    public const string Delete = \"delete\";\n    public const string Edit = \"edit\";\n    public const string New = \"new\";\n    public const string Copy = \"copy\";\n    public const string Data = \"data\";\n    public const string Publish = \"publish\";\n    internal const string Metadata = \"metadata\";\n\n\n    public const string Layout = \"layout\";\n    public const string Code = \"code\";\n    public const string Fields = \"fields\";\n    public const string Template = \"template\";\n    public const string Query = \"query\";\n    public const string View = \"view\";\n    public const string Edition = \"edition\";\n\n\n    public const string More = \"more\";\n\n    public const string Info = \"info\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/OldToolbarsForItems/EntityEditInfo.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Sxc.Data.Sys.Decorators;\n\n// ReSharper disable InconsistentNaming\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\ninternal class EntityEditInfo\n{\n    public EntityEditInfo(IEntity? entity = null)\n    {\n        // a null value/missing is also valid, when all you want is a new/add toolbar\n        if (entity == null)\n            return;\n\n        isPublished = entity.IsPublished;\n        title = entity.GetBestTitle();\n        entityGuid = entity.EntityGuid;\n\n        var editDecorator = entity.GetDecorator<EntityInBlockDecorator>();\n        if (editDecorator != null)\n        {\n            sortOrder = editDecorator.SortOrder;\n            if (editDecorator.ParentGuid == null)\n            {\n                useModuleList = true;\n            }\n            else \n                // only set parent if not empty - as it's always a valid int and wouldn't be null\n            {\n                parent = editDecorator.ParentGuid;\n                fields = editDecorator.FieldName;\n                entityId = entity.EntityId;\n                contentType = entity.Type.Name;\n            }\n        }\n        else\n        {\n            entityId = entity.EntityId;\n            contentType = entity.Type.Name;\n        }\n    }\n\n    internal const string KeyIndex = \"sortOrder\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public int? sortOrder { get; set; }\n\n    internal const string KeyUseModule = \"useModuleList\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public bool? useModuleList { get; set; }\n\n    internal const string KeyPublished = \"isPublished\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public bool? isPublished { get; set; }\n\n    internal const string KeyEntityId = \"entityId\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public int? entityId { get; set; }\n\n    internal const string KeyContentType = \"contentType\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? contentType { get; set; }\n\n    internal const string KeyPrefill = \"prefill\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public object? prefill { get; set; }\n\n    internal const string KeyTitle = \"title\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? title { get; set; }\n\n    internal const string KeyEntityGuid = \"entityGuid\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public Guid? entityGuid { get; set; }\n\n    internal const string KeyParent = \"parent\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public Guid? parent { get; set; }\n\n    internal const string KeyFields = \"fields\";\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? fields { get; set; }\n\n    internal static string[] KeysOfLists = [KeyIndex, KeyUseModule, KeyParent, KeyFields];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/OldToolbarsForItems/ItemToolbar.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sxc.Web.Sys.Html;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.ToolbarConstants;\nusing JsonSerializer = System.Text.Json.JsonSerializer;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\n// Which can create different generations of toolbars\n// The current setup is quite complex as it handles many different scenarios and skips certain values in those scenarios\ninternal class ItemToolbar: ItemToolbarBase\n{\n    protected readonly List<ItemToolbarAction> Actions = [];\n    protected readonly object? ClassicToolbarOrNull;\n    protected readonly object? Settings;\n\n    public ItemToolbar(IEntity? entity, string? actions = null, string? newType = null, object? prefill = null, object? settings = null, object? toolbar = null): base(\"TlbCls\")\n    {\n        Settings = settings;\n\n        // Case 1 - we have a classic V3 Toolbar object\n        if (toolbar != null)\n        {\n            ClassicToolbarOrNull = toolbar;\n            return;\n        }\n            \n        // Case 2 build a toolbar based on the actions or just from empty definition\n        if (actions == null)\n        {\n            Actions.Add(new(entity) { contentType = newType, prefill = prefill });\n            return;\n        }\n\n        // Case 3 - we have multiple actions\n        var actList = actions.CsvToArrayWithoutEmpty();\n        foreach (var act in actList)\n            Actions.Add(new(entity)\n            {\n                action = act,\n                contentType = newType,\n                prefill = prefill\n            });\n\n    }\n\n    private string ToolbarObjJson()\n        => JsonSerializer.Serialize(\n            ClassicToolbarOrNull ?? (Actions.Count == 1 ? Actions.First() : Actions),\n            JsonOptions.SafeJsonForHtmlAttributes);\n\n\n    private string SettingsJson => JsonSerializer.Serialize(Settings, JsonOptions.SafeJsonForHtmlAttributes);\n\n\n    [JsonIgnore]\n    public override string ToolbarAsTag\n        => ToolbarTagTemplate\n            .Replace(ToolbarTagPlaceholder, $\" {HtmlAttribute.Create(JsonToolbarNodeName, ToolbarJson )} {AttributeSettings()} \");\n\n    protected string ToolbarJson => ToolbarObjJson();\n\n    private string AttributeSettings()\n        => HtmlAttribute.Create(JsonSettingsNodeName, SettingsJson).ToString() ?? \"\";\n\n    public override string ToolbarAsAttributes()\n        => HtmlAttribute.Create(ToolbarAttributeName,\n            \"{\\\"\" + JsonToolbarNodeName + \"\\\":\" + ToolbarObjJson() + \",\\\"\" + JsonSettingsNodeName + \"\\\":\" + SettingsJson + \"}\").ToString()!;\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/OldToolbarsForItems/ItemToolbarAction.cs",
    "content": "﻿using System.Text.Json.Serialization;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\ninternal class ItemToolbarAction(IEntity? entity = null) : EntityEditInfo(entity)\n{\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    // ReSharper disable once InconsistentNaming\n    public string? action { get; set; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/OldToolbarsForItems/ItemToolbarBase.cs",
    "content": "﻿using ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\ninternal abstract class ItemToolbarBase(string logName) : ServiceBase($\"{SxcLogName}.{logName}\")\n{\n    public abstract string ToolbarAsTag { get; }\n\n    /// <summary>\n    /// Generate the attributes to add to a toolbar tag \n    /// </summary>\n    /// <returns></returns>\n    public abstract string ToolbarAsAttributes();\n\n    public RawHtmlString Render(bool inTag) => new(inTag ? ToolbarAsAttributes() : ToolbarAsTag);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/OldToolbarsForItems/ItemToolbarPicker.cs",
    "content": "﻿using ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\ninternal class ItemToolbarPicker\n{\n    internal static ItemToolbarBase ItemToolbar(IEntity? entity, string? actions = null, string? newType = null,\n        object? prefill = null, object? settings = null, object? toolbar = null)\n    {\n        // #DropRoutingToolbarBuilderThroughEditService v20\n        // Case v13+ Toolbar Builder\n        if (toolbar is IToolbarBuilder)\n            throw new($\"Toolbar using old API provided a new {nameof(IToolbarBuilder)} - unexpected, pls contact iJungleboy to fix.\");\n            //return new ItemToolbarV14(toolbarBuilder, entity);\n\n        // Case 1 - use the simpler string format in V10.27\n        var (isV10, _) = CheckIfParamsMeanV10(toolbar, settings, prefill);\n        if (isV10)\n        {\n            // check conflicting prefill format\n            if (prefill != null && prefill is not string)\n                throw new(\"Tried to build toolbar in new V10 format, but prefill is not a string. In V10.27+ it expects a string in url format like field=value&field2=value2\");\n\n            return new ItemToolbarV10(entity, newType, (string)prefill!, settings as string, toolbar);\n        }\n\n        // Case 2 - we have a classic V3 Toolbar object\n        if (toolbar != null)\n        {\n            // check conflicting parameters\n            if (actions != null || newType != null || prefill != null)\n                throw new(\n                    \"trying to build toolbar but got both toolbar and actions/prefill/newType - this is conflicting, cannot continue\");\n        }\n\n        return new ItemToolbar(entity, actions, newType, prefill, settings, toolbar);\n    }\n\n    internal static (bool IsV10, List<string>? Rules) CheckIfParamsMeanV10(object? toolbar = null, object? settings = null, object? prefill = null)\n    {\n        // Case 1 - use the simpler string format in V10.27\n        var toolbarAsStringArray = ToolbarV10OrNull(toolbar);\n        if (settings is string || toolbar is string || prefill is string || toolbarAsStringArray != null)\n        {\n            return (true, toolbarAsStringArray);\n        }\n        return (false, null);\n    }\n\n    /// <summary>\n    /// Check if the configuration we got is a V10 Toolbar\n    /// </summary>\n    /// <param name=\"toolbar\"></param>\n    /// <returns></returns>\n    internal static List<string>? ToolbarV10OrNull(object? toolbar)\n    {\n        // Fix 14.04 - I believe this case somehow got lost in history\n        if (toolbar is string strToolbar)\n            return [strToolbar];\n\n        // Note: This is a bit complex because previously we checked for this:\n        // return toolbar is IEnumerable<string> array && array.FirstOrDefault() != null;\n        // But that failed, because sometimes razor made the new [] { \"...\" } be an object list instead\n        // This is why it's more complex that you would intuitively do it - see https://github.com/2sic/2sxc/issues/2561\n\n        if (toolbar is not IEnumerable<object> objEnum)\n            return null;\n\n        var asArray = objEnum.ToArray();\n        return !asArray.All(o => o is string or IRawHtmlString)\n            ? null\n            : asArray\n                .Select(o => o.ToString() ?? \"\")\n                .Where(s => s != \"\")\n                .ToList();\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/OldToolbarsForItems/ItemToolbarV10.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sxc.Web.Sys.Html;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\nusing static System.String;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\ninternal class ItemToolbarV10(\n    IEntity? entity,\n    string? newType = null,\n    string? prefill = null,\n    string? settings = null,\n    object? toolbar = null,\n    string? logName = null)\n    : ItemToolbarBase(logName ?? \"TlbV10\")\n{\n    protected readonly string? Settings = settings;\n    protected readonly List<string> Rules = ItemToolbarPicker.ToolbarV10OrNull(toolbar) ?? [];\n    protected readonly EntityEditInfo TargetAction = new(entity) { contentType = newType, prefill = prefill };\n\n    public override string ToolbarAsTag \n        =>\n            ToolbarConstants.ToolbarTagTemplate.Replace(ToolbarConstants.ToolbarTagPlaceholder, ToolbarAttributes(ToolbarConstants.JsonToolbarNodeName));\n\n    protected string? ToolbarJson => _toolbarJson.Get(ToolbarV10Json);\n    private readonly GetOnce<string> _toolbarJson = new();\n\n    public override string ToolbarAsAttributes() => ToolbarAttributes(ToolbarConstants.ToolbarAttributeName);\n\n    protected virtual string ToolbarAttributes(string tlbAttrName) => $\" {HtmlAttribute.Create(tlbAttrName, ToolbarJson)} \";\n\n    private string ToolbarV10Json()\n    {\n        // add params if we have any\n        if (TargetAction != null! /* paranoid */)\n        {\n            var asUrl = new ObjectToUrl().Serialize(TargetAction);\n            if (!IsNullOrWhiteSpace(asUrl))\n                Rules.Add(\"params?\" + asUrl);\n        }\n\n        // Add settings if we have any\n        if (Settings.HasValue())\n            Rules.Add($\"settings?{Settings}\");\n\n        return JsonSerializer.Serialize(Rules, JsonOptions.SafeJsonForHtmlAttributes);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/OldToolbarsForItems/ItemToolbarV14.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sxc.Web.Sys.Html;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\ninternal class ItemToolbarV14(IToolbarBuilder toolbar, IEntity? entity = null)\n    : ItemToolbarV10(entity, null, null, null, toolbar, \"TlbV14\")\n{\n    public const string ContextAttributeName = \"sxc-context\";\n\n    protected readonly IToolbarBuilder ToolbarBuilder = toolbar;\n\n    protected override string ToolbarAttributes(string tlbAttrName) \n        => $\" {ContextAttribute()} {HtmlAttribute.Create(tlbAttrName, ToolbarJson)} \";\n\n    protected string? ContextAttribute()\n    {\n        var ctx = (ToolbarBuilder as IToolbarBuilderInternal)?.GetContext();\n        return ctx == null\n            ? null\n            : HtmlAttribute.Create(ContextAttributeName, JsonSerializer.Serialize(ctx, JsonOptions.SafeJsonForHtmlAttributes)).ToString();\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/ToolbarButtonActions.cs",
    "content": "﻿using ToSic.Eav.Data.Raw.Sys;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.VisualQuery;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\n[PrivateApi]\n[VisualQuery(\n    NiceName = \"ToolbarButtonActions\",\n    NameId = \"529752a2-11ea-473b-a81f-5634f935e57f\",\n    NameIds = [\"System.ToolbarButtonActions\"], // Internal name for the system, used in some entity-pickers. Can change at any time.\n    Type = DataSourceType.System,\n    Audience = Audience.System,\n    DataConfidentiality = DataConfidentiality.Public,\n    UiHint = \"Buttons\")]\n// ReSharper disable once UnusedMember.Global\npublic class ToolbarButtonActions : CustomDataSource\n{\n    public ToolbarButtonActions(Dependencies services)\n        : base(services, logName: \"CDS.TlbAct\")\n    {\n        ProvideOutRaw(\n            Generators,\n            options: () => new()\n            {\n                AutoId = false,\n                TitleField = \"Name\",\n                TypeName = nameof(ToolbarButtonActions),\n            });\n\n    }\n\n    private IEnumerable<IRawEntity> Generators()\n    {\n        var l = Log.Fn<IEnumerable<IRawEntity>>();\n        var list = new[]\n            {\n                \"app\",\n                \"app-import\",\n                \"app-settings\",\n                \"app-resources\",\n                \"apps\",\n                \"system\",\n                \"insights\",\n\n                \"add\",\n                \"add-existing\",\n                \"list\",\n                \"movedown\",\n                \"moveup\",\n                \"remove\",\n                \"replace\",\n\n                \"delete\",\n                \"edit\",\n                \"new\",\n                \"copy\",\n                \"data\",\n                \"publish\",\n                \"metadata\",\n\n                \"layout\",\n                \"code\",\n                \"fields\",\n                \"template\",\n                \"query\",\n                \"view\",\n                \"edition\",\n\n\n                \"more\",\n\n                \"info\",\n            }\n            .OrderBy(a => a)\n            .Select(action => new RawEntity(new()\n            {\n                { \"Name\", action },\n            }))\n            .ToList();\n\n        return l.Return(list, $\"{list.Count}\");\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/ToolbarButtonDecorator.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\n/// <summary>\n/// This is a decorator for Content-Types, which allows special configuration of buttons etc. on that type\n/// </summary>\n/// <remarks>\n/// WIP new in v14; as of now only used on NoteDecorator, should have more soon\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record ToolbarButtonDecorator : ModelFromEntity\n{\n    public const string TypeName = \"ToolbarButtonDecorator\";\n    public const string ContentTypeNameId = \"acc185a7-f300-4468-bce8-d6a64038989d\";\n\n    public static string KeyColor = \"color\";\n    public static string KeyIcon = \"icon\";\n    public static string KeyData = \"data\";\n    public static string KeyNote = \"note\";\n\n    public string Command => GetThis(\"\");\n\n    public bool UiData => GetThis(false);\n\n    public string Ui => GetThis(\"\");\n\n    public string UiIcon => GetThis(\"\");\n\n    public string UiColor=> GetThis(\"\").Trim('#');\n\n    public string AllRules()\n    {\n        var addOns = new\n        {\n            icon = UiIcon,\n            color = UiColor\n        };\n\n        return ToolbarBuilderUtilities.GetUi2Url()\n            .SerializeWithChild(Ui, addOns) ?? \"\";\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/ToolbarButtonDecoratorHelper.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Models;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ToolbarButtonDecoratorHelper(IAppReaderFactory appReaders, ScopedCache<Dictionary<string, ToolbarButtonDecorator?>> cache) : ServiceBase($\"{SxcLogName}.TbdHlp\", connect: [appReaders])\n{\n    public IAppIdentity? MainAppIdentity { get; set; }\n\n    internal ToolbarButtonDecorator? GetDecorator(IAppIdentity? appIdentity, string? typeName, string? command)\n    {\n        // If no special context was given, use the main one from the current context\n        appIdentity ??= MainAppIdentity;\n\n        if (appIdentity == null || !typeName.HasValue() || !command.HasValue())\n            return null;\n\n        var cacheKey = $\"{appIdentity.Show()}/{typeName}/{command}\";\n\n        if (cache.Cache.TryGetValue(cacheKey, out var cached))\n            return cached;\n\n        var appReader = appReaders.Get(appIdentity);\n\n        var type = appReader.TryGetContentType(typeName);\n        if (type == null)\n            return null;\n\n        var result = type.Metadata\n            .GetModels<ToolbarButtonDecorator>()\n            .FirstOrDefault(d => d.Command.EqualsInsensitive(command));\n\n        cache.Cache[cacheKey] = result;\n\n        return result;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/ToolbarConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ToolbarConstants\n{\n    private const string ForI18N = \"i18n:\";\n    private const string ToolbarPrefixRaw = \"Toolbar.\";\n    public const string ToolbarLabelPrefix = ForI18N + ToolbarPrefixRaw;\n\n    internal const string RuleToolbar = \"toolbar\";\n    internal const string Empty = \"empty\";\n    internal const string Default = \"default\";\n\n    internal const string RuleShow = \"show\";\n    internal const string RuleColor = \"color\";\n    internal const string RuleTooltip = \"title\";\n    internal const string RuleGroup = \"group\";\n    internal const string RuleClass = \"class\";\n    internal const string RulePosition = \"pos\";\n\n    internal const string NoteFormatHtml = \"html\";\n    internal const string NoteSettingHtml = \"asHtml\";\n\n    // Parameter prefixes, so that e.g. form params become \"form:key=value\"\n    public const string RuleParamPrefixPrefill = \"prefill:\";\n    public const string RuleParamPrefixForm = \"form:\";\n    //public const string RuleParamPrefixFormItem = \"form-item:\";\n    public const string RuleParamPrefixFilter = \"filter:\";\n\n    public const string RuleParamUiFields = \"uifields\";\n\n    public const string ToolbarAttributeName = \"sxc-toolbar\";\n    public const string JsonToolbarNodeName = \"toolbar\";\n    public const string JsonSettingsNodeName = \"settings\";\n\n    public const string ToolbarTagPlaceholder = \"{contents}\";\n    public const string ToolbarTagTemplate = \"<ul class=\\\"sc-menu\\\" {contents} ></ul>\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys/ToolbarContextExtensions.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static class ToolbarContextExtensions\n{\n    public static string? ToRuleString(this ToolbarContext? tlbCtx)\n        => tlbCtx == null\n            ? null\n            : tlbCtx.Custom.HasValue()\n                ? tlbCtx.Custom\n                : UrlParts.ConnectParameters(\n                    $\"{ToolbarContext.CtxZone}={tlbCtx.ZoneId}\",\n                    $\"{ToolbarContext.CtxApp}={tlbCtx.AppId}\"\n                );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRule.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOps;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal abstract class ToolbarRule: ToolbarRuleBase\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"command\"></param>\n    /// <param name=\"ui\"></param>\n    /// <param name=\"parameters\"></param>\n    /// <param name=\"operation\"></param>\n    /// <param name=\"operationCode\">This is a string from the original command, which could affect the operator. It's only used to override the operator if there is a relevant match. </param>\n    /// <param name=\"context\"></param>\n    protected ToolbarRule(string command, string? ui = null, string? parameters = null, char? operation = null, string? operationCode = null, ToolbarContext? context = null)\n    {\n        Command = command;\n        Operation = operation == (char)OprNone ? null : operation; // reset operation if it's none\n        Parameters = parameters ?? \"\";\n        Ui = ui ?? \"\";\n        Context = context;\n\n        if (!operationCode.HasValue())\n            return;\n        var targetCouldBeOperation = ToolbarRuleOperation.Pick(operationCode, OprUnknown);\n        if (targetCouldBeOperation != (char)OprUnknown) \n            Operation = targetCouldBeOperation;\n    }\n\n    public char? Operation { get; protected init; }\n\n    public string Command { get; protected init; }\n\n    public string? CommandValue { get; protected init; }\n\n    public string Parameters { get; }\n\n    public string Ui { get; }\n\n    public virtual string GeneratedCommandParams()\n        => UrlParts.ConnectParameters(Context.ToRuleString());\n\n    public virtual string GeneratedUiParams() => \"\";\n\n    public override string ToString()\n    {\n        switch (Operation)\n        {\n            case ToolbarRuleOperation.SkipInclude:\n                return \"\";\n            // If Operation is remove, don't add all the additional stuff. Enhanced in 17.10\n            case ToolbarRuleOperation.RemoveOperation:\n                return Operation + Command;\n        }\n\n        var result = Operation + Command + (CommandValue.HasValue() ? \"=\" + CommandValue : \"\");\n\n        var genUi = GeneratedUiParams();\n        if (genUi.HasValue())\n            result += \"&\" + genUi;\n        if (Ui.HasValue())\n            result += \"&\" + Ui;\n            \n        var genCmdParams = GeneratedCommandParams();\n        var hasGeneratedCmdParams = genCmdParams.HasValue();\n        var hasCmdParams = Parameters.HasValue();\n\n        // Stop if nothing to add\n        if (!hasGeneratedCmdParams && !hasCmdParams)\n            return result;\n            \n        result += \"?\" + UrlParts.ConnectParameters(genCmdParams, Parameters);\n        return result;\n    }\n\n    protected string BuildValidParameterList(IEnumerable<(string, string?)> values)\n    {\n        var keep = values.Where(set => !string.IsNullOrWhiteSpace(set.Item2));\n        return string.Join(\"&\", keep.Select(set => $\"{set.Item1}={set.Item2}\"));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleBase.cs",
    "content": "﻿using ToSic.Razor.Markup;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ToolbarRuleBase: RawHtmlString\n{\n\n    protected ToolbarRuleBase(): base(string.Empty) {}\n\n    protected ToolbarRuleBase(string rule): base(rule) { }\n\n\n    public ToolbarContext? Context { get; protected set; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleContext.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ToolbarRuleContext(\n    object? target,\n    ToolbarContext? context = null,\n    ToolbarButtonDecoratorHelper? decoHelper = null)\n    : ToolbarRuleTargeted(target, CommandName, null, null, null, context, decoHelper)\n{\n    internal const string CommandName = \"context\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleCustom.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\ninternal class ToolbarRuleCustom(\n    string command,\n    string? ui = null,\n    string? parameters = null,\n    char? operation = null,\n    string? operationCode = null,\n    ToolbarContext? context = null)\n    : ToolbarRule(command, ui: ui, parameters: parameters, operation: operation, operationCode: operationCode,\n        context: context);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleForEntity.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ToolbarRuleForEntity: ToolbarRuleTargeted\n{\n    internal ToolbarRuleForEntity(\n        string commandName,\n        object? target = null,   // IEntity, DynEntity or int\n        char? operation = null,\n        string? contentType = null,\n        string? ui = null, \n        string? parameters = null,\n        ToolbarContext? context = null,\n        ToolbarButtonDecoratorHelper? decoHelper = null,\n        string[]? propsSkip = null,\n        string[]? propsKeep = null\n    ) : base(target, commandName, operation: operation, ui: ui, parameters: parameters, context: context, decoHelper: decoHelper)\n    {\n        if (target is int intTarget)\n            EditInfo.entityId = intTarget;\n        if (contentType != null)\n            EditInfo.contentType = contentType;\n\n        if (propsSkip != null)\n            _urlValueFilterNames = new(true, propsSkip);\n        else if (propsKeep != null)\n            _urlValueFilterNames = new(false, propsKeep);\n    }\n\n    /// <summary>\n    /// The filter for what entity properties to keep in the params. By default, keep all.\n    /// </summary>\n    private readonly UrlValueFilterNames _urlValueFilterNames = new(true, []);\n\n\n    protected IEntity? TargetEntity => _entity.Get(() => Target as IEntity ?? (Target as ICanBeEntity)?.Entity);\n    private readonly GetOnce<IEntity?> _entity = new();\n\n    internal EntityEditInfo EditInfo => _editInfo.Get(() => new(TargetEntity))!;\n    private readonly GetOnce<EntityEditInfo> _editInfo = new();\n\n    protected override string DecoratorTypeName => TargetEntity?.Type?.Name ?? \"\";\n\n    public override string GeneratedCommandParams()\n        => UrlParts.ConnectParameters(EntityParamsList(), base.GeneratedCommandParams());\n\n    protected string? EntityParamsList()\n    {\n        var obj2Url = new ObjectToUrl(null, [_urlValueFilterNames]);\n        return obj2Url.Serialize(EditInfo);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleForParams.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\ninternal class ToolbarRuleForParams(\n    object? target,\n    string? ui = null,\n    string? parameters = null,\n    ToolbarContext? context = null,\n    ToolbarButtonDecoratorHelper? decoHelper = null)\n    : ToolbarRuleForEntity(CommandName, target, null, null, ui: ui, parameters: parameters, context, decoHelper)\n{\n    public const string CommandName = \"params\";\n\n    //internal ToolbarRuleForParams(\n    //    ToolbarRuleForParams original,\n    //    object target,\n    //    string? ui = null,\n    //    string? parameters = null\n    //) : this(target, ui ?? original?.Ui, parameters ?? original?.Parameters, original?.Context, original?.DecoHelper)\n    //{}\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleGeneric.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\ninternal class ToolbarRuleGeneric(string rule) : ToolbarRuleBase(rule);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleMetadata.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Web.Sys.Url;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.EntityEditInfo;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ToolbarRuleMetadata(\n    object target,\n    string typeName,\n    char operation,\n    string? ui = null,\n    string? parameters = null,\n    ToolbarContext? context = null,\n    ToolbarButtonDecoratorHelper? decoHelper = null\n    ) : ToolbarRuleTargeted(target, ActionNames.Metadata, operation: operation, ui: ui, parameters: parameters, context: context, decoHelper: decoHelper)\n{\n    protected override string DecoratorTypeName => typeName;\n\n    public override string GeneratedCommandParams() \n        => UrlParts.ConnectParameters(MetadataCommandParams(), base.GeneratedCommandParams());\n\n    private string MetadataCommandParams()\n    {\n        if (string.IsNullOrWhiteSpace(typeName))\n            return \"error=NoContentType\";\n        if (typeName.Contains(\",\"))\n            return \"error=CommaFoundInContentType\";\n        if (Target is not IHasMetadata hasMetadata)\n            return \"error=TargetWithoutMetadata\";\n\n        // 1. check if it's a valid target\n        var targetId = hasMetadata.Metadata.Target;\n\n        // Check if it already has this metadata\n        var existing = hasMetadata.Metadata.OfType(typeName).FirstOrDefault();\n\n        // add / update rule\n        var newRule = $\"{KeyEntityId}={existing?.EntityId ?? 0}\"\n                      + (existing == null\n                          ? $\"&{KeyContentType}={typeName}&{MdFor()}\"\n                          : \"\");\n        return newRule;\n\n        // Build target string containing IDs if not yet created\n        string MdFor() =>\n            \"for=\" + targetId.TargetType + \",\" +\n            (targetId.KeyGuid != null ? $\"guid,{targetId.KeyGuid}\"\n                : targetId.KeyString != null ? $\"string,{targetId.KeyString}\"\n                : $\"number,{targetId.KeyNumber}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleOperation.cs",
    "content": "﻿using ToSic.Sys.Utils;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOps;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\n/// <summary>\n/// This is just a documentation class to show all possible values for a `operation` parameter.\n///\n/// _WARNING_ Do not reference this object, it can change at any time.\n/// It's only here for documentation. \n/// </summary>\ninternal class ToolbarRuleOperation\n{\n    /// <summary>\n    /// Symbol to make sure a button is explicitly added.\n    /// Useful to force when a button would otherwise remain hidden because of a permission or another condition. \n    /// </summary>\n    protected internal const char AddOperation = '+';\n\n    /// <summary>\n    /// Symbol to add a button but still respect it's internal show/hide conditions. \n    /// </summary>\n    protected internal const char AutoOperation = '±';\n\n    /// <summary>\n    /// Symbol to modify a button in a toolbar - for example to force it to show.\n    /// </summary>\n    protected internal const char ModifyOperation = '%';\n\n    /// <summary>\n    /// Symbol to remove a button in a toolbar.\n    /// </summary>\n    protected internal const char RemoveOperation = '-';\n\n    protected internal const char UnknownOperation = '¿';\n\n    protected internal const char NoOperation = ' ';\n\n    protected internal const char SkipInclude = '^';\n\n    /// <summary>\n    /// Verb to make sure a button is explicitly added.\n    /// Useful to force when a button would otherwise remain hidden because of a permission or another condition. \n    /// </summary>\n    protected internal const string AddVerb = \"add\";\n\n    /// <summary>\n    /// Verb to add a button but still respect it's internal show/hide conditions. \n    /// </summary>\n    protected internal const string AutoVerb = \"auto\";\n\n    /// <summary>\n    /// Verb to modify a button in a toolbar - for example to force it to show.\n    /// </summary>\n    protected internal const string ModifyVerb = \"modify\";\n\n    /// <summary>\n    /// Verb to remove a button in a toolbar.\n    /// </summary>\n    protected internal const string RemoveVerb = \"remove\";\n\n    internal static Dictionary<string, ToolbarRuleOps> ToolbarRuleOpSynonyms =\n        new(StringComparer.InvariantCultureIgnoreCase)\n        {\n            { ModifyVerb, OprModify },\n            { AddVerb, OprAdd },\n            { AutoVerb, OprAuto },\n            { RemoveVerb, OprRemove },\n        };\n\n    internal static char Pick(string? op, ToolbarRuleOps defOp, bool? condition = default)\n        => condition == false\n            ? SkipInclude\n            : PrePick(op, defOp);\n\n    private static char PrePick(string? op, ToolbarRuleOps defOp)\n    {\n        if (!op.HasValue())\n            return (char)defOp;\n        op = op.Trim();\n\n        if (op.Length == 1 && Enum.IsDefined(typeof(ToolbarRuleOps), (int)op[0]))\n            return op[0];\n\n        if (ToolbarRuleOpSynonyms.TryGetValue(op, out var foundSyn))\n            return (char)foundSyn;\n\n        return (char)defOp;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleOps.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\ninternal enum ToolbarRuleOps\n{\n    OprAdd = ToolbarRuleOperation.AddOperation,\n    OprAuto = ToolbarRuleOperation.AutoOperation,\n    OprModify = ToolbarRuleOperation.ModifyOperation,\n    OprRemove = ToolbarRuleOperation.RemoveOperation,\n    [PrivateApi]\n    OprUnknown = ToolbarRuleOperation.UnknownOperation,\n    [PrivateApi]\n    OprNone = ToolbarRuleOperation.NoOperation,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\ninternal class ToolbarRuleSettings(\n#pragma warning disable CS9113 // Parameter is unread.\n    NoParamOrder npo = default,\n#pragma warning restore CS9113 // Parameter is unread.\n    string? show = null,\n    string? hover = null,\n    string? follow = null,\n    string? classes = null,\n    string? autoAddMore = null,\n    string? ui = null,\n    string? parameters = null) : ToolbarRule(CommandName, ui: ui ?? \"\", parameters: parameters ?? \"\")\n{\n    private const string CommandName = \"settings\";\n    private readonly (string, string?)[] _uiParams =\n        [\n            (\"show\", show),\n            (\"hover\", hover),\n            (\"follow\", follow),\n            (\"autoAddMore\", autoAddMore),\n            (\"classes\", classes),\n        ];\n\n    public override string GeneratedUiParams() => BuildValidParameterList(_uiParams);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleTargeted.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOps;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\n/// <summary>\n/// A toolbar rule for a specific target\n/// </summary>\ninternal abstract class ToolbarRuleTargeted: ToolbarRule\n{\n    protected ToolbarRuleTargeted(\n        object? target, \n        string command, \n        string? ui = null, \n        string? parameters = null, \n        char? operation = null,\n        ToolbarContext? context = null,\n        ToolbarButtonDecoratorHelper? decoHelper = null\n    ) : base(command, ui, parameters: parameters, operation: operation, operationCode: target as string, context: context)\n    {\n        Target = target;\n        DecoHelper = decoHelper;\n\n        var operationCode = target as string;\n        // Special case, if target is \"-\" or \"remove\" etc.\n        if (!operationCode.HasValue())\n            return;\n\n        var targetCouldBeOperation = ToolbarRuleOperation.Pick(operationCode, OprUnknown);\n        if (targetCouldBeOperation == (char)OprUnknown)\n            return;\n\n        Target = null;\n        Operation = targetCouldBeOperation;\n    }\n\n    internal object? Target { get; set; }\n\n    protected readonly ToolbarButtonDecoratorHelper? DecoHelper;\n\n    public override string GeneratedUiParams()\n        => UrlParts.ConnectParameters(UiParams(), base.GeneratedUiParams());\n\n\n    #region Decorators\n\n    protected virtual string DecoratorTypeName => \"\";\n\n    protected ToolbarButtonDecorator? Decorator => _decorator.Get(() =>\n    {\n        var decoTypeName = DecoratorTypeName;\n        return decoTypeName.HasValue() ? DecoHelper?.GetDecorator(Context, decoTypeName ?? \"\", Command) : null;\n    });\n    private readonly GetOnce<ToolbarButtonDecorator?> _decorator = new();\n    private string UiParams() => Decorator?.AllRules() ?? \"\";\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.Rules/ToolbarRuleToolbar.cs",
    "content": "﻿\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\ninternal class ToolbarRuleToolbar: ToolbarRule\n{\n    internal const string RuleToolbar = \"toolbar\";\n    internal const string Empty = \"empty\";\n    internal const string Default = \"default\";\n\n    public ToolbarRuleToolbar(string template = \"\", string? ui = \"\"): base(RuleToolbar, ui: ui ?? \"\")\n    {\n        CommandValue = template ?? \"\";\n    }\n\n    public bool IsDefault => TemplateName == Default;\n\n    public string TemplateName => CommandValue.HasValue() ? CommandValue : Default;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/FilterValueProcessor.cs",
    "content": "﻿using System.Collections;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class FilterValueProcessor : UrlValueProcess\n{\n\n    public override NameObjectSet? Process(NameObjectSet? set)\n    {\n        // Basic cases where we don't change anything\n        if (set?.Value == null || set.Value is string || set.Value.IsNumeric())\n            return set;\n\n        // If the value is an entity / dynamic-entity, return it as an id\n        if (set.Value is ICanBeEntity entity)\n            return new(set, value: entity.Entity.EntityId);\n\n        // Check array / list of items to filter for\n        // Make sure that if they have IDs or Entity-like objects they will be reduced to their ID\n        if (set.Value is IEnumerable enumerable)\n        {\n            var ids = enumerable.Cast<object>().Select(o =>\n                {\n                    if (o is string str) return str;\n                    if (o.IsNumeric()) return o.ToString();\n                    if (o is ICanBeEntity oEnt) return oEnt.Entity.EntityId.ToString();\n                    return null;\n                })\n                .Where(v => v != null)\n                .ToArray();\n            return new(set, value: ids);\n        }\n\n        // Fallback\n        return set;\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder.cs",
    "content": "﻿using System.Collections;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Web.Sys.Html;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\n/// <summary>\n/// INTERNAL: Toolbar Builder implementation.\n/// </summary>\n/// <remarks>\n/// We cannot make this internal :(\n/// Reason is that as soon as we run something like `Kit.Toolbar.Empty(Content)` in a razor file,\n/// the result is dynamic - so the compiler evaluates the final object at runtime.\n/// If the ToolbarBuilder is internal, things start to fail.\n/// like AsTag() will fail, saying that RawHtmlString doesn't have that\n/// So for now :( it must remain public.\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial record ToolbarBuilder: HybridHtmlString, IEnumerable<string>, IToolbarBuilder, INeedsExecutionContext\n{\n\n    #region Constructors and Init\n\n    public record Dependencies(\n        LazySvc<ToolbarButtonDecoratorHelper> ToolbarButtonHelper,\n        LazySvc<IAppsCatalog> AppsCatalog)\n        : DependenciesRecord(connect: [ToolbarButtonHelper, AppsCatalog]);\n\n    /// <summary>\n    /// Public constructor for DI\n    /// </summary>\n    /// <param name=\"services\"></param>\n    public ToolbarBuilder(Dependencies services) =>\n        Services = services.ConnectServices(Log);\n\n    protected Dependencies Services { get; init; }\n\n    public ILog Log { get; } = new Log(SxcLogName + \".TlbBld\");\n    \n\n    public void ConnectToRoot(IExecutionContext? exCtx)\n    {\n        if (exCtx == null)\n            return;\n        ExCtx = exCtx;\n        CurrentAppIdentity = exCtx.GetApp().PureIdentity();\n        Services.ToolbarButtonHelper.Value.MainAppIdentity = CurrentAppIdentity;\n    }\n\n    private IAppIdentity? CurrentAppIdentity { get; set; }\n\n    private IExecutionContext ExCtx { get; set; } = null!;\n\n    #endregion\n\n    #region Object state, init only for cloning\n\n    internal ToolbarBuilderConfiguration Configuration { get; init; } = new();\n\n    [field: AllowNull, MaybeNull]\n    private ToolbarBuilderUtilities Utils => field ??= new();\n\n    internal List<ToolbarRuleBase> Rules { get; init; } = [];\n\n    #endregion\n\n\n    internal IToolbarBuilder Toolbar(\n        string toolbarTemplate,\n        object? target = default,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = default,\n        object? parameters = default,\n        object? prefill = default\n    )\n    {\n        var updated = this.AddInternal([new ToolbarRuleToolbar(toolbarTemplate, ui: PrepareUi(ui))]);\n        // If anything is not null, then we must specify it\n        return new[] { target, parameters, prefill, tweak }.Any(x => x != null)\n            ? updated.Parameters(target, tweak: tweak, parameters: parameters, prefill: prefill)\n            : updated;\n    }\n\n\n    private T? FindRule<T>() where T : class => Rules.FirstOrDefault(r => r is T) as T;\n\n\n    #region Enumerators\n\n    [PrivateApi]\n    public IEnumerator<string> GetEnumerator()\n    {\n        var rulesToDeliver = Rules;\n\n        // **Special**\n        // Previously standalone toolbars also hovered based on their wrapper DIV.\n        // But this isn't actually useful anymore - normally hover is done with a non-standalone toolbar.\n        // But we cannot change the JS defaults, because that would affect old toolbars\n        // So any standalone toolbar created using the tag-builder will automatically add a settings\n        // to not-hover by default. \n        // The rule must be added to the top of the list, so that any other settings will take precedence,\n        // Including UI rules added to the toolbar itself\n        if (Configuration.HtmlMode == ToolbarHtmlModes.Standalone)\n        {\n            var standaloneSettings = new ToolbarRuleSettings(show: \"always\", hover: \"none\");\n            rulesToDeliver = [standaloneSettings, .. Rules];\n        }\n\n        return rulesToDeliver.Select(r => r.ToString()).GetEnumerator();\n    }\n\n    [PrivateApi]\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilderConfiguration.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\ninternal record ToolbarBuilderConfiguration\n{\n    /// <summary>\n    /// How the HTML is created - for tag, attribute, etc.\n    /// </summary>\n    public string? HtmlMode { get; init; }\n\n    /// <summary>\n    /// Condition to choose if this toolbar should be rendered at all.\n    /// </summary>\n    public bool? Condition { get; init; }\n\n    /// <summary>\n    /// Condition to choose if this toolbar should be rendered at all.\n    /// </summary>\n    public Func<bool>? ConditionFunc { get; init; }\n\n    /// <summary>\n    /// Setting from toolbar API.\n    /// </summary>\n    public bool? ShowForEveryone { get; init; }\n\n    /// <summary>\n    /// Final effect, which will be reviewed when showing the toolbar; set/read internally.\n    /// </summary>\n    internal bool? ShowForce { get; init; }\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>New v20</remarks>\n    public List<string>? ShowForRoles { get; init; }\n\n    public List<string>? ShowDenyRoles { get; init; }\n\n    /// <summary>\n    /// Temporary group identifier, which is used for all following buttons which are specified.\n    /// </summary>\n    public string? Group { get; init; }\n\n    /// <summary>\n    /// Item to check if the toolbar should be in demo mode.\n    /// </summary>\n    public ICanBeEntity? DemoCheckItem { get; init; }\n\n    /// <summary>\n    /// Message to show if the toolbar is in demo mode.\n    /// </summary>\n    public string? DemoMessage { get; init; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilderUtilities.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\n/// <summary>\n/// Special utilities for the Toolbar Builder,\n/// which should only be created once per use case to optimize performance.\n///\n/// Note that previously this was part of the ToolbarBuilder,\n/// but the effect was since the toolbar builder is re-created constantly, the\n/// helpers were also recreated constantly. \n/// </summary>\ninternal class ToolbarBuilderUtilities\n{\n    #region Parameters Processing\n\n    /// <summary>\n    /// Helper to process 'parameters' to url, ensuring lower-case etc. \n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public ObjectToUrl Par2Url => field ??= new(null, [new UrlValueCamelCase()]);\n\n\n    /// <summary>\n    /// Helper to process 'filter' to url - should not change the case of the properties and auto-fix some special scenarios\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public ObjectToUrl Filter2Url => field ??= new(null, [new FilterValueProcessor()])\n    {\n        ArrayBoxStart = \"[\",\n        ArrayBoxEnd = \"]\"\n    };\n\n\n\n    /// <summary>\n    /// Helper to process 'prefill' - should not change the case of the properties\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public ObjectToUrl Prefill2Url => field ??= new(null);\n\n    public string? PrepareParams(object? parameters, ITweakButton? tweaks = null)\n    {\n        var strParams = Par2Url.Serialize(parameters);\n        return MergeWithTweaks(strParams, tweaks?.ParamsMerge);\n    }\n\n    #endregion\n\n\n    #region UI Processing\n\n    internal static ObjectToUrl GetUi2Url() => new(null, [\n        new UrlValueCamelCase(),\n        new UiValueProcessor()\n    ]);\n\n\n    public string? PrepareUi(\n        object? ui,\n        object? uiMerge = null,\n        string? uiMergePrefix = null,\n        string? group = null, // current button-group name which must be merged into the Ui parameter\n        IEnumerable<object?>? tweaks = default\n    )\n    {\n        var uiString = Ui2Url.SerializeWithChild(ui, uiMerge, uiMergePrefix);\n        if (group.HasValue())\n            uiString = Ui2Url.SerializeWithChild(uiString, $\"group={group}\");\n        return MergeWithTweaks(uiString, tweaks);\n    }\n\n    [field: AllowNull, MaybeNull]\n    private ObjectToUrl Ui2Url => field ??= GetUi2Url();\n\n    #endregion\n\n    /// <summary>\n    ///  new v15 - add UI tweaks - must come last / after group\n    /// </summary>\n    /// <param name=\"previous\"></param>\n    /// <param name=\"tweaks\"></param>\n    /// <returns></returns>\n    private string? MergeWithTweaks(string? previous, IEnumerable<object?>? tweaks = null)\n    {\n        // new v15 - add UI tweaks - must come last / after group\n        if (tweaks == null)\n            return previous;\n\n        return tweaks.Aggregate(previous, (prev, t) => Ui2Url.SerializeWithChild(prev, t));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_As.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n\n    public IToolbarBuilder AsTag(object? target = null) =>\n        With(mode: ToolbarHtmlModes.Standalone, target: target);\n\n    public IToolbarBuilder AsAttributes(object? target = null) =>\n        With(mode: ToolbarHtmlModes.OnTag, target: target);\n\n    public IToolbarBuilder AsJson(object? target = null) =>\n        With(mode: ToolbarHtmlModes.Json, target: target);\n\n    /// <summary>\n    /// Helper for the AsTag, AsAttributes, AsJson methods.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"mode\"></param>\n    /// <param name=\"target\"></param>\n    /// <returns></returns>\n    private IToolbarBuilder With(NoParamOrder npo = default, string? mode = default, object? target = default)\n    {\n        // Create clone before starting to log so it's in there too\n        var clone = target == null\n            ? this\n            : (ToolbarBuilder)Parameters(target);   // Params will already copy/clone it\n\n        return mode == null\n            ? clone\n            : clone with\n            {\n                Configuration = Configuration with\n                {\n                    HtmlMode = mode\n                }\n            };\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_Button.cs",
    "content": "﻿using static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOps;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n\n    /// <inheritdoc />\n    public IToolbarBuilder Button(\n        string name,\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null,\n        string? context = null\n    )\n    {\n        var pars = PreCleanParams(tweak, defOp: OprNone, operation: operation, ui: ui, parameters: parameters);\n\n        return EntityRule(name, target, pars).Builder;\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_CommandsAdmin.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    private IToolbarBuilder AddAdminAction(\n        string verb,\n        // ReSharper disable once UnusedParameter.Local\n        NoParamOrder npo,\n        object? ui,\n        object? parameters,\n        string? operation,\n        object? target,\n        Func<ITweakButton, ITweakButton>? tweak,\n        [CallerMemberName] string? methodName = default\n    )\n    {\n        // process tweaks, but skip early to reduce calls if null\n        var tweaks = tweak == null\n            ? null\n            : RunTweaksOrErrorIfCombined(tweak: tweak, ui: ui, parameters: parameters, methodName: methodName);\n        var paramsTweaked = tweaks == null && parameters == null\n            ? null\n            : Utils.PrepareParams(parameters, tweaks);\n\n        var uiTweaked = PrepareUi(ui, tweaks: tweaks?.UiMerge);\n        TargetCheck(target);\n        return this.AddInternal([\n                new ToolbarRuleCustom(\n                    verb,\n                    operation: ToolbarRuleOperation.Pick(operation, ToolbarRuleOps.OprAuto, tweaks?.ConditionValue),\n                    ui: uiTweaked,\n                    parameters: paramsTweaked,\n                    operationCode: operation.HasValue() ? null : target as string)\n            ],\n            methodName: methodName);\n    }\n        \n        \n    public IToolbarBuilder App(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.App, npo, ui, parameters, operation, target, tweak);\n\n    public IToolbarBuilder AppImport(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.AppImport, npo, ui, parameters, operation, target, tweak);\n\n    public IToolbarBuilder AppResources(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.AppResources, npo, ui, parameters, operation, target, tweak);\n\n    public IToolbarBuilder AppSettings(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.AppSettings, npo, ui, parameters, operation, target, tweak);\n\n    public IToolbarBuilder Apps(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.Apps, npo, ui, parameters, operation, target, tweak);\n\n    public IToolbarBuilder System(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.System, npo, ui, parameters, operation, target, tweak);\n\n\n    public IToolbarBuilder Insights(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.Insights, npo, ui, parameters, operation, target, tweak);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_CommandsForLists.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.EntityEditInfo;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOps;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    private IToolbarBuilder AddListAction(\n        string commandName,\n        object? target,\n        NoParamOrder npo,\n        string? contentType,\n        object? ui,\n        object? parameters,\n        string? operation,\n        Func<ITweakButton, ITweakButton>? tweak,\n        [CallerMemberName] string? methodName = default)\n    {\n        TargetCheck(target);\n        var pars = PreCleanParams(tweak, defOp: OprAuto, operation: operation, ui: ui, parameters: parameters, methodName: methodName);\n        var command = new ToolbarRuleForEntity(commandName, target, \n            contentType: contentType,\n            ui: pars.Ui,\n            parameters: pars.Parameters,\n            propsKeep: KeysOfLists, \n            operation: pars.Operation);\n        return this.AddInternal([command], methodName: methodName);\n\n    }\n\n\n    public IToolbarBuilder Add(\n        object? target = null,\n        NoParamOrder npo = default,\n        string? contentType = null,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddListAction(ActionNames.Add, target, npo, contentType, ui, parameters, operation, tweak);\n\n    public IToolbarBuilder AddExisting(\n        object? target = null,\n        NoParamOrder npo = default,\n        string? contentType = null,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddListAction(ActionNames.AddExisting, target, npo, contentType, ui, parameters, operation, tweak);\n\n    public IToolbarBuilder List(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddListAction(ActionNames.List, target, npo, null, ui, parameters, operation, tweak);\n\n\n    public IToolbarBuilder MoveDown(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddListAction(ActionNames.MoveDown, target, npo, null, ui, parameters, operation, tweak);\n\n    public IToolbarBuilder MoveUp(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddListAction(ActionNames.MoveUp, target, npo, null, ui, parameters, operation, tweak);\n\n    public IToolbarBuilder Remove(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddListAction(ActionNames.Remove, target, npo, null, ui, parameters, operation, tweak);\n\n    public IToolbarBuilder Replace(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddListAction(ActionNames.Replace, target, npo, null, ui, parameters, operation, tweak);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_CommandsItems.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.EntityEditInfo;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOps;\n\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    private class CleanedParams\n    {\n        public char Operation { get; init; }\n        public string? Ui { get; init; }\n        public string? Parameters { get; init; }\n    }\n\n    private class CleanedParamsWithParts: CleanedParams\n    {\n        public Dictionary<string, CleanedParams>? Parts;\n    }\n\n    private CleanedParamsWithParts PreCleanParams(\n        Func<ITweakButton, ITweakButton>? tweak,\n        ToolbarRuleOps defOp, \n        NoParamOrder npo = default,\n        string? operation = default, \n        object? ui = default, \n        object? uiMerge = default, \n        string? uiMergePrefix = default, \n        object? parameters = default, \n        object? prefill = default,\n        object? filter = default,\n        string? fields = default,\n        ITweakButton? initialButton = default,\n        [CallerMemberName] string? methodName = default)\n    {\n        // process tweaks, but skip early to reduce calls if null\n        var tweaks = tweak == null\n            ? null\n            : RunTweaksOrErrorIfCombined(tweak: tweak, initial: initialButton, ui: ui, parameters: parameters, prefill: prefill, filter: filter, methodName: methodName);\n\n        var paramsString = tweaks == null && parameters == null\n            ? null\n            : Utils.PrepareParams(parameters, tweaks);\n\n        var parsWithPrefill = Utils.Prefill2Url.SerializeWithChild(paramsString, prefill, ToolbarConstants.RuleParamPrefixPrefill);\n        if (fields != null)\n            parsWithPrefill = Utils.Filter2Url.SerializeWithChild(parsWithPrefill, new { fields });\n\n        var namedParts = tweaks?.Named.Any() == true\n            ? tweaks.Named\n                .ToDictionary(\n                    kvp => kvp.Key,\n                    CleanedParams (kvp) => PreCleanParams(tweak: kvp.Value, defOp: OprNone)\n                )\n            : null;\n\n        return new()\n        {\n            Operation = ToolbarRuleOperation.Pick(operation, defOp, tweaks?.ConditionValue),\n            Ui = PrepareUi(ui, uiMerge, uiMergePrefix, tweaks: tweaks?.UiMerge),\n            Parameters = Utils.Filter2Url.SerializeWithChild(parsWithPrefill, filter, ToolbarConstants.RuleParamPrefixFilter),\n            Parts = namedParts\n        };\n\n    }\n\n    private (ToolbarRuleForEntity Rule, IToolbarBuilder Builder) EntityRule(\n        string verb, \n        object? target,\n        CleanedParams pars,\n        string []? propsSkip = null,\n        string[]? propsKeep = null,\n        string? contentType = null\n    )\n    {\n        TargetCheck(target);\n        var command = new ToolbarRuleForEntity(verb, target, pars.Operation,\n            ui: pars.Ui, parameters: pars.Parameters,\n            contentType: contentType,\n            propsKeep: propsKeep, propsSkip: propsSkip,\n            decoHelper: Services.ToolbarButtonHelper.Value);\n        var builder = this.AddInternal([command], methodName: verb);\n        return (command, builder);\n    }\n\n    public IToolbarBuilder Delete(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null)\n    {\n        // Set default operation based on what toolbar is used\n        var isDefToolbar = FindRule<ToolbarRuleToolbar>()?.IsDefault ?? false;\n        var defOp = isDefToolbar ? OprModify : OprAdd;\n\n        var pars = PreCleanParams(tweak, defOp: defOp, operation: operation, ui: ui, uiMerge: \"show=true\", parameters: parameters);\n\n        return EntityRule(ActionNames.Delete, target, pars, \n            propsKeep: [KeyTitle, KeyEntityId, KeyEntityGuid]).Builder;\n    }\n\n    public IToolbarBuilder Edit(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? operation = null)\n    {\n        var pars = PreCleanParams(tweak, defOp: OprAdd, operation: operation, ui: ui, parameters: parameters, prefill: prefill);\n        return EntityRule(ActionNames.Edit, target, pars, propsSkip: [KeyEntityGuid, KeyTitle, KeyPublished]).Builder;\n    }\n\n    public IToolbarBuilder New(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? operation = null)\n    {\n        var pars = PreCleanParams(tweak, defOp: OprAdd, operation: operation, ui: ui, parameters: parameters, prefill: prefill);\n\n        return EntityRule(ActionNames.New, target, pars,\n            propsSkip: [KeyEntityGuid, KeyEntityId, KeyTitle, KeyPublished],\n            contentType: target as string).Builder;\n    }\n\n\n\n    public IToolbarBuilder Publish(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null)\n    {\n        var pars = PreCleanParams(tweak, defOp: OprAdd, operation: operation, ui: ui, parameters: parameters);\n\n        return EntityRule(ActionNames.Publish, target, pars,\n            propsKeep: [KeyEntityId, KeyPublished, KeyIndex, KeyUseModule]).Builder;\n    }\n\n\n    /// <inheritdoc />\n    public IToolbarBuilder Metadata(\n        object target,\n        string? contentTypes = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? operation = null,\n        string? context = null)\n    {\n        var l = Log.Fn<IToolbarBuilder>();\n        var pars = PreCleanParams(tweak, defOp: OprAdd, operation: operation, ui: ui, parameters: parameters, prefill: prefill);\n\n        // Note: DO NOT check the target, as here an IAsset is absolutely valid\n        // TargetCheck(target);\n\n        var finalTypes = GetMetadataTypeNames(target, contentTypes);\n        var realContext = GenerateContext(target, context);\n\n        var mdsToAdd = finalTypes\n            .Select(ToolbarRuleBase (type) =>\n            {\n                var parsForThis = pars.Parts?.TryGetValue(type, out var p) == true\n                    ? p\n                    : pars;\n\n                return new ToolbarRuleMetadata(\n                    target,\n                    type,\n                    operation: parsForThis.Operation,\n                    ui: parsForThis.Ui,\n                    parameters: parsForThis.Parameters,\n                    context: realContext,\n                    decoHelper: Services.ToolbarButtonHelper.Value\n                );\n            })\n            .ToArray();\n\n        return l.ReturnAsOk(this.AddInternal(mdsToAdd));\n    }\n\n    /// <inheritdoc />\n    public IToolbarBuilder Copy(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        string? contentType = null,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? operation = null,\n        string? context = null)\n    {\n        var pars = PreCleanParams(tweak, defOp: OprAdd, operation: operation, ui: ui, parameters: parameters, prefill: prefill);\n\n        return EntityRule(ActionNames.Copy, target, pars, propsKeep: [KeyEntityId, KeyContentType],\n            contentType: contentType).Builder;\n    }\n\n\n    public IToolbarBuilder Data(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? filter = null,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    )\n    {\n        var pars = PreCleanParams(tweak, defOp: OprAdd, operation: operation, ui: ui, parameters: parameters, filter: filter);\n\n        return EntityRule(ActionNames.Data, target, pars, propsKeep: [KeyContentType], contentType: target as string)\n            .Builder;\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_CommandsView.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.EntityEditInfo;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOps;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    public IToolbarBuilder Layout(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.Layout, npo, ui, parameters, operation, target, tweak);\n\n\n    public IToolbarBuilder Code(\n        object target,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    )\n    {\n        // If we don't have a tweak then create the params the classic way\n        if (tweak == null)\n        {\n            var paramsWithCode = new ObjectToUrl().SerializeWithChild(parameters, (target as string).HasValue() ? \"call=\" + target : \"\", \"\");\n            return AddAdminAction(ActionNames.Code, npo, ui, paramsWithCode, operation, target, tweak);\n        }\n\n        // if we have a tweak, we must place the call into that to avoid an error that parameters & tweak are provided\n        ITweakButton ReTweak(ITweakButton _) => tweak(new TweakButton.TweakButton().Parameters(\"call\", target?.ToString()));\n        return AddAdminAction(ActionNames.Code, npo, ui, parameters, operation, target, ReTweak);\n    }\n\n\n    public IToolbarBuilder Fields(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    )\n    {\n        var pars = PreCleanParams(tweak, defOp: OprAdd, operation: operation, ui: ui, parameters: parameters);\n        return EntityRule(ActionNames.Fields, target, pars, propsKeep: [KeyContentType], contentType: target as string).Builder;\n    }\n\n\n    public IToolbarBuilder Template(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.Template, npo, ui, parameters, operation, target, tweak);\n\n    public IToolbarBuilder Query(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.Query, npo, ui, parameters, operation, target, tweak);\n\n    public IToolbarBuilder View(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        string? operation = null\n    ) => AddAdminAction(ActionNames.View, npo, ui, parameters, operation, target, tweak);\n\n    public IToolbarBuilder Edition(\n        NoParamOrder npo = default,\n        string? editions = default,\n        Func<ITweakButton, ITweakButton>? tweak = default\n    )\n    {\n        var paramsMergeInTweak = editions == default ? null : new { editions };\n        return AddAdminAction(ActionNames.Edition, npo, null, paramsMergeInTweak, null, null, tweak);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_Config.cs",
    "content": "﻿\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    public IToolbarBuilder More(NoParamOrder npo = default, object? ui = default)\n        => this.AddInternal([new ToolbarRuleCustom(ActionNames.More, ui: PrepareUi(ui))]);\n\n    public IToolbarBuilder For(object target)\n        => Parameters(target);\n\n    public IToolbarBuilder DetectDemo(ICanBeEntity root, NoParamOrder npo = default, string? message = default)\n        => this with { Configuration = Configuration with { DemoCheckItem = root, DemoMessage = message } };\n\n    public IToolbarBuilder Condition(bool condition)\n        => this with { Configuration = Configuration with { Condition = condition } };\n\n    public IToolbarBuilder Condition(Func<bool> condition)\n        => this with { Configuration = Configuration with { ConditionFunc = condition } };\n\n    public IToolbarBuilder Audience(\n        NoParamOrder npo = default,\n        bool? everyone = default,\n        IEnumerable<string>? roleNames = default,\n        IEnumerable<string>? denyRoleNames = default)\n    {\n        if (everyone == null && roleNames == null && denyRoleNames == null)\n            return this;\n\n        var config = Configuration;\n\n        if (everyone != null)\n            config = config with { ShowForEveryone = everyone };\n        if (roleNames != null)\n            config = config with { ShowForRoles = roleNames.ToList() };\n        if (denyRoleNames != null)\n            config = config with { ShowDenyRoles = denyRoleNames.ToList() };\n\n        return this with { Configuration = config };\n    }\n\n    public IToolbarBuilder Group(string? name = null)\n    {\n        // Auto-determine the group name if none was provided\n        // Maybe? only on null, because \"\" would mean to reset it again?\n        if (name.IsEmpty())\n            name = Configuration.Group.HasValue()\n                ? Configuration.Group + \"*\" // add an uncommon character so each group has another name\n                : \"custom\";\n\n        // Note that we'll add the new buttons directly using AddInternal, so it won't\n        // auto-add other UI params such as the previous group\n        return name.StartsWith(\"-\")\n            // It's a remove-group rule\n            ? this.AddInternal([new ToolbarRuleGeneric($\"-group={name.Substring(1)}\")])\n            // It's an add group - set the current group and add the button-rule\n            : (this with { Configuration = Configuration with { Group = name } })\n            .AddInternal([new ToolbarRuleGeneric($\"+group={name}\")]);\n    }\n\n    //public const string custom = \"custom\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_Context.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Catalog;\nusing ToSic.Eav.Metadata;\nusing ToSic.Eav.Metadata.Sys;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder : IToolbarBuilderInternal\n{\n    private const int NoAppId = -1;\n\n    public IToolbarBuilder Context(\n        object target\n    )\n    {\n        // Get context, specify \"true\" to force it to be added\n        var context = GenerateContext(target, true.ToString());\n        var rule = new ToolbarRuleContext(null, context, Services.ToolbarButtonHelper.Value);\n        return this.AddInternal([rule]);\n    }\n\n    /// <summary>\n    /// See if toolbar itself has a context, or there are rules which have a context,\n    /// or any of the rules have one\n    /// </summary>\n    /// <returns></returns>\n    ToolbarContext? IToolbarBuilderInternal.GetContext()\n        => Rules.OfType<ToolbarRuleContext>().FirstOrDefault()?.Context\n           ?? Rules.FirstOrDefault(r => r.Context != null)?.Context;\n\n\n    private ToolbarContext? GenerateContext(object? target, string? context)\n    {\n        var l = Log.Fn<ToolbarContext>($\"{nameof(context)}:{context}\");\n        // Check if context had already been prepared\n        if (context.ContainsInsensitive(\"context:\"))\n            return l.Return(new(context!), \"contains context:\");\n\n        if (target == null)\n            return l.ReturnNull(\"no target\");\n        if (context.EqualsInsensitive(false.ToString()))\n            return l.ReturnNull(\"context=false\");\n        var appsCatalog = Services.AppsCatalog.Value;\n        if (appsCatalog == null)\n            return l.ReturnNull(\"no AppStates\");\n\n        // Try to find the context\n        var appId = FindContextAppId(target);\n\n        // If nothing found\n        if (appId is 0 or NoAppId or KnownAppsConstants.TransientAppId or < 1)\n            return l.ReturnNull(\"no app identified\");\n\n        // This throws if the app doesn't exist in any zone\n        var identity = appsCatalog.AppIdentity(appId);\n\n        // If we're not forcing the context \"true\" then check cases where it's not needed\n        if (!context.EqualsInsensitive(true.ToString()))\n            // If we're still on the same app, and we didn't force the context, return null\n            if (CurrentAppIdentity?.AppId == identity.AppId)\n            {\n                // ensure we're not in a global context where the current-context is already special\n                var globalAppId = appsCatalog.GetPrimaryAppOfAppId(appId, Log);\n                if (globalAppId != identity.AppId)\n                    return l.ReturnNull($\"same app and not Global, context not forced: {identity.Show()}\");\n            }\n\n        var result = new ToolbarContext(identity);\n        return l.Return(result, \"ok\");\n    }\n\n    private int FindContextAppId(object target)\n    {\n        var l = Log.Fn<int>();\n        return target switch\n        {\n            IEntity entity => l.Return(entity.AppId, \"entity-appid\"),\n            ICanBeEntity canBeEntity => l.Return(canBeEntity.Entity?.AppId ?? NoAppId, \"dyn/typed entity\"),\n            IHasMetadata md when md.Metadata.Any() => l.Return(md.Metadata.FirstOrDefault()?.AppId ?? NoAppId, \"metadata\"),\n            IHasMetadata { Metadata: IMetadataInternals mdInternal } => l.Return(mdInternal.Context(\"todo\")?.AppId ?? NoAppId, \"metadata internal\"),\n            _ => l.Return(NoAppId, \"no app id\")\n        };\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_DemoToolbar.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleToolbar;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    /// <summary>\n    /// Detect if switch to demo is needed.\n    /// </summary>\n    /// <returns></returns>\n    private bool ShouldSwitchToItemDemoMode()\n    {\n        // If no root provided, we can't check demo mode as of now, so return\n        var root = Configuration?.DemoCheckItem?.Entity;\n        if (root == null)\n            return false;\n\n        // If root is not demo, then don't use demo mode\n        if (!root.IsDemoItemSafe())\n            return false;\n\n        // Check if we have a target, if not, then go into demo-mode\n        var target = (FindRule<ToolbarRuleForParams>()?.Target as ICanBeEntity)?.Entity;\n        if (target == null)\n            return true;\n\n        // If the root and target are the same, then the toolbar should work\n        // because it's meant to create a new entry right here\n        if (root.EntityId == target.EntityId)\n            return false;\n\n        return true;\n    }\n\n    /// <summary>\n    /// Create a fresh Toolbar which only shows infos about item being in demo-mode\n    /// </summary>\n    /// <returns></returns>\n    private ToolbarBuilder CreateStandaloneItemDemoToolbar()\n    {\n        var rules = new List<ToolbarRuleBase>();\n\n        if (!AddRuleOfOriginal<ToolbarRuleToolbar>(t => new(Empty, t.Ui)))\n            rules.Add(new ToolbarRuleToolbar(Empty));\n        AddRuleOfOriginal<ToolbarRuleForParams>();\n        AddRuleOfOriginal<ToolbarRuleSettings>();\n\n        var tlb = this with { Rules = rules };\n        var keyOrMessage = Configuration?.DemoMessage;\n        var allResources = ExCtx.GetDataStack<ITypedStack>(ExecutionContextStateNames.AllResources);\n        var message = keyOrMessage == null\n            ? allResources.Get<string>($\"{AppStackConstants.RootNameResources}.Toolbar.IsDemoSubItem\")\n            : keyOrMessage.StartsWith($\"{AppStackConstants.RootNameResources}.\")\n                ? allResources.Get<string>(keyOrMessage)\n                : keyOrMessage;\n        tlb = (ToolbarBuilder)tlb.Info(tweak: b => b.Note(message));\n        return tlb;\n\n        // Helper to check if a rule exists on the original\n        // and add it to the new toolbar if it does\n        // optionally tweak it if necessary\n        // return true/false to indicate if it was added\n        bool AddRuleOfOriginal<T>(Func<T, T>? tweak = null) where T : ToolbarRuleBase\n        {\n            var possibleParams = FindRule<T>();\n            if (possibleParams == null)\n                return false;\n            var tweaked = tweak?.Invoke(possibleParams);\n            rules.Add(tweaked ?? possibleParams);\n            return true;\n        }\n    }\n\n\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_Helpers.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    private string? PrepareUi(object? ui, object? uiMerge = default, string? uiMergePrefix = default, IEnumerable<object?>? tweaks = default) \n        => Utils.PrepareUi(ui, uiMerge, uiMergePrefix, Configuration?.Group, tweaks: tweaks);\n\n    private ITweakButton? RunTweaksOrErrorIfCombined(\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        ITweakButton? initial = default,\n        object? ui = default,\n        object? parameters = default,\n        object? prefill = default,\n        object? filter = default,\n        [CallerMemberName] string? methodName = null)\n    {\n        var tweaks = tweak?.Invoke(initial ?? new TweakButton.TweakButton());\n        ErrorIfTweakCombined(tweaks, ui, parameters, prefill, filter, methodName);\n        return tweaks;\n    }\n\n    private void ErrorIfTweakCombined(ITweakButton? tweak, object? ui, object? parameters, object? prefill, object? filter, string? methodName)\n    {\n        // No tweak, nothing to check\n        if (tweak == null)\n            return;\n        // If tweak exist, skip if nothing else was provided\n        if ((parameters ?? ui ?? prefill ?? filter) == null)\n            return;\n\n        // Figure out what name to show and alternative options\n        (string Name, string Alternatives) err = ui != null\n            ? (nameof(ui), $\".{nameof(ITweakButton.Ui)}(...), {nameof(ITweakButton.Show)}() or other methods\")\n            : parameters != null\n                ? (nameof(parameters), $\".{nameof(ITweakButton.Parameters)}(...) or other methods\")\n                : prefill != null\n                    ? (nameof(prefill), $\".{nameof(ITweakButton.Prefill)}(...)\")\n                    : filter != null\n                        ? (nameof(filter), $\".{nameof(ITweakButton.Filter)}(...)\")\n                        : (\"unknown\", \"unknown problem, pls contact us\");\n\n        throw new ArgumentException(\n            $\"You called .{methodName}(...) using the '{nameof(tweak)}:' parameter. \" +\n            $\"You also supplied a '{err.Name}:'. This is not allowed. When you use 'tweak', use {err.Alternatives} instead. See https://go.2sxc.org/tweak-buttons\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_InfoNote.cs",
    "content": "﻿using static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOps;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    public IToolbarBuilder Info(\n        NoParamOrder npo = default,\n        string? link = default,\n        string? target = default,\n        Func<ITweakButton, ITweakButton>? tweak = default\n    ) => InfoLikeButton(npo: npo,\n        verb: ActionNames.Info,\n        paramsMergeInTweak: link != default ? new { link, target } : null,\n        tweak: tweak);\n\n    private IToolbarBuilder InfoLikeButton(\n        NoParamOrder npo,\n        string verb,\n        object? paramsMergeInTweak,\n        Func<ITweakButton, ITweakButton>? tweak\n    )\n    {\n        tweak ??= TweakButton.TweakButton.NoOp; \n        var initial = paramsMergeInTweak == null\n            ? null\n            : new TweakButton.TweakButton().Parameters(paramsMergeInTweak);\n        var pars = PreCleanParams(tweak, defOp: OprNone, initialButton: initial);\n        return EntityRule(verb, null, pars).Builder;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_MetadataRecommendations.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    private ICollection<string> GetMetadataTypeNames(object? target, string? contentTypes)\n    {\n        var types = contentTypes.CsvToArrayWithoutEmpty();\n        if (!types.Any())\n            return FindMetadataRecommendations(target);\n\n        var typesToReturn = types\n            .SelectMany(t => t == \"*\" ? FindMetadataRecommendations(target) : [t])\n            .ToList();\n\n        return typesToReturn;\n    }\n\n    private string[] FindMetadataRecommendations(object? target)\n    {\n        var l = Log.Fn<string[]>();\n        // ReSharper disable once ConvertIfStatementToSwitchStatement\n        if (target == null)\n            return l.Return([], \"null\");\n\n        if (target is IHasMetadata withMetadata)\n            target = withMetadata.Metadata;\n\n        if (target is not IMetadata mdOf)\n            return l.Return([], \"not metadata\");\n\n        var recommendations = mdOf.Target?.Recommendations ?? [];\n\n        return l.Return(recommendations, \"ok\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_SettingsAndParams.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    public IToolbarBuilder Settings(\n        NoParamOrder npo = default,\n        string? show = default,\n        string? hover = default,\n        string? follow = default,\n        string? classes = default,\n        string? autoAddMore = default,\n        object? ui = default,\n        object? parameters = default)\n        => this.AddInternal([\n            new ToolbarRuleSettings(show: show, hover: hover, follow: follow, classes: classes,\n                autoAddMore: autoAddMore,\n                ui: PrepareUi(ui), parameters: Utils.Par2Url.Serialize(parameters))\n        ]);\n\n\n    public IToolbarBuilder Parameters(\n        object? target = default,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = default,\n        object? parameters = default,\n        object? prefill = default,\n        string? context = default\n    )\n    {\n        TargetCheck(target);\n        var clone = new ToolbarBuilder(this) { Rules = [.. Rules] }; // initialize Rules with spread operator syntax because it is reference type\n\n        // see if we already have a params rule, if yes remove to then later clone and add again\n        var previous = clone.FindRule<ToolbarRuleForParams>();\n        if (previous != null)\n            clone.Rules.Remove(previous);\n\n        // detect if the first parameter (target) is a parameters object\n        (target, parameters) = FixTargetIsParameters(target, parameters);\n\n        // Use new or previous target\n        target ??= previous?.Target;\n\n        // Must create a new one, to not change the original which is still in the original object\n        var uiWithPrevious = PrepareUi(previous?.Ui, ui);\n        var partsWithPrevious = Utils.Par2Url.SerializeWithChild(previous?.Parameters, parameters);\n        var parts = PreCleanParams(tweak, defOp: ToolbarRuleOps.OprNone, ui: uiWithPrevious, parameters: partsWithPrevious, prefill: prefill);\n\n        //var parsWithPrefill = Utils.Prefill2Url.SerializeWithChild(partsWithPrevious, prefill, PrefixPrefill);\n\n        var newParamsRule = new ToolbarRuleForParams(target,\n            parts.Ui,\n            parts.Parameters,\n            GenerateContext(target, context) ?? previous?.Context,\n            Services.ToolbarButtonHelper.Value);\n\n        clone.Rules.Add(newParamsRule);\n\n        return clone;\n    }\n\n    private static void TargetCheck(object? target)\n    {\n        if (target is IAsset)\n            throw new(\"Got a 'target' parameter which seems to be an adam-file. \" +\n                      \"This is not allowed. \" +\n                      \"Were you trying to target the .Metadata of this file? if so, add .Metadata to the target object.\");\n\n    }\n\n    private static (object? target, object? parameters) FixTargetIsParameters(object? target, object? parameters)\n    {\n        // No target, or parameters supplied\n        if (parameters != null || target == null)\n            return (target, parameters);\n\n        // Basically only keep the target as is, if it's a known target\n        if (target is IEntity or ICanBeEntity or IEnumerable<IEntity> or IEnumerable<ICanBeEntity>)\n            return (target, null);\n\n        return (null, target);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarBuilder_ToString.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing Attribute = ToSic.Razor.Markup.Attribute;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\npartial record ToolbarBuilder\n{\n    private const string ErrRenderMessage = \"error: can't render toolbar to html, missing context\";\n\n    /// <summary>\n    /// Also overwrite ToString() to keep functionality similar to before switch from class to record.\n    /// Probably not relevant though.\n    /// </summary>\n    /// <returns></returns>\n    public override string ToString() => ToHtmlString();\n\n    protected override string ToHtmlString()\n    {\n        // Get edit, but don't exit if null, as the Render (later on) will add comments if Edit is null\n        var editSvc = ExCtx.GetService<IEditService>(reuse: true);\n\n        // As the config can change before render, put `this` into a variable first\n        var finalToolbar = this;\n        var (enabled, showNonAdmin) = CheckShowConditions(editSvc);\n\n        // If we show to everyone, then we must make sure that the toolbars API is loaded in JS\n        // since in this case it may not be activated\n        if (showNonAdmin)\n        {\n            ExCtx.GetService<IPageService>(reuse: true)\n                .Activate(SxcPageFeatures.ToolbarsInternal.NameId);\n\n            finalToolbar = this with { Configuration = Configuration with { ShowForce = true } };\n        }\n\n        // Show toolbar or a Demo-Informative-Toolbar\n        if (ShouldSwitchToItemDemoMode())\n            finalToolbar = CreateStandaloneItemDemoToolbar();       // Implement Demo-Mode with info-button only\n\n        // don't show toolbar if not enabled (or not for everyone)\n        if (!enabled)\n            return \"\";\n        return finalToolbar.Render(editSvc);\n    }\n\n    private (bool enabled, bool showNonAdmin) CheckShowConditions(IEditService? editSvc)\n    {\n        // Get initial enabled from the Edit Service\n        var enabled = editSvc?.Enabled == true;\n\n        // Check force show for Everyone, because\n        // 1. the configuration says so\n        // 2. because the page-level Edit object says we're in demo mode\n        var showNonAdmins = Configuration.ShowForEveryone == true;\n        enabled = enabled || showNonAdmins;\n\n        // Check if enabled for certain groups\n        if (ExCtx != null! /* paranoid */)\n        {\n            var user = ExCtx.GetCmsContext().User;\n            var overrideShow = new ToolbarConfigurationShowHelper()\n                .OverrideShowBecauseOfRoles(Configuration, user);\n            enabled = overrideShow ?? enabled;\n            showNonAdmins = overrideShow ?? showNonAdmins;\n        }\n\n        // If enabled, then still check if conditions would deny again\n        // Check if conditions don't allow - in which case we return nothing.\n        // Only test conditions if the toolbar would show - otherwise ignore\n        if (!enabled)\n            return (enabled, showNonAdmins);\n\n        if (Configuration.Condition == false || Configuration.ConditionFunc?.Invoke() == false)\n            return (false, false);\n\n        return (enabled, showNonAdmins);\n    }\n\n\n\n\n    private string Render(IEditService? edit)\n    {\n        var mode = (Configuration.HtmlMode ?? ToolbarHtmlModes.OnTag).ToLowerInvariant();\n        switch (mode)\n        {\n            // ReSharper disable AssignNullToNotNullAttribute\n            case ToolbarHtmlModes.OnTag:\n                return edit == null\n                    ? new Attribute(ToolbarConstants.ToolbarAttributeName, ErrRenderMessage).ToString() // add error\n                    //: edit.TagToolbar(this)?.ToString();\n                    : new ItemToolbarV14(this).Render(true).ToString();\n            case ToolbarHtmlModes.Standalone:\n                return edit == null\n                    ? $\"<!-- {ErrRenderMessage} -->\" // add error\n                    //: edit.Toolbar(this)?.ToString();       // Show toolbar\n                    : new ItemToolbarV14(this).Render(false).ToString();\n            // ReSharper restore AssignNullToNotNullAttribute\n            case ToolbarHtmlModes.Json:\n                var rules = Rules\n                    .Select(r => r.ToString())\n                    .Where(r => r != \"\")\n                    .ToArray();\n                return JsonSerializer.Serialize(rules, JsonOptions.SafeJsonForHtmlAttributes);\n            default:\n                return $\"error: toolbar ToString mode '{mode}' is not known\";\n        }\n\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarConfigurationShowHelper.cs",
    "content": "﻿using ToSic.Sxc.Cms.Users;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\ninternal class ToolbarConfigurationShowHelper\n{\n    public bool? OverrideShowBecauseOfRoles(ToolbarBuilderConfiguration config, IUserModel user)\n    {\n        if (config == null || user == null)\n            return null;\n\n        // 99% never have this configured\n        if (config.ShowForRoles == null && config.ShowDenyRoles == null)\n            return null;\n\n        var enabledFor = config.ShowForRoles?.ToArray().TrimmedAndWithoutEmpty() ?? [];\n        var denyFor = config.ShowDenyRoles?.ToArray().TrimmedAndWithoutEmpty() ?? [];\n        var roles = user.Roles.Select(r => r.Name);\n\n        // Check allow\n        if (enabledFor.Any(eg => roles.Contains(eg, StringComparer.InvariantCultureIgnoreCase)))\n            return true;\n\n        // Check deny\n        if (denyFor.Any(eg => roles.Contains(eg, StringComparer.InvariantCultureIgnoreCase)))\n            return false;\n\n        return null;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarHtmlModes.cs",
    "content": "﻿namespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\ninternal class ToolbarHtmlModes\n{\n    public const string OnTag = \"tag\";\n    public const string Standalone = \"html\";\n    public const string Json = \"json\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/ToolbarServiceExtensions.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\ninternal static class ToolbarBuilderExtensions\n{\n    /// <summary>\n    /// Add one or more rules (as strings or ToolbarRule objects) according to the conventions of the [js toolbar](xref:JsCode.Toolbars.Simple)\n    /// </summary>\n    /// <returns>a _new_ toolbar builder - see [guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Index)</returns>\n    /// <remarks>\n    /// History\n    /// * Added in 2sxc 13\n    /// </remarks>\n    public static ToolbarBuilder AddInternal(this ToolbarBuilder original, ToolbarRuleBase[] newRules, [CallerMemberName] string? methodName = default)\n    {\n        var l = original.Log.Fn<ToolbarBuilder>(methodName);\n        if (!newRules.Any())\n            return l.Return(original, \"no new rules\");\n\n        // Create clone with all rules\n        var clone = original with\n        {\n            Rules = original.Rules.Concat(newRules).ToList(),\n        };\n\n\n        return l.Return(clone, $\"clone with {newRules.Length} new rules\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.ToolbarBuilder/UiValueProcessor.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.ToolbarButtonDecorator;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\n\ninternal class UiValueProcessor: UrlValueProcess\n{\n\n    public override NameObjectSet? Process(NameObjectSet? set)\n    {\n        if (set == null)\n            return null;\n        // Colors - remove any # like #CCDDFF\n        if (set.Name == KeyColor)\n            return set.Value is string color && color.HasValue() && color.Contains(\"#\")\n                ? new(set, value: color.Replace(\"#\", \"\"))\n                : set;\n\n        // Data: must always be object and base64\n        // WIP!\n        if (set.Name == KeyData || set.Name == KeyNote)\n        {\n            if (set.Value == null)\n                return set;\n            var json = JsonSerializer.Serialize(set.Value, JsonOptions.SafeJsonForHtmlAttributes);\n            return new(set, value: $\"{Json64Prefix}{Base64.Encode(json)}\");\n        }\n\n        // All others such as icons - make safe\n        return MakeSafe(set);\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Edit/Toolbar/Sys.TweakButton/TweakButton.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Immutable;\nusing System.Text.Json;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.Toolbar.Sys.TweakButton;\n\n/// <summary>\n/// Must be public because of side effect with old/dynamic razor.\n/// Example which would fail if it's internal:\n/// - `tweak: b => b.Tooltip(Resources.LabelRegistrations).Filter(\"EventDate\", d.EntityId))`\n/// In this case `.Filter` would fail because the tooltip comes from a dynamic object,\n/// so then the compiler will eval the resulting object, and it can't be internal.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class TweakButton: ITweakButton\n{\n    public IImmutableList<object?> UiMerge { get; }\n\n    public IImmutableList<object?> ParamsMerge { get; }\n\n    public IImmutableDictionary<string, Func<ITweakButton, ITweakButton>> Named { get; }\n\n    public bool? ConditionValue { get; }\n\n    internal TweakButton()\n    {\n        UiMerge = ImmutableList.Create<object?>();\n        ParamsMerge = ImmutableList.Create<object?>();\n        Named = new Dictionary<string, Func<ITweakButton, ITweakButton>>().ToImmutableDictionary();\n    }\n\n    private TweakButton(ITweakButton original,\n        IImmutableList<object?>? ui = default,\n        IImmutableList<object?>? parameters = default,\n        IImmutableDictionary<string,\n        Func<ITweakButton, ITweakButton>>? named = default,\n        bool? condition = null)\n    {\n        UiMerge = ui ?? original?.UiMerge ?? ImmutableList.Create<object?>();\n        ParamsMerge = parameters ?? original?.ParamsMerge ?? ImmutableList.Create<object?>();\n        Named = named ?? original?.Named ?? new Dictionary<string, Func<ITweakButton, ITweakButton>>().ToImmutableDictionary();\n        ConditionValue = condition ?? original?.ConditionValue;\n    }\n\n    /// <summary>\n    /// Helper to create an empty TweakButton function as fallback when not provided.\n    /// </summary>\n    /// <param name=\"btn\"></param>\n    /// <returns></returns>\n    internal static ITweakButton NoOp(ITweakButton btn) => btn;\n\n    #region UI\n\n    public ITweakButton Note(\n        string? note,\n        NoParamOrder npo = default,\n        string? type = default,\n        string? background = default,\n        int delay = default,\n        int linger = default,\n        string? format = default\n    )\n    {\n        var noteProps = new Dictionary<string, object?> { [nameof(note)] = note };\n        if (type != default)\n            noteProps[nameof(type)] = type;\n        if (background != default)\n            noteProps[nameof(background)] = background;\n        if (delay != default)\n            noteProps[nameof(delay)] = delay;\n        if (linger != default)\n            noteProps[nameof(linger)] = linger;\n        if (format != default)\n            noteProps[ToolbarConstants.NoteSettingHtml] = format.EqualsInsensitive(ToolbarConstants.NoteFormatHtml);\n        return Ui(new { note = noteProps });\n    }\n\n    public ITweakButton Show(bool show = true)\n        => Ui(ToolbarConstants.RuleShow, show ? \"true\" : \"false\");\n\n    public ITweakButton Color(string? color = default, NoParamOrder npo = default, string? background = default,\n        string? foreground = default)\n    {\n        if (color == default)\n        {\n            color = background;\n            if (foreground != default) color += $\",{foreground}\";\n        }\n\n        // Remove hashes, because they break the URL api, and spaces, as they shouldn't be there\n        color = color?.Replace(\"#\", \"\").Replace(\" \", \"\");\n\n        return Ui(ToolbarConstants.RuleColor, color);\n    }\n\n    public ITweakButton Tooltip(string value)\n        => value.IsEmptyOrWs() ? this : Ui(ToolbarConstants.RuleTooltip, value);\n\n    public ITweakButton Group(string value)\n        => value.IsEmptyOrWs() ? this : Ui(ToolbarConstants.RuleGroup, value);\n\n    public ITweakButton Icon(string value)\n        => value.IsEmptyOrWs() ? this : Ui(new { icon = value });\n\n    public ITweakButton Classes(string value)\n        => value.IsEmptyOrWs() ? this : Ui(ToolbarConstants.RuleClass, value);\n\n    public ITweakButton Position(int value)\n        => Ui(ToolbarConstants.RulePosition, value);\n\n    public ITweakButton Ui(object? value)\n        => value == null ? this : new(this, UiMerge.Add(value));\n\n    public ITweakButton Ui(string name, object? value)\n        => (value ?? name) == null ? this : Ui($\"{name}={value}\");\n\n    #endregion\n\n    #region Params\n\n    /// <summary>\n    /// Do null-check, then convert any possible object to url using an additional prefix\n    /// </summary>\n    /// <param name=\"value\"></param>\n    /// <param name=\"prefix\"></param>\n    /// <returns></returns>\n    private ITweakButton ParamObjInternal(object? value, string? prefix)\n        => value == null\n            ? this\n            : ParamAddProcessed(new ObjectToUrl().SerializeChild(value, prefix));\n\n    private ITweakButton ParamObjInternal(string name, object? value, string? prefix)\n        // todo: check if we can properly serialize the value...object\n        => (value ?? name) == null\n            ? this\n            : ParamAddProcessed(new ObjectToUrl().SerializeChild($\"{name}={ValueToString(value)}\", prefix));\n\n    private ITweakButton ParamAddProcessed(object? value)\n        => new TweakButton(this, parameters: ParamsMerge.Add(value));\n\n    public ITweakButton Filter(object value)\n        => ParamObjInternal(value, ToolbarConstants.RuleParamPrefixFilter);\n\n    public ITweakButton Filter(string name, object value)\n        => ParamObjInternal(name, value, ToolbarConstants.RuleParamPrefixFilter);\n\n    public ITweakButton FormParameters(object value)\n        => ParamObjInternal(value, ToolbarConstants.RuleParamPrefixForm);\n    \n    public ITweakButton FormParameters(string name, object value)\n        => ParamObjInternal(name, value, ToolbarConstants.RuleParamPrefixForm);\n\n    public ITweakButton Parameters(object? value)\n        => value == null ? this : ParamAddProcessed(value);\n\n    public ITweakButton Parameters(string name, object? value)\n        => ParamObjInternal(name, value, null /* no special prefix */);\n\n    public ITweakButton Prefill(object value)\n        => ParamObjInternal(value, ToolbarConstants.RuleParamPrefixPrefill);\n\n    public ITweakButton Prefill(string name, object value)\n        => ParamObjInternal(name, value, ToolbarConstants.RuleParamPrefixPrefill);\n\n    public ITweakButton UiFields(string value)\n        => ParamObjInternal(ToolbarConstants.RuleParamUiFields, value, null /* no special prefix */);\n\n    public ITweakButton XCustom(string prefix, string name, object value)\n        => ParamObjInternal(name, value, prefix + (prefix.EndsWith(\":\") ? \"\" : \":\"));\n\n    /// <summary>\n    /// WIP trying to get Filter with an array of IDs to return [1,2,3] instead of Int32[]\n    /// </summary>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    private static string? ValueToString(object? value)\n        => value switch\n        {\n            null => null,\n            string str => str,\n            bool bln => bln.ToString().ToLower(),\n            IEnumerable => JsonSerializer.Serialize(value),\n            _ => value.ToString()\n        };\n\n    /// <summary>\n    /// Special internal add-rule, which is typically on the main toolbar,\n    /// but will then only be applied to buttons with exactly this name...?\n    ///\n    /// Used in image responsive to add notes to the buttons,\n    /// but different notes for e.g. Copyright etc.\n    ///\n    /// Not fully documented or standardized.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"tweak\"></param>\n    /// <returns></returns>\n    public ITweakButton AddNamed(string name, Func<ITweakButton, ITweakButton>? tweak)\n        => tweak == null ? this : new(this, named: Named.Add(name, tweak));\n\n    #endregion\n\n    public ITweakButton Condition(bool value)\n        => new TweakButton(this, condition: value);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Properties/SxcEditInternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Services\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Render\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.UnitTests\")]\n\n\n// for old toolbars\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Core\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Services/IEditService.cs",
    "content": "﻿using ToSic.Razor.Markup;\nusing ToSic.Sxc.Edit.Toolbar;\n// ReSharper disable RedundantExtendsListEntry\n#pragma warning disable CS0108, CS0114\n\n// ReSharper disable UnusedMember.Global\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Edit`](xref:ToSic.Sxc.Services.ServiceKit16.Edit) with status and commands to configure the in-page editing system.\n/// </summary>\n/// <remarks>\n/// You will never create this yourself, as get this automatically in Razor or WebAPIs on an object called `Edit`.\n/// \n/// History\n/// \n/// * First version created ca. v2 - originally as `ToSic.Sxc.Web.IInPageEditEditingHelper`\n/// * Moved to `ToSic.Sxc.Services.IEditService` in v13.05\n/// </remarks>\n[PublicApi]\npublic interface IEditService: IHasLog // , INeedsCodeApiService\n{\n    /// <summary>\n    /// If editing is enabled or not\n    /// </summary>\n    /// <returns>True if enabled, false if not.</returns>\n    bool Enabled\n    {\n        get;\n        // 2022-03-29 2dm disabled this private-api, as it was shown in the docs anyhow\n        // [PrivateApi(\"hide the set - it's only used for demo code\")]\n        set;\n    }\n\n    /// <summary>\n    /// Generate a toolbar tag - must be used in normal html, not as an attribute. <br/>\n    /// See also [](xref:NetCode.Razor.Edit.Toolbar)\n    /// </summary>\n    /// <param name=\"target\">\n    /// The content-item this toolbar is for, can be null. <br/>\n    /// Usually a [](xref:NetCode.DynamicData.DynamicEntity) or a [](xref:NetCode.DynamicData.Entity)\n    ///\n    /// If the first parameter is a <see cref=\"IToolbarBuilder\"/> then all other parameters will be ignored. \n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"actions\">\n    ///     List of actions on this toolbar. If null, will use default actions for this item.\n    ///     If provided, must be comma-separated action-names - see [](xref:JsCode.Commands.Index).\n    /// </param>\n    /// <param name=\"contentType\">Content-type of this toolbar, used when it has `new` or `add` buttons.\n    ///     This allows you to create a button for a new \"Category\" and another button for a new \"BlogPost\" etc.\n    /// </param>\n    /// <param name=\"prefill\">\n    ///     Allows a `new` dialog to receive values as a prefill.\n    ///     For example to already specify a date, title, category, etc. <br/>\n    ///     It's a dynamic object, see also the JS documentation on the prefill.\n    /// </param>\n    /// <param name=\"toolbar\">\n    /// Full manual toolbar configuration. Setting this will cause `actions` to be ignored. <br/>\n    /// See [](xref:Basics.Browser.EditUx.Toolbars.Index)\n    ///\n    /// If the the `toolbar` is a <see cref=\"IToolbarBuilder\"/> then other parameters except for the `target` will be ignored. \n    /// </param>\n    /// <param name=\"settings\">\n    ///     Toolbar settings controlling hover etc. <br/>\n    ///     See [](xref:JsCode.Toolbars.Settings)\n    /// </param>\n    /// <param name=\"condition\">\n    /// Condition will make that no toolbar is created, if it's 0, false or \"false\"\n    /// </param>\n    /// <returns>If the user is an editor, it returns HTML UL tag containing all the toolbar configuration.</returns>\n    /// <remarks>\n    /// **History**\n    /// 1. Added in 2sxc 8.04\n    /// 1. `condition` added in 2sxc 12.05\n    /// 1. option to just use a ToolbarBuilder as first parameter or `toolbar` parameter added in v13 - this will skip all other parameters\n    /// 1. Enhanced to return `IRawHtmlString` instead of `IHybridHtmlString` in 16.02\n    /// </remarks>\n    IRawHtmlString? Toolbar(\n        object? target = null,\n        NoParamOrder npo = default,\n        string? actions = null,\n        string? contentType = null,\n        object? condition = null,\n        object? prefill = null,\n        object? settings = null,\n        object? toolbar = null);\n\n    /// <summary>\n    /// Generate a toolbar attribute inside an html-tag <br/>\n    /// See also @HowTo.Razor.Edit.Toolbar\n    /// </summary>\n    /// <param name=\"target\">\n    /// The optional content-item this toolbar is for. Can be null. <br/>\n    /// Usually a [](xref:NetCode.DynamicData.DynamicEntity) or a [](xref:NetCode.DynamicData.Entity)\n    ///\n    /// If the first parameter is a <see cref=\"IToolbarBuilder\"/> then all other parameters will be ignored. \n    /// </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"actions\">\n    ///     List of actions on this toolbar. If null, will use default actions for this item.\n    ///     If provided, must be comma-separated action-names - see [](xref:JsCode.Commands.Index).\n    /// </param>\n    /// <param name=\"contentType\">Content-type of this toolbar, used when it has `new` or `add` buttons.\n    ///     This allows you to create a button for a new \"Category\" and another button for a new \"BlogPost\" etc.\n    /// </param>\n    /// <param name=\"prefill\">\n    ///     Allows a `new` dialog to receive values as a prefill.\n    ///     For example to already specify a date, title, category, etc. <br/>\n    ///     It's a dynamic object, see also the JS documentation on the prefill.\n    /// </param>\n    /// <param name=\"toolbar\">\n    /// Full manual toolbar configuration. Setting this will cause `actions` to be ignored. <br/>\n    /// See [](xref:Basics.Browser.EditUx.Toolbars.Index)\n    ///\n    /// If the the `toolbar` is a <see cref=\"IToolbarBuilder\"/> then other parameters except for the `target` will be ignored. \n    /// </param>\n    /// <param name=\"settings\">\n    ///     Toolbar settings controlling hover etc. <br/>\n    ///     See [](xref:JsCode.Toolbars.Settings)\n    /// </param>\n    /// <param name=\"condition\">\n    /// Condition will make that no toolbar is created, if it's 0, false or \"false\"\n    /// </param>\n    /// <returns>If the user is an editor, it returns the attribute containing all the toolbar configuration.</returns>\n    /// <remarks>\n    /// **History**\n    /// 1. Added in 2sxc 9.40\n    /// 1. `condition` added in 2sxc 12.05\n    /// 1. option to just use a ToolbarBuilder as first parameter or `toolbar` parameter added in v13 - this will skip all other parameters\n    /// 1. Enhanced to return `IRawHtmlString` instead of `IHybridHtmlString` in 16.02\n    /// </remarks>\n    IRawHtmlString? TagToolbar(\n        object? target = null,\n        NoParamOrder npo = default,\n        string? actions = null,\n        string? contentType = null,\n        object? condition = null,\n        object? prefill = null,\n        object? settings = null,\n        object? toolbar = null);\n\n    /// <summary>\n    /// Get html-attributes to mark the current context\n    /// these will be added to a wrapper tag (usually a div)\n    /// so that in-page editing knows what the context is <br/>\n    /// Please read more about [](xref:Basics.Cms.InnerContent.Index)\n    /// </summary>\n    /// <param name=\"target\">The content-item for which the new context should be.\n    ///     This item usually has a field which has [](xref:Basics.Cms.InnerContent.Index)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"field\">the field of this content-item, which contains the inner-content-items</param>\n    /// <param name=\"contentType\">type name used for 'new' items in a toolbar - usually for inner-content and list-contexts</param>\n    /// <param name=\"newGuid\">the guid of a new item - use null for auto-generate</param>\n    /// <param name=\"apps\">Restrict the apps which can be added to this placeholder</param>\n    /// <param name=\"max\">Limit the amount of content-blocks that can be added to this placeholder</param>\n    /// <returns>An <see cref=\"IRawHtmlString\"/> object containing an html-attribute to add to the wrapper of the inner content</returns>\n    /// <remarks>\n    /// **History** <br/>\n    /// 1. Introduced in 2sxc 8.4\n    /// 1. Enhanced with apps and max in 10.27\n    /// 1. Enhanced to return `IRawHtmlString` instead of `IHybridHtmlString` in 16.02\n    /// </remarks>\n    IRawHtmlString? ContextAttributes(\n        ICanBeEntity target, \n        NoParamOrder npo = default, \n        string? field = null, \n        string? contentType = null,\n        Guid? newGuid = null,\n        string? apps = null,\n        int max = 100);\n\n    // 2024-01-10 2dm disabled #WrapInContext - was for internal only, seems not to be used? Was created 2018? https://github.com/2sic/2sxc/issues/1479\n    ///// <summary>\n    ///// Wrap something in a context wrapper-tag\n    ///// This is mainly meant for internal use\n    ///// </summary>\n    ///// <param name=\"content\">the string / tags to wrap</param>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    ///// <param name=\"tag\">optional tag to use for the wrapper, default is div</param>\n    ///// <param name=\"full\">include full context (default is partial context only)</param>\n    ///// <param name=\"enableEdit\">include information needed for editing</param>\n    ///// <param name=\"instanceId\">id to include in context - important for API calls</param>\n    ///// <param name=\"contentBlockId\">content block this is for - important for API calls</param>\n    ///// <returns></returns>\n    ///// <remarks>\n    ///// **History** <br/>\n    ///// 1. Introduced in 2sxc 8.4\n    ///// 1. Enhanced to return `IRawHtmlString` instead of `IHybridHtmlString` in 16.02\n    ///// </remarks>\n    //[PrivateApi]\n    //IRawHtmlString WrapInContext(object content,\n    //    NoParamOrder npo = default,\n    //    string tag = SxcUiConstants.DefaultContextTag,\n    //    bool full = false,\n    //    bool? enableEdit = null,\n    //    int instanceId = 0,\n    //    int contentBlockId = 0\n    //);\n\n    /// <summary>\n    /// Ensure that the UI will load the correct assets to enable editing. See [](xref:NetCode.Razor.Edit.Enable)\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"js\">optional, default false. automatically true if `api` or `forms` is true<br/>\n    ///     Will add the basic JS APIs ($2sxc) usually for enabling WebApi calls from your JS code. <br/>\n    ///     _added in v10.20_\n    /// </param>\n    /// <param name=\"api\">optional, default false. automatically true, if `forms` is true<br/>\n    ///     If JS etc. should be included to enable editing API - ensures JavaScripts are loaded enabling commands to run</param>\n    /// <param name=\"forms\">optional, default false. <br/>\n    ///     Ensures JavaScripts are loaded enabling forms to open</param>\n    /// <param name=\"context\">optional, default false. <br/>\n    ///     If context ([](xref:Basics.Browser.EditUx.EditContext)) should be added, to ensure in-instance data editing</param>\n    /// <param name=\"autoToolbar\">optional, default false. <br/>\n    ///     Disables the automatic generation of a toolbar (this is important, as there usually won't be a toolbar in public pages, which would then trigger the fallback-toolbar to be generated)</param>\n    /// <param name=\"styles\">optional, default false. <br/>\n    ///     Ensures styles to be loaded, which would be necessary for the standard toolbars to look right</param>\n    /// <returns>null - but we wanted to make sure it returns something, so you can use it in razor like @Edit.Enable(...)</returns>\n    /// <remarks>\n    /// **History** <br/>\n    /// 1. Introduced in 2sxc 9.30\n    /// 2. Enhanced with parameter jsApi in 10.20\n    /// 3. Being deprecated in 12.02, as you should now use the IPageService instead for most of these features\n    /// </remarks>\n    string? Enable(NoParamOrder npo = default,\n        bool? js = null,\n        bool? api = null,\n        bool? forms = null,\n        bool? context = null,\n        bool? autoToolbar = null,\n        bool? styles = null);\n\n    /// <summary>\n    /// Generate an HTML attribute by converting the value to JSON\n    /// - but only in edit mode\n    /// </summary>\n    /// <param name=\"name\">the attribute name, used for ...=</param>\n    /// <param name=\"value\">the attribute value, used for =\"...\"</param>\n    /// <returns>A string but as HtmlString, so it can be used with @Attribute(...)</returns>\n    IRawHtmlString? Attribute(string name, string value);\n\n    /// <summary>\n    /// Generate an HTML attribute by converting the value to JSON\n    /// - but only in edit mode\n    /// </summary>\n    /// <param name=\"name\">the attribute name, used for ...=</param>\n    /// <param name=\"value\">the attribute value, used for =\"...\"</param>\n    /// <returns>A string but as HtmlString, so it can be used with @Attribute(...)</returns>\n    IRawHtmlString? Attribute(string name, object value);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/Services/IToolbarService.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Toolbar`](xref:ToSic.Sxc.Services.ServiceKit16.Toolbar) to generate edit toolbars in the front-end.\n/// </summary>\n/// <remarks>\n/// It's especially useful custom and/or complex rules like Metadata-buttons.\n/// \n/// History\n/// \n/// * uses the [](xref:NetCode.Conventions.Functional)\n/// * Added in 2sxc 13\n/// * parameter `target` added to `Default()` and `Empty()` in v14.03\n/// </remarks>\n[PublicApi]\npublic interface IToolbarService\n{\n    /// <summary>\n    /// Build a Toolbar configuration using the `default` template/buttons to use with `@Edit.Toolbar`\n    /// It's a fluid API, so the returned object can be extended with further `Add(...)` or special helpers to quickly create complex configurations.\n    /// For guidance what to give it, also check out the [toolbar docs](xref:JsCode.Toolbars.Simple).\n    /// </summary>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters (new v16.02)</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"prefill\">_optional_ prefill for the edit-UI, see [prefill guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Prefill)</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// History\n    /// * Added in 2sxc 13\n    /// * target, ui, parameters added in v14.04\n    /// </remarks>\n    IToolbarBuilder Default(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null\n    );\n\n    /// <summary>\n    /// Build a Toolbar configuration using the `empty` toolbar to use with `@Edit.Toolbar`\n    /// It's a fluid API, so the returned object can be extended with further `Add(...)` or special helpers to quickly create complex configurations.\n    /// For guidance what to give it, also check out the [toolbar docs](xref:JsCode.Toolbars.Simple).\n    /// </summary>\n    /// <param name=\"target\">_optional_ entity-like target, see [target guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Target)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters (new v16.02)</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"prefill\">_optional_ prefill for the edit-UI, see [prefill guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Prefill)</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// History\n    /// * Added in 2sxc 13\n    /// * target, ui, parameters added in v14.04\n    /// </remarks>\n    IToolbarBuilder Empty(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null\n    );\n\n    /// <summary>\n    /// Build an **empty** Toolbar with a Metadata button.\n    /// \n    /// This is the same as `.Empty().Metadata(...)`\n    /// </summary>\n    /// <param name=\"target\">The target object which should receive metadata. Must support <see cref=\"ToSic.Eav.Metadata.IHasMetadata\"/> </param>\n    /// <param name=\"contentTypes\">Name of one or more content-types for which to generate the button(s). For many, use comma `,` to separate. If not specified, will try to lookup config (v14)</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters (new v16.02)</param>\n    /// <param name=\"ui\">_optional_ configuration how to show, see [ui guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Ui)</param>\n    /// <param name=\"parameters\">_optional_ parameters for the command, see [parameters guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Parameters)</param>\n    /// <param name=\"prefill\">_optional_ prefill for the edit-UI, see [prefill guide](xref:ToSic.Sxc.Services.ToolbarBuilder.Prefill)</param>\n    /// <param name=\"context\">EXPERIMENTAL - not final</param>\n    /// <returns>An toolbar builder with empty configuration and just this button on it</returns>\n    /// <remarks>\n    /// History\n    /// * Added in 2sxc 13\n    /// * contentTypes changed from one to many in v14\n    /// * contentTypes can also have `*` or `YourCustomType,*` in v14\n    /// * contentTypes can also be optional, in which case it behaves as if it was `*` in v14 - if no config is found, it will not add a metadata-button\n    /// * parameter context added in 2sxc 14 - still WIP/experimental\n    /// </remarks>\n    IToolbarBuilder Metadata(\n        object target,\n        string? contentTypes = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? context = null\n    );\n\n\n    /// <summary>\n    /// Build an **empty** Toolbar with a Edit button.\n    /// \n    /// This is the same as `.Empty().Edit(...)`\n    /// </summary>\n    /// <param name=\"target\">The target object which should receive metadata. Must support <see cref=\"ToSic.Eav.Metadata.IHasMetadata\"/> </param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"tweak\">Functional [Tweak API](xref:ToSic.Sxc.Services.ToolbarBuilder.TweakButtons) to modify UI and parameters (new v16.02)</param>\n    /// <returns>An toolbar builder with empty configuration and just this button on it</returns>\n    /// <remarks>\n    /// History\n    /// * Added in 2sxc 17\n    /// </remarks>\n    IToolbarBuilder Edit(\n        object target,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/StartupSxcEdit.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Edit.EditService;\nusing ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Edit.Toolbar.Sys;\nusing ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\nusing ToSic.Sxc.Services;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcEdit\n{\n    public static IServiceCollection AddSxcEdit(this IServiceCollection services)\n    {\n        services.TryAddTransient<IEditService, EditService>();\n\n        // v14 Toolbar Builder\n        services.TryAddTransient<IToolbarBuilder, ToolbarBuilder>();\n        services.TryAddTransient<ToolbarBuilder.Dependencies>();\n        services.TryAddTransient<ToolbarButtonDecoratorHelper>();\n\n        return services;\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/ToSic.Sxc.Edit.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Edit</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Cms\\ToSic.Sxc.Cms.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Edit/ToSic.Sxc.Edit.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=edit_005Ctoolbar_005Cinternal_005Coldtoolbarsforitems/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=edit_005Ctoolbar_005Csys_005Coldtoolbarsforitems/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/EngineAppRequirements.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Metadata.Requirements.Sys;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sys.Requirements;\n\nnamespace ToSic.Sxc.Engines;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EngineAppRequirements(IRequirementsService requirements) : EngineRequirementsBase(\"Eng.AppReq\", connect: [requirements])\n{\n    public RenderEngineResult? CheckExpectedNoRenderConditions(EngineSpecs engineSpecs)\n    {\n        var l = Log.Fn<RenderEngineResult>();\n\n        // Check App Requirements (new 16.08)\n        var block = engineSpecs.Block;\n        var appReqProblems = GetMessageForRequirements(block.Context.AppReaderRequired);\n        if (appReqProblems != null)\n            return l.Return(appReqProblems, \"error\");\n\n        var view = engineSpecs.View;\n        if (view.ContentType == \"\" || view.ContentItem != null || block.Configuration.Content.Any(e => e != null))\n            return l.ReturnNull(\"all ok\");\n\n        var result = new RenderEngineResult\n        {\n            Html = EngineMessages.ToolbarForEmptyTemplate,\n            ActivateJsApi = false,\n            Assets = [],\n            ErrorCode = null,\n            ExceptionsOrNull = null, // should be null, to indicate no exceptions\n        };\n        return l.Return(result, \"error\");\n\n    }\n\n    private bool RequirementsMet(IAppReader appReader) \n        => !RequirementsStatus(appReader).SafeAny();\n\n    private List<RequirementStatus> RequirementsStatus(IAppReader appReader)\n        => appReader.GetPiggyBackExpiring(\"AppRequirementsStatus\",\n            // take the requirements reported by the app\n            () => requirements.UnfulfilledRequirements(appReader.Specs.Metadata)\n                // Merge with the basic requirements for 2sxc 17 to work\n                //.Concat(requirements.UnfulfilledRequirements(SysFeatureSuggestions.CSharp08.ToListOfOne()).ToList())\n                .ToList()\n            ).Value;\n\n    internal RenderEngineResult? GetMessageForRequirements(IAppReader? appReader)\n    {\n        var l = Log.Fn<RenderEngineResult>();\n\n        // 1. Preflight\n        // 1.1. make sure we have an App-State\n        if (appReader == null)\n            return l.ReturnNull(\"no appState\");\n\n        if (RequirementsMet(appReader))\n            return l.ReturnNull(\"all seems ok\");\n\n        var result = BuildRenderEngineResult(RequirementsStatus(appReader));\n\n        return l.Return(result, \"error\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/EngineCheckTemplate.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sys.Code.Help;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Engines;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EngineCheckTemplate(LazySvc<AppPermissionCheck> appPermCheckLazy)\n    : ServiceBase(\"Sxc.EngChk\", connect: [appPermCheckLazy])\n{\n    /// <summary>\n    /// Template Exceptions like missing configuration or defined type not found\n    /// </summary>\n    /// <exception cref=\"RenderingException\"></exception>\n    internal void CheckExpectedTemplateErrors(IView view, IAppReadContentTypes appState)\n    {\n        if (view == null)\n            throw new RenderingException(ErrHelpConfigMissing);\n\n        if (appState == null)\n            throw new RenderingException(ErrHelpConfigMissing, \"AppState is null\");\n\n        if (view.ContentType != \"\" && appState.TryGetContentType(view.ContentType) == null)\n            throw new RenderingException(ErrHelpTypeMissing);\n    }\n\n    private static readonly CodeHelp ErrHelpConfigMissing = new()\n    {\n        Name = \"Template Config Missing\",\n        Detect = \"\",\n        LinkCode = \"err-view-config-missing\",\n        UiMessage = \"Template Configuration Missing\",\n    };\n\n    private static readonly CodeHelp ErrHelpTypeMissing = new()\n    {\n        Name = \"Content Type Missing\",\n        Detect = \"\",\n        LinkCode = \"err-view-type-missing\",\n        UiMessage = \"The contents of this module cannot be displayed because I couldn't find the assigned content-type.\",\n    };\n\n\n\n    internal void ThrowIfViewPermissionsDenyAccess(IView view, IContextOfApp appContext)\n    {\n        // do security check IF security exists\n        // should probably happen somewhere else - so it doesn't throw errors when not even rendering...\n        var templatePermissions = appPermCheckLazy.Value\n            .ForItem(appContext, appContext.AppReaderRequired, view.Entity);\n\n        // Views only use permissions to prevent access, so only check if there are any configured permissions\n        if (appContext.User.IsSiteAdmin || !templatePermissions.HasPermissions)\n            return;\n\n        if (!templatePermissions.UserMay(GrantSets.ReadSomething).Allowed)\n            // TODO: maybe create an exception which inherits from UnauthorizedAccess - in case this improves behavior / HTTP response\n            throw new RenderingException(ErrorHelpNotAuthorized, new UnauthorizedAccessException(\n                $\"{ErrorHelpNotAuthorized.UiMessage} See {ErrorHelpNotAuthorized.LinkCode}\"));\n    }\n\n    private static readonly CodeHelp ErrorHelpNotAuthorized = new()\n    {\n        Name = \"Not Authorized\",\n        Detect = \"\",\n        LinkCode = \"https://2sxc.org/help?tag=view-permissions\",\n        UiMessage = \"This view is not accessible for the current user. To give access, change permissions in the view settings.\",\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/EngineDefinitionAttribute.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Engines;\n\n/// <summary>\n/// Attribute to mark all IEngine implementations\n/// </summary>\n[AttributeUsage(AttributeTargets.Class)]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EngineDefinitionAttribute: Attribute\n{\n    public EngineDefinitionAttribute() { }\n\n    public string Name { get; set; } = EavConstants.NullNameId;\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/EngineFactory.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys.Views;\n\nnamespace ToSic.Sxc.Engines;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EngineFactory(Generator<IRazorEngine> razorEngineGen, Generator<ITokenEngine> tokenEngineGen)\n    : ServiceBase($\"{SxcLogName}.EngFct\", connect: [razorEngineGen, tokenEngineGen]), IEngineFactory\n{\n    public IEngine CreateEngine(IView view) => view.IsRazor\n        ? razorEngineGen.New()\n        : tokenEngineGen.New();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/EngineMessages.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\n\nnamespace ToSic.Sxc.Engines;\n\ninternal class EngineMessages\n{\n    public const string Warning = \"warning\";\n\n    [PrivateApi]\n    internal static string ToolbarForEmptyTemplate = ErrorBoxWithMenu(\n        \"This is a new module without demo data \"\n        + \"(see <a href='https://go.2sxc.org/no-demo-data' target='_blank'>help</a>). \"\n        + \"Please add content. \"\n        + EmptyTemplateToolbar\n    );\n\n    private const string EmptyTemplateToolbar = \"<ul class='sc-menu' data-toolbar='{\\\"sortOrder\\\":0,\\\"useModuleList\\\":true,\\\"action\\\":\\\"edit,layout\\\"}'></ul>\";\n\n    internal static string BasicToolbar\n        = \"<ul class='sc-menu' data-toolbar='\" +\n          JsonSerializer.Serialize(new { sortOrder = 0, useModuleList = true, action = \"edit\" },\n              JsonOptions.SafeJsonForHtmlAttributes) +\n          \"'></ul>\";\n\n    internal static string ErrorBoxWithMenu(string contents) \n        => $\"<div class='dnnFormMessage dnnFormInfo alert alert-warning'>{contents}{BasicToolbar}</div>\";\n\n    internal static string Box(string contents, string level = \"info\")\n        => $\"<div class='alert alert-{level}'>{contents}</div>\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/EnginePolymorphism.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Engines;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EnginePolymorphism(PolymorphConfigReader polymorphism, IServerPaths serverPaths)\n    : ServiceBase(\"Sxc.EngPly\", connect: [polymorphism, serverPaths])\n{\n    internal (string? NewPath, string? Edition) PolymorphTryToSwitchPath(string root, IView view, IAppReader appReader)\n    {\n        var subPath = view.Path;\n        var l = Log.Fn<(string? NewPath, string? Edition)>($\"{root}, {subPath}\");\n        // Get initial path - here the file is already reliably stored\n        view.EditionPath = subPath.ToAbsolutePathForwardSlash();\n        subPath = view.EditionPath.TrimPrefixSlash();\n\n        // Figure out the current edition - if none, stop here\n        // New 2023-03-20 - if the view comes with a preset edition, it's an ajax-preview which should be respected\n        var edition = polymorphism.UseViewEditionOrGet(view, appReader);\n        \n        if (edition == null)\n            return l.Return((null, null), \"no edition detected\");\n        l.A($\"edition '{edition}' detected\");\n\n        // Case #1 where edition is between root and path\n        // like subPath = \"View.cshtml\" and there is a \"bs5/View.cshtml\"\n        (var newPath, view) = PolymorphTestPathAndSetIfFound(view, root, edition, subPath);\n        if (newPath != null)\n            return l.Return((newPath, edition), $\"found edition {edition}\");\n\n        // Case #2 where edition _replaces_ an edition in the current path\n        // like subPath =\"bs5/View.cshtml\" and there is a \"bs4/View.cshtml\"\n        l.A(\"tried inserting path, will check if sub-path\");\n        var pathWithoutFirstFolder = Text.After(subPath, \"/\");\n        \n        // If there was no root path, exit now.\n        if (pathWithoutFirstFolder.IsEmpty())\n            return l.ReturnNull(\"view is not in subfolder, so no edition to replace, stopping now\");\n\n        (newPath, view) = PolymorphTestPathAndSetIfFound(view, root, edition, pathWithoutFirstFolder);\n        if (newPath != null)\n        {\n            return l.Return((newPath, edition), $\"edition {edition} up one path\");\n        }\n\n        // Since obviously something tried to get/set an edition\n        // we'll still register it on the view so the UI knows about it.\n        view.Edition = subPath.Before(\"/\");\n        return l.ReturnNull($\"edition {edition} not found\");\n    }\n\n    private (string? Edition, IView View) PolymorphTestPathAndSetIfFound(IView view, string root, string edition, string subPath)\n    {\n        var l = Log.Fn<(string?, IView)>($\"root: {root}; edition: {edition}; subPath: {subPath}\");\n        var fullPathForTest = Path.Combine(root, edition, subPath).ToAbsolutePathForwardSlash();\n        if (!File.Exists(serverPaths.FullAppPath(fullPathForTest)))\n            return l.Return((null, view),\"not found\");\n        view.Edition = edition;\n        view.EditionPath = Path.Combine(edition, subPath).ToAbsolutePathForwardSlash();\n        return l.Return((fullPathForTest, view), $\"edition {edition}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/EngineRequirementsBase.cs",
    "content": "﻿using ToSic.Eav.Sys;\nusing ToSic.Sys.Capabilities.SysFeatures;\nusing ToSic.Sys.Code.Help;\nusing ToSic.Sys.Requirements;\n\nnamespace ToSic.Sxc.Engines;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class EngineRequirementsBase(string logName, object[]? connect = default) : ServiceBase(logName, connect: connect)\n{\n    protected static RenderEngineResult BuildRenderEngineResult(ICollection<RequirementStatus> reqStatus)\n    {\n        var exList2 = reqStatus\n            .Select(r => new RenderingException(ErrHelpRequirementsNotMet with\n                {\n                    Name = r.Aspect.Name,\n                    UiMessage = $\"Requirement <em>{r.Aspect.Name}</em> is missing ({r.Aspect.NameId})\",\n                    LinkCode = \"sysfeats\",\n                }))\n            .Cast<Exception>()\n            .ToList();\n\n        var aspectMessages = reqStatus\n            .Select(r =>\n                \"<li>\" +\n                $\"<strong>{r.Aspect.Name}</strong> <code>{r.Aspect.NameId}</code> <br> {r.Aspect.Description}.\" +\n                (r.Aspect is SysFeature sysFeat ? $\"<br>See ➡️ <a href='{sysFeat.Link}' target='_blank'>{sysFeat.Link}</a>\" : \"\") +\n                \"</li>\")\n            .ToList();\n\n        var html = EngineMessages.Box(\n            \"<h2>Feature Missing</h2>\" +\n            \"<p>\" +\n            \"One or more features are missing. It's either required for 2sxc, or the App is configured to warn you when an required feature/capability is missing. \" +\n            \"</p>\" +\n            \"<ol>\" +\n            string.Join(\"\", aspectMessages) +\n            \"</ol>\" +\n            \"<p>\" +\n            \"<br>\" +\n            $\"To install features follow these instructions ➡️ <a href='{EavConstants.GoUrlSysFeats}' target='_blank'>{EavConstants.GoUrlSysFeats}</a>.\" +\n            \"</p>\",\n            EngineMessages.Warning);\n\n        var result = new RenderEngineResult\n        {\n            Html = html,\n            ActivateJsApi = false,\n            Assets = [],\n            ErrorCode = null,\n            ExceptionsOrNull = exList2,\n        };\n        return result;\n    }\n\n    private static readonly CodeHelp ErrHelpRequirementsNotMet = new()\n    {\n        Name = \"Requirement Not Met\",\n        Detect = \"\",\n        LinkCode = \"err-view-config-missing\",\n        UiMessage = \"Important Requirements not Met\"\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/IEngine.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Render.Sys.Specs;\n\nnamespace ToSic.Sxc.Engines;\n\n/// <summary>\n/// The sub-system in charge of taking\n/// - a configuration for an instance (aka Module)\n/// - a template\n/// and using all that to produce an html-string for the browser. \n/// </summary>\n[PrivateApi(\"used to be InternalApi_DoNotUse_MayChangeWithoutNotice, hidden in 17.08\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IEngine: IHasLog\n{\n    //void Init(IBlock block);\n\n    /// <summary>\n    /// Renders a template, returning a string with the rendered template.\n    /// </summary>\n    /// <returns>The string - usually HTML - which the engine created. </returns>\n    RenderEngineResult Render(IBlock block, RenderSpecs specs);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/IEngineFactory.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys.Views;\n\nnamespace ToSic.Sxc.Engines;\n\npublic interface IEngineFactory\n{\n    IEngine CreateEngine(IView view);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/IRazorEngine.cs",
    "content": "﻿namespace ToSic.Sxc.Engines;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IRazorEngine: IEngine;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/ITokenEngine.cs",
    "content": "﻿namespace ToSic.Sxc.Engines;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ITokenEngine : IEngine;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/RenderingException.cs",
    "content": "﻿using ToSic.Sys.Code.Help;\nusing ToSic.Sys.Exceptions;\n\nnamespace ToSic.Sxc.Engines;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class RenderingException: Exception, IExceptionWithHelp\n{\n    public RenderingException(CodeHelp help, string? message = default) : base(message ?? help.UiMessage)\n    {\n        Helps = [help];\n    }\n        \n\n    public RenderingException(CodeHelp help, Exception inner) : base(\"Rendering Exception\", inner)\n    {\n        Helps = [help];\n    }\n\n    public List<CodeHelp> Helps { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/Sys/EngineSpecs.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Code.Sys.HotBuild;\n\nnamespace ToSic.Sxc.Engines.Sys;\n\n/// <summary>\n/// WIP - trying to make engine more robust and dropping init\n/// </summary>\npublic record EngineSpecs\n{\n    public required IView View { get; init; }\n    public required string TemplatePath { get; init; }\n    public required string? Edition;\n    public required IApp App { get; init; }\n    public required IDataSource DataSource { get; init; }\n    public required IBlock Block { get; init; }\n    public required string? RuntimeKey { get; init; }\n\n    public HotBuildSpec ToHotBuildSpec() => new(App.AppId, Edition, App.Name, RuntimeKey);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/Sys/EngineSpecsService.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Engines.Sys;\n\npublic class EngineSpecsService(\n    IServerPaths serverPaths,\n    EnginePolymorphism enginePolymorphism,\n    EngineCheckTemplate engineCheckTemplate,\n    IRuntimeKeyService runtimeKeyService\n) : ServiceBase(\"Sxc.EgSpec\", connect: [serverPaths, enginePolymorphism, engineCheckTemplate, runtimeKeyService])\n{\n    /// <summary>\n    /// Do various preflight checks and create the Engine Specs according to the information in the BlockSpecs\n    /// </summary>\n    /// <param name=\"block\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"RenderingException\"></exception>\n    public EngineSpecs GetSpecs(IBlock block)\n    {\n        var l = Log.Fn<EngineSpecs>();\n\n        // Do various pre-checks and path variations\n        var view = block.View!;\n        var appReader = block.Context.AppReaderRequired;\n        var appPathRootInInstallation = block.App.PathSwitch(view.IsShared, PathTypes.PhysRelative);\n        var (polymorphPathOrNull, edition) = enginePolymorphism\n            .PolymorphTryToSwitchPath(appPathRootInInstallation, view, appReader);\n\n        var templatePath = polymorphPathOrNull\n                           ?? Path.Combine(appPathRootInInstallation, view.Path).ToAbsolutePathForwardSlash();\n\n        // Throw Exception if Template does not exist\n        if (!File.Exists(serverPaths.FullAppPath(templatePath)))\n            throw new RenderingException(new()\n            {\n                Name = \"Template File Not Found\",\n                Detect = \"\",\n                LinkCode = \"err-template-not-found\",\n                UiMessage = $\"The template file '{templatePath}' does not exist.\",\n            });\n\n        // check common errors\n        engineCheckTemplate.CheckExpectedTemplateErrors(view, appReader);\n\n        // check access permissions - before initializing or running data-code in the template\n        engineCheckTemplate.ThrowIfViewPermissionsDenyAccess(view, block.Context);\n\n        var appRuntimeKey = runtimeKeyService.AppRuntimeKey(block.App);\n\n        // All ok, set properties\n        var engineSpecs = new EngineSpecs()\n        {\n            App = block.App,\n            Block = block,\n            DataSource = block.Data,\n            Edition = edition,\n            TemplatePath = templatePath,\n            View = view,\n            RuntimeKey = appRuntimeKey\n        };\n\n        return l.Return(engineSpecs);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/Sys/ISetDynamicModel.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys.Specs;\n\nnamespace ToSic.Sxc.Engines.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ISetDynamicModel\n{\n    void SetDynamicModel(RenderSpecs renderSpecs);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Engines/Sys/ViewDataWithModel.cs",
    "content": "﻿namespace ToSic.Sxc.Engines.Sys;\n\n/// <summary>\n/// Contains data for the view, including the model.\n/// </summary>\n/// <remarks>\n/// Additional data ATM is meant for passing back information after running the view.\n/// Specific example ATM is caching information, which will be used to decide if the result should be cached or not.\n/// \n/// This is currently done this way because we're not sure how else to get this information back to the engine,\n/// because the Razor View engine is a bit internal and can't just change the return signature.\n/// </remarks>\npublic record ViewDataWithModel\n{\n    public object? Data { get; init; }\n\n    public bool AlwaysCache { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using static ToSic.Sxc.Sys.SxcLogging;\nglobal using ToSic.Sys.Utils;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Polymorphism/IPolymorphismResolver.cs",
    "content": "﻿using ToSic.Sxc.Polymorphism.Sys;\n\nnamespace ToSic.Sxc.Polymorphism;\n\n/// <summary>\n/// A polymorphism resolver - which can determine alternate editions for a view / template\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPolymorphismResolver: ISwitchableService\n{\n    string? Edition(PolymorphismConfiguration config, string? overrule, ILog log);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Polymorphism/Sys/PolymorphConfigReader.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Web.Sys.Http;\n\nnamespace ToSic.Sxc.Polymorphism.Sys;\n\n/// <summary>\n/// Mini service to read the polymorph config of the app\n/// and then resolve the edition based on an <see cref=\"IPolymorphismResolver\"/>\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PolymorphConfigReader(LazySvc<ServiceSwitcher<IPolymorphismResolver>> resolvers, LazySvc<IHttp> http) : ServiceBase(\"Plm.Managr\", connect: [resolvers ])\n{\n    public PolymorphismConfiguration Configuration = null!;\n    private int _appId;\n\n    /// <summary>\n    /// Helper to either use the edition set by the view (like in preview mode)\n    /// or to use this same PolymorphConfigReader to figure out the edition.\n    /// Since the reader should only be created if necessary, it's handed in as a function.\n    /// </summary>\n    public string? UseViewEditionOrGet(IBlock block)\n        => !block.ViewIsReady\n            ? null\n            : UseViewEditionOrGet(block.View, block.Context.AppReaderRequired);\n\n    public string? UseViewEditionOrGet(IView? view, IAppReader? appReader)\n    {\n        var viewEdition = view?.Edition.NullIfNoValue();\n        if (viewEdition != null)\n            return viewEdition;\n\n        // note: up until v20 2025-06-19 this always worked without null-checking the app-reader.\n        // so for now, we'll assume all paths always work, which is why we use appReader! here.\n        _appId = appReader!.AppId;\n        Init(appReader.List);\n        return Edition();\n    }\n\n    public PolymorphConfigReader Init(IEnumerable<IEntity> list)\n    {\n        Configuration = list.FirstModel<PolymorphismConfiguration>(nullHandling: ModelNullHandling.PreferModel)!;\n        return this;\n    }\n\n    public string? Edition()\n    {\n        var l = Log.Fn<string?>();\n        try\n        {\n            var resolver = Configuration.Resolver;\n            if (resolver.IsEmpty()) \n                return l.ReturnNull(\"no resolver\");\n\n            var rInfo = resolvers.Value.ByNameId(resolver, true);\n            if (rInfo == null)\n                return l.ReturnNull(\"resolver not found\");\n            l.A($\"resolver for {resolver} found\");\n            var overrule = http.Value.GetCookie($\"app-{_appId}-edition\").NullIfNoValue();\n            l.A($\"overrule: '{overrule}'\");\n            var result = rInfo.Edition(Configuration, overrule, Log);\n\n            return l.Return(result, \"ok\");\n        }\n        // We don't expect errors - but such a simple helper just shouldn't be able to throw errors\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnNull(\"error\");\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Polymorphism/Sys/PolymorphismConfiguration.cs",
    "content": "﻿using ToSic.Eav.Models;\n\nnamespace ToSic.Sxc.Polymorphism.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record PolymorphismConfiguration : ModelFromEntityBasic\n{\n    public const string ContentTypeNameId = \"3937fa17-ef2d-40a7-b089-64164eb10bab\";\n    public const string ContentTypeName = \"2sxcPolymorphismConfiguration\";\n\n    public string Mode => GetThis(\"\");\n\n    public string UsersWhoMaySwitchEditions => GetThis(\"\");\n\n    [field: AllowNull, MaybeNull]\n    public List<int> UsersWhoMaySwitch => field ??= new Func<List<int>>(() => UsersWhoMaySwitchEditions\n        .Split(',')\n        .Select(s => s.Trim())\n        .Select(s => int.TryParse(s, out var result) ? result : -1)\n        .Where(i => i > 0)\n        .ToList()\n    )();\n\n    public string? Resolver => SplitMode().Resolver;\n\n    public string? Parameters => SplitMode().Parameters;\n\n    private (string? Resolver, string? Parameters) SplitMode()\n    {\n        if (_resolverAndParameters != default)\n            return _resolverAndParameters;\n\n        var rule = Mode;\n        if (string.IsNullOrEmpty(Mode))\n            return (null, null);\n        var parts = rule.Split('?');\n        var resolver = parts[0];\n        var parameters = parts.Length > 0 ? parts[1] : null;\n        return _resolverAndParameters = (resolver, parameters);\n    }\n    private (string? Resolver, string? Parameters) _resolverAndParameters;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Properties/SxcEnginesAssemblyVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Render\")]\n\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Render.Sys.Output/ClientAssetConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Render.Sys.Output;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ClientAssetConstants\n{\n    #region Constants for placement in resulting HTML\n\n    public const string AddToBody = \"body\";\n    public const string AddToHead = \"head\";\n    public const string AddToBottom = \"bottom\";\n\n    #endregion\n\n    public const int CssDefaultPriority = 99;\n    public const int JsDefaultPriority = 100;\n\n    public const string AttributeDefer = \"defer\";\n    public const string AttributeAsync = \"async\";\n\n    public const string AssetOptimizationsAttributeName = \"data-enableoptimizations\";\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Render.Sys.Output/ClientAssetExtractSettingsForOneAssetType.cs",
    "content": "﻿namespace ToSic.Sxc.Render.Sys.Output;\n\n/// <summary>\n/// \n/// </summary>\n/// <param name=\"ExtractAll\">Extract all assets, even if they don't have an auto-optimize attribute.</param>\n/// <param name=\"Location\"></param>\n/// <param name=\"Priority\">Default Priority - will be used for sorting when added to page</param>\n/// <param name=\"AutoDefer\">Automatically add a `defer` attribute to scripts</param>\n/// <param name=\"AutoAsync\">Automatically add as `async` attribute to scripts</param>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record ClientAssetExtractSettingsForOneAssetType(bool ExtractAll, string Location, int Priority, bool AutoDefer, bool AutoAsync);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Render.Sys.Output/ClientAssetsExtractSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Render.Sys.Output;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ClientAssetsExtractSettings\n{\n    public ClientAssetsExtractSettings(\n        bool extractAll = false,\n        int cssPriority = default,\n        string? cssLocation = default,\n        int jsPriority = default,\n        string? jsLocation = default,\n        ClientAssetExtractSettingsForOneAssetType? js = default,\n        ClientAssetExtractSettingsForOneAssetType? css = default)\n    {\n        var jsLoc = jsLocation ?? ClientAssetConstants.AddToBody;\n        var cssLoc = cssLocation ?? ClientAssetConstants.AddToHead;\n        var jsPrio = jsPriority == default ? ClientAssetConstants.JsDefaultPriority : jsPriority;\n        var cssPrio = cssPriority == default ? ClientAssetConstants.CssDefaultPriority : cssPriority;\n\n        Css = css ?? new ClientAssetExtractSettingsForOneAssetType(extractAll, cssLoc, cssPrio, false, false);\n        Js = js ?? new ClientAssetExtractSettingsForOneAssetType(extractAll, jsLoc, jsPrio, false, false);\n    }\n\n    public ClientAssetExtractSettingsForOneAssetType Css { get; }\n\n    public ClientAssetExtractSettingsForOneAssetType Js { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Render.Sys.Output/IBlockResourceExtractor.cs",
    "content": "﻿using ToSic.Sxc.Engines;\n\nnamespace ToSic.Sxc.Render.Sys.Output;\n\n/// <summary>\n/// System to automatically pick up JS/CSS files which should be bundled\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IBlockResourceExtractor: IHasLog\n{\n    RenderEngineResult Process(string html);\n\n    /// <summary>\n    /// Scan the html for possible JS/CSS files which should be bundled and extract these. \n    /// </summary>\n    /// <param name=\"html\">html to extract from</param>\n    /// <param name=\"settings\">settings to use</param>\n    /// <returns>\n    /// Original html without the js/css tags which were bundled (so they get removed here)\n    /// Second return-param is an information if the core $2sxc.js should be included\n    /// </returns>\n    RenderEngineResult Process(string html, ClientAssetsExtractSettings settings);\n\n    RenderEngineResult Process(RenderEngineResultRaw resultRaw);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Render.Sys.Specs/RenderPartialSpecs.cs",
    "content": "﻿namespace ToSic.Sxc.Render.Sys.Specs;\n\n/// <summary>\n/// Class to forward to rendering partials.\n/// It's empty - if any platform (like Razor) support it, it must inherit it and implement more properties.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record RenderPartialSpecs;\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/Render.Sys.Specs/RenderSpecs.cs",
    "content": "﻿using ToSic.Sxc.Engines;\nusing ToSic.Sys.Data;\n\nnamespace ToSic.Sxc.Render.Sys.Specs;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record RenderSpecs\n{\n    //public RenderSpecs() { }\n\n    /// <summary>\n    /// The data / view model to be used in the Razor file.\n    /// </summary>\n    public object? Data { get; init; }\n\n    /// <summary>\n    /// Data is used as dictionary in various cases - for MyModel and cache checking.\n    /// This is done here / early to avoid having to convert it in every place where it's used.\n    /// </summary>\n    public IDictionary<string, object?>? DataDic => _dataDic.Get(() => Data?.ToDicInvariantInsensitive());\n    private readonly GetOnce<IDictionary<string, object?>?> _dataDic = new();\n\n    /// <summary>\n    /// Info if LightSpeed should be used for rendering - ATM just used for the statistics in the UI.\n    /// </summary>\n    public bool UseLightspeed { get; init; }\n\n    /// <summary>\n    /// Would contain errors from dnn requirements check (like c# 8.0)\n    /// </summary>\n    public RenderEngineResult? RenderEngineResult { get; init; }\n\n    /// <summary>\n    /// Override default behavior in Oqtane\n    /// </summary>\n    public bool IncludeAllAssetsInOqtane { get; init; }\n\n    /// <summary>\n    /// Information about the partial caching, if it is used.\n    /// </summary>\n    /// <remarks>\n    /// Additional data ATM is meant for passing back information after running the view.\n    /// Specific example ATM is caching information, which will be used to decide if the result should be cached or not.\n    /// \n    /// This is currently done this way because we're not sure how else to get this information back to the engine,\n    /// because the Razor View engine is a bit internal and can't just change the return signature.\n    /// </remarks>\n    public RenderPartialSpecs PartialSpecs { get; init; } = new();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/StartupSxcEngines.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Engines.Sys;\nusing ToSic.Sxc.Polymorphism.Sys;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcEngines\n{\n    public static IServiceCollection AddSxcEngines(this IServiceCollection services)\n    {\n        services.TryAddTransient<EngineFactory>();\n        services.TryAddTransient<IEngineFactory, EngineFactory>();\n\n        services.TryAddTransient<EngineCheckTemplate>();\n        services.TryAddTransient<EnginePolymorphism>();\n        services.TryAddTransient<EngineAppRequirements>();\n\n        // Polymorphism\n        services.TryAddTransient<PolymorphConfigReader>();\n\n        // New v21\n        services.TryAddTransient<EngineSpecsService>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Engines/ToSic.Sxc.Engines.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <!-- Just used for string Before() etc. -->\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Engines</AssemblyName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.GetByName;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/CopyrightPreset.cs",
    "content": "﻿using ToSic.Eav.Models;\n\nnamespace ToSic.Sxc.Images.Sys;\n\n/// <summary>\n/// This is a copyright information type.\n/// Each entity contains one copyright, such as \"MIT\" or \"CC BY-NC-SA\".\n/// These can be defined in each system and then selected when adding copyright info to an image.\n/// </summary>\n// TODO: LOCATION / NAMESPACE not final\n[PrivateApi(\"WIP v16.08\")]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record CopyrightPreset : ModelFromEntity\n{\n    public const string ContentTypeNameId = \"ac3df5f0-c637-45e7-a52b-b323d50e52ac\";\n    public const string ContentTypeName = \"🖺Copyright\";\n\n\n    /// <summary>\n    /// The title.\n    /// </summary>\n    public string? CopyrightMessage => GetThis<string>(null);\n\n    #region Not used fields - these fields never show in the UI, so we can probably remove them some day 2026-01\n\n    /// <summary>\n    /// The primary type, such as \"MIT\" or \"CC BY-NC-SA\". Can also be \"none\" or \"copyright\" without further details.\n    /// </summary>\n    public string? CopyrightType => GetThis<string>(null);\n\n    public int CopyrightYear => GetThis(0);\n\n    public string? CopyrightOwner => GetThis<string>(null);\n\n    public string? CopyrightLink => GetThis<string>(null);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/ImageConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys;\n\n[PrivateApi(\"Can and will change any time, don't use outside of 2sxc\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ImageConstants\n{\n    internal const int MaxSize = 3200;\n    internal const int MaxQuality = 100;\n    internal const string DontSetParam = \"(none)\";\n\n    // https://imageresizing.net/docs/v4/reference\n    public const string ModeCrop = \"crop\";\n    public const string ModeMax = \"max\";\n    public const string ModePad = \"pad\";\n    public const string ModeCarve = \"carve\";\n    public const string ModeStretch = \"stretch\";\n    public const int IntIgnore = 0;\n\n    /// <summary>\n    /// In case a srcset is being generated with a '*' factor and we don't have a number, assume 1200.\n    /// This is an ideal number, as it's quite big but not huge, and will usually be easily divisible by 2,3,4,6 etc.\n    /// </summary>\n    public const int FallbackWidthForSrcSet = 1200;\n\n    public const int FallbackHeightForSrcSet = 0;\n\n    internal static string? FindKnownScaleOrNull(string? scale)\n    {\n        // ReSharper disable RedundantCaseLabel\n        // ReSharper disable StringLiteralTypo\n        switch (scale?.ToLowerInvariant())\n        {\n            case \"up\":\n            case \"upscaleonly\":\n                return \"upscaleonly\";\n            case \"both\":\n                return \"both\";\n            case \"down\":\n            case \"downscaleonly\":\n                return \"downscaleonly\";\n            case null:\n            default:\n                return null;\n        }\n        // ReSharper restore RedundantCaseLabel\n        // ReSharper restore StringLiteralTypo\n    }\n\n\n    // ----- ----- ----- Image Formats ----- ----- -----\n\n    internal static string? FindKnownFormatOrNull(string? format)\n        => format?.ToLowerInvariant() switch\n        {\n            Jpg or \"jpeg\" => Jpg,\n            Png => Png,\n            Gif => Gif,\n            Webp => Webp,\n            _ => null\n        };\n\n\n    public const string Jpg = \"jpg\";\n    public const string Gif = \"gif\";\n    public const string Png = \"png\";\n    public const string Svg = \"svg\";\n    public const string Tif = \"tif\";\n    public const string Webp = \"webp\";\n\n    public static readonly Dictionary<string, ImageFormat> FileTypes = BuildFileTypes();\n\n    /// <summary>\n    /// Note: we're keeping our own list, because they are not many, and because the APIs in .net core/framework are different to find the mime types\n    /// </summary>\n    /// <returns></returns>\n    private static Dictionary<string, ImageFormat> BuildFileTypes()\n    {\n        var webPInfo = new ImageFormat(Webp, \"image/webp\", true);\n        var dic = new Dictionary<string, ImageFormat>(StringComparer.InvariantCultureIgnoreCase)\n        {\n            { Jpg, new(Jpg, \"image/jpeg\", true, new List<ImageFormat> { webPInfo }) },\n            { Gif, new(Gif, \"image/gif\", true) },\n            { Png, new(Png, \"image/png\", true, new List<ImageFormat> { webPInfo }) },\n            { Svg, new(Svg, \"image/svg+xml\", false) },\n            { Tif, new(Tif, \"image/tiff\", true) },\n            { Webp, webPInfo }\n        };\n        dic[\"jpeg\"] = dic[Jpg];\n        dic[\"tiff\"] = dic[Tif];\n        return dic;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/ImageFormat.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ImageFormat : IImageFormat\n{\n    /// <inheritdoc />\n    public string Format { get; }\n\n    /// <inheritdoc />\n    public string MimeType { get; }\n\n    /// <inheritdoc />\n    public bool CanResize { get; }\n\n    public IList<IImageFormat> ResizeFormats { get; }\n\n    public ImageFormat(string format, string mimeType, bool canResize, IEnumerable<IImageFormat>? better = null)\n    {\n        Format = format;\n        MimeType = mimeType;\n        CanResize = canResize;\n        ResizeFormats = canResize\n            ? better?.Union([this]).ToList() ?? [this]\n            : [];\n    }\n\n    public ImageFormat(IImageFormat original, bool preserveSizes)\n    {\n        Format = original.Format;\n        MimeType = original.MimeType;\n        CanResize = original.CanResize;\n        ResizeFormats = preserveSizes ? original.ResizeFormats : new List<IImageFormat>();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/ImageService/ImageService.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\n\nnamespace ToSic.Sxc.Images.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal partial class ImageService(ImgResizeLinker imgLinker, IFeaturesService features)\n    : ServiceWithContext(SxcLogName + \".ImgSvc\", connect: [features, imgLinker]), IImageService\n{\n    #region Constructor and Inits\n\n    internal ImgResizeLinker ImgLinker { get; } = imgLinker;\n    internal IFeaturesService Features { get; } = features;\n\n    internal IEditService? EditOrNull => ExCtx.GetService<IEditService>(reuse: true);\n\n    internal IToolbarService? ToolbarOrNull => _toolbarSvc.Get(() => ExCtx.GetService<IToolbarService>(reuse: true));\n    private readonly GetOnce<IToolbarService?> _toolbarSvc = new();\n\n    [field: AllowNull, MaybeNull]\n    private IPageService PageService => field ??= ExCtx.GetService<IPageService>(reuse: true);\n\n    #endregion\n\n    /// <inheritdoc />\n    public IResponsiveImage Img(\n        object? link = null,\n        object? settings = null,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? factor = null,\n        object? width = default,\n        string? imgAlt = null,\n        string? imgAltFallback = default,\n        string? imgClass = null,\n        object? imgAttributes = default,\n        object? toolbar = default,\n        object? recipe = null)\n    {\n        var specs = ResponsiveSpecsOfTarget.ExtractSpecs(link);\n        var finalSettings = SettingsInternal(settings ?? specs.ResizeSettingsOrNull(), factor: factor, width: width, recipe: recipe);\n        ITweakMedia tweaker = new TweakMedia(\n            ImageSvc: this,\n            TargetSpecs: specs,\n            ResizeSettings: finalSettings,\n            VDec: new(),\n            Img: new(Class: imgClass, Alt: imgAlt, AltFallback: imgAltFallback, Attributes: TweakMedia.CreateAttribDic(imgAttributes, nameof(imgAttributes))),\n            Pic: new(),\n            ToolbarObj: toolbar\n        );\n        if (tweak != default) tweaker = tweak(tweaker);\n\n        return new ResponsiveImage(\n            this,\n            PageService,\n            new(specs, Tweaker: (TweakMedia)tweaker),\n            Log);\n    }\n\n\n    /// <inheritdoc />\n    public IResponsivePicture Picture(\n        object? link = default,\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakMedia, ITweakMedia>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        string? imgAlt = default,\n        string? imgAltFallback = default,\n        string? imgClass = default,\n        object? imgAttributes = default,\n        string? pictureClass = default,\n        object? pictureAttributes = default,\n        object? toolbar = default,\n        object? recipe = default)\n    {\n        var specs = ResponsiveSpecsOfTarget.ExtractSpecs(link);\n        var finalSettings = SettingsInternal(settings ?? specs.ResizeSettingsOrNull(), factor: factor, width: width, recipe: recipe);\n        ITweakMedia tweaker = new TweakMedia(\n            ImageSvc: this,\n            TargetSpecs: specs,\n            ResizeSettings: finalSettings,\n            VDec: new(),\n            Img: new(Class: imgClass, Alt: imgAlt, AltFallback: imgAltFallback, Attributes: TweakMedia.CreateAttribDic(imgAttributes, nameof(imgAttributes))),\n            Pic: new(pictureClass, Attributes: TweakMedia.CreateAttribDic(pictureAttributes, nameof(pictureAttributes))),\n            ToolbarObj: toolbar\n        );\n        if (tweak != default)\n            tweaker = tweak(tweaker);\n        return new ResponsivePicture(\n            this,\n            PageService,\n            new(specs, Tweaker: (TweakMedia)tweaker),\n            Log);\n    }\n\n    /// <inheritdoc />\n    public override bool Debug\n    {\n        get;\n        set\n        {\n            field = value;\n            ImgLinker.Debug = value;\n            Features.Debug = value;\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/ImageService/ImageService_GetFormat.cs",
    "content": "﻿using ToSic.Sys.Utils;\nusing static ToSic.Sxc.Sys.Configuration.SxcFeatures;\n\nnamespace ToSic.Sxc.Images.Sys;\n\npartial class ImageService\n{\n    /// <inheritdoc />\n    public IImageFormat GetFormat(string? path)\n    {\n        // 1. check extension makes sense / lower case\n        if (path.IsEmpty())\n            return new ImageFormat(\"\", \"\", false);\n        path = path.Split('?')[0];\n        var extension = path.ToLowerInvariant();\n        if (extension.Contains(\".\"))\n            extension = Path.GetExtension(extension).Trim('.');\n\n        // 2. See if we know of this - if yes, return - but strip sub-formats if the feature is disabled\n        if (ImageConstants.FileTypes.TryGetValue(extension, out var result))\n            return Features.IsEnabled(ImageServiceMultiFormat.NameId)\n                ? result\n                : new(result, false);\n\n        // 3. Otherwise, just return an object without known mime type\n        return new ImageFormat(extension, \"\", false);\n\n        // 4. Future / maybe: Otherwise check system for mime type and try to build a recommendation\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/ImageService/ImageService_Settings.cs",
    "content": "﻿using ToSic.Sxc.Images.Sys.ResizeSettings;\nusing ToSic.Sys.Utils;\nusing static Connect.Koi.CssFrameworks;\n\nnamespace ToSic.Sxc.Images.Sys;\n\npartial class ImageService\n{\n    /// <inheritdoc />\n    public IResizeSettings Settings(\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakResize, ITweakResize>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        object? height = default,\n        object? quality = default,\n        string? resizeMode = default,\n        string? scaleMode = default,\n        string? format = default,\n        object? aspectRatio = default,\n        string? parameters = default,\n        object? recipe = default\n    ) => SettingsInternal(settings: settings, npo: npo, tweak: tweak,\n        factor: factor, width: width, height: height, quality: quality,\n        resizeMode: resizeMode, scaleMode: scaleMode, format: format, aspectRatio: aspectRatio,\n        parameters: parameters, recipe: recipe);\n\n    /// <summary>\n    /// Internal Get-Settings, with class result (not interface).\n    /// </summary>\n    /// <returns>an internal settings record which could be further manipulated</returns>\n    internal ResizeSettings.ResizeSettings SettingsInternal(\n        object? settings = default,\n        NoParamOrder npo = default,\n        Func<ITweakResize, ITweakResize>? tweak = default,\n        object? factor = default,\n        object? width = default,\n        object? height = default,\n        object? quality = default,\n        string? resizeMode = default,\n        string? scaleMode = default,\n        string? format = default,\n        object? aspectRatio = default,\n        string? parameters = default,\n        object? recipe = default\n    )\n    {\n        var realSettings = GetBestSettings(settings);\n\n        var almostFinal = ImgLinker.ResizeParamMerger.BuildResizeSettings(npo: npo, settings: realSettings, factor: factor,\n            width: width, height: height, quality: quality, resizeMode: resizeMode,\n            scaleMode: scaleMode, format: format, aspectRatio: aspectRatio, parameters: parameters, advanced: AdvancedSettings.Parse(recipe));\n\n        return (tweak?.Invoke(new TweakResize(almostFinal)) as TweakResize)?.Settings\n               ?? almostFinal;\n    }\n\n    #region Settings Handling\n\n    /// <summary>\n    /// Use the given settings or try to use the default content-settings if available\n    /// </summary>\n    /// <param name=\"settings\"></param>\n    /// <returns></returns>\n    private object? GetBestSettings(object? settings)\n    {\n        var l = Log.Fn<object?>(enabled: Debug);\n        return settings switch\n        {\n            null or true => l.Return(GetSettingsByName(\"Content\"), \"null/default\"),\n            string strName when strName.HasValue() => l.Return(GetSettingsByName(strName), $\"name: {strName}\"),\n            _ => l.Return(settings, \"unchanged\")\n        };\n    }\n\n\n    internal ICanGetByName? GetSettingsByName(string strName)\n        => ResizeParamMerger.GetImageSettingsByName(ExCtxOrNull, strName, Debug, Log);\n\n    // 2025-06 2dm - doesn't seem to be used; believe it was a feature that was never finished\n    ///// <summary>\n    ///// Convert to Multi-Resize Settings\n    ///// </summary>\n    ///// <param name=\"value\"></param>\n    ///// <returns></returns>\n    //private AdvancedSettings? ToAdv(object value) => AdvancedSettings.Parse(value);\n\n    #endregion\n\n    /// <inheritdoc />\n    public Recipe Recipe(string variants) => new(variants: variants);\n\n    /// <inheritdoc />\n    public Recipe Recipe(\n        Recipe recipe,\n        NoParamOrder npo = default,\n        string? name = default,\n        int width = default,\n        string? variants = default,\n        IDictionary<string, object?>? attributes = default,\n        IEnumerable<Recipe>? recipes = default,\n        bool? setWidth = default,\n        bool? setHeight = default,\n        string? forTag = default,\n        string? forFactor = default,\n        string? forCss = default\n    )\n        => new(recipe, name: name, width: width, variants: variants, attributes: attributes, recipes: recipes, \n            setWidth: setWidth, setHeight: setHeight, forTag: forTag, forFactor: forFactor, forCss: forCss);\n\n    internal string? OverrideCssFramework\n    {\n        get\n        {\n            // If Koi knows the framework, then no need to check features\n            if (!ImgLinker.Koi.IsUnknown)\n                return null;\n\n            // Get list of features, and only re-check if the count changed\n            var fka = PageService.FeatureKeysAdded;\n            if (fka.Count == _lastCheckCount)\n                return field;\n            _lastCheckCount = fka.Count;\n\n            // Determine framework override\n            // Note that BootstrapX is more of a test flag, so check it first\n            return field = fka.Contains(\"BootstrapX\") ? \"bsX\"\n                : fka.Contains(nameof(Bootstrap6)) ? Bootstrap6\n                : fka.Contains(nameof(Bootstrap5)) ? Bootstrap5\n                : null;\n        }\n    }\n\n    private int _lastCheckCount;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/ImageService/TweakMedia.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Images.Sys.ResizeSettings;\nusing ToSic.Sys.Utils;\nusing static System.StringComparer;\n\nnamespace ToSic.Sxc.Images.Sys;\n\ninternal record TweakMedia(\n    ImageService ImageSvc,\n    ResponsiveSpecsOfTarget TargetSpecs,\n    ResizeSettings.ResizeSettings ResizeSettings,\n    ImageDecoratorVirtual VDec,\n    ImageSpecs Img,\n    PictureSpecs Pic,\n    object? ToolbarObj)\n    : ITweakMedia\n{\n    #region Resize Settings\n\n    /// <inheritdoc />\n    public ITweakMedia Resize(Func<ITweakResize, ITweakResize>? tweak = default)\n    {\n        var updated = (tweak?.Invoke(new TweakResize(ResizeSettings)) as TweakResize)?.Settings ?? ResizeSettings;\n        return this with { ResizeSettings = updated };\n    }\n\n    /// <inheritdoc />\n    public ITweakMedia Resize(string? name, NoParamOrder npo = default, Func<ITweakResize, ITweakResize>? tweak = default)\n    {\n        var settings = name.HasValue() && ImageSvc != null // during tests, ImageSvc may be blank\n            ? ImageSvc.ImgLinker.ResizeParamMerger.BuildResizeSettings(settings: ImageSvc.GetSettingsByName(name))\n            : ResizeSettings;\n        var updated = (tweak?.Invoke(new TweakResize(settings)) as TweakResize)?.Settings ?? settings;\n        return this with { ResizeSettings = updated };\n    }\n\n    /// <inheritdoc />\n    public ITweakMedia Resize(IResizeSettings settings, NoParamOrder npo = default, Func<ITweakResize, ITweakResize>? tweak = default)\n    {\n        var retyped = settings as ResizeSettings.ResizeSettings ?? throw new ArgumentException(@\"Can't properly convert to expected type\", nameof(settings));\n        var updated = (tweak?.Invoke(new TweakResize(retyped)) as TweakResize)?.Settings ?? retyped;\n        return this with { ResizeSettings = updated };\n    }\n\n    #endregion\n\n    #region Lightbox\n\n    /// <inheritdoc />\n    public ITweakMedia LightboxEnable(bool isEnabled = true)\n        => this with { VDec = VDec with { LightboxIsEnabled = isEnabled } };\n\n    /// <inheritdoc />\n    public ITweakMedia LightboxGroup(string group)\n        => this with { VDec = VDec with { LightboxGroup = group } };\n\n    /// <inheritdoc />\n    public ITweakMedia LightboxDescription(string description)\n        => this with { VDec = VDec with { DescriptionExtended = description } };\n\n    #endregion\n\n    #region Image Properties\n\n    public ITweakMedia ImgClass(string imgClass)\n        => this with { Img = Img with { Class = imgClass } };\n\n    public ITweakMedia ImgAlt(string alt)\n        => this with { Img = Img with { Alt = alt } };\n\n    public ITweakMedia ImgAltFallback(string imgAltFallback)\n        => this with { Img = Img with { AltFallback = imgAltFallback } };\n\n    public ITweakMedia ImgAttributes(IDictionary<string, string> attributes)\n        => this with { Img = Img with { Attributes = CreateAttribDic(attributes, nameof(attributes)) } };\n\n    public ITweakMedia ImgAttributes(IDictionary<string, object> attributes)\n        => this with { Img = Img with { Attributes = CreateAttribDic(attributes, nameof(attributes)) } };\n\n    public ITweakMedia ImgAttributes(object attributes)\n        => this with { Img = Img with { Attributes = CreateAttribDic(attributes, nameof(attributes)) } };\n\n    #endregion\n\n    #region Picture Properties\n\n    public ITweakMedia PictureClass(string pictureClass)\n        => this with { Pic = Pic with { Class = pictureClass } };\n\n    public ITweakMedia PictureAttributes(IDictionary<string, string> attributes)\n        => this with { Pic = Pic with { Attributes = CreateAttribDic(attributes, nameof(attributes)) } };\n    \n    public ITweakMedia PictureAttributes(IDictionary<string, object> attributes)\n        => this with { Pic = Pic with { Attributes = CreateAttribDic(attributes, nameof(attributes)) } };\n\n    public ITweakMedia PictureAttributes(object attributes)\n        => this with { Pic = Pic with { Attributes = CreateAttribDic(attributes, nameof(attributes)) } };\n\n    #endregion\n\n    #region Toolbar\n    \n    public ITweakMedia Toolbar(bool enabled)\n        => this with { ToolbarObj = enabled };\n\n    public ITweakMedia Toolbar(IToolbarBuilder toolbar)\n        => this with { ToolbarObj = toolbar };\n\n    #endregion\n\n    #region TweakInput - attempted in v20.09 but doesn't work - reason is we would have to pass the tweak very, very deep into the system which we stopped\n\n    ///// <summary>\n    ///// Reuse the existing TweakInput to store input tweaks\n    ///// </summary>\n    //private TweakInput<string>? TweakInput { get; init; }\n\n    //[PublicApi]\n    //public ITweakMedia Input(string replace, NoParamOrder npo = default)\n    //    => this with { TweakInput = (TweakInput ?? new TweakInput<string>()).CloneWith(_ => replace) };\n\n    //[PublicApi]\n    //public ITweakMedia Input(Func<string> func, NoParamOrder npo = default)\n    //    => this with { TweakInput = (TweakInput ?? new TweakInput<string>()).CloneWith(_ => func()) };\n\n    //[PublicApi]\n    //public ITweakMedia Input(Func<string, string> func, NoParamOrder npo = default)\n    //    => this with { TweakInput = (TweakInput ?? new TweakInput<string>()).CloneWith(tv => func(tv.Value!)) };\n\n    //[PublicApi]\n    //public ITweakMedia Process(Func<ITweakData<string>, string> func, NoParamOrder npo = default)\n    //    => this with { TweakInput = (TweakInput ?? new TweakInput<string>()).CloneWith(func) };\n\n    #endregion\n\n    internal static IDictionary<string, object?>? CreateAttribDic(object? attributes, string name)\n        => attributes switch\n        {\n            null => null,\n            IDictionary<string, object?> ok => ok.ToInvariant(),\n            IDictionary<string, string> strDic => strDic.ToDictionary(\n                pair => pair.Key,\n                object? (pair) => pair.Value, InvariantCultureIgnoreCase\n            ),\n            _ => attributes.IsAnonymous()\n                ? attributes.ToDicInvariantInsensitive()\n                : throw new ArgumentException($@\"format of {name} unknown: {name.GetType().Name}\", nameof(attributes))\n        };\n}\n\n/// <summary>\n/// Fake image decorator so the code can run stable without having to check if this exists or not.\n/// </summary>\n/// <param name=\"LightboxIsEnabled\"></param>\n/// <param name=\"LightboxGroup\"></param>\n/// <param name=\"DescriptionExtended\"></param>\ninternal record ImageDecoratorVirtual(\n    bool? LightboxIsEnabled = default,\n    string? LightboxGroup = default,\n    string? DescriptionExtended = default\n) : IImageDecorator;\n\ninternal record ImageSpecs(\n    string? Class = default,\n    string? Alt = default,\n    string? AltFallback = default,\n    IDictionary<string, object?>? Attributes = default\n);\n\ninternal record PictureSpecs(\n    string? Class = default,\n    IDictionary<string, object?>? Attributes = default\n);\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/ImgResizeLinker.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing System.Collections.Specialized;\nusing Connect.Koi;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.Metadata;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Images.Sys.ResizeSettings;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Capabilities.Features;\nusing static ToSic.Sxc.Sys.Configuration.SxcFeatures;\nusing static ToSic.Sxc.Images.Sys.ImageConstants;\nusing static ToSic.Sxc.Images.Sys.ImageDecorator;\nusing static ToSic.Sxc.Images.RecipeVariant;\n\nnamespace ToSic.Sxc.Images.Sys;\n\n[PrivateApi(\"Internal stuff\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ImgResizeLinker(\n    LazySvc<ISysFeaturesService> features,\n    LazySvc<ICss> koi,\n    LazySvc<ISite> siteLazy,\n    ResizeDimensionGenerator dimGen)\n    : ServiceBase($\"{SxcLogName}.ImgRes\", connect: [features, koi, dimGen, siteLazy]), ICanDebug\n{\n    public bool Debug { get; set; }\n\n    internal readonly ResizeDimensionGenerator DimGen = dimGen;\n\n    public ICss Koi => koi.Value;\n\n    private bool UseFactors => features.Value.IsEnabled(ImageServiceUseFactors);\n\n    /// <summary>\n    /// Make sure this is in sync with the Link.Image\n    /// </summary>\n    public string? ImageUrl(\n        string? url = default,\n        object? settings = default,\n        object? factor = default,\n        NoParamOrder npo = default,\n        IField? field = default,  // todo\n        object? width = default,\n        object? height = default,\n        object? quality = default,\n        string? resizeMode = default,\n        string? scaleMode = default,\n        string? format = default,\n        object? aspectRatio = default,\n        string? parameters = default,\n        IExecutionContext? executionContext = default\n    )\n    {\n        var l = (Debug ? Log : null).Fn<string?>($\"{nameof(url)}:{url}\");\n\n        // Modern case - all settings have already been prepared, the other settings are ignored\n        if (settings is ResizeSettings.ResizeSettings resizeSettings)\n        {\n            var basic = ImgResizeSettings(url, resizeSettings, field).Url;\n            return l.Return(basic, \"prepared:\" + basic);\n        }\n\n        resizeSettings = ResizeParamMerger.BuildResizeSettings(\n            settings, factor: factor, width: width, height: height, quality: quality, resizeMode: resizeMode,\n            scaleMode: scaleMode, format: format, aspectRatio: aspectRatio,\n            parameters: parameters, executionContext: executionContext);\n\n        var result = ImgResizeSettings(url, resizeSettings, field).Url;\n        return l.Return(result, \"built:\" + result);\n    }\n        \n    internal OneResize ImgResizeSettings(string? url, ResizeSettings.ResizeSettings settings, IHasMetadata? field, string? overrideFramework = null)\n    {\n        var l = Log.Fn<OneResize>();\n        var srcSetSettings = settings.Find(SrcSetType.Img, useFactors: UseFactors, overrideFramework ?? Koi.Framework);\n        return l.Return(ConstructUrl(url, settings, srcSetSettings, field), \"no srcset\");\n    }\n        \n\n    internal string? SrcSet(string? url, ResizeSettings.ResizeSettings settings, SrcSetType srcSetType, IHasMetadata? field = null, string? overrideFramework = null)\n    {\n        var l = Log.Fn<string?>();\n\n        var srcSetSettings = settings.Find(srcSetType, useFactors: UseFactors, overrideFramework ?? Koi.Framework);\n\n        var srcSetParts = srcSetSettings?.VariantsParsed;\n\n        // Basic case -no srcSet config. In this case the src-set can just contain the url.\n        if (srcSetParts == null || srcSetParts.Length == 0)\n            return l.Return(ConstructUrl(url, settings, srcSetSettings, field).Url, \"no srcset\");\n\n        var results = srcSetParts\n            .Select(ssPart =>\n        {\n            if (ssPart.SizeType == SizeDefault)\n                return ConstructUrl(url, settings, srcSetSettings, null, ssPart);\n\n            var one = ConstructUrl(url, settings, srcSetSettings, fieldForMd: field, partDef: ssPart);\n            // this must happen at the end\n            one = one with { Suffix = ssPart.SrcSetSuffix(one.Width) };\n            return one;\n        });\n        var result = string.Join(\",\\n\", results.Select(r => r.UrlWithSuffix()));\n\n        return l.Return(result, \"srcset\");\n    }\n\n\n\n    private OneResize ConstructUrl(string? url, ResizeSettings.ResizeSettings resizeSettings, Recipe? srcSetSettings, IHasMetadata? fieldForMd, RecipeVariant? partDef = null)\n    {\n        var one = DimGen.ResizeDimensions(resizeSettings, srcSetSettings, partDef) with\n        {\n            Recipe = srcSetSettings,\n        };\n        \n\n        var imgDecorator = fieldForMd == null\n            ? null \n            : _imgDecCache.GetOrAdd(fieldForMd, f => GetOrNull(f, siteLazy.Value.SafeLanguagePriorityCodes()));\n\n        var resizeMode = resizeSettings.ResizeMode;\n        if (imgDecorator?.CropBehavior == NoCrop)\n        {\n            resizeMode = ModeMax;\n            one = one with\n            {\n                ShowAll = true,\n                Height = 0, // if we show all, the height may not match crop-height\n            };\n        }\n\n        var resizerNvc = new NameValueCollection();\n        ImgAddIfRelevant(resizerNvc, \"w\", one.Width, \"0\");\n        ImgAddIfRelevant(resizerNvc, \"h\", one.Height, \"0\");\n        ImgAddIfRelevant(resizerNvc, \"quality\", resizeSettings.Quality, \"0\");\n        ImgAddIfRelevant(resizerNvc, \"mode\", resizeMode, DontSetParam);\n        ImgAddIfRelevant(resizerNvc, \"scale\", resizeSettings.ScaleMode, DontSetParam);\n        ImgAddIfRelevant(resizerNvc, \"format\", resizeSettings.Format, DontSetParam);\n\n        // Get resize instructions of the data if it has any\n        var modifier = imgDecorator?.GetAnchorOrNull();\n        if (modifier?.Param != null)\n            ImgAddIfRelevant(resizerNvc, modifier.Value.Param, modifier.Value.Value);\n\n        url = UrlHelpers.AddQueryString(url, resizerNvc);\n\n        if (resizeSettings.Parameters != null && resizeSettings.Parameters.HasKeys())\n            url = UrlHelpers.AddQueryString(url, resizeSettings.Parameters);\n\n        var result = Tags.SafeUrl(url).ToString();\n        one = one with { Url = result };\n        return one;\n    }\n\n    // cache buffer settings which had already been looked up\n    private readonly ConcurrentDictionary<IHasMetadata, ImageDecorator?> _imgDecCache = new();\n\n\n    // ReSharper disable once UnusedMethodReturnValue.Local\n    private bool ImgAddIfRelevant(NameValueCollection resizer, string? key, object? value, string irrelevant = \"\")\n    {\n        var l = (Debug ? Log : null).Fn<bool>();\n        if (key == null || value == null)\n            return l.ReturnFalse($\"Won't add '{key}', since key or value are null\");\n\n        var strValue = value.ToString();\n        if (string.IsNullOrEmpty(strValue))\n            return l.ReturnFalse($\"Won't add '{key}' since value as string would be null\");\n\n        if (strValue.Equals(irrelevant, StringComparison.InvariantCultureIgnoreCase))\n            return l.ReturnFalse($\"Won't add '{key}' since value would be irrelevant\");\n\n        resizer.Add(key, strValue);\n        return l.ReturnTrue($\"Added key {key}\");\n    }\n\n\n    [field: AllowNull, MaybeNull]\n    internal ResizeParamMerger ResizeParamMerger\n    {\n        get\n        {\n            if (field != null)\n                return field;\n            field = new(Log);\n            if (Debug)\n                field.Debug = true;\n            return field;\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys/ResizeSettingsHelper.cs",
    "content": "﻿using ToSic.Sys.Utils;\nusing static ToSic.Sxc.Sys.Plumbing.ParseObject;\n\nnamespace ToSic.Sxc.Images.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static class ResizeSettingsExtensions\n{\n    internal static Recipe? Find(this ResizeSettings.ResizeSettings? resizeSettings, SrcSetType srcSetType, bool useFactors, string? cssFramework)\n    {\n        if (resizeSettings == null)\n            return null;\n        var advanced = resizeSettings.Advanced;\n        var mainRecipe = advanced?.Recipe;\n        if (mainRecipe == null)\n            return null;\n        var subRecipes = advanced!.AllSubRecipes;\n\n        // No sub-recipes - return main\n        if (subRecipes.SafeNone()) return mainRecipe;\n\n        // Prepare list of frameworks, targets and factors to use in the loops\n        var frameworks = cssFramework == null\n            ? [null]\n            : new[] { cssFramework, null };\n\n        var primaryTarget = srcSetType == SrcSetType.Img ? \"img\" : \"source\";\n        var targetsToTest = new[] { primaryTarget, Recipe.RuleForDefault };\n\n        var factor = resizeSettings.FactorToUse; // DNearZero(resizeSettings.Factor) ? 1 : resizeSettings.Factor;\n        var factorsToTest = useFactors\n            ? [factor, null]\n            : new[] { (double?)null };\n\n        // Get PiggyBack cache to rarely rerun LINQ\n        var pgb = advanced.PiggyBack;\n\n        // Loop all combinations\n        foreach (var cssFw in frameworks)\n        {\n            var cssKey = cssFw.AsKey();\n            var cssRecipes = pgb.GetOrGenerate(cssKey, \n                () => subRecipes.Where(r => r.ForCss == cssFw).ToList());\n            if (!cssRecipes.Any())\n                continue;\n            foreach (var f in factorsToTest)\n            {\n                var factorKey = cssKey + \"-\" + (f == null\n                        ? ((string?)null).AsKey()\n                        : f.ToString().AsKey()\n                    );\n                var recList = pgb.GetOrGenerate(factorKey, \n                    () => cssRecipes.Where(m => f == null ? m.FactorParsed == 0 : DNearZero(m.FactorParsed - f.Value)).ToList());\n                foreach (var target in targetsToTest)\n                {\n                    var match = recList.FirstOrDefault(m => m.ForTag == target);\n                    if (match != null) return match;\n                }\n            }\n        }\n\n\n        return mainRecipe;\n    }\n}\n\ninternal enum SrcSetType\n{\n    Img,\n    Source\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.ImageflowRewrite/ImageflowRewrite.cs",
    "content": "﻿using System.Collections.Specialized;\n\nnamespace ToSic.Sxc.Images;\n\n// Is executed in dnn imageflow module and oqtane imageflow module to\n// rewrite query string params before imageflow middleware take a care of them.\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ImageflowRewrite\n{\n    public static readonly string Quality = \"quality\";\n    //public static readonly string JpgQuality = \"jpg.quality\";\n    public static readonly string PngQuality = \"png.quality\";\n    public static readonly string WebpQuality = \"webp.quality\";\n\n    [return: NotNullIfNotNull(nameof(queryString))]\n    public static NameValueCollection? QueryStringRewrite(NameValueCollection? queryString)\n    {\n        // rewrite query string\n        if (queryString != null && !string.IsNullOrEmpty(queryString[Quality]))\n        {\n            var value = queryString[Quality];\n            // use the quality parameter of format,\n            // rather than reusing the jpeg quality command.\n            AddKeyWhenMissing(queryString, PngQuality, value);\n            AddKeyWhenMissing(queryString, WebpQuality, value);\n        }\n        return queryString;\n    }\n\n    public static NameValueCollection AddKeyWhenMissing(NameValueCollection queryString, string key, string? value)\n    {\n        if (string.IsNullOrEmpty(queryString[key]))\n            queryString.Add(key, value);\n        return queryString;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.Metadata/ImageMetadataRecommendationsService.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Utils;\nusing IFeaturesService = ToSic.Sxc.Services.IFeaturesService;\n\nnamespace ToSic.Sxc.Images.Sys.Metadata;\n\n/// <summary>\n/// Small service to image metadata additional recommendations as configured.\n/// </summary>\nclass ImageMetadataRecommendationsService(IFeaturesService featuresSvc) : ServiceWithContext(\"Img.MdRecS\", connect: [featuresSvc]), IImageMetadataRecommendationsService\n{\n    /// <summary>\n    /// Optionally add image-metadata recommendations\n    /// </summary>\n    public void SetImageRecommendations(IMetadata? mdOf, string? path)\n    {\n        if (mdOf?.Target == null || !path.HasValue())\n            return;\n        var ext = Path.GetExtension(path);\n        if (ext.HasValue() && AssetTypeNames.IsImage(ext))\n            mdOf.Target.Recommendations = GetImageRecommendations();\n    }\n\n    public string[] GetImageRecommendations()\n    {\n        var sysSettings = ExCtxOrNull?.GetDataStack<ITypedStack>(ExecutionContextStateNames.AllSettings);\n        if (sysSettings == null || !featuresSvc.IsEnabled(BuiltInFeatures.CopyrightManagement.NameId))\n            return ImageRecommendationsBasic;\n\n        var useCopyright = sysSettings.Bool($\"{CopyrightSettings.SettingsPath}.{nameof(CopyrightSettings.ImagesInputEnabled)}\");\n        return useCopyright\n            ? ImageRecommendationsCopyright\n            : ImageRecommendationsBasic;\n    }\n\n    /// <summary>\n    /// Basic recommendations for image metadata - just the ImageDecorator\n    /// </summary>\n    private static string[] ImageRecommendationsBasic => [ImageDecorator.TypeNameId];\n\n    /// <summary>\n    /// Advanced recommendations for image metadata (if enabled) - with additional Copyright\n    /// </summary>\n    private static string[] ImageRecommendationsCopyright => [CopyrightDecorator.ContentTypeNameId, ImageDecorator.TypeNameId];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.ResizeSettings/OneResize.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys.ResizeSettings;\n\n/// <summary>\n/// The final sizes to be used when resizing\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal record OneResize: ICanDump\n{\n    public int Width { get; init; }\n    public int Height { get; set; }\n    public string? Url { get; init; }\n    public string? Suffix { get; init; }\n\n    public string UrlWithSuffix() => $\"{Url}{Suffix}\";\n\n    public Recipe? Recipe { get; init; }\n\n    /// <summary>\n    /// Will be set based on image metadata, to determine that the image should be shown completely (like a logo) and not cropped.\n    /// This means the image could be a different size than expected\n    /// </summary>\n    public bool ShowAll { get; init; } = false;\n\n    [PrivateApi]\n    public string Dump() => $\"{nameof(Width)}: {Width}, {nameof(Height)}: {Height}, {nameof(Url)}: {Url}, {nameof(Suffix)}: {Suffix}, \" +\n                            $\"{nameof(ShowAll)}: {ShowAll}, {nameof(Recipe)}: \" + \"{\" + Recipe?.Dump() + \"}\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.ResizeSettings/RecipeQuality.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys.ResizeSettings;\n\n/// <summary>\n/// This is not ready yet.\n/// Goal is that different image formats and different sizes can have other quality specs.\n/// This is so WebP can use different quality params, or very small JGPs need a higher quality than lager JPGs\n/// </summary>\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class RecipeQuality(RecipeQuality original, int forWidth, string forFormat, int quality)\n{\n    public int ForWidth { get; } = forWidth;\n\n    public string ForFormat { get; } = forFormat ?? original.ForFormat;\n\n    public int Quality { get; } = quality;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.ResizeSettings/ResizeDimensionGenerator.cs",
    "content": "﻿using static ToSic.Sxc.Images.Sys.ImageConstants;\nusing static ToSic.Sxc.Images.RecipeVariant;\nusing static ToSic.Sxc.Sys.Plumbing.ParseObject;\n\nnamespace ToSic.Sxc.Images.Sys.ResizeSettings;\n\n[PrivateApi(\"Internal stuff\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ResizeDimensionGenerator() : ServiceBase(\"Img.ResDim\")\n{\n    internal bool Debug = false;\n        \n\n    /// <summary>\n    /// Get the best matching dimension (width/height) based on what's specified\n    /// </summary>\n    private static int BestWidthOrHeightBasedOnSrcSet(int initial, int srcSetOverride, RecipeVariant partDef, int fallbackIfNoOriginal)\n    {\n        // SrcSet defined a value, use that\n        if (srcSetOverride != 0) return srcSetOverride;\n\n        // No need to recalculate anything, return original\n        if (partDef.SizeType != SizePixelDensity && partDef.SizeType != SizeFactorOf) return initial;\n\n        // If we're doing a factor-of, we always need an original value. If it's missing, use the fallback\n        if (partDef.SizeType == SizeFactorOf && initial == 0) initial = fallbackIfNoOriginal;\n\n        // Calculate the expected value based on Size=Scale-Factor * original\n        return (int)(partDef.Size * initial);\n    }\n\n\n    internal OneResize ResizeDimensions(ResizeSettings settings, Recipe? recipe, RecipeVariant? partDef = null)\n    {\n        var factor = settings.FactorToUse;\n        // if (DNearZero(factor)) factor = 1; // in this case we must still calculate, and should assume factor is exactly 1\n\n        // First width - quite complicated\n        var maybeWidth = FigureOutBestWidth(settings, recipe, partDef, factor);\n\n\n        // Now height - might be incomplete, but ATM this isn't actually used much\n        var probablyH = partDef == null\n            ? settings.Height\n            : BestWidthOrHeightBasedOnSrcSet(settings.Height, partDef.Height, partDef,\n                FallbackHeightForSrcSet);\n\n        (int Width, int Height) dim = (maybeWidth, probablyH);\n\n        dim.Height = HeightFromAspectRatioOrFactor(dim, factor, settings.UseAspectRatio, settings.AspectRatio);\n\n        dim = KeepInRangeProportional(dim);\n\n        return new()\n        {\n            Width = dim.Width,\n            Height = dim.Height\n        };\n    }\n\n    private static int FigureOutBestWidth(ResizeSettings settings, Recipe? recipe, RecipeVariant? partDef, double factor)\n    {\n        // Priority 1: The value on the part definition. If it's non-zero, don't change the width by any other factor\n        var width = partDef?.Width ?? 0;\n        if (width != 0)\n            return width;\n\n        // Priority #2: The value from the factor map/recipe, which was selected based on this factor. \n        // It must be adjusted by part definition, as we may be looping through various sizes\n        width = settings.UseFactorMap\n            ? IntOrZeroAsNull(recipe?.Width) ?? 0\n            : 0;\n        if (width != 0)\n            return (int)(width * (partDef?.AdditionalFactor ?? 1));\n\n        // Priority #3: If we have a Part-Definition, calculate the values now\n        width = (int)(settings.Width * factor);\n\n        if (partDef != null)\n            width = BestWidthOrHeightBasedOnSrcSet(width, partDef.Width, partDef,\n                FallbackWidthForSrcSet);\n\n        return width;\n    }\n\n\n    private int HeightFromAspectRatioOrFactor((int Width, int Height) dims, double factor, bool useAspectRatio, double aspectRatio)\n    {\n        var maybeLog = Debug ? Log : null;\n        var l = maybeLog.Fn<int>();\n\n        var hasAspectRatio = !DNearZero(aspectRatio);\n\n        // Height should only get Aspect Ratio if the Height wasn't specifically provided\n        var newH = useAspectRatio && hasAspectRatio\n            ? dims.Width / aspectRatio\n            : dims.Height * factor;  // Note that often dims.H is 0, so this will still be 0\n\n        return l.Return((int)newH, $\"H:{newH}\");\n    }\n\n\n    internal (int W, int H) KeepInRangeProportional((int W, int H) original)\n    {\n        var maybeLog = Debug ? Log : null;\n        var l = maybeLog.Fn<(int, int)>();\n\n        // Simple case - it fits into the max-range\n        if (original.W <= MaxSize && original.H <= MaxSize)\n            return l.Return(original, \"is already within bounds\");\n\n        // Harder - at least one doesn't fit - must figure out multiplier and adjust\n        var correctionFactor = (float)Math.Max(original.W, original.H) / MaxSize;\n        var newW = (int)Math.Min(original.W / correctionFactor, MaxSize);   // use Math.Min to avoid rounding errors leading to > 3200\n        var newH = (int)Math.Min(original.H / correctionFactor, MaxSize);\n\n        return l.Return((newW, newH), $\"W:{newW}, H:{newH}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.ResizeSettings/ResizeParamMerger.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Images.Sys.ImageConstants;\nusing static ToSic.Sxc.Sys.Plumbing.ParseObject;\n\nnamespace ToSic.Sxc.Images.Sys.ResizeSettings;\n\n/// <summary>\n/// This merges predefined settings with custom specified parameters to create a stable resize-Parameters object for further use\n/// </summary>\ninternal class ResizeParamMerger(ILog parentLog) : HelperBase(parentLog, $\"{SxcLogName}.ImgRPM\")\n{\n    private const string ResizeModeField = \"ResizeMode\";\n    private const string ScaleModeField = \"ScaleMode\";\n    private const string QualityField = \"Quality\";\n    private const string WidthField = \"Width\";\n    private const string HeightField = \"Height\";\n    private const string AspectRatioField = \"AspectRatio\";\n    private const string AdvancedField = \"Advanced\";\n    private const string FormatField = \"Format\";\n    private const string ParametersField = \"Parameters\";\n\n    public bool Debug = false;\n\n    internal ResizeSettings BuildResizeSettings(\n        object? settings = null,\n        NoParamOrder npo = default,\n        object? factor = null,\n        object? width = null,\n        object? height = null,\n        object? quality = null,\n        string? resizeMode = null,\n        string? scaleMode = null,\n        string? format = null,\n        object? aspectRatio = null,\n        string? parameters = null,\n        AdvancedSettings? advanced = default,\n        IExecutionContext? executionContext = default\n    )\n    {\n        var l = (Debug ? Log : null).Fn<ResizeSettings>();\n        // Common mistake: both height and aspect ratio provided\n        if (aspectRatio != null && height != null)\n        {\n            l.ReturnNull(\"error\");\n            const string messageOnlyOneOrNone = \"only one or none of these should be provided, other can be zero\";\n            throw new ArgumentOutOfRangeException($\"{nameof(aspectRatio)},{nameof(height)}\", messageOnlyOneOrNone);\n        }\n\n        // Helper for resize parameters\n        var paramHelper = new ResizeParams(Log);\n\n        // If we already got resize settings, then clone/merge\n        if (settings is IResizeSettings typeSettings)\n            return l.Return(new(\n                typeSettings,\n                format: ResizeParams.FormatOrNull(format),\n                width: ResizeParams.WidthOrNull(width),\n                height: ResizeParams.HeightOrNull(height),\n                aspectRatio: ResizeParams.AspectRatioOrNull(aspectRatio),\n                factor: ResizeParams.FactorOrNull(factor),\n                quality: ResizeParams.QualityOrNull(quality),\n                resizeMode: ResizeParams.ResizeModeOrNull(resizeMode),\n                scaleMode: ResizeParams.ScaleModeOrNull(scaleMode),\n                parameters: ResizeParams.ParametersOrNull(parameters),\n                advanced: advanced\n            ), $\"Is {nameof(ResizeSettings)}, will clone/init\");\n\n        // Check if the settings is the expected type or null/other type\n        var settingsOrNull = TryToCastSettings(settings, executionContext);\n        l.A($\"Has Settings: {settingsOrNull != null}; type: {settings?.GetType().FullName}\");\n\n        var formatValue = ResizeParams.FormatOrNull(KeepBestString(format, settingsOrNull?.Get(FormatField)));\n\n        var resizeParams = BuildCoreSettings(paramHelper, width, height, factor, aspectRatio, formatValue, settingsOrNull);\n\n        // Add more URL parameters if known\n        resizeParams.Parameters = ResizeParams.ParametersOrNull(KeepBestString(parameters, settingsOrNull?.Get(ParametersField)));\n\n        // Aspects which aren't affected by aspect ratio\n        var qParamInt2 = ResizeParams.QualityOrNull(quality);\n        resizeParams.Quality = qParamInt2 ?? IntOrZeroAsNull(settingsOrNull?.Get(QualityField)) ?? IntIgnore;\n        resizeParams.ResizeMode = ResizeParams.ResizeModeOrNull(KeepBestString(resizeMode, settingsOrNull?.Get(ResizeModeField)));\n        resizeParams.ScaleMode = ResizeParams.ScaleModeOrNull(KeepBestString(scaleMode, settingsOrNull?.Get(ScaleModeField)));\n\n        resizeParams.Advanced = advanced ?? GetMultiResizeSettings(settingsOrNull);\n\n        return l.Return(resizeParams, \"\");\n    }\n\n    private ICanGetByName? TryToCastSettings(object? settings, IExecutionContext? exCtxOrNull)\n        => settings switch\n        {\n            null => null,\n            string name => GetImageSettingsByName(exCtxOrNull, name, Debug, Log),\n            ICanGetByName getSettings => getSettings,\n            IEnumerable<ICanGetByName> settingsList => settingsList.FirstOrDefault(),\n            _ => settings.IsAnonymous()\n                ? new ObjectWrapperCanGetByName(settings)\n                : null,\n        };\n\n    internal static ICanGetByName? GetImageSettingsByName(IExecutionContext? exCtxOrNull, string strName, bool debug, ILog log)\n    {\n        var l = log.Fn<ICanGetByName?>($\"{strName}; code root: {exCtxOrNull != null}\", enabled: debug);\n        var settings = exCtxOrNull?.GetDataStack<ITypedStack>(ExecutionContextStateNames.AllSettings);\n        var imageSettings = settings?.Get($\"Settings.Images.{strName}\");\n        // imageSettings is a ListTypedItems<ITyped> because it's a child-list of entities\n        var result = (imageSettings as IEnumerable<ITyped>)?.FirstOrDefault();\n        return l.Return(result, $\"found: {result != null}\");\n    }\n\n\n\n    private AdvancedSettings? GetMultiResizeSettings(ICanGetByName? getSettings)\n    {\n        try\n        {\n            // Check if we have a property-lookup (usually an entity) and if yes, use the piggy-back\n            var result = (getSettings as IPropertyLookup)?.GetOrCreateInPiggyBack(AdvancedField, ParseAdvancedSettingsJson, Log);\n            return result ?? ParseAdvancedSettingsJson(getSettings?.Get(AdvancedField));\n        }\n        catch\n        {\n            /* ignore */\n            return null;\n        }\n\n        AdvancedSettings ParseAdvancedSettingsJson(object? value)\n            => AdvancedSettings.FromJson(value, Log);\n    }\n\n    internal ResizeSettings BuildCoreSettings(ResizeParams resP, object? width, object? height, object? factor, object? aspectRatio, string? format, ICanGetByName? settingsOrNull)\n    {\n        var l = (Debug ? Log : null).Fn<ResizeSettings>();\n\n        // Try to pre-process parameters and prefer them\n        // The manually provided values must remember Zeros because they deactivate presets\n        (int? W, int? H) parameters = (ResizeParams.WidthOrNull(width), ResizeParams.HeightOrNull(height));\n        IfDebugLogPair(\"Params\", parameters);\n\n        // Pre-Clean the values - all as strings\n        (object? W, object? H) set = (settingsOrNull?.Get(WidthField), settingsOrNull?.Get(HeightField));\n        if (settingsOrNull != null)\n            IfDebugLogPair(\"Settings\", set);\n\n        (int W, int H) safe = (IntOrZeroAsNull(set.W) ?? IntIgnore, IntOrZeroAsNull(set.H) ?? IntIgnore);\n        IfDebugLogPair(\"Safe\", safe);\n\n        var factorFinal = ResizeParams.FactorOrNull(factor) ?? IntIgnore;\n        var arFinal = ResizeParams.AspectRatioOrNull(aspectRatio)\n                      ?? ResizeParams.AspectRatioOrNull(settingsOrNull?.Get(AspectRatioField)) ?? IntIgnore;\n        l.A(Debug, $\"Resize Factor: {factorFinal}, Aspect Ratio: {arFinal}\");\n\n        var basedOnName = settingsOrNull?.Get(\"ItemIdentifier\") as string;\n\n        var resizeSettings = new ResizeSettings(\n            width: parameters.W,\n            height: parameters.H,\n            fallbackWidth: safe.W,\n            fallbackHeight: safe.H,\n            aspectRatio: arFinal,\n            factor: factorFinal,\n            format: format,\n            basedOn: basedOnName\n        );\n\n        return l.Return(resizeSettings);\n\n        // Helper to debug\n        void IfDebugLogPair<T>(string prefix, (T W, T H) values)\n        {\n            if (Debug) Log.A($\"{prefix}: W:{values.W}, H:{values.H}\");\n        }\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.ResizeSettings/ResizeParams.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Web.Sys.Url;\nusing static ToSic.Sxc.Images.Sys.ImageConstants;\nusing static ToSic.Sxc.Sys.Plumbing.ParseObject;\n\nnamespace ToSic.Sxc.Images.Sys.ResizeSettings;\n\n/// <summary>\n/// Helper to process optional parameters and figure out if they should be used or not\n/// </summary>\ninternal class ResizeParams(ILog parentLog) : HelperBase(parentLog, $\"{SxcLogName}.ResPar\")\n{\n    internal static double? AspectRatioOrNull(object? aspectRatio) \n        => DoubleOrNullWithCalculation(aspectRatio);\n\n\n    internal static double? FactorOrNull(object? factor) \n        => DoubleOrNullWithCalculation(factor);\n\n    public static string? FormatOrNull(object? format)\n        => FindKnownFormatOrNull(RealStringOrNull(format));\n\n    internal static int? QualityOrNull(object? quality)\n    {\n        var qParamDouble = DoubleOrNull(quality);\n        if (qParamDouble.HasValue)\n            qParamDouble = DNearZero(qParamDouble.Value)  // ignore if basically 0\n                ? null\n                : qParamDouble.Value > 1\n                    ? qParamDouble\n                    : qParamDouble * 100;\n        var qParamInt = (int?)qParamDouble;\n        return qParamInt;\n    }\n\n    internal static NameValueCollection? ParametersOrNull(string? parameters)\n        => string.IsNullOrWhiteSpace(parameters)\n            ? null\n            : UrlHelpers.ParseQueryString(parameters);\n\n\n    public static string? ResizeModeOrNull(string? resizeMode)\n        => resizeMode; // this one doesn't do any conversion atm\n\n    public static string? ScaleModeOrNull(string? scaleMode)\n        => FindKnownScaleOrNull(scaleMode);\n\n    internal static int? WidthOrNull(object? width)\n        => IntOrNull(width);\n    internal static int? HeightOrNull(object? height)\n        => IntOrNull(height);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.ResizeSettings/ResizeSettings.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Images.Sys.ImageConstants;\nusing static ToSic.Sxc.Sys.Plumbing.ParseObject;\n\nnamespace ToSic.Sxc.Images.Sys.ResizeSettings;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal record ResizeSettings : IResizeSettings, IResizeSettingsInternal\n{\n    /// <summary>\n    /// Name of the settings used initially\n    /// </summary>\n    public string? BasedOn { get; }\n\n    public int Width { get; init; } = IntIgnore;\n    public int Height { get; init; } = IntIgnore;\n    public int Quality { get; set; } = IntIgnore;\n    public string? ResizeMode { get; set; }\n    public string? ScaleMode { get; set; }\n    public string? Format { get; init; }\n    public double Factor { get; init; } = 1;\n    public double AspectRatio { get; init; }\n    public NameValueCollection? Parameters { get; set; }\n\n\n    public bool UseFactorMap { get; set; } = true;\n    public bool UseAspectRatio { get; set; } = true;\n\n    public AdvancedSettings? Advanced { get; set; }\n\n    /// <summary>\n    /// Constructor to create new\n    /// </summary>\n    public ResizeSettings(int? width, int? height, int fallbackWidth, int fallbackHeight, double aspectRatio, double factor, string? format, string? basedOn)\n    {\n        Width = width ?? fallbackWidth;\n        Height = height ?? fallbackHeight;\n        // If the width was given by the parameters, then don't use FactorMap\n        UseFactorMap = width == null;\n        // If the height was supplied by parameters, don't use aspect ratio\n        UseAspectRatio = height == null;\n\n        AspectRatio = aspectRatio;\n        Factor = factor;\n        Format = format;\n        BasedOn = basedOn;\n    }\n\n    /// <summary>\n    /// Constructor to copy\n    /// </summary>\n    public ResizeSettings(\n        IResizeSettings original,\n        NoParamOrder npo = default,\n        int? width = null,\n        int? height = null,\n        double? aspectRatio = null,\n        double? factor = null,\n        int? quality = null,\n        string? format = null,\n        string? resizeMode = null,\n        string? scaleMode = null,\n        NameValueCollection? parameters = null,\n        AdvancedSettings? advanced = null\n    )\n    {\n        if (original == null) throw new ArgumentNullException(nameof(original));\n        Width = width ?? original.Width;\n        Height = height ?? original.Height;\n        Quality = quality ?? original.Quality;\n        ResizeMode = resizeMode ?? original.ResizeMode;\n        ScaleMode = scaleMode ?? original.ScaleMode;\n        Format = format ?? original.Format;\n        Factor = factor ?? original.Factor;\n        Parameters = parameters ?? original.Parameters;\n        AspectRatio = aspectRatio ?? original.AspectRatio;\n\n        BasedOn = original.BasedOn;\n\n        // workaround, as it's not part of the interface ATM\n        if (original is ResizeSettings typed)\n        {\n            UseAspectRatio = typed.UseAspectRatio;\n            UseFactorMap = typed.UseFactorMap;\n        }\n\n        Advanced = advanced ?? (original as IResizeSettingsInternal)?.Advanced;\n    }\n\n    /// <summary>\n    /// Should the factor be used? only if it's clearly away from zero.\n    /// </summary>\n    private bool FactorUsed => !DNearZero(Factor) && !DNearZero(Factor - 1); // so ~0 and ~1 are not used\n\n    /// <summary>\n    /// The factor to use, which is either the factor, or 1 if it's not used\n    /// </summary>\n    internal double FactorToUse => FactorUsed ? Factor : 1;\n\n    internal string ToHtmlInfo(ImageDecorator? decoOrNull)\n    {\n        const string notSet = \"default/not set\";\n        const double floatTolerance = 0.01;\n\n        // Special message for height, in case it has a decorator\n        // which overrules the default height\n        var height = $\"{(Height != IntIgnore ? Height : notSet)}\";\n        var resize = ResizeMode ?? notSet;\n        var scale = ScaleMode ?? notSet;\n        var cropCenter = ImageDecorator.DefaultCropCenter;\n        var aspectRatio = $\"{(Math.Abs(AspectRatio - IntIgnore) > floatTolerance ? AspectRatio : notSet)}\";\n        \n\n        var noCrop = decoOrNull?.CropBehavior == ImageDecorator.NoCrop;\n        if (noCrop)\n        {\n            height = $\"<s>{height}</s> - no-crop = use image as is\";\n            resize = $\"<s>{resize}</s> - {ImageDecorator.NoCrop}\";\n            aspectRatio = $\"<s>{aspectRatio}</s> - no-crop\";\n            cropCenter = $\"<s>{cropCenter}</s> - no-crop\";\n        }\n        else\n        {\n            if (!UseAspectRatio)\n                aspectRatio = $\"<s>{aspectRatio}</s> - not used, height is set\";\n            if (decoOrNull?.CropBehavior == ImageDecorator.ToCrop)\n                cropCenter = decoOrNull.CropToNiceName;\n        }\n\n        var basedOn = BasedOn.HasValue() ? $\"<strong>Settings.Images.{BasedOn}</strong>\" : \"<em>no presets</em>\";\n        var hasSpecialSettings = decoOrNull != null ? \"✅\" : \"no\";\n\n        var result = $@\"<strong>🖼️ Resize Specs</strong>\n\nBased On: {basedOn}\nCustom Image Settings: {hasSpecialSettings}\nWidth: {(Width != IntIgnore ? Width : notSet)}\nHeight: {height}\nQuality: {(Quality != IntIgnore ? Quality : notSet)}\nResizeMode: {resize}\nScaleMode: {scale}\nFormat: {Format ?? notSet}\nFactor: {(FactorUsed ? Factor.ToString(\"0.####\") : notSet)}\nAspectRatio: {aspectRatio}\nUrl Parameters: {Parameters}\nCrop Center: {cropCenter}\n\n<em>This is the primary size. Other responsive sizes derive from this.</em>\";\n        \n        return result.Replace(\", \", \"\\n\").Replace(\"\\n\", \"<br>\\n\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.ResizeSettings/TweakResize.cs",
    "content": "﻿namespace ToSic.Sxc.Images.Sys.ResizeSettings;\n\ninternal record TweakResize(ResizeSettings Settings): ITweakResize\n{\n    public ITweakResize Width(int width)\n        => new TweakResize(Settings: Settings with { Width = width, UseFactorMap = false });\n\n    public ITweakResize Height(int height)\n        => new TweakResize(Settings: Settings with { Height = height, UseAspectRatio = false });\n\n    public ITweakResize Factor(double factor)\n        => new TweakResize(Settings: Settings with { Factor = factor });\n\n    public ITweakResize Factor(string factor)\n    {\n        var f = ResizeParams.FactorOrNull(factor);\n        return f == null ? this : new(Settings: Settings with { Factor = f.Value });\n    }\n\n    public ITweakResize AspectRatio(double aspectRatio)\n        => new TweakResize(Settings: Settings with { AspectRatio = aspectRatio });\n\n    public ITweakResize AspectRatio(string aspectRatio)\n    {\n        var a = ResizeParams.AspectRatioOrNull(aspectRatio);\n        return a == null ? this : new(Settings: Settings with { AspectRatio = a.Value });\n    }\n\n    public ITweakResize Quality(double quality)\n    {\n        var q = ResizeParams.QualityOrNull(quality);\n        return q == null ? this : new(Settings: Settings with { Quality = q.Value });\n    }\n\n    public ITweakResize ResizeMode(string resizeMode)\n        => new TweakResize(Settings: Settings with { ResizeMode = resizeMode });\n\n    public ITweakResize ScaleMode(string scaleMode)\n    {\n        var s = ResizeParams.ScaleModeOrNull(scaleMode);\n        return s == null ? this : new(Settings: Settings with { ScaleMode = s });\n    }\n\n    public ITweakResize Format(string format)\n    {\n        var f = ResizeParams.FormatOrNull(format);\n        return f == null ? this : new(Settings: Settings with { Format = f });\n    }\n\n    public ITweakResize Parameters(string parameters)\n    {\n        var p = ResizeParams.ParametersOrNull(parameters);\n        return p == null ? this : new(Settings: Settings with { Parameters = p });\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.Responsive/LightboxHelpers.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Images;\n\ninternal class LightboxHelpers\n{\n    internal const string Attribute = \"data-cms-lightbox\";\n    internal const string AttributeGroup = \"data-cms-lightbox-group\";\n    internal const string SettingsName = \"Lightbox\";\n    internal const string JsCall = \"window.Fancybox.bind()\";\n\n    /// <summary>\n    /// Create the args-list for the lightbox initialization\n    /// </summary>\n    /// <param name=\"imageGroup\">Name of the image group</param>\n    /// <returns></returns>\n    internal static object[] CreateArgs(string? imageGroup)\n    {\n        var hasGroup = imageGroup.HasValue();\n        return\n        [\n            hasGroup\n                ? $\"[{AttributeGroup}=\\\"{imageGroup}\\\"]\"\n                : $\"[{Attribute}=\\\"\\\"]\",\n            new\n            {\n                groupAll = hasGroup,\n                Thumbs = new\n                {\n                    autoStart = false\n                }\n            }\n        ];\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.Responsive/ResponsiveBase.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Html5;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Images.Sys.ResizeSettings;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.Html;\nusing ToSic.Sys.Utils;\nusing static System.StringComparer;\n\nnamespace ToSic.Sxc.Images;\n\n/// <remarks>\n/// Must be public, otherwise it breaks in dynamic use :(\n/// </remarks>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract record ResponsiveBase: HybridHtmlStringLog, IResponsiveImage\n{\n    /// <summary>\n    /// Constructor is internal so 1. it can't be created from outside and 2. it has parameters which are internal.\n    /// </summary>\n    internal ResponsiveBase(ImageService imgService, IPageService pageService, ResponsiveSpecs specs, ILog parentLog, string logName)\n        : base(parentLog, $\"Img.{logName}\")\n    {\n        Specs = specs;\n        PageService = pageService;\n        ImgService = imgService;\n    }\n\n    internal ResponsiveSpecsOfTarget Target => Specs.Target;\n\n    internal ResponsiveSpecs Specs { get; init; }\n    internal ImageService ImgService { get; init; }\n    protected IPageService PageService { get; init; }\n    internal TweakMedia Tweaker => Specs.Tweaker;\n    internal ResizeSettings Settings => Tweaker.ResizeSettings;\n\n    private OneResize ThisResize => _thisResize.Get(() => { \n        var t = ImgService.ImgLinker.ImgResizeSettings(Target.Link.Url, Settings, Target.HasMdOrNull, overrideFramework: ImgService.OverrideCssFramework);\n        Log.A(ImgService.Debug, $\"{nameof(ThisResize)}: \" + t.Dump());\n        return t;\n    })!;\n    private readonly GetOnce<OneResize> _thisResize = new();\n\n\n\n\n    /// <summary>\n    /// ToString must be specified by each implementation\n    /// </summary>\n    /// <returns></returns>\n    protected override string ToHtmlString() => Tag.ToString();\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public virtual Img Img => field ??= GetImg();\n\n    private Img GetImg()\n    {\n        var l = Log.Fn<Img>(enabled: ImgService.Debug);\n        var imgTag = ToSic.Razor.Blade.Tag.Img().Src(Src);\n\n        // Add all kind of attributes if specified\n        var imgSpecs = Tweaker.Img;\n        imgTag = AddAttributes(imgTag, imgSpecs.Attributes);\n        imgTag = AddAttributes(imgTag, ThisResize.Recipe?.Attributes, imgSpecs.Attributes?.Keys);\n\n        // Only add Alt, Class etc. if they were really specified / known\n        if (Alt != null)\n            imgTag = imgTag.Alt(Alt);\n        if (Class != null)\n            imgTag = imgTag.Class(Class);\n        if (TryGetAttribute(imgSpecs.Attributes, Recipe.SpecialPropertyStyle, out var style))\n            imgTag = imgTag.Style(style);\n        if (TryGetAttribute(ThisResize.Recipe?.Attributes, Recipe.SpecialPropertyStyle, out style))\n            imgTag = imgTag.Style(style);\n        if (Width != null)\n            imgTag = imgTag.Width(Width);\n        if (Height != null)\n            imgTag = imgTag.Height(Height);\n\n        // Add lightbox if configured & enabled on the specific image...\n        var enabled = Tweaker.VDec.LightboxIsEnabled\n                      ?? Target.ImgDecoratorOrNull?.LightboxIsEnabled\n                      ?? Target.FieldImgDecoratorOrNull?.LightboxIsEnabled\n                      ?? false;\n\n        if (enabled)\n            imgTag = AddLightbox(\n                imgTag,\n                imageGroup: Tweaker.VDec.LightboxGroup.NullIfNoValue()\n                            ?? Target.ImgDecoratorOrNull?.LightboxGroup.NullIfNoValue()\n                            ?? Target.FieldImgDecoratorOrNull?.LightboxGroup,\n                description: Tweaker.VDec.DescriptionExtended\n                             ?? Target.ImgDecoratorOrNull?.DescriptionExtended\n            );\n\n        // #alwaysOnImg\n        //if (Params.Toolbar as string == \"img\")\n        {\n            var tlb = ToolbarOrNull(/*true*/);\n            if (tlb != null)\n                imgTag = imgTag.Attr(tlb);\n        }\n\n        return l.Return(imgTag);\n    }\n\n\n    /// <summary>\n    /// Mark the image for lightbox use, and possibly give it the attributes like\n    /// - data-title=\"My caption\"\n    /// - data-alt=\"My alt text\"\n    /// - large image\n    /// </summary>\n    /// <param name=\"original\"></param>\n    /// <param name=\"imageGroup\"></param>\n    /// <param name=\"description\"></param>\n    /// <returns></returns>\n    private Img AddLightbox(Img original, string? imageGroup, string? description)\n    {\n        var l = Log.Fn<Img>();\n\n        // Mark image for lightbox use, different html for single image or group\n        var img = imageGroup.HasValue()\n            ? original.Attr(LightboxHelpers.AttributeGroup, imageGroup)\n            : original.Attr(LightboxHelpers.Attribute);\n\n        var lsSettings = ImgService.SettingsInternal(LightboxHelpers.SettingsName);\n        var lsUrl = ImgService.ImgLinker.ImgResizeSettings(Target.Link.Url, settings: lsSettings, Target.HasMdOrNull, overrideFramework: ImgService.OverrideCssFramework).Url;\n        \n        // Add Lightbox caption and src\n        var caption = Alt + description;\n        img = img\n            .Attr(\"data-src\", lsUrl)\n            .Attr(\"data-caption\", caption);\n\n        // 2. Turn on lightbox feature of 2sxc\n        // ...make sure it will also load the activation JS\n        // Note: it would be better to just activate \"lightbox\", but ATM the features don't support finding dependent features from WebResources\n        PageService.Activate(SxcPageFeatures.TurnOn.NameId, /*SxcPageFeatures.Lightbox.NameId,*/ SxcPageFeatures.WebResourceFancybox4.NameId);\n        PageService.TurnOn(LightboxHelpers.JsCall, noDuplicates: true, args: LightboxHelpers.CreateArgs(imageGroup));\n\n        return l.Return(img, \"\");\n    }\n\n    [PrivateApi]\n    protected TImg AddAttributes<TImg>(TImg imgTag, IDictionary<string, object?>? addAttributes, IEnumerable<string>? skip = default) where TImg : Tag<TImg>\n    {\n        var l = Log.Fn<TImg>();\n        if (addAttributes == null || addAttributes.Count == 0)\n            return l.Return(imgTag, \"nothing to add\");\n\n        string[] exclude = [..Recipe.SpecialProperties, ..skip ?? [] ];\n\n        var dic = addAttributes\n            .Where(pair => !exclude.Contains(pair.Key, comparer: InvariantCultureIgnoreCase))\n            .ToDictionary(p => p.Key, p => p.Value);\n        if (dic.Count == 0)\n            return l.Return(imgTag, \"only special props\");\n\n        l.A(ImgService.Debug, \"will add properties from attributes\");\n        foreach (var a in dic)\n            imgTag = imgTag.Attr(a.Key, a.Value);\n\n        return l.Return(imgTag, \"added\");\n    }\n\n\n    public IHtmlTag Tag => _tag.Get(GetOutermostTag)!;\n    private readonly GetOnce<IHtmlTag> _tag = new();\n\n    protected virtual IHtmlTag GetOutermostTag() => Img;\n\n\n    /// <summary>\n    /// Get the toolbar - or null, based on\n    /// - various conditions if toolbars are available\n    /// - the question if it is being retrieved for the IMG tag or not.\n    /// </summary>\n    /// <returns></returns>\n    private IToolbarBuilder? ToolbarOrNull()\n    {\n        // attach edit if we are in edit-mode and the link was generated through a call\n        if (ImgService.EditOrNull?.Enabled != true)\n            return null;\n        if (Target.FieldOrNull?.Parent == null)\n            return null;\n\n        // Check if it's not a demo-entity, in which case editing settings shouldn't happen\n        if (Target.FieldOrNull.Parent.Entity.DisableInlineEditSafe())\n            return null;\n\n        // Get toolbar - if it's null (basically when the ImageService fails) stop here\n        return Toolbar();\n    }\n\n    #region Toolbar\n\n    /// <inheritdoc />\n    // note: it's a method but ATM always returns the cached toolbar\n    // still implemented as a method, so we could add future parameters if necessary\n    public IToolbarBuilder? Toolbar() => _toolbar.Get(() => new ResponsiveToolbarBuilder(Log).Toolbar(ImgService, Target, Tweaker, Settings, Src));\n\n    private readonly GetOnce<IToolbarBuilder?> _toolbar = new();\n\n    #endregion\n\n\n    /// <inheritdoc />\n    public string? Description => _description.Get(() => Target.ImgDecoratorOrNull?.Description);\n    private readonly GetOnce<string?> _description = new();\n\n    /// <inheritdoc />\n    public string? DescriptionExtended => _descriptionDet.Get(() => Target.ImgDecoratorOrNull?.DescriptionExtended);\n    private readonly GetOnce<string?> _descriptionDet = new();\n\n    /// <inheritdoc />\n    public string? Alt => _alt.Get(() =>\n        // If alt is specified, it takes precedence - even if it's an empty string, because there must have been a reason for this\n        Tweaker.Img.Alt\n        // If we take the image description, empty does NOT take precedence, it will be treated as not-set\n        ?? Description.NullIfNoValue()\n        // If all else fails, take the fallback specified in the call - IF it's allowed\n        ?? (Target.ImgDecoratorOrNull?.SkipFallbackTitle ?? false ? null : Tweaker.Img.AltFallback)\n    );\n    private readonly GetOnce<string?> _alt = new();\n\n\n    /// <inheritdoc />\n    public string? Class => _imgClass.Get(() => StyleOrClassGenerator(Tweaker.Img.Class, Recipe.SpecialPropertyClass));\n    private readonly GetOnce<string?> _imgClass = new();\n\n    private string? StyleOrClassGenerator(string? codePart, string key)\n    {\n        var l = (ImgService.Debug ? Log : null).Fn<string?>();\n        var hasOnImgClass = codePart.HasValue();\n        var hasOnAttrs = TryGetAttribute(ThisResize.Recipe?.Attributes, key, out var attrValue);\n\n        return hasOnImgClass switch\n        {\n            // Must use null if neither are useful\n            false when !hasOnAttrs => l.ReturnNull(\"null/nothing\"),\n            true when hasOnAttrs => l.Return($\"{codePart} {attrValue}\", \"both\"),\n            true => l.Return(codePart, \"code only\"),\n            _ => l.Return(attrValue, \"attr only\")\n        };\n    }\n\n    [PrivateApi]\n    protected bool TryGetAttribute(IDictionary<string, object?>? attribs, string key, out string? value)\n    {\n        if (attribs == null)\n        {\n            value = null;\n            return false;\n        }\n        var found = attribs.TryGetValue(key, out var attrValue);\n        value = attrValue?.ToString();\n        return found && value.HasValue();\n    }\n\n\n    /// <inheritdoc />\n    public bool ShowAll => ThisResize.ShowAll;\n\n    /// <inheritdoc />\n    public string? SrcSet => _srcSet.Get(SrcSetGenerator);\n    private readonly GetOnce<string?> _srcSet = new();\n    private string? SrcSetGenerator()\n    {\n        var isEnabled = ImgService.Features.IsEnabled(SxcFeatures.ImageServiceMultipleSizes.NameId);\n        var hasVariants = (ThisResize?.Recipe?.Variants).HasValue();\n        var l = (ImgService.Debug ? Log : null).Fn<string?>($\"{nameof(isEnabled)}: {isEnabled}, {nameof(hasVariants)}: {hasVariants}\");\n        return isEnabled && hasVariants\n            ? l.Return(ImgService.ImgLinker.SrcSet(Target.Link.Url!, Settings, SrcSetType.Img,\n                Target.HasMdOrNull, overrideFramework: ImgService.OverrideCssFramework))\n            : l.ReturnNull();\n    }\n\n\n\n    /// <inheritdoc />\n    public string? Width => _width.Get(() => UseIfActive(ThisResize.Recipe?.SetWidth, ThisResize.Width));\n    private readonly GetOnce<string?> _width = new();\n\n    /// <inheritdoc />\n    public string? Height => _height.Get(() => UseIfActive(ThisResize.Recipe?.SetHeight, ThisResize.Height));\n    private readonly GetOnce<string?> _height = new();\n\n    /// <inheritdoc />\n    public string? Sizes => _sizes.Get(() => UseIfActive(ImgService.Features.IsEnabled(SxcFeatures.ImageServiceSetSizes.NameId), ThisResize.Recipe?.Sizes));\n    private readonly GetOnce<string?> _sizes = new();\n\n    private string? UseIfActive<T>(bool? active, T value, [CallerMemberName] string? name = default)\n    {\n        var l = (ImgService.Debug ? Log : null).Fn<string>($\"{name}: active: {active}; value: {value}\");\n        return active == true && value.IsNotDefault()\n            ? l.ReturnAndLog($\"{value}\")\n            : l.ReturnNull(\"disabled\");\n    }\n\n\n    /// <inheritdoc />\n    public string Src => ThisResize.Url ?? \"\";\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.Responsive/ResponsiveImage.cs",
    "content": "﻿using ToSic.Razor.Html5;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Images;\n\n/// <remarks>\n/// Must be public, otherwise it breaks in dynamic use :(\n/// </remarks>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record ResponsiveImage: ResponsiveBase\n{\n    [PrivateApi(\"don't show\")]\n    internal ResponsiveImage(ImageService imgService, IPageService pageService, ResponsiveSpecs specs, ILog parentLog)\n        : base(imgService, pageService, specs, parentLog, \"Img\")\n    { }\n\n    /// <summary>\n    /// Same as base / initial implementation, but add srcset if available\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public override Img Img => field ??= GenerateImg();\n\n    private Img GenerateImg()\n    {\n        var img = base.Img;\n        if (!string.IsNullOrEmpty(SrcSet))\n            img = img.Srcset(SrcSet);\n        if (!string.IsNullOrEmpty(Sizes))\n            img = img.Sizes(Sizes);\n        return img;\n    }\n\n    /// <summary>\n    /// Necessary so it also works with ToString() otherwise the record will show the JSON.\n    /// </summary>\n    public override string ToString() => ToHtmlString();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.Responsive/ResponsivePicture.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Razor.Html5;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Images.Sys.ResizeSettings;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Images;\n\n/// <remarks>\n/// Must be public, otherwise it breaks in dynamic use :(\n/// </remarks>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record ResponsivePicture: ResponsiveBase, IResponsivePicture\n{\n    internal ResponsivePicture(ImageService imgService, IPageService pageService, ResponsiveSpecs specs, ILog parentLog)\n        : base(imgService, pageService, specs, parentLog, \"Picture\")\n    { }\n\n    [field: AllowNull, MaybeNull]\n    public Picture Picture => field ??= GeneratePicture();\n\n    private Picture GeneratePicture()\n    {\n        var pic = ToSic.Razor.Blade.Tag.Picture(Sources, Img);\n        var picSpecs = Tweaker.Pic;\n        pic = AddAttributes(pic, picSpecs.Attributes);\n        if (Tweaker.Pic.Class.HasValue())\n            pic = pic.Class(Tweaker.Pic.Class);\n        if (TryGetAttribute(picSpecs.Attributes, Recipe.SpecialPropertyStyle, out var style))\n            pic = pic.Style(style);\n        return pic;\n    }\n\n    /// <summary>\n    /// Necessary so it also works with ToString() otherwise the record will show the JSON.\n    /// </summary>\n    public override string ToString() => ToHtmlString();\n\n    protected override IHtmlTag GetOutermostTag() => Picture;\n\n    [field: AllowNull, MaybeNull]\n    public TagList Sources => field ??= SourceTagsInternal(Target.Link.Url, Settings);\n\n    private TagList SourceTagsInternal(string? url, IResizeSettings resizeSettings)\n    {\n        var logOrNull = ImgService.Debug ? Log : null;\n        var l = logOrNull.Fn<TagList>();\n        // Check formats\n        var defFormat = ImgService.GetFormat(url);\n\n        // Determine if we have many formats, otherwise just use the current one\n        var formats = defFormat.ResizeFormats.Any()\n            ? defFormat.ResizeFormats\n            : [defFormat];\n            \n        var useMultiSrcSet = ImgService.Features.IsEnabled(SxcFeatures.ImageServiceMultipleSizes.NameId);\n\n        l.A($\"{nameof(formats)}: {formats.Count}, {nameof(useMultiSrcSet)}: {useMultiSrcSet}\");\n\n        // Generate Meta Tags\n        var sources = formats\n            .Select(resizeFormat =>\n            {\n                // We must copy the settings, because we change them and this shouldn't affect anything else\n                var formatSettings = new ResizeSettings(resizeSettings, format: resizeFormat != defFormat ? resizeFormat.Format : null);\n                var srcSet = useMultiSrcSet\n                    ? ImgService.ImgLinker.SrcSet(url, formatSettings, SrcSetType.Source, Target.HasMdOrNull, overrideFramework: ImgService.OverrideCssFramework)\n                    : ImgService.ImgLinker.ImgResizeSettings(url, formatSettings, Target.HasMdOrNull, overrideFramework: ImgService.OverrideCssFramework).Url;\n                var source = ToSic.Razor.Blade.Tag.Source().Type(resizeFormat.MimeType).Srcset(srcSet);\n                if (!string.IsNullOrEmpty(Sizes)) source.Sizes(Sizes);\n                return source;\n            });\n        var result = ToSic.Razor.Blade.Tag.TagList(sources);\n        return l.Return(result, $\"{result.Count()}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.Responsive/ResponsiveSpecs.cs",
    "content": "﻿using ToSic.Eav.Metadata;\n\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Field;\nusing ToSic.Sxc.Data.Sys.Fields;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Images;\n\n/// <summary>\n/// Helper class to handle all kinds of parameters passed to a responsive tag\n/// </summary>\n[PrivateApi]\ninternal record ResponsiveSpecs(ResponsiveSpecsOfTarget Target, TweakMedia Tweaker);\n\n/// <summary>\n/// Initial specs of a specific target - typically a field,\n/// extracted / prepared for responsive image processing.\n/// </summary>\n/// <param name=\"FieldOrNull\">The field used for this responsive output - can be null!</param>\n/// <param name=\"HasMdOrNull\"></param>\n/// <param name=\"ImgDecoratorOrNull\">Image Decorator of the current image.</param>\n/// <param name=\"Link\">The only reliable object which knows about the url. Never null.</param>\n/// <param name=\"FieldImgDecoratorOrNull\"></param>\ninternal record ResponsiveSpecsOfTarget(\n    IField? FieldOrNull,\n    IHasMetadata? HasMdOrNull,\n    ImageDecorator? ImgDecoratorOrNull,\n    IHasLink Link,\n    ImageDecorator? FieldImgDecoratorOrNull\n)\n{\n    internal string? ResizeSettingsOrNull()\n        => ImgDecoratorOrNull?.ResizeSettings?.NullIfNoValue()\n           ?? FieldImgDecoratorOrNull?.ResizeSettings?.NullIfNoValue();\n\n    internal static ResponsiveSpecsOfTarget ExtractSpecs(object? target)\n    {\n        // Handle null and already-typed scenarios\n        switch (target)\n        {\n            case null:\n                return new(null, null, null, new HasLink(\"\"), null);\n            case ResponsiveSpecsOfTarget already:\n                return already;\n        }\n\n        // Figure out what field it's from - either because it's a hyperlink - or an image inside a WYSIWYG field\n        var field = target as IField\n                    ?? (target as IFromField)?.Field;\n\n        // The main Metadata provider is either the target itself, or the field holding it (can be null)\n        var mdProvider = target as IHasMetadata\n                         ?? field;\n\n        // The primary decorator - either of the field (e.g. Hyperlink-field with recommendations etc.)\n        // or using the metadata-provider of the target\n        var imgDecorator = (field as Field)?.ImageDecoratorOrNull\n                           ?? ImageDecorator.GetOrNull(mdProvider, []);\n\n        // get the image decorator of the field of the content-type - e.g. the WYSIWYG field or Hyperlink field\n        // Note: Parent / Type should never be null, except when the data is being mocked.\n        var inputImgDecorator = ImageDecorator.GetOrNull(field?.Parent?.Type?[field.Name], []);\n\n        // figure out the link - either because it's already an IHasLink object, or it's possibly a string (or null-link)\n        var link = target as IHasLink\n                   ?? new HasLink(target as string ?? \"\");\n\n        return new(field, mdProvider, imgDecorator, link, inputImgDecorator);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Images/Sys.Responsive/ResponsiveToolbarBuilder.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Sxc.Adam.Sys.Security;\nusing ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Edit.Toolbar.Sys;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Images.Sys.ResizeSettings;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Images;\n\ninternal class ResponsiveToolbarBuilder(ILog parentLog) : HelperBase(parentLog, $\"{SxcLogName}.ImgTlb\")\n{\n    // note: it's a method but ATM always returns the cached toolbar\n    // still implemented as a method, so we could add future parameters if necessary\n    public IToolbarBuilder? Toolbar(ImageService imgService, ResponsiveSpecsOfTarget target, TweakMedia tweaker, ResizeSettings? settings, string src)\n    {\n        var l = Log.Fn<IToolbarBuilder?>();\n        switch (tweaker.ToolbarObj)\n        {\n            case false:\n                return l.ReturnNull(\"false\");\n            case IToolbarBuilder customToolbar:\n                return l.Return(customToolbar, \"already set\");\n        }\n\n        // If we're creating an image for a string value, it won't have a field or parent.\n        if (target.FieldOrNull?.Parent == null)\n            return l.ReturnNull(\"no field\");\n\n        // If the HasMd is null, or the Metadata is null (e.g. image from another website)\n        if (target.HasMdOrNull?.Metadata == null)\n            return l.ReturnNull(\"no metadata\");\n\n        // Determine if this is an \"own\" adam file, because only field-owned files should allow config\n        var isInSameEntity = AdamSecurity.PathIsInItemAdam(target.FieldOrNull.Parent.Guid, \"\", src);\n\n        // Construct the toolbar; in edge cases the toolbar service could be missing\n        var imgTlb = imgService.ToolbarOrNull?.Empty().Settings(\n            hover: \"right-middle\",\n            // Delay show of toolbar if it's a shared image, as it shouldn't be used much\n            ui: isInSameEntity ? null : \"delayShow=1000\"\n        );\n\n        // Try to add the metadata button (or just null if not available)\n        imgTlb = imgTlb?.Metadata(target.HasMdOrNull,\n            tweak: t =>\n            {\n                // Add note only for the ImageDecorator Metadata, not for other buttons\n                // Note: Using experimental AddNamed feature which doesn't exist on the ITweakButton interface\n                var modified = t.AddNamed(ImageDecorator.TypeNameId, btn =>\n                {\n                    // add label like \"Image Settings and Cropping\" - i18n\n                    btn = btn.Tooltip($\"{ToolbarConstants.ToolbarLabelPrefix}MetadataImage\");\n\n                    // Check if we have special resize metadata\n                    var md = target.HasMdOrNull.Metadata\n                        .First(typeName: ImageDecorator.NiceTypeName)\n                        .NullOrGetWith(imgDeco => new ImageDecorator(imgDeco, []));\n\n                    // Try to add note\n                    var note = settings?.ToHtmlInfo(md);\n                    if (note.HasValue())\n                        btn = btn.Note(note, format: \"html\", background: \"#DFC2F2\", delay: 1000);\n\n                    // if image is from elsewhere, show warning\n                    btn = isInSameEntity\n                        ? btn\n                        : btn.FormParameters(ImageDecorator.ShowWarningGlobalFile, true);\n                    return btn;\n                });\n\n                // Add note for Copyright - if there is Metadata for that\n                target.HasMdOrNull.Metadata.FirstModel<CopyrightDecorator>()\n                    .DoIfNotNull(copyright => modified = modified.AddNamed(\n                        CopyrightDecorator.ContentTypeNameId,\n                        btn => btn\n                            .Tooltip(\"Copyright\")\n                            .Note(copyright.CopyrightMessage.NullIfNoValue() ??\n                                  copyright.Copyrights?.FirstOrDefault()?.GetBestTitle() ?? \"\"\n                            )\n                    ));\n\n\n                return modified;\n            });\n\n        return l.ReturnAsOk(imgTlb);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/Properties/AssemblyInternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Services\")]\n\n\n// Unit tests\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.SystemTests\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/StartupSxcImages.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Images.Sys.Metadata;\nusing ToSic.Sxc.Images.Sys.ResizeSettings;\nusing ToSic.Sxc.Services;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcImages\n{\n    public static IServiceCollection AddSxcImages(this IServiceCollection services)\n    {\n        // new in v12.02/12.04 Image Link Resize Helper\n        services.TryAddTransient<ImgResizeLinker>();\n        services.TryAddTransient<IImageService, ImageService>();\n        services.TryAddTransient<ResizeDimensionGenerator>();\n\n        // New v20 ImageMetadataRecommendation\n        services.TryAddTransient<IImageMetadataRecommendationsService, ImageMetadataRecommendationsService>();\n\n        return services;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/ToSic.Sxc.Images.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Images</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Edit\\ToSic.Sxc.Edit.csproj\" />\n  </ItemGroup>\n\n  <!-- Include Connect.Koi -->\n  <ItemGroup>\n    <Reference Include=\"Connect.Koi\">\n      <HintPath>..\\..\\..\\Dependencies\\Koi\\netstandard2.0\\Connect.Koi.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Images/ToSic.Sxc.Images.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Cimageservice/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Cinternal_005Cimageflowrewrite/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Cresizesettings/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Cresponsive/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Csys_002Eimageflowrewrite/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Csys_002Eimageservice/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Csys_002Eresizesettings/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Csys_002Eresponsive/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Csys_005Cimageflowrewrite/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Csys_005Cimageservice/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=images_005Csys_005Csys_002Eimageflowrewrite/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Properties/SxcLightSpeedAssemblyVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.WebApi\")]\n\n// Tests\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.SystemTests\")]"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/StartupSxcLightSpeed.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcLightSpeed\n{\n    public static IServiceCollection AddSxcLightSpeed(this IServiceCollection services)\n    {\n        // v13 LightSpeed\n        services.TryAddTransient<IOutputCache, LightSpeed>();\n        services.TryAddTransient<OutputCacheManager>();\n        services.TryAddTransient<LightSpeedStats>();\n\n        return services;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/ToSic.Sxc.LightSpeed.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.LightSpeed</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n  </ItemGroup>\n\n\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net472'\">\n    <Reference Include=\"System.Runtime.Caching\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <PackageReference Include=\"System.Runtime.Caching\" Version=\"9.0.0\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/ToSic.Sxc.LightSpeed.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=web_002Esys_002Elightspeed_005Crazorpartial/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/IOutputCache.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Render.Sys;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOutputCache: IHasLog\n{\n    bool IsEnabled { get; }\n\n    IOutputCache Init(int moduleId, int pageId, IBlock block);\n\n    OutputCacheItem? Existing { get; }\n\n    bool Save(IRenderResult data);\n\n    // #RemovedV20 #OldDnnAutoJQuery\n    //#if NETFRAMEWORK\n    //    bool Save(IRenderResult data, bool enforcePre1025);\n    //#endif\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/LightSpeed.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Services.Cache;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Sys.Configuration.SxcFeatures;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class LightSpeed(\n    ISysFeaturesService features,\n    LazySvc<ISite> site,\n    LazySvc<OutputCacheManager> outputCacheManager,\n    LazySvc<INamedCacheDependencyService> namedDependencies\n) : ServiceBase(SxcLogName + \".Lights\", connect: [features, outputCacheManager, namedDependencies]), IOutputCache\n{\n    [field: AllowNull, MaybeNull]\n    private LightSpeedConfigHelper LsConfigHelper => field ??= new(Log);\n\n    public IOutputCache Init(int moduleId, int pageId, IBlock block)\n    {\n        var l = Log.Fn<IOutputCache>($\"mod: {moduleId}\");\n        _moduleId = moduleId;\n        _pageId = pageId;\n        _block = block;\n        bool isEnabled;\n        try\n        {\n            isEnabled = IsEnabled;\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return(this, \"exception during init\");\n        }\n        return l.Return(this, $\"{isEnabled}\");\n    }\n    private int _moduleId;\n    private int _pageId;\n    private IBlock? _block;\n    private IAppReader? AppReaderOrNull => field ??= _block?.Context?.AppReaderOrNull;\n\n    public bool Save(IRenderResult data) => AddToLightSpeed(data);\n\n    // #RemovedV20 #OldDnnAutoJQuery\n    //#if NETFRAMEWORK\n    //    public bool Save(IRenderResult data, bool enforcePre1025)\n    //        => AddToLightSpeed(data, cacheData => cacheData.EnforcePre1025 = enforcePre1025);\n    //#endif\n\n    // #RemovedV20 #OldDnnAutoJQuery\n    public bool AddToLightSpeed(IRenderResult? data/*, Action<OutputCacheItem>? doOtherStuff = null*/)\n    {\n        var l = Log.Fn<bool>(timer: true);\n\n        // Check many exit-early clauses\n        try\n        {\n            if (!IsEnabled) return l.ReturnFalse(\"disabled\");\n            if (data == null) return l.ReturnFalse(\"null\");\n            if (data.IsError) return l.ReturnFalse(\"error\");\n            if (!data.CanCache) return l.ReturnFalse(\"can't cache\");\n            if (data.OutputCacheSettings?.IsEnabled == false)\n                return l.ReturnFalse(\"disabled in settings from code\"); // new v19.03.03\n            if (data == Existing?.Data) return l.ReturnFalse(\"not new\");\n            if (data.DependentApps.SafeNone()) return l.ReturnFalse(\"app not initialized\");\n            if (!UrlParams.CachingAllowed) return l.ReturnFalse(\"url params not allowed\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnFalse(\"exception during exit-early clauses\");\n        }\n\n        // Figure out dependent apps\n        try\n        {\n            l.A($\"{nameof(data.DependentApps)} count {data.DependentApps.Count}\");\n\n            // when dependent apps have disabled caching, parent app should not cache also\n            if (!IsEnabledOnDependentApps(data.DependentApps))\n                return l.ReturnFalse(\"disabled in dependent app\");\n\n            // respect primary app (of site) as dependent app to ensure cache invalidation when primary app is changed\n            if (AppReaderOrNull == null)\n                return l.ReturnFalse(\"no app\");\n\n            l.A($\"Found {data.DependentApps.Count} apps: \" +\n                string.Join(\",\", data.DependentApps.Select(da => da.AppId)));\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnFalse(\"exception during dependent apps\");\n        }\n\n        // Add to cache\n        try\n        {\n            var cacheItem = new OutputCacheItem(LightSpeedDataCompression.OptimizeForCache(\n                data,\n                useCompression: features.IsEnabled(LightSpeedOutputCacheCompression.NameId)\n            ));\n            // #RemovedV20 #OldDnnAutoJQuery\n            //doOtherStuff?.Invoke(cacheItem);\n\n            var duration = Duration;\n            // only add if we really have a duration; -1 is disabled, 0 is not set...\n            if (duration <= 0)\n                return l.ReturnFalse($\"not added as duration is {duration}\");\n\n            var appPathsToMonitor = features.IsEnabled(LightSpeedOutputCacheAppFileChanges.NameId)\n                ? data.DependentApps.SelectMany(da => da.PathsToMonitor).ToList()\n                : null;\n            l.A($\"{nameof(appPathsToMonitor)} done\");\n\n            // The returned list always includes the app-wide output-cache marker and may also include\n            // named external dependency keys declared through Kit.OutputCache.DependOn(...).\n            var externalCacheKeys = NamedDependencies.GetOrEnsureKeys(\n                CacheDependencyScopes.OutputCache,\n                AppReaderOrNull.AppId,\n                data.OutputCacheSettings?.ExternalDependencyKeys\n            );\n            l.A($\"{nameof(externalCacheKeys)} done\");\n\n            // add to cache and log\n            string? cacheKey = null;\n            l.Do(message: \"outputCacheManager add\", timer: true,\n                action: () => cacheKey = OutCacheMan.Add(\n                    CacheKey,\n                    cacheItem,\n                    duration,\n                    data.DependentApps.SelectMany(r => r.CacheKeys).ToList(),\n                    externalCacheKeys,\n                    appPathsToMonitor\n                )\n            );\n\n            return l.ReturnTrue($\"added for {duration}s; cache key: '{cacheKey}'\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnFalse(\"exception during add to cache\");\n        }\n    }\n\n    /// <summary>\n    /// find if caching is enabled on all dependent apps\n    /// </summary>\n    private bool IsEnabledOnDependentApps(List<IDependentApp> dependentApps)\n    {\n        var l = Log.Fn<bool>(timer: true);\n        var appWhereNotEnabled = dependentApps\n            .FirstOrDefault(dependentApp => !dependentApp.IsEnabled);\n\n        return appWhereNotEnabled != null\n            ? l.ReturnFalse($\"Can't cache; caching disabled on dependent app {appWhereNotEnabled.AppId}\")\n            : l.ReturnTrue(\"ok\");\n    }\n\n    private int Duration => _duration ??= _block!.Context.User switch\n    {\n        { IsSystemAdmin: true } => AppConfig.DurationSystemAdmin,\n        { IsSiteAdmin: true } => AppConfig.DurationEditors,\n        { IsAnonymous: false } => AppConfig.DurationUsers,\n        _ => AppConfig.Duration\n    };\n    private int? _duration;\n\n    private (bool CachingAllowed, string Extension) UrlParams => _urlParams.Get(() =>\n        LightSpeedUrlParams.GetUrlParams(ViewConfigOrNull ?? AppConfig, _block?.Context.Page.Parameters, Log)\n    );\n    private readonly GetOnce<(bool CachingAllowed, string Extension)> _urlParams = new();\n\n    private string CurrentCulture => _currentCulture.Get(() => site.Value.SafeCurrentCultureCode())!;\n    private readonly GetOnce<string> _currentCulture = new();\n\n\n    private string CacheKey => _key.Get(() => Log.Quick(()\n        => OutputCacheKeys.ModuleKey(_pageId, _moduleId, UserIdOrAnon, ViewKey, UrlParams.Extension, CurrentCulture)\n    ))!;\n    private readonly GetOnce<string> _key = new();\n\n    private int? UserIdOrAnon => _userId.Get(() => _block?.Context.User.IsAnonymous == false ? _block.Context.User.Id : null);\n    private readonly GetOnce<int?> _userId = new();\n\n    // Note 2023-10-30 2dm changed the handling of the preview template and checks if it's set. In case caching is too aggressive this can be the problem. Remove early 2024\n    private string? ViewKey => _viewKey.Get(() => _block is { ConfigurationIsReady: true, Configuration.PreviewViewEntity: not null }\n        ? $\"{_block.Configuration.AppId}:{_block.Configuration.View?.Id}\"\n        : null\n    );\n    private readonly GetOnce<string?> _viewKey = new();\n\n    public OutputCacheItem? Existing => _existing.Get(GetExisting);\n    private readonly GetOnce<OutputCacheItem?> _existing = new();\n\n    private OutputCacheItem? GetExisting()\n    {\n        var l = Log.Fn<OutputCacheItem>();\n        try\n        {\n            // If App not known, it can't have a cache - exit early\n            if (AppReaderOrNull == null)\n                return l.ReturnNull(\"no app\");\n\n            // If Cache is enabled, try to get\n            var result = IsEnabled\n                ? OutCacheMan.Get(CacheKey)\n                : null;\n\n            // Not found, exit\n            if (result == null)\n                return l.ReturnNull(\"not in cache\");\n\n            // This is a bit unclear - it seems that only if dependent apps are registered, will the cache be treated as valid...?\n            // compare cache time-stamps\n            var dependentApp = result.DependentApps?.FirstOrDefault();\n            return dependentApp == null\n                ? l.ReturnNull(\"no dep app\")\n                : l.Return(result, \"found\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnNull(\"error\");\n        }\n    }\n\n\n    public bool IsEnabled => _enabled.Get(GetLightSpeedIsEnabled);\n    private readonly GetOnce<bool> _enabled = new();\n\n    private bool GetLightSpeedIsEnabled()\n    {\n        var l = Log.Fn<bool>();\n\n        //// No real app yet, probably module was just added\n        //if (_block.App == null)\n        //    return false;\n\n        // This is called from outside, so we need to catch all exceptions as it should never break in production\n        try\n        {\n            // special - Oqtane seems to call this much earlier than Dnn, even on non-existing modules.\n            // so on new modules this would fail and throw an error. So we'll just return false in this case.\n            if (AppReaderOrNull == null)\n                return l.ReturnFalse(\"disabled, no app\");\n\n            // Normal check.\n            l.A(\"before features check\");\n            var feat = features.IsEnabled(LightSpeedOutputCache.NameId);\n            l.A($\"features: {feat}\");\n            if (!feat)\n                return l.ReturnFalse(\"disabled, feature\");\n\n            var appMaybeEnabled = AppConfig.IsEnabledNullable;\n            l.A(\"before app config deny check\");\n            if (appMaybeEnabled == false)\n                return l.ReturnFalse(\"disabled, app explicit\");\n\n            var viewMaybeEnabled = ViewConfigOrNull?.IsEnabledNullable;\n            l.A(\"before view config deny check\");\n            if (viewMaybeEnabled == false)\n                return l.ReturnFalse(\"disabled, view explicit\");\n\n            l.A(\"before view/app is enabled check - either should be true\");\n            if (appMaybeEnabled != true && viewMaybeEnabled != true)\n                return l.ReturnFalse($\"disabled, neither app '{appMaybeEnabled}' nor view '{viewMaybeEnabled}' enabled\");\n\n            l.A(\"before url params check\");\n            if (!UrlParams.CachingAllowed)\n                return l.ReturnFalse(\"disabled, url params not allowed\");\n\n            l.A(\"all done\");\n            return l.ReturnTrue(\"enabled\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnFalse(\"exception\");\n        }\n    }\n\n    /// <summary>\n    /// Lightspeed Configuration at App Level\n    /// </summary>\n    private LightSpeedDecorator AppConfig => _lsd.Get(() => LsConfigHelper.GetLightSpeedConfigOfApp(AppReaderOrNull))!;\n    private readonly GetOnce<LightSpeedDecorator> _lsd = new();\n\n    /// <summary>\n    /// Lightspeed Configuration at View Level\n    /// </summary>\n    private LightSpeedDecorator? ViewConfigOrNull => _viewConfig.Get(() => LsConfigHelper.ViewConfigOrNull(_block));\n    private readonly GetOnce<LightSpeedDecorator?> _viewConfig = new();\n\n    private OutputCacheManager OutCacheMan => outputCacheManager.Value;\n    private INamedCacheDependencyService NamedDependencies => namedDependencies.Value;\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/LightSpeedDataCompression.cs",
    "content": "using ToSic.Sxc.Render.Sys;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\ninternal static class LightSpeedDataCompression\n{\n    internal static IRenderResult OptimizeForCache(IRenderResult data, bool useCompression, int minBytes = RenderResultHtmlCompression.DefaultMinBytes)\n    {\n        if (!useCompression || data is not RenderResult renderResult)\n            return data;\n\n        if (renderResult.Html is not { Length: > 0 } html)\n            return data;\n\n        // Use UTF-8 byte count because compression operates on the encoded payload, not the .NET string length.\n        var originalHtmlUtf8Bytes = RenderResultHtmlCompression.GetUtf8ByteCount(html);\n        if (originalHtmlUtf8Bytes < minBytes)\n            return data;\n\n        var compressedHtml = RenderResultHtmlCompression.Compress(html);\n        if (compressedHtml.Length >= originalHtmlUtf8Bytes)\n            return data;\n\n        return renderResult with\n        {\n            Html = null,\n            CompressedHtml = compressedHtml,\n            CompressedTrueSize = originalHtmlUtf8Bytes,\n        };\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/LightSpeedStats.cs",
    "content": "﻿using System.Runtime.Caching;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Memory;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\n/// <summary>\n/// Statistics for LightSpeed\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LightSpeedStats(MemoryCacheService memoryCacheService) : ServiceBase(SxcLogName + \".LightSpeedStats\", connect: [memoryCacheService])\n{\n    private MemorySizeEstimator Estimator => field ??= new(Log);\n\n    private static string[] CacheKeyPrefixes =>\n    [\n        OutputCacheKeys.GlobalCacheKeyModuleRoot,\n        OutputCacheKeys.GlobalCacheKeyPartialRoot\n    ];\n\n    public Dictionary<int, LightSpeedStat> GetStats()\n    {\n        var all = MemoryCache.Default\n            .Where(pair => CacheKeyPrefixes.Any(prefix => pair.Key.StartsWith(prefix)))\n            .Select(pair => (pair.Value as OutputCacheItem)!)\n            .Where(p => p != null!)\n            .ToList();\n\n        var allStats = all\n            .GroupBy(i => i.AppId)\n            .ToDictionary(\n                g => g.Key,\n                g =>\n                {\n                    var stats = Estimator.EstimateMany(g.ToArray<object>());\n                    var compressed = g.Where(i => (i?.Data as IOptimizeMemory)?.UseCompression == true);\n                    var compressedStats = Estimator.EstimateMany(compressed.ToArray<object>());\n\n                    return new LightSpeedStat(\n                        g.Count(),\n                        stats.Total,\n                        compressedStats.Total,\n                        stats.Total - compressedStats.Total,\n                        compressedStats.Expanded,\n                        stats.Total - compressedStats.Total + compressedStats.Expanded\n                    );\n                });\n\n        return allStats;\n    }\n\n}\n\npublic record LightSpeedStat(int Count, long MemoryUse, long Compressed, long Uncompressed, long Expanded, long GrandTotal);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/LightSpeedUrlParams.cs",
    "content": "﻿using ToSic.Sxc.Configuration.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sys.Caching.PiggyBack;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\ninternal class LightSpeedUrlParams\n{\n    internal static (bool CachingAllowed, string Extension) GetUrlParams(LightSpeedDecorator? lsConfig, IParameters? pageParameters, ILog log, bool usePiggyBack = true)\n    {\n        var l = log.Fn<(bool, string)>();\n\n        // Preflight exit checks\n        if (lsConfig == null)\n            return l.Return((false, \"\"), \"no config\");\n        if (lsConfig.IsEnabledNullable == false)\n            return l.Return((false, \"\"), \"Disabled at view level\");\n        if (!lsConfig.ByUrlParameters)\n            return l.Return((true, \"\"), \"Enabled without url parameters\");\n        if (pageParameters == null)\n            return l.Return((false, \"\"), \"No page parameters / context, probably an error, certainly don't cache.\");\n\n        // Get the parameter names from the config - use piggyback if possible\n        var namesCsv = usePiggyBack && (lsConfig as ICanBeEntity)?.Entity is IHasPiggyBack withCache\n            ? withCache.GetPiggyBack(nameof(LightSpeedUrlParams), () => ExtractConfigCsv(lsConfig))\n            : ExtractConfigCsv(lsConfig);\n\n        var result = ParseParameters(lsConfig, namesCsv, pageParameters, log);\n        return l.Return(result);\n    }\n\n    private static (bool CachingAllowed, string Extension) ParseParameters(LightSpeedDecorator lsConfig, string namesCsv, IParameters pageParameters, ILog log)\n    {\n        var l = log.Fn<(bool, string)>();\n\n        if (pageParameters == null! /* paranoid */)\n            return l.Return((false, \"\"), \"No page parameters / context, probably an error, certainly don't cache.\");\n\n        if (namesCsv.Length == 0)\n        {\n            // No names given, so we must check if there were parameters which would trigger no-cache\n            if (pageParameters.Count == 0)\n                return l.Return((true, \"\"), \"Enabled since no UrlParams to respect\");\n\n            if (lsConfig.UrlParametersOthersDisableCache)\n                return l.Return((false, \"\"), \"Disabled because View has no UrlParams, so none are respected\");\n        }\n        else\n        {\n            l.A($\"View UrlParams: '{namesCsv}'\");\n            if (namesCsv == \"*\")\n                l.A(\"All url parameters allowed - this is probably a bad idea!\");\n            else\n            {\n                var before = pageParameters;\n                pageParameters = pageParameters.Filter(namesCsv);\n                if (pageParameters.Count != before.Count && lsConfig.UrlParametersOthersDisableCache)\n                    return l.Return((false, \"\"),\n                        $\"Disabled because View has UrlParams, but others are not allowed. Original: {before}\");\n            }\n        }\n\n        // Finalize URL parameters\n        var urlParams = pageParameters.ToString(sort: true);\n        if (string.IsNullOrWhiteSpace(urlParams))\n            return l.Return((true, \"\"), \"no url params found\");\n\n        return lsConfig.UrlParametersCaseSensitive\n            ? l.ReturnAndLog((true, urlParams), \"case sensitive\")\n            : l.ReturnAndLog((true, urlParams.ToLowerInvariant()), \"case insensitive\");\n    }\n\n    private static string ExtractConfigCsv(LightSpeedDecorator lsConfig)\n    {\n        var paramNames = ConfigStringHelpers.ConfigPairs(lsConfig.UrlParameterNames);\n\n        // Get the params, filter them new v17.10 and return the string - or exit\n        var namesCsv = string.Join(\",\", paramNames.Select(p => p.Key)).Trim();\n        return namesCsv;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/OutputCacheItem.cs",
    "content": "using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Memory;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OutputCacheItem(IRenderResult data) : ICanEstimateSize, ITimestamped\n{\n    public IRenderResult Data { get; } = data;\n\n    public int AppId => Data.AppId;\n\n    public List<IDependentApp>? DependentApps => Data.DependentApps;\n\n//#if NETFRAMEWORK\n//    /// <summary>\n//    /// This is only used in Dnn - might be solved with generics some time, but ATM this is just simpler\n//    /// </summary>\n//    public bool EnforcePre1025 = true;\n\n//#endif\n    public SizeEstimate EstimateSize(ILog? log = default)\n                => (Data as ICanEstimateSize)?.EstimateSize(log)\n                    ?? new SizeEstimate(0, 0, IsUnknown: true);\n\n    /// <summary>\n    /// Timestamp info to better analyze cache data\n    /// </summary>\n    long ITimestamped.CacheTimestamp { get; } = DateTime.Now.Ticks;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/OutputCacheKeys.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.LightSpeed;\npublic class OutputCacheKeys\n{\n    internal const string GlobalCacheKeyModuleRoot = \"Sxc-LightSpeed.Module.\";\n    internal const string GlobalCacheKeyPartialRoot = \"Sxc-LightSpeed.Partial.\";\n\n    /// <summary>\n    /// Determine the cache key for module data.\n    /// </summary>\n    /// <param name=\"pageId\"></param>\n    /// <param name=\"moduleId\"></param>\n    /// <param name=\"userId\">optional, set if vary-by-user</param>\n    /// <param name=\"viewKey\">View key is important in case the user is doing previews and temporarily changing the view</param>\n    /// <param name=\"suffix\">url parameters which are cache relevant</param>\n    /// <param name=\"currentCulture\"></param>\n    /// <returns></returns>\n    internal static string ModuleKey(int pageId, int moduleId, int? userId, string? viewKey, string? suffix, string? currentCulture)\n    {\n        var id = $\"{GlobalCacheKeyModuleRoot}p:{pageId}-m:{moduleId}\";\n        if (userId.HasValue)\n            id += $\"-u:{userId.Value}\";\n        if (viewKey != null)\n            id += $\"-v:{viewKey}\";\n        if (suffix != null)\n            id += $\"-s:{suffix}\";\n        if (currentCulture != null)\n            id += $\"-c:{currentCulture}\";\n        return id;\n    }\n    //public static string PartialSettingsKey(int appId, string path /*, int moduleId, int? userId, string? viewKey, string? suffix,  string? currentCulture */)\n    //    => PartialSettingsKey(appId.ToString(), path);\n\n    public static string PartialSettingsKey(string appKey, string path /*, int moduleId, int? userId, string? viewKey, string? suffix,  string? currentCulture */)\n    {\n        var id = $\"{GlobalCacheKeyPartialRoot}Settings.a:{appKey}-p:{path}\";\n        //if (userId.HasValue)\n        //    id += $\"-u:{userId.Value}\";\n        //if (viewKey != null)\n        //    id += $\"-v:{viewKey}\";\n        //if (suffix != null)\n        //    id += $\"-s:{suffix}\";\n        //if (currentCulture != null)\n        //    id += $\"-c:{currentCulture}\";\n        return id;\n    }\n\n    //public static string PartialKey(int appId, string path /*, int moduleId, int? userId, string? viewKey, string? suffix,  string? currentCulture */)\n    //    => PartialKey(appId.ToString(), path);\n\n    public static string PartialKey(string appKey, string path /*, int moduleId, int? userId, string? viewKey, string? suffix,  string? currentCulture */)\n    {\n        var id = $\"{GlobalCacheKeyPartialRoot}a:{appKey}-p:{path}\";\n        //if (userId.HasValue)\n        //    id += $\"-u:{userId.Value}\";\n        //if (viewKey != null)\n        //    id += $\"-v:{viewKey}\";\n        //if (suffix != null)\n        //    id += $\"-s:{suffix}\";\n        //if (currentCulture != null)\n        //    id += $\"-c:{currentCulture}\";\n        return id;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/OutputCacheManager.cs",
    "content": "﻿using ToSic.Sys.Caching;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\npublic class OutputCacheManager(MemoryCacheService memoryCacheService, LazySvc<ISysFeaturesService> featuresDoNotConnect) : ServiceBase(SxcLogName + \".OutputCacheManager\", connect: [memoryCacheService])\n{\n    public string Add(string cacheKey, OutputCacheItem data, int duration, List<string> apps, IEnumerable<string>? externalDependencies, IList<string>? appPaths)\n    {\n        var l = Log.Fn<string>($\"key: {cacheKey}\", timer: true);\n\n        // if we don't have a duration = 0 (which would be never expire), don't even add\n        if (duration == 0)\n            return l.ReturnAsError(\"duration 0, will not add\");\n\n        try\n        {\n            // Never store 0, that's like never-expire\n            //var expiration = new TimeSpan(0, 0, duration);\n            // LightSpeed entries watch:\n            // 1. the app cache keys collected from dependent apps\n            // 2. the optional external dependency keys declared via DependOn(...)\n            // 3. the LightSpeed feature key itself\n            List<string> keys = [\n                .. apps,\n                .. (externalDependencies ?? []).Distinct(StringComparer.Ordinal),\n                MemoryCacheService.ExpandDependencyId(featuresDoNotConnect.Value)\n            ];\n\n            l.A(\"Keys: \" + string.Join(\", \", keys));\n\n            // experimental, maybe use as replacement... v17.09+\n            var policyMaker = memoryCacheService.NewPolicyMaker()\n                .SetSlidingExpiration(duration)   // Never store 0, that's like never-expire\n                .WatchCacheKeys(keys);\n\n            if (appPaths?.Any() == true)\n                policyMaker = policyMaker\n                    .WatchFolders(appPaths.ToDictionary(p => p, _ => true));\n\n            memoryCacheService.Set(cacheKey, data, policyMaker);\n            \n            return l.ReturnAsOk(cacheKey);\n        }\n        catch\n        {\n            /* ignore for now */\n        }\n        return l.ReturnAsError(\"error\");\n    }\n\n    public OutputCacheItem? Get(string key) => memoryCacheService.Get<OutputCacheItem>(key);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.LightSpeed/Web.Sys.LightSpeed/RazorPartial/RazorPartialCachingHelper.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Code.Razor.Sys;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Cache;\nusing ToSic.Sxc.Services.Cache.Sys;\nusing ToSic.Sxc.Services.Cache.Sys.CacheKey;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\n/// <summary>\n/// Helper to manage Razor partial caching.\n/// </summary>\n/// <param name=\"normalizedPath\"></param>\n/// <param name=\"exCtx\"></param>\n/// <param name=\"featureSvc\"></param>\n/// <param name=\"parentLog\"></param>\npublic class RazorPartialCachingHelper(int appId, string normalizedPath, IDictionary<string, object?>? model, IExecutionContext exCtx, IFeaturesService featureSvc, ILog parentLog) : HelperBase(parentLog, \"Rzr.Cache\")\n{\n\n    private bool IsEnabled => _isEnabled ??= featureSvc.IsEnabled(SxcFeatures.LightSpeedOutputCachePartials.NameId);\n    private bool? _isEnabled;\n\n    private string AppRuntimeKey => _appRuntimeKey ??= (exCtx.GetApp() as IAppWithInternal)?.AppReader.Specs.RuntimeKey ?? appId.ToString();\n    private string? _appRuntimeKey;\n\n    /// <summary>\n    /// Underlying cache service, taken from the execution context so it knows more about the current request.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    private ICacheService CacheSvc => field ??= exCtx.GetService<ICacheService>();\n\n    /// <summary>\n    /// Cache specs prepared for the current partial rendering - contains the path.\n    /// </summary>\n    // [field: AllowNull, MaybeNull]\n    [field: AllowNull, MaybeNull]\n    public ICacheSpecs CacheSpecsRawWithModel => field\n        ??= CacheSvc.CreateSpecs(CacheSpecConstants.PrefixForDontPrefix + OutputCacheKeys.PartialKey(AppRuntimeKey, normalizedPath))\n            .AttachModel(model);\n\n    /// <summary>\n    /// The specs for the partial rendering - these may get changed by the Razor at runtime, so create once and keep it mutable.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public RenderPartialSpecsWithCaching RenderPartialSpecsForRazor => field ??= new()\n    {\n        CacheSpecs = CacheSpecsRawWithModel.Disable(),\n    };\n\n    [field: AllowNull, MaybeNull]\n    private ICacheSpecs CacheSpecsForSettings => field\n        ??= CacheSvc.CreateSpecs(CacheSpecConstants.PrefixForDontPrefix + OutputCacheKeys.PartialSettingsKey(AppRuntimeKey, normalizedPath));\n\n    private CacheKeyConfig? CacheSpecsConfig => _cacheSpecsConfig.Get(() => CacheSvc.Get<CacheKeyConfig>(CacheSpecsForSettings));\n    private readonly GetOnce<CacheKeyConfig?> _cacheSpecsConfig = new();\n\n    private ICacheSpecs? GetSpecsBasedOnSettings()\n    {\n        var l = Log.Fn<ICacheSpecs?>();\n        var config = CacheSpecsConfig;\n        if (config == null)\n            return l.ReturnNull(\"settings for partial not in cache\");\n\n        var foundation = config.RestoreBy(CacheSpecsRawWithModel);\n\n        return l.Return(foundation, $\"CacheKey to look for: '{foundation.Key}'\");\n    }\n\n    /// <summary>\n    /// Try to get the data from the cache.\n    /// </summary>\n    /// <returns></returns>\n    public IRenderResult? TryGetFromCache()\n    {\n        var l = Log.Fn<IRenderResult?>();\n        if (!IsEnabled)\n            return l.ReturnNull(\"feature not enabled\");\n\n\n        // Check if it's disabled for this elevation, in which case we should not pick it up\n        var config = CacheSpecsConfig;\n        if (config == null)\n            return AttachListenerAndExit(\"no config\");\n        var user = exCtx.GetCmsContext().User;\n        var elevation = user.GetElevation();\n        if (!config.ForElevation.IsEnabledFor(elevation))\n            return AttachListenerAndExit($\"user elevation '{elevation.ToString()}' not enabled, ignore cache.\");\n\n        var specsBasedOnSettings = GetSpecsBasedOnSettings();\n        if (specsBasedOnSettings == null)\n            return AttachListenerAndExit(\"no settings\");\n\n        var cached = CacheSvc.Get<OutputCacheItem>(specsBasedOnSettings);\n        return cached == null\n            ? AttachListenerAndExit(\"not cached\") :\n            // If we have a cached result, return it\n            l.Return(cached.Data, \"is cached\");\n\n        IRenderResult? AttachListenerAndExit(string message)\n        {\n            // WIP if it is enabled, we should attach a listener\n            Listener = PageService.Listeners.CreateRenderListener();\n            return l.ReturnNull(message);\n        }\n    }\n\n    public bool IsFullyEnabled => IsEnabled && RenderPartialSpecsForRazor.CacheSpecs.IsEnabled;\n\n    public bool SaveToCacheIfEnabled(string html)\n    {\n        var l = Log.Fn<bool>();\n        var partialRenderSpecs = RenderPartialSpecsForRazor.CacheSpecs;\n        if (!IsFullyEnabled)\n            return l.ReturnFalse(\"no partial caching\");\n\n        l.A($\"Add to cache\");\n        CacheSvc.Set(partialRenderSpecs, new OutputCacheItem((Listener ?? new RenderResult()) with \n        {\n            AppId = appId,\n            Html = html,\n            IsPartial = true,\n        }));\n\n        // detach listener if it exists, so it doesn't get saved to cache\n        if (Listener != null)\n        {\n            l.A(\"detaching listener\");\n            PageService.Listeners.RemoveListener(Listener);\n        }\n\n        // also add the configuration to the cache, so it can decide which specs to use next time\n        var storedConfig = CacheSpecsConfig;\n        var newConfig = partialRenderSpecs.GetConfig();\n        if (storedConfig == newConfig)\n            return l.ReturnTrue(\"Saved to cache; config unchanged\"); // only update cached config if it changed\n\n        // If the config changed, we need to\n        // - create fresh settings specs which will be persisted with the same policy as the data we just saved\n        // - save the config for the settings\n        var newCacheSpecsForSettings = CacheSpecsForSettings.WithPolicyOf(partialRenderSpecs);\n        CacheSvc.Set(newCacheSpecsForSettings, newConfig);\n        return l.ReturnTrue(\"Saved to cache, config updated\");\n    }\n\n    #region WIP Listener\n\n    [field: AllowNull, MaybeNull]\n    public Services.Page.Sys.PageService PageService =>\n        field ??= (Services.Page.Sys.PageService)exCtx.GetService<Services.IPageService>(reuse: true);\n    public RenderResult? Listener { get; set; }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Configuration.Sys/ConfigStringHelpers.cs",
    "content": "﻿using ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Configuration.Sys;\n\npublic class ConfigStringHelpers\n{\n    public static List<string> ConfigLinesWithoutComments(string config)\n    {\n        var paramNames = string.IsNullOrWhiteSpace(config)\n            ? []\n            : config\n                .SplitNewLine()\n                .Where(line => !string.IsNullOrWhiteSpace(line) && !line.StartsWith(\"//\"))\n                .Select(line => (line.Before(\" //\") ?? line).TrimEnd())\n                .Where(line => !string.IsNullOrWhiteSpace(line))\n                .ToList();\n        return paramNames;\n    }\n\n    public static List<(string Key, string? Values)> ConfigPairs(string config)\n    {\n        var lines = ConfigLinesWithoutComments(config);\n        var pairs = lines\n            .Select(line =>\n            {\n                var pair = line.Split('=');\n                // it's very important that if there is no \"=\" then we must use null for the value\n                // as that specifies that any value is possible, while an empty string would specify that only an empty value is possible\n                var values = pair.Length == 2 ? pair[1].Trim() : null;\n                return (Key: pair[0].Trim(), Values: values);\n            })\n            .Where(pair => !string.IsNullOrWhiteSpace(pair.Key))\n            .ToList();\n\n        return pairs;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.GetByName;\nglobal using ToSic.Sys.Utils;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Properties/SxcRenderAssemblyVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.WebApi\")]\n\n// probably just for the module service...\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Services\")]\n\n// output cache variables\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.LightSpeed\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.RenderTests\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.UnitTests\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.SystemTests\")]"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/IRenderResult.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Services.OutputCache;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.ClientAssets;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\nnamespace ToSic.Sxc.Render.Sys;\n\n// TODO: Probably remove this interface, as using the record directly is probably better.\n\n/// <summary>\n/// Contains everything which results from a render of a Block\n/// Incl. all the features that are activated, page changes etc.\n/// It's kind of like a bundle of things the CMS must then do to deliver to the page\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IRenderResult\n{\n    /// <summary>\n    /// The resulting HTML to add to the page\n    /// </summary>\n    string? Html { get; }\n\n    /// <summary>\n    /// Determines if this render-result can be cached.\n    /// Should be false in case of errors or not-yet initialized content\n    /// </summary>\n    bool CanCache { get; }\n\n    /// <summary>\n    /// Information that the result contains an error message and should be treated differently, like no caching\n    /// </summary>\n    bool IsError { get; }\n\n    /// <summary>\n    /// Built-in page features (like jQuery, 2sxc.JsCode, ...) which were requested by the code and should be enabled\n    /// </summary>\n    IList<IPageFeature>? Features { get; }\n\n    /// <summary>\n    /// Assets (js, css) which must be added to the page\n    /// </summary>\n    IList<ClientAsset>? Assets { get; }\n\n    /// <summary>\n    /// Changes to the page properties - like Title, Description, Keywords etc.\n    /// </summary>\n    IList<PagePropertyChange>? PageChanges { get; }\n\n    /// <summary>\n    /// Changes to the Page Header like Meta-Tags etc.\n    /// </summary>\n    IList<HeadChange>? HeadChanges { get; }\n\n    /// <summary>\n    /// Features which are defined in the SystemSettings and wer requested by the code and should be enabled.\n    /// </summary>\n    IList<PageFeatureFromSettings>? FeaturesFromResources { get; }\n\n    /// <summary>\n    /// List of HttpHeaders to add to the response in format \"key:value\"\n    /// </summary>\n    IList<HttpHeader>? HttpHeaders { get; }\n\n    /// <summary>\n    /// Optional HTTP-Status Code which the code returned.\n    /// Typically used on details-pages, which could return a 404 or similar.\n    /// If it's applied to the Response, it should probably also include the <see cref=\"HttpStatusMessage\"/>\n    /// </summary>\n    int? HttpStatusCode { get; }\n\n    /// <summary>\n    /// Optional status message which could give the <see cref=\"HttpStatusCode\"/> some context.\n    /// </summary>\n    string? HttpStatusMessage { get; }\n\n    [PrivateApi]\n    List<IDependentApp>? DependentApps { get; }\n\n    [PrivateApi(\"not in use yet\")]\n    int ModuleId { get; }\n\n\n    bool CspEnabled { get; }\n    bool CspEnforced { get; }\n    List<CspParameters>? CspParameters { get; }\n\n    /// <summary>\n    /// Errors such as not-activated features\n    /// </summary>\n    List<string>? Errors { get; }\n\n    /// <summary>\n    /// Info for LightSpeedStats (to group by AppId)\n    /// </summary>\n    int AppId { get; }\n\n    /// <summary>\n    /// Optional caching settings. New 19.03.03\n    /// </summary>\n    public OutputCacheSettings? OutputCacheSettings { get; init; }\n\n    /// <summary>\n    /// Determine if this is just a partial render result, meaning it should be treated differently by the cache.\n    /// </summary>\n    public bool IsPartial { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/IRenderingHelpers.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Render.Sys;\n\n[PrivateApi(\"Internal only\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IRenderingHelper: IHasLog\n{\n    IRenderingHelper Init(IBlock block);\n\n    string WrapInContext(string? content,\n        NoParamOrder npo = default,\n        int instanceId = 0,\n        int contentBlockId = 0,\n        bool editContext = false,\n        bool jsApiContext = false,\n        string tag = \"div\",\n        bool addLineBreaks = true,\n        string? errorCode = default,\n        List<Exception>? exsOrNull = default,\n        RenderStatistics? statistics = default\n    );\n\n    string? DesignErrorMessage(List<Exception> exs, bool addToEventLog, string? msgVisitors = null, string? additionalInfo = null, bool addContextWrapper = false, bool encodeMessage = true);\n\n    string? DesignError(string msgSuperUser, string? msgVisitors = null, bool addContextWrapper = false,\n        bool encodeMessage = true, List<Exception>? exsOrNull = default);\n\n    string? DesignWarningForSuperUserOnly(string warning, bool addContextWrapper = false, bool encodeMessage = true);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/InTextContentBlockRenderer.cs",
    "content": "﻿using System.Text;\nusing System.Text.RegularExpressions;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sys.Performance;\n\nnamespace ToSic.Sxc.Render.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class InTextContentBlockRenderer(SimpleRenderer simpleRenderer)\n    : ServiceBase(SxcLogName + \".RndTxt\", connect: [simpleRenderer])\n{\n    // RegEx formulas\n    static readonly Regex InlineCbDetector = new(\"<hr[^>]+sxc[^>]+>\", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled);\n    static readonly Regex  GuidExtractor = new(\"guid=\\\\\\\"([^\\\\\\\"]*)\\\\\\\"\", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled);\n\n    public string RenderMerge(IBlock block, IEntity parent, string? field, string textTemplate, IEditService edit)\n    {\n        var l = Log.Fn<string>($\"{nameof(parent)}: {parent.EntityId}, {nameof(field)}: '{field}'\");\n        // do basic checking\n        if (!InlineCbDetector.IsMatch(textTemplate))\n            return l.Return(textTemplate, \"no inner content\");\n\n        var result = new StringBuilder();\n        var charProgress = 0;\n\n        var matches = InlineCbDetector.Matches(textTemplate);\n        if (matches.Count == 0)\n            return l.Return(textTemplate, \"no inline block placeholders found\");\n\n        l.A($\"Found {matches.Count} inner content placeholders\");\n\n        //var items = parent.Children(field);\n        var items = parent\n            .Children(field)\n            .Where(child => child != null)\n            .Cast<IEntity>()\n            .ToListOpt();\n\n        foreach (Match curMatch in matches)\n            l.Do(message: $\"Match at text pos: {curMatch.Index}\", action: () =>\n            {\n                var l2 = l.Fn();\n                // Get characters before the first match\n                if (curMatch.Index > charProgress)\n                    result.Append(textTemplate.Substring(charProgress, curMatch.Index - charProgress));\n                charProgress = curMatch.Index + curMatch.Length;\n\n                // get the infos we need to retrieve the value, get it. \n                var marker = curMatch.Value.Replace(\"\\'\", \"\\\"\");\n\n                if (marker.IndexOf(\"sxc=\\\"sxc-content-block\\\"\", StringComparison.Ordinal) == 0)\n                {\n                    l2.Done(\"marker is incomplete, won't process\");\n                    return;\n                }\n\n                var guidMatch = GuidExtractor.Match(marker);\n                var likelyGuid = guidMatch.Groups[1].Value;\n\n                // check if guid is valid\n                if (!Guid.TryParse(likelyGuid, out var guid))\n                {\n                    l2.Done(\"Marker can't be converted to guid, won't process\");\n                    return;\n                }\n\n                var subItem = items.FirstOrDefault(i => i.EntityGuid == guid);\n\n                var contents = simpleRenderer.RenderWithEditContext(block, parent, subItem, field, guid, edit);\n\n                result.Append(contents);\n                l2.Done(\"done\");\n            });\n\n        // attach the rest of the text (after the last match)\n        result.Append(textTemplate.Substring(charProgress));\n\n        // Ready to finish, but first, ensure repeating if desired\n        var finalResult = result.ToString();\n        return l.Return(finalResult, \"ok\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/RenderResult.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Services.OutputCache;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.ClientAssets;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing ToSic.Sxc.Web.Sys.Html;\nusing ToSic.Sys.Memory;\n\n#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.\n\nnamespace ToSic.Sxc.Render.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record RenderResult : HybridHtmlString, IRenderResult, ICanEstimateSize, IOptimizeMemory\n{\n    /// <summary>\n    /// Estimated size of this object in memory, with all the default properties but without the payload.\n    /// </summary>\n    private const int DefaultEstimatedSize = 300;\n\n    #region HybridHtmlString / HybridHtmlRecord ToString() overrides\n\n    protected override string ToHtmlString() => Html!;\n\n    /// <summary>\n    /// Return a string for the recommended way in ASP.net to render it, which just uses a &lt;%= theRenderResult %&gt;\n    /// </summary>\n    /// <returns></returns>\n    public override string ToString() => Html!;\n\n    #endregion\n\n    /// <inheritdoc />\n    public string? Html\n    {\n        get => !UseCompression\n            ? _html\n            : CompressedHtml == null\n                ? null\n                : RenderResultHtmlCompression.Decompress(CompressedHtml);\n        init => _html = value;\n    }\n    private readonly string? _html;\n\n    public bool UseCompression => CompressedHtml != null;\n\n    public byte[]? CompressedHtml\n    {\n        get;\n        init\n        {\n            field = value;\n            if (value != null)\n                _html = null;\n        }\n    }\n\n    public int? CompressedTrueSize { get; init; }\n\n    /// <inheritdoc />\n    public bool CanCache { get; init; }\n\n    /// <inheritdoc />\n    public bool IsError { get; init; }\n\n    /// <inheritdoc />\n    public IList<IPageFeature>? Features { get; init; }\n\n    /// <inheritdoc />\n    public IList<ClientAsset>? Assets { get; init; }\n\n    /// <inheritdoc />\n    public IList<PagePropertyChange>? PageChanges { get; init; }\n\n    /// <inheritdoc />\n    public IList<HeadChange>? HeadChanges { get; init; }\n\n    /// <inheritdoc />\n    public IList<PageFeatureFromSettings>? FeaturesFromResources { get; init; }\n\n    /// <inheritdoc />\n    public int? HttpStatusCode { get; init; }\n\n    /// <inheritdoc />\n    public string? HttpStatusMessage { get; init; }\n\n    /// <inheritdoc />\n    public List<IDependentApp> DependentApps { get; } = [];\n\n\n    public int ModuleId { get; init; }\n\n    public IList<HttpHeader>? HttpHeaders { get; init; }\n\n    public bool CspEnabled { get; init; } = false;\n    public bool CspEnforced { get; init; } = false;\n\n    /// <summary>\n    /// CspParameter - for now, MUST be a real List, since it will be modified a few times\n    /// </summary>\n    public List<CspParameters>? CspParameters { get; init; }\n\n    public List<string>? Errors { get; init; }\n\n    /// <inheritdoc />\n    public int AppId { get; init; }\n\n    public OutputCacheSettings? OutputCacheSettings { get; init; }\n\n    /// <summary>\n    /// Cache information to report size etc. when needed\n    /// </summary>\n    SizeEstimate ICanEstimateSize.EstimateSize(ILog? log)\n    {\n        var l = log.Fn<SizeEstimate>();\n        var estimator = new MemorySizeEstimator(log);\n        try\n        {\n            var known = new SizeEstimate(0, DefaultEstimatedSize, IsUnknown: true);\n            if (UseCompression && CompressedHtml != null)\n                known += new SizeEstimate(CompressedHtml.Length, Expanded: CompressedTrueSize ?? 0);\n            else if (_html != null)\n                known += new SizeEstimate(_html.Length);\n            if (Errors != null)\n                known += estimator.Estimate(Errors);\n            return l.Return(known);\n        }\n        catch\n        {\n            return l.ReturnAsError(new(IsError: true));\n        }\n    }\n\n    /// <summary>\n    /// Determine if this is just a partial render result, meaning it should be treated differently by the cache.\n    /// </summary>\n    public bool IsPartial { get; init; }\n\n    public List<string>? PartialActivateWip { get; init; }\n\n    public List<(IHtmlTag Tag, bool NoDuplicates)>? PartialModuleTags { get; init; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/RenderResultHtmlCompression.cs",
    "content": "using System.IO.Compression;\nusing System.Text;\n\nnamespace ToSic.Sxc.Render.Sys;\n\ninternal static class RenderResultHtmlCompression\n{\n    private static readonly UTF8Encoding Utf8NoBom = new(false);\n\n    public const int DefaultMinBytes = 5_000;\n\n    public static int GetUtf8ByteCount(string html)\n        => Utf8NoBom.GetByteCount(html);\n\n    public static byte[] Compress(string html)\n    {\n        using var output = new MemoryStream();\n        using (var compressionStream = new GZipStream(output, CompressionLevel.Fastest, leaveOpen: true))\n        using (var writer = new StreamWriter(compressionStream, Utf8NoBom, bufferSize: 1024, leaveOpen: true))\n            writer.Write(html);\n\n        return output.ToArray();\n    }\n\n    public static string Decompress(byte[] compressedHtml)\n    {\n        using var input = new MemoryStream(compressedHtml);\n        using var decompressionStream = new GZipStream(input, CompressionMode.Decompress, leaveOpen: true);\n        using var reader = new StreamReader(decompressionStream, Utf8NoBom, detectEncodingFromByteOrderMarks: false);\n        return reader.ReadToEnd();\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/RenderService.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Blocks.Sys.BlockBuilder;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Render.Sys.RenderBlock;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\n\nnamespace ToSic.Sxc.Render.Sys;\n\n/// <summary>\n/// Block-Rendering system. It's responsible for taking a Block and delivering HTML for the output. <br/>\n/// It's used for InnerContent, so that Razor-Code can easily render additional content blocks. <br/>\n/// See also [](xref:Basics.Cms.InnerContent.Index)\n/// </summary>\n[PrivateApi(\"Hide Implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class RenderService(RenderService.Dependencies services) : ServiceWithContext(\"Sxc.RndSvc\", connect: [services]),\n    IRenderService\n{\n    #region Constructor & ConnectToRoot\n\n    public record Dependencies(\n        Generator<IEditService> EditGenerator,\n        LazySvc<IModuleAndBlockBuilder> Builder,\n        Generator<SimpleRenderer> SimpleRenderer,\n        Generator<InTextContentBlockRenderer> InTextRenderer,\n        Generator<IBlockBuilder> BlockBuilderGenerator,\n        LazySvc<ILogStore> LogStore)\n        : DependenciesRecord(connect: [EditGenerator, Builder, SimpleRenderer, InTextRenderer, LogStore, BlockBuilderGenerator]);\n\n    // ReSharper disable once InconsistentNaming\n\n    #endregion\n\n    //#endregion\n\n\n    /// <summary>\n    /// Render one content block\n    /// This is accessed through DynamicEntity.Render()\n    /// At the moment it MUST stay internal, as it's not clear what API we want to surface\n    /// </summary>\n    /// <param name=\"parent\">The parent-item containing the content-blocks and providing edit-context</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"item\">The content-block item to render. Optional, by default the same item is used as the context.</param>\n    /// <param name=\"data\">TODO V16.00</param>\n    /// <param name=\"field\">Optional: </param>\n    /// <param name=\"newGuid\">Internal: this is the guid given to the item when being created in this block. Important for the inner-content functionality to work. </param>\n    /// <returns></returns>\n    public IRawHtmlString One(\n        ICanBeItem parent,\n        NoParamOrder npo = default,\n        ICanBeEntity? item = null,\n        object? data = null,\n        string? field = null,\n        Guid? newGuid = null)\n    {\n        item ??= parent.Item;\n        var block = ExCtx.GetBlock();\n        var simpleRenderer = services.SimpleRenderer.New();\n        return Tag.Custom(field == null\n            ? simpleRenderer.Render(block, item.Entity, data: data) // without field edit-context\n            : simpleRenderer.RenderWithEditContext(block, parent, item, field, newGuid, GetEditService(), data)); // with field-edit-context data-list-context\n    }\n\n    /// <summary>\n    /// Render content-blocks into a larger html-block containing placeholders\n    /// </summary>\n    /// <param name=\"parent\">The parent-item containing the content-blocks and providing edit-context</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"field\">Required: Field containing the content-blocks. </param>\n    /// <param name=\"max\">BETA / WIP</param>\n    /// <param name=\"merge\">Optional: html-text containing special placeholders.</param>\n    /// <param name=\"apps\">BETA / WIP</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Changed result object to `IRawHtmlString` in v16.02 from `IHybridHtmlString`\n    /// </remarks>\n    public IRawHtmlString All(\n        ICanBeItem parent,\n        NoParamOrder npo = default,\n        string? field = null,\n        string? apps = null,\n        int max = 100,\n        string? merge = null)\n    {\n        if (string.IsNullOrWhiteSpace(field))\n            throw new ArgumentNullException(\"To render all items, you must specify a field where the items are stored.\", nameof(field));\n\n        var block = ExCtx.GetBlock();\n        var editService = GetEditService();\n        return Tag.Custom(merge == null\n            ? services.SimpleRenderer.New().RenderListWithContext(block, parent.Entity, field, apps, max, editService)\n            : services.InTextRenderer.New().RenderMerge(block, parent.Entity, field, merge, editService)\n        );\n    }\n\n\n    /// <inheritdoc />\n    public virtual IRenderResult Module(int pageId, int moduleId, NoParamOrder npo = default, object? data = null)\n    {\n        var l = Log.Fn<IRenderResult>($\"{nameof(pageId)}: {pageId}, {nameof(moduleId)}: {moduleId}\");\n\n        // This service is often used from a theme/skin, in which case it doesn't have a ExecutionContext,\n        // which also means that it was not logged - which we're doing here.\n        if (ExCtxOrNull == null)\n            services.LogStore.Value.Add(\"render-service\", Log);\n\n        var moduleBlock = services.Builder.Value.BuildBlock(pageId, moduleId);\n\n        moduleBlock.BlockFeatureKeys.Add(SxcPageFeatures.JsApiOnModule.NameId);\n        var builder = services.BlockBuilderGenerator.New().Setup(moduleBlock);\n        var result = builder.Run(true, specs: new() { Data = data });\n\n        return l.ReturnAsOk(result);\n    }\n\n    /// <summary>\n    /// create edit-object which is necessary for context attributes\n    /// We need a new one for each parent\n    /// </summary>\n    private IEditService GetEditService() => ExCtx.GetService<IEditService>(reuse: true);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/RenderStatistics.cs",
    "content": "﻿namespace ToSic.Sxc.Render.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class RenderStatistics\n{\n    public int RenderMs { get; set; }\n\n    public bool UseLightSpeed { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/RenderingHelper.cs",
    "content": "﻿using System.Text.Json;\nusing System.Web;\nusing ToSic.Eav.ImportExport.Integration;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Edit.Sys;\n\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sxc.Web.Sys.Html;\nusing static ToSic.Sxc.Blocks.BlockBuildingConstants;\n\nnamespace ToSic.Sxc.Render.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class RenderingHelper(ILinkPaths linkPaths, LazySvc<IEnvironmentLogger> errorLogger, Generator<JsContextAll> jsContextAllGen)\n    : ServiceBase(\"Sxc.RndHlp\", connect: [linkPaths, errorLogger, jsContextAllGen]), IRenderingHelper\n{\n    #region Constructors and DI\n\n    public IRenderingHelper Init(IBlock block)\n    {\n        Block = block;\n        Context = block.Context;\n        AppRootPath = linkPaths.AsSeenFromTheDomainRoot(\"~/\");\n        return this;\n    }\n\n    #endregion\n\n    public const string DefaultVisitorError = \"Error Showing Content - please login as admin for details.\";\n\n    protected IContextOfBlock Context = null!;\n    protected IBlock Block = null!;\n    protected string AppRootPath = null!;\n\n\n    public string WrapInContext(string? content,\n        NoParamOrder npo = default,\n        int instanceId = 0,\n        int contentBlockId = 0,\n        bool editContext = false,\n        bool jsApiContext = false,\n        string tag = SxcUiConstants.DefaultContextTag,\n        bool addLineBreaks = true,\n        string? errorCode = default,\n        List<Exception>? exsOrNull = default,\n        RenderStatistics? statistics = default\n    )\n    {\n        var contextAttribs = ContextAttributes(instanceId, contentBlockId, editContext, jsApiContext, errorCode, exsOrNull, statistics);\n\n        var lineBreaks = addLineBreaks ? \"\\n\" : \"\";\n\n        return $\"<{tag} class='{SxcUiConstants.ClassToMarkContentBlock}' {contextAttribs}>{lineBreaks}\" +\n               $\"{content}\" +\n               $\"{lineBreaks}</{tag}>\";\n    }\n\n    private string ContextAttributes(int instanceId, int contentBlockId, bool includeEditInfos, bool includeJsApiContext, string? errorCode,\n        List<Exception>? exsOrNull, RenderStatistics? statistics)\n    {\n        var contextAttribs = \"\";\n        if (instanceId != 0)\n            contextAttribs += $\" data-cb-instance='{instanceId}'\";\n\n        if (contentBlockId != 0)\n            contextAttribs += $\" data-cb-id='{contentBlockId}'\";\n\n        // optionally add editing infos\n        if (includeEditInfos || includeJsApiContext)\n        {\n            var ctxGen = jsContextAllGen.New();\n            var context = includeEditInfos\n                ? ctxGen.GetJsContext(AppRootPath, Block, errorCode, exsOrNull, statistics)\n                : ctxGen.GetJsApiOnly(Block);\n\n            var contextInfos = JsonSerializer.Serialize(context, JsonOptions.SafeJsonForHtmlAttributes);\n            contextAttribs += HtmlAttribute.Create(\"data-edit-context\", contextInfos);\n        }\n        return contextAttribs;\n    }\n\n    private const string ErrPrefix = \"Error:\";\n    private const string WarnPrefix = \"Warning:\";\n\n    public string DesignErrorMessage(List<Exception> exs, bool addToEventLog, string? msgVisitors = null,\n        string? additionalInfo = null, bool addContextWrapper = false, bool encodeMessage = true)\n    {\n        var ex = exs?.FirstOrDefault();\n        if (addToEventLog && ex != null)\n            errorLogger.Value.LogException(ex);\n        return DesignError($\"{ex}{additionalInfo}\", msgVisitors, addContextWrapper, encodeMessage, exsOrNull: exs);\n    }\n\n    public string DesignError(string msgSuperUser, string? msgVisitors = null, bool addContextWrapper = false, bool encodeMessage = true, List<Exception>? exsOrNull = default)\n    {\n        var msg = Context.User.IsSystemAdmin\n            ? $\"{ErrPrefix} {msgSuperUser}\"\n            : msgVisitors ?? DefaultVisitorError;\n        return DesignMessage(msg, addContextWrapper, encodeMessage, ErrorGeneral);\n    }\n\n    private string DesignMessage(string msg, bool addContextWrapper, bool encodeMessage, string? errorCode = default, List<Exception>? exsOrNull = default)\n    {\n        if (encodeMessage)\n            msg = HttpUtility.HtmlEncode(msg);\n\n        // Try to spot the code file which caused the problem, and add an emoji to better spot it.\n        msg = MarkCodeFilesOfApp(msg);\n\n        // add dnn-error-div-wrapper together with a special HTML marker so errors can handled better\n        msg = $\"<div class='dnnFormMessage dnnFormWarning'>{ErrorHtmlMarker}{msg}</div>\";\n\n        // add another, minimal id-wrapper for those cases where the rendering-wrapper is missing\n        if (addContextWrapper)\n            msg = WrapInContext(msg, instanceId: Context.Module.Id, contentBlockId: Context.Module.Id, errorCode: errorCode, exsOrNull: exsOrNull);\n\n        return msg;\n    }\n\n    private static string MarkCodeFilesOfApp(string msg)\n    {\n        const string simpleMatch = \".cshtml:\";\n        if (msg.Contains(simpleMatch))\n            msg = msg.Replace(simpleMatch, \".cshtml🎯:\");\n        else msg = msg.Replace(\".cshtml\", \".cshtml🎯\");\n        return msg;\n    }\n\n    public string? DesignWarningForSuperUserOnly(string warning, bool addContextWrapper = false, bool encodeMessage = true) =>\n        Context.User.IsSystemAdmin \n            ? DesignMessage($\"{WarnPrefix} {warning}\", addContextWrapper, encodeMessage) \n            : null;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys/SimpleRenderer.cs",
    "content": "﻿using System.Text;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Render.Sys.RenderBlock;\nusing ToSic.Sxc.Services;\nusing ToSic.Sys.Performance;\n\nnamespace ToSic.Sxc.Render.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SimpleRenderer(Generator<BlockOfEntity> blkFrmEntGen, Generator<IBlockBuilder> blockBuilderGenerator)\n    : ServiceBase(SxcLogName + \"RndSmp\", connect: [blkFrmEntGen, blockBuilderGenerator])\n{\n    private const string EmptyMessage = \"<!-- auto-render of item {0} -->\";\n\n    public string? Render(IBlock parentBlock, IEntity entity, object? data = default)\n    {\n        var l = Log.Fn<string?>();\n\n        // if not the expected content-type, just output a hidden html placeholder\n        if (entity.Type.Name != AppConstants.ContentGroupRefTypeName)\n        {\n            l.A(\"empty, will return hidden html placeholder\");\n            return string.Format(EmptyMessage, entity.EntityId);\n        }\n\n        // render it\n        l.A(\"found, will render\");\n        var blockOfEntity = blkFrmEntGen.New().GetBlockOfEntity(parentBlock, entity);\n        var builder = blockBuilderGenerator.New().Setup(blockOfEntity);\n        var result = builder.Run(false, specs: new() { Data = data });\n\n        // Special: during Run() various things are picked up like header changes, activations etc.\n        // Depending on the code flow, it could have picked up changes of other templates (not this one)\n        // because these were scoped, \n        // must attach additional info to the parent block, so it doesn't loose header changes and similar\n\n        return l.Return(result.Html);\n    }\n\n    private const string WrapperTemplate = \"<div class='{0}' {1}>{2}</div>\";\n    private const string WrapperMultiItems = \"sc-content-block-list\"; // tells quickE that it's an editable area\n    private const string WrapperSingleItem = WrapperMultiItems + \" show-placeholder single-item\"; // enables a placeholder when empty, and limits one entry\n\n    internal string RenderWithEditContext(IBlock block, ICanBeEntity parent, ICanBeEntity? subItem, string? cbFieldName, Guid? newGuid, IEditService edit, object? data = default)\n    {\n        var l = Log.Fn<string>();\n        var attribs = edit.ContextAttributes(parent, field: cbFieldName, newGuid: newGuid);\n        var inner = subItem == null\n            ? \"\"\n            : Render(block, subItem.Entity, data: data);\n        var cbClasses = edit.Enabled ? WrapperSingleItem : \"\";\n        // ReSharper disable FormatStringProblem\n        return l.Return(string.Format(WrapperTemplate, args: [cbClasses, attribs, inner]));\n        // ReSharper restore FormatStringProblem\n    }\n\n    public string RenderListWithContext(IBlock block, IEntity parent, string? fieldName, string? apps, int max, IEditService edit)\n    {\n        var l = Log.Fn<string>();\n        var innerBuilder = new StringBuilder();\n        var children = parent.Entity\n            .Children(fieldName)\n            .Where(child => child != null)\n            .ToListOpt();\n        foreach (var child in children)\n            innerBuilder.Append(Render(block, child!));\n\n        //var found = parent.TryGetMember(fieldName, out var objFound);\n        //if (found && objFound is IList<DynamicEntity> items)\n        //    foreach (var cb in items)\n        //        innerBuilder.Append(Render(block, cb.Entity));\n\n        // ReSharper disable FormatStringProblem\n        var result = string.Format(WrapperTemplate, args: [\n            edit.Enabled ? WrapperMultiItems : \"\",\n            edit.ContextAttributes(parent, field: fieldName, apps: apps, max: max),\n            innerBuilder\n        ]);\n        // ReSharper restore FormatStringProblem\n        return l.Return(result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/ContentBlockDto.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentBlockDto : EntityDto\n{\n    public bool IsCreated { get; }\n    public bool IsList { get; }\n    public int TemplateId { get; }\n\n    /// <summary>\n    /// Query ID so the ui can ???\n    /// </summary>\n    public int? QueryId { get; }\n\n    /// <summary>\n    /// The name to show in the layout button, new v17.07\n    /// </summary>\n    [JsonPropertyName(\"queryName\")]\n    public string? QueryName { get; }\n\n    /// <summary>\n    /// The name to show in the layout button, new v17.07\n    /// </summary>\n    [JsonPropertyName(\"queryInfo\")]\n    public string? QueryInfo { get; }\n\n    public string ContentTypeName { get; }\n    public string AppUrl { get; }\n    public string AppSharedUrl { get; }\n    public int? AppSettingsId { get; }\n    public int? AppResourcesId { get; }\n\n    public bool IsContent { get; }\n    public bool HasContent { get; }\n    public bool SupportsAjax { get; }\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Edition { get; }\n\n    [JsonPropertyName(\"editions\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Editions { get; }\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? TemplatePath { get; }\n\n    [JsonPropertyName(\"templateIsShared\")]\n    public bool TemplateIsShared { get; }\n\n    /// <summary>\n    /// The view name to show on the layout button, new v17\n    /// </summary>\n    [JsonPropertyName(\"viewName\")]\n    public string? ViewName { get; }\n\n    /// <summary>\n    /// Will be true if the view was replaced based on URL parameters.\n    /// This is to prevent the user from accidentally saving the temporarily set view.\n    /// </summary>\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    [JsonPropertyName(\"viewSwitchDisabled\")]\n    public bool? ViewSwitchDisabled { get; }\n\n    /// <summary>\n    /// The app name to show on the layout button, new v17\n    /// </summary>\n    [JsonPropertyName(\"appName\")]\n    public string AppName { get; }\n\n    /// <summary>\n    /// Render time in milliseconds to show in the layout button, new v17\n    /// </summary>\n    [JsonPropertyName(\"renderMs\")]\n    public int RenderMs { get; }\n\n    /// <summary>\n    /// Tell the UI if LightSpeed was used to render this block, new v17\n    /// </summary>\n    [JsonPropertyName(\"renderLightspeed\")]\n    public bool RenderLightspeed { get; }\n\n    public ContentBlockDto(IBlock block, RenderStatistics? statistics, IAppJsonConfigurationService appJson)\n    {\n        IsCreated = block.ContentGroupExists;\n        IsContent = block.IsContentApp;\n\n        var configuration = block.ConfigurationIsReady ? block.Configuration : null;\n        Id = configuration?.Id ?? 0;\n        Guid = configuration?.Guid ?? Guid.Empty;\n        AppId = block.AppId;\n\n        // App properties\n        var app = block.AppOrNull;\n        AppName = app?.Name ?? \"\";\n        AppUrl = app?.Path ?? \"\" + \"/\";\n        AppSharedUrl = app?.PathShared ?? \"\" + \"/\";\n        AppSettingsId = app?.Settings?.Entity?.Attributes?.Count > 0\n            ? app?.Settings?.EntityId\n            : null;    // the real id (if entity exists), 0 (if entity missing, but type has fields), or null (if not available)\n        AppResourcesId = app?.Resources?.Entity?.Attributes?.Count > 0\n            ? app?.Resources?.EntityId\n            : null;  // the real id (if entity exists), 0 (if entity missing, but type has fields), or null (if not available)\n\n        // View properties\n        var view = block.ViewIsReady ? block.View : null;\n        HasContent = view != null && (configuration?.Exists ?? false);\n\n        ZoneId = block.ZoneId;\n        TemplateId = view?.Id ?? 0;\n        Edition = view?.Edition;\n        ViewName = view?.Name;\n        ViewSwitchDisabled = view?.IsReplaced;\n        TemplatePath = view?.EditionPath.PrefixSlash();\n        TemplateIsShared = view?.IsShared ?? false;\n        ContentTypeName = view?.ContentType ?? \"\";\n\n        // Query properties\n        var query = view?.Query;\n        QueryId = query?.Id; // will be null if not defined\n        QueryName = query?.Title;\n\n        try\n        {\n            if (query != null)\n            {\n                var streamInfo = block.Data?.Out\n                    .Select(pair => new\n                    {\n                        pair.Key,\n                        Count = pair.Value?.List?.Count() ?? 0,\n                        FirstType = pair.Value?.List?.FirstOrDefault()?.Type?.Name\n                    })\n                    .ToList()\n                    ?? [];\n\n                // Create a csv list of stream names with count and first type\n                var msg = streamInfo.Aggregate(\"\", (current, stream)\n                    => current + $\"<br>- {stream.Key} ({stream.Count}{stream.FirstType.NullOrGetWith(ft => $\", first is {ft}\") ?? \" items\"}), \");\n\n                QueryInfo = $\"Query Streams: {msg}\";\n            }\n        }\n        catch\n        {\n            /* ignore */\n        }\n\n        IsList = configuration?.View?.UseForList ?? false;\n        SupportsAjax = block.IsContentApp || (app?.Configuration?.EnableAjax ?? false);\n\n        RenderMs = statistics?.RenderMs ?? -1;\n        RenderLightspeed = statistics?.UseLightSpeed ?? false;\n\n        if (app == null)\n            return;\n\n        try\n        {\n            var appJsonData = appJson.GetAppJson(app.AppId);\n            if (appJsonData?.Editions != null)\n            {\n                Editions = string.Join(\",\", appJsonData.Editions.Keys);\n            }\n        }\n        catch\n        {\n            /* ignore */\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/ContentBlockReferenceDto.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Data.Sys.Decorators;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentBlockReferenceDto\n{\n    /// <summary>\n    /// Info how this item is edited (draft required / optional)\n    /// </summary>\n    [JsonPropertyName(\"publishingMode\")]\n    public string PublishingMode { get; }\n        \n    /// <summary>\n    /// ID of the reference item\n    /// </summary>\n    [JsonPropertyName(\"id\")]\n    public int Id { get; }\n\n    /// <summary>\n    /// GUID of parent\n    /// </summary>\n    [JsonPropertyName(\"parentGuid\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public Guid? ParentGuid { get; }\n        \n    /// <summary>\n    /// Field it's being referenced in\n    /// </summary>\n    [JsonPropertyName(\"parentField\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? ParentField { get; }\n        \n    /// <summary>\n    /// Index / sort-order, where this is in the list of content-blocks\n    /// </summary>\n    [JsonPropertyName(\"parentIndex\")]\n    public int ParentIndex { get; }\n        \n    /// <summary>\n    /// If this should be regarded as part of page - relevant for page publishing features\n    /// </summary>\n    [JsonPropertyName(\"partOfPage\")]\n    public bool PartOfPage { get; }\n\n    internal ContentBlockReferenceDto(IBlock contentBlock, PublishingMode publishingMode)\n    {\n        Id = contentBlock.ContentBlockId;\n            \n        // if the CBID is the Mod-Id, then it's part of page\n        PartOfPage = contentBlock.ParentId == contentBlock.ContentBlockId;\n            \n        PublishingMode = publishingMode.ToString();\n            \n        // try to get more information about the block\n        // if it's an inner-content having a configuration entity\n        var decorator = (contentBlock as ICanBeEntity)?.Entity.GetDecorator<EntityInListDecorator>();\n        if (decorator == null)\n            return;\n        ParentGuid = decorator.ParentGuid;\n        ParentField = decorator.FieldName;\n        ParentIndex = decorator.SortOrder;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/EntityDto.cs",
    "content": "﻿namespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class EntityDto\n{\n    public int ZoneId { get; protected set; }  // the zone of the content-block\n    public int AppId { get; protected set; }   // the zone of the content-block\n    public Guid Guid { get; protected set; }   // the entity-guid of the content-block\n    public int Id { get; protected set; }      // the entity-id of the content-block\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/ErrorDto.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Problems;\nusing ToSic.Sxc.Render.Sys.Problems;\nusing ToSic.Sys.Code.InfoSystem;\nusing static System.Text.Json.Serialization.JsonIgnoreCondition;\nusing static ToSic.Sxc.Blocks.Sys.Problems.ProblemReport;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ErrorDto\n{\n    [JsonPropertyName(\"type\")]\n    public string? Type { get; }\n\n    [JsonPropertyName(\"problems\")]\n    [JsonIgnore(Condition = WhenWritingDefault)]\n    public IEnumerable<ProblemReport>? Problems { get; }\n\n    internal ErrorDto(IBlock block, string? errorCode, List<Exception>? exsOrNull, CodeInfosInScope codeWarnings)\n    {\n        // New mechanism in 16.01\n        Type = errorCode;\n\n        if (!block.Context.User.IsSiteAdmin)\n            return;\n\n        // New problems report in 16.02\n        var problems = new List<ProblemReport>(block.Problems);\n        var additional = new ProblemSuggestions().AddSuggestions(block, exsOrNull, errorCode);\n        problems.AddRange(additional);\n\n        problems.AddRange(codeWarnings\n            .GetWarnings()\n            .GroupBy(w => w.Use.Change)\n            .Select(warningGroup => new ProblemReport\n            {\n                Code = \"warning\",\n                Severity = ErrorSeverity.warning,\n                Link = warningGroup.Key.Link,\n                Message =\n                    $\"{warningGroup.Key.Message} ({warningGroup.Count()} cases{(warningGroup.Count() > 3 ? \" - possibly in a loop\" : \"\")})\",\n            }));\n\n        if (codeWarnings.GetObsoletes().Any())\n            problems.Add(new()\n            {\n                Code = \"obsolete\",\n                Severity = ErrorSeverity.warning\n            });\n\n        var appId = block.AppOrNull?.AppId;\n        if (appId != null && codeWarnings.CodeInfoStats.AppHasWarnings(appId.Value))\n            problems.Add(new()\n            {\n                Code = \"obsolete-app\",\n                Severity = ErrorSeverity.warning\n            });\n\n        Problems = problems.Any() ? problems : null;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/IJsApiService.cs",
    "content": "﻿namespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IJsApiService\n{\n    string GetJsApiJson(int? pageId = null, string? siteRoot = null, string? rvt = null, bool withPublicKey = false);\n\n    JsApi GetJsApi(int? pageId, string? siteRoot, string? rvt, bool withPublicKey = false);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/JsApi.cs",
    "content": "﻿using System.Text.Json.Serialization;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n/// <summary>\n/// This is a special json-structure which will be added to the page head.\n/// It's necessary for API calls to just-work, since the JS needs to know the API-URLs and more.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class JsApi\n{\n    public const string MetaName = \"_jsApi\";\n    public const string ExtensionPlaceholder = \"e.x.t\";\n\n    [JsonPropertyName(\"platform\")]\n    public required string Platform { get; init; }\n\n    [JsonPropertyName(\"page\")]\n    public required int Page { get; init; }\n\n    [JsonPropertyName(\"root\")]\n    public required string Root { get; init; }\n\n    [JsonPropertyName(\"api\")]\n    public required string Api { get; init; }\n\n    [JsonPropertyName(\"appApi\")]\n    public required string AppApi { get; init; }\n\n    [JsonPropertyName(\"uiRoot\")]\n    public required string UiRoot { get; init; }\n\n    [JsonPropertyName(\"rvtHeader\")]\n    public required string RvtHeader { get; init; }\n\n    [JsonPropertyName(\"rvt\")]\n    public required string Rvt { get; init; }\n\n    [JsonPropertyName(\"dialogQuery\")]\n    public required string? DialogQuery { get; init; }\n\n    [JsonPropertyName(\"publicKey\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public required string? PublicKey { get; init; }\n\n    /// <summary>\n    /// Debug information while we're developing the on-module info\n    /// </summary>\n    [JsonIgnore]\n    public string Source => \"module JsApi\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/JsApiCacheService.cs",
    "content": "﻿using System.Collections.Concurrent;\nusing ToSic.Sxc.Web.Sys.Http;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class JsApiCacheService(IHttp http) : ServiceBase(\"JsApi\", connect: [http])\n{\n    private const string JsApiKey = \"JsApi\";\n\n    /// <summary>\n    /// Create the JsAPI - or get from cache.\n    /// This is why we provide functions for most properties, so they don't need to be accessed if not needed.\n    /// </summary>\n    /// <returns></returns>\n    public JsApi JsApiJson(\n        string platform,\n        int pageId,\n        Func<string> siteRoot,\n        Func<string> apiRoot,\n        Func<string> appApiRoot,\n        Func<string> uiRoot,\n        string rvtHeader,\n        Func<string> rvt,\n        bool withPublicKey,\n        Func<string> secureEndpointPublicKey,\n        string? dialogQuery = null // these are any platform specific url query params to the dialog; can be null\n    )\n    {\n        // Minor hack: if with secure endpoint, use negative page-id for cache\n        var cacheKey = withPublicKey ? -pageId : pageId;\n\n        if (Cache.TryGetValue(cacheKey, out var jsApi))\n            return jsApi;\n\n        jsApi = new()\n        {\n            Platform = platform.ToLowerInvariant(),\n            Page = pageId,\n            Root = siteRoot.Invoke(),\n            Api = apiRoot.Invoke(),\n            AppApi = appApiRoot.Invoke(),\n            UiRoot = uiRoot.Invoke(),\n            RvtHeader = rvtHeader,\n            Rvt = rvt.Invoke(),\n            DialogQuery = dialogQuery,\n            PublicKey = withPublicKey ? secureEndpointPublicKey.Invoke() : null,\n        };\n        Cache.AddOrUpdate(cacheKey, jsApi, (_, _) => jsApi);\n            \n        return jsApi;\n    }\n\n    [field: AllowNull, MaybeNull]\n    private ConcurrentDictionary<int, JsApi> Cache => field ??= GetCache();\n\n    private ConcurrentDictionary<int, JsApi> GetCache()\n    {\n        if (http.Current.Items[JsApiKey] is ConcurrentDictionary<int, JsApi> cache)\n            return cache;\n        cache = new();\n        http.Current.Items[JsApiKey] = cache;\n        return cache;\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/JsApiServiceUnknown.cs",
    "content": "﻿#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\ninternal class JsApiServiceUnknown(WarnUseOfUnknown<JsApiServiceUnknown> _) : ServiceBase($\"{LogScopes.NotImplemented}.JsApi\"), IJsApiService, IIsUnknown\n{\n    public string GetJsApiJson(int? pageId, string? siteRoot = null, string? rvt = null, bool withPublicKey = false) => null!;\n\n    public JsApi GetJsApi(int? pageId, string? siteRoot, string? rvt, bool withPublicKey = false) => null!;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/JsContextAll.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Eav.Data.Sys.Ancestors;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sys.Code.InfoSystem;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class JsContextAll(JsContextLanguage jsLangCtxSvc, IJsApiService jsApiService, CodeInfosInScope codeWarnings, IAppJsonConfigurationService appJson, LazySvc<IFeaturesService> featuresSvc)\n    : ServiceBase(\"Sxc.CliInf\", connect: [jsLangCtxSvc, jsApiService, appJson, codeWarnings])\n{\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public JsContextEnvironment? Environment;\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public JsContextUser? User;\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public JsContextLanguage? Language;\n        \n    [JsonPropertyName(\"contentBlockReference\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public ContentBlockReferenceDto? ContentBlockReference; // todo: still not sure if these should be separate...\n        \n    [JsonPropertyName(\"contentBlock\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public ContentBlockDto? ContentBlock;\n\n    [JsonPropertyName(\"error\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public ErrorDto? Error;\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public UiDto? Ui;\n\n    [JsonPropertyName(\"jsApi\")]\n    public JsApi? JsApi;\n\n    public JsContextAll GetJsApiOnly(IBlock block)\n    {\n        var l = Log.Fn<JsContextAll>();\n\n        var addPublicKey = Features(block).Contains(SxcPageFeatures.EncryptFormData)\n            && featuresSvc.Value.IsEnabled(SxcFeatures.NetworkDataEncryption.NameId);\n\n        JsApi = jsApiService.GetJsApi(\n            pageId: block.Context.Page.Id,\n            siteRoot: null,\n            rvt: null,\n            withPublicKey: addPublicKey\n        );\n        return l.Return(this);\n    }\n\n    public JsContextAll GetJsContext(string systemRootUrl, IBlock block, string? errorCode, List<Exception>? exsOrNull,\n        RenderStatistics? statistics)\n    {\n        var l = Log.Fn<JsContextAll>();\n        var ctx = block.Context;\n\n        Environment = new(systemRootUrl, ctx);\n        Language = jsLangCtxSvc.Init(ctx.Site);\n\n        // New in v13 - if the view is from remote, don't allow design\n        var blockCanDesign = !block.ViewIsReady || block.View.Entity.HasAncestor()\n            ? (bool?)false\n            : null;\n\n        User = new(ctx.User, block.AppOrNull?.Data.List ?? []);\n\n        ContentBlockReference = new(block, ctx.Publishing.Mode);\n        ContentBlock = new(block, statistics, appJson);\n\n        // If auto toolbar is false / not certain, and we have features activated...\n        // find out if the Toolbars-Auto is enabled, in which case we should activate them\n        var autoToolbar = ctx.Permissions.IsContentAdmin\n                          || Features(block).Contains(SxcPageFeatures.ToolbarsAutoInternal);\n\n        l.A($\"{nameof(autoToolbar)}: {autoToolbar}\");\n\n        Ui = new(autoToolbar);\n\n        GetJsApiOnly(block);\n\n        Error = new(block, errorCode, exsOrNull, codeWarnings);\n        return l.Return(this);\n    }\n\n    private List<IPageFeature> Features(IBlock block)\n        => _pageFeatures ??= BlockFeaturesHelpers.BlockFeatures(block, Log);\n\n    private List<IPageFeature>? _pageFeatures;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/JsContextEnvironment.cs",
    "content": "﻿using ToSic.Eav.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Web.Sys.Parameters;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class JsContextEnvironment(string systemRootUrl, IContextOfBlock ctx)\n{\n    public int WebsiteId { get; } = ctx.Site.Id;\n    public string WebsiteUrl { get; } = \"//\" + ctx.Site.UrlRoot + \"/\";\n    public int PageId { get; } = ctx.Page.Id;\n    public string PageUrl { get; } = ctx.Page.Url;\n\n    // ReSharper disable once InconsistentNaming\n#pragma warning disable IDE1006\n    public IEnumerable<KeyValuePair<string, string>> parameters { get; } = ctx.Page.Parameters?.Where(p => p.Key != OriginalParameters.NameInUrlForOriginalParameters)!;\n#pragma warning restore IDE1006\n\n    public int InstanceId { get; } = ctx.Module.Id;\n\n    public string SxcVersion { get; } = EavSystemInfo.VersionWithStartUpBuild;\n\n    public string SxcRootUrl { get; } = systemRootUrl;\n\n    public bool IsEditable { get; } = ctx.Permissions.IsContentAdmin;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/JsContextLanguage.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class JsContextLanguage(LazySvc<IZoneMapper> zoneMapperLazy)\n{\n    public string? Current { get; private set; }\n    public string? Primary { get; private set; }\n    public IEnumerable<ClientInfoLanguage>? All { get; private set; }\n\n    public JsContextLanguage Init(ISite site)\n    {\n        Current = site.CurrentCultureCode;\n        Primary = site.DefaultCultureCode;\n        All = zoneMapperLazy.Value\n            .CulturesEnabledWithState(site) // .Where(c => c.IsEnabled)\n            .Select(c => new ClientInfoLanguage { key = c.Code.ToLowerInvariant(), name = c.Culture });\n        return this;\n    }\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ClientInfoLanguage\n{\n    // key and name must be lowercase, has side effects in EAV\n    // ReSharper disable InconsistentNaming\n    public string? key;\n    public string? name;\n    // ReSharper restore InconsistentNaming\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/JsContextUser.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class JsContextUser(IUser user, IEnumerable<IEntity>? dataList)\n{\n    public bool CanDevelop { get; } = user.IsSystemAdmin;\n\n    public bool CanAdmin { get; } = user.IsSiteAdmin;\n\n    [JsonPropertyName(\"canSwitchEdition\")]\n    public bool CanSwitchEdition { get; }\n        = dataList.FirstModel<PolymorphismConfiguration>(nullHandling: ModelNullHandling.PreferNull)\n              ?.UsersWhoMaySwitch.Contains(user.Id)\n          ?? false;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.JsContext/UiDto.cs",
    "content": "﻿using System.Text.Json.Serialization;\n\n// ReSharper disable UnusedMember.Global\n\nnamespace ToSic.Sxc.Render.Sys.JsContext;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class UiDto(bool autoToolbar)\n{\n    public bool AutoToolbar { get; } = autoToolbar;\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Edition { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ModuleHtml/IModuleHtmlService.cs",
    "content": "﻿using ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Render.Sys.ModuleHtml;\n\n[PrivateApi(\"Probably always internal, as there is probably no reason to make it public\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IModuleHtmlService: IHasLog\n{\n    /// <summary>\n    /// Tags added by code, errors, TurnOn etc. which are added to the end of the module.\n    /// Retrieves and clears stored tags for the specified module to prevent duplicate data accumulation.\n    /// </summary>\n    /// <param name=\"moduleId\">The ID of the module.</param>\n    /// <returns>A read-only collection of HTML tags associated with the module.</returns>\n    /// <remarks>\n    /// The .net Framework implementation (DNN) will ignore the ModuleId.\n    /// </remarks>\n    IReadOnlyCollection<IHtmlTag> GetMoreTagsAndFlush(int moduleId);\n\n    /// <summary>\n    /// Add a tag (like a TurnOn) to the end of the module\n    /// Adds an HTML tag to the collection of tags to be rendered at the end of the module,\n    /// optionally preventing duplicates and scoping to a specific module ID.\n    /// </summary>\n    /// <param name=\"tag\">The HTML tag to add.</param>\n    /// <param name=\"moduleId\">\n    ///     The ID of the module to which the tag should be scoped; defaults to the current module.\n    /// </param>\n    /// <param name=\"nameId\">\n    ///     An optional identifier for the tag; if not provided, the string representation of the tag is used.\n    ///     This identifier helps prevent duplicate tags if <paramref name=\"noDuplicates\"/> is set to true.\n    /// </param>\n    /// <param name=\"noDuplicates\">\n    ///     If true, the tag will only be added if it does not already exist in the collection.\n    /// </param>\n    /// <remarks>\n    /// The .net Framework implementation (DNN) will ignore the ModuleId.\n    /// </remarks>\n    /// <returns>\n    /// The same tag if it was added, or null if it was not added due to duplication.\n    /// </returns>\n    IHtmlTag? AddTag(IHtmlTag tag, int moduleId, string? nameId = null, bool noDuplicates = false);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ModuleHtml/ModuleHtmlService.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Services.OutputCache;\n\nnamespace ToSic.Sxc.Render.Sys.ModuleHtml;\n\n/// <summary>\n/// Provides functionality to manage module rendering and HTML tag collections,\n/// ensuring proper scoping of services for each module instance (sometimes difficult in Oqtane applications).\n/// </summary>\n/// <remarks>\n/// IModuleService is registered as a scoped service.\n/// In the Oqtane Interactive Server, the Dependency Injection (DI) session scope is bound to the first HTTP request\n/// of the user's browser session and remains unchanged during subsequent SignalR communications (until a full page reload).\n/// Consequently, scoped services share the same instance for all 2sxc module instances across all pages during a user's session.\n/// To prevent conflicts, the `ModuleId` is used to scope the `ModuleService` functionality to each module rendering.\n/// </remarks>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ModuleHtmlService() : ServiceBase(SxcLogName + \".ModSvc\"), IModuleHtmlService\n{\n    /// <summary>\n    /// Stores ModuleServiceData instances, scoped by ModuleId.\n    /// </summary>\n    private readonly Dictionary<int, ModuleTags> _moduleTags = new();\n\n    /// <inheritdoc />\n    public IHtmlTag? AddTag(IHtmlTag tag, int moduleId, string? nameId = null, bool noDuplicates = false)\n    {\n        //if (tag is null)\n        //    return;\n        nameId ??= tag.ToString();\n\n#if NETFRAMEWORK\n        // DNN implementation must flush the moduleID. It is not used to differentiate the cache, as that is already handled.\n        moduleId = default;\n#endif\n        var moduleServiceData = GetOrCreateModuleData(moduleId);\n        if (noDuplicates && moduleServiceData.ExistingKeys.Contains(nameId))\n            return null;\n        moduleServiceData.ExistingKeys.Add(nameId);\n        moduleServiceData.MoreTags.Add(tag);\n        return tag;\n    }\n\n    /// <inheritdoc />\n    public IReadOnlyCollection<IHtmlTag> GetMoreTagsAndFlush(int moduleId = default)\n    {\n#if NETFRAMEWORK\n        // DNN implementation must flush the moduleID. It is not used to differentiate the cache, as that is already handled.\n        moduleId = default;\n#endif\n\n        // If there is nothing to get, exit early\n        if (!_moduleTags.TryGetValue(moduleId, out var moduleServiceData))\n            return [];\n\n        // Reset module data to avoid duplicates on subsequent calls\n        _moduleTags.Remove(moduleId);\n        // old code till 2025-03-17, remove ca. Q3 2025\n        // _moduleData[moduleId] = new();\n\n        return moduleServiceData.MoreTags;\n    }\n\n    private ModuleTags GetOrCreateModuleData(int moduleId)\n    {\n       if (_moduleTags.TryGetValue(moduleId, out var moduleServiceData))\n            return moduleServiceData;\n\n        // Handle the case where the moduleId does not exist\n        return _moduleTags[moduleId] = new();\n    }\n\n    #region Output Caching\n\n    // Output-cache settings and DependOn(...) calls can happen in any order during one render,\n    // so we keep a small per-module buffer until the final render result is assembled.\n    public void ConfigureOutputCache(int moduleId, OutputCacheSettings settings)\n    {\n        var cacheState = GetOrCreateOutputCacheData(moduleId);\n        // Dependencies are accumulated separately because multiple DependOn(...) calls may follow.\n        cacheState.Settings = settings with { ExternalDependencyKeys = null };\n\n        foreach (var dependency in settings.ExternalDependencyKeys ?? [])\n            cacheState.ExternalDependencyKeys.Add(dependency.Trim());\n    }\n\n    public void AddOutputCacheDependency(int moduleId, string key)\n    {\n        if (string.IsNullOrWhiteSpace(key))\n            return;\n\n        // DependOn(...) is additive for the current render, so just normalize and union the key.\n        GetOrCreateOutputCacheData(moduleId).ExternalDependencyKeys.Add(key.Trim());\n    }\n\n    public OutputCacheSettings? GetOutputCache(int moduleId)\n    {\n        if (!_moduleOutputCache.TryGetValue(moduleId, out var cacheState))\n            return null;\n\n        // Flush once consumed so the next render starts with a clean state buffer.\n        _moduleOutputCache.Remove(moduleId);\n\n        var hasDependencies = cacheState.ExternalDependencyKeys.Count > 0;\n        if (cacheState.Settings == null && !hasDependencies)\n            return null;\n\n        // Rehydrate the final settings object with the merged dependency keys collected during rendering.\n        return (cacheState.Settings ?? new()) with\n        {\n            ExternalDependencyKeys = hasDependencies\n                ? cacheState.ExternalDependencyKeys.OrderBy(key => key, StringComparer.Ordinal).ToArray()\n                : null\n        };\n    }\n\n    private ModuleOutputCacheState GetOrCreateOutputCacheData(int moduleId)\n    {\n        if (_moduleOutputCache.TryGetValue(moduleId, out var cacheState))\n            return cacheState;\n\n        return _moduleOutputCache[moduleId] = new();\n    }\n\n    // Separate from _moduleTags because tags and output-cache state are flushed at different points in the pipeline.\n    private readonly Dictionary<int, ModuleOutputCacheState> _moduleOutputCache = new();\n\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ModuleHtml/ModuleOutputCacheState.cs",
    "content": "using ToSic.Sxc.Services.OutputCache;\n\nnamespace ToSic.Sxc.Render.Sys.ModuleHtml;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n/// <summary>\n/// Temporary per-module buffer for output-cache configuration collected during a single render.\n/// It exists because OutputCache.Configure(...) and OutputCache.DependOn(...) may happen at different times,\n/// but the final merged settings are only needed when the render result is finalized.\n/// </summary>\ninternal sealed class ModuleOutputCacheState\n{\n    // Last explicit OutputCache.Configure(...) settings captured for this module render.\n    public OutputCacheSettings? Settings { get; set; }\n\n    // Union of all DependOn(...) keys collected while the module is rendering.\n    public HashSet<string> ExternalDependencyKeys { get; } = new(StringComparer.OrdinalIgnoreCase);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ModuleHtml/ModuleTags.cs",
    "content": "using ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Render.Sys.ModuleHtml;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record ModuleTags\n{\n    public List<IHtmlTag> MoreTags { get; init; } = [];\n    public HashSet<string> ExistingKeys { get; init; } = [];\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.Problems/ProblemSuggestions.cs",
    "content": "﻿using ToSic.Sxc.Apps;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Problems;\nusing ToSic.Sys.Code.Help;\nusing ToSic.Sys.Exceptions;\n\n// ReSharper disable ConvertTypeCheckPatternToNullCheck\n\nnamespace ToSic.Sxc.Render.Sys.Problems;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ProblemSuggestions\n{\n    private const string Mobius5NameId = \"ea777610-00e3-462f-8a3e-90a09a6e1109\";\n    private const string Blog6NameId = \"72e406fd-500f-4632-82ca-942b22358b56\";\n\n    public IEnumerable<ProblemReport> AddSuggestions(IBlock block, List<Exception>? exsOrNull, string? errorCode)\n    {\n        var suggestions = new List<ProblemReport>();\n\n        // Add suggestions for any exceptions in the code\n        if (exsOrNull.SafeAny())\n        {\n            // deduplicate - in case we have many of the same errors\n            var unique = exsOrNull\n                .GroupBy(e => e.Message)\n                .Select(g => g.First())\n                .ToList();\n\n            foreach (var ex in unique)\n                if ((ex as IExceptionWithHelp)?.Helps is IEnumerable<CodeHelp> helps)\n                    suggestions.AddRange(helps.Select(h => new ProblemReport\n                    {\n                        Link = h.Link.NullIfNoValue(),\n                        Message = h.DetailsHtml ?? h.UiMessage,\n                        Severity = ProblemReport.ErrorSeverity.warning,\n                    }));\n        }\n\n\n        if (errorCode == null || block?.AppOrNull == null)\n            return suggestions;\n\n        // Special suggestion for Blog v6.0.0/1\n        AddWarning1601(block.App, \"Blog\", Blog6NameId, new(6, 0, 0), suggestions, \"app-blog-upgrade601\");\n        AddWarning1601(block.App, \"Blog\", Blog6NameId, new(6, 0, 1), suggestions, \"app-blog-upgrade601\");\n\n        // Special Suggestions for Mobius 5.7.0\n        AddWarning1601(block.App, \"Mobius\", Mobius5NameId, new(5, 7, 0), suggestions, \"app-mobius-upgrade570\");\n\n        return suggestions;\n    }\n\n    private static void AddWarning1601(IApp app, string appName, string nameId, Version version, List<ProblemReport> suggestions, string shortLink)\n    {\n        if (app.NameId != nameId || app.Configuration.Version.CompareTo(version) != 0)\n            return;\n        suggestions.Add(new()\n        {\n            Scope = ProblemReport.ErrorScope.app,\n            Severity = ProblemReport.ErrorSeverity.error,\n            Message = $\"The {appName} App {version} used some very new APIs in 2sxc 16.01 which had to be revised in 16.02. Check this guide for what to fix.\",\n            Link = $\"https://go.2sxc.org/{shortLink}\"\n        });\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.RenderBlock/BlockBuilder.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Render.Sys.ModuleHtml;\nusing ToSic.Sxc.Sys.Integration.Installation;\nusing ToSic.Sxc.Web.Sys.PageService;\nusing ToSic.Sys.Capabilities.Licenses;\nusing ToSic.Sys.Code.InfoSystem;\n\nnamespace ToSic.Sxc.Render.Sys.RenderBlock;\n\n/// <summary>\n/// This is an instance-context of a Content-Module. It basically encapsulates the instance-state, incl.\n/// IDs of Zone and App, the App, EAV-Context, Template, Content-Groups (if available), Environment and OriginalModule (in case it's from another portal)\n/// It is needed for just about anything, because without this set of information\n/// it would be hard to get anything done .\n/// Note that it also adds the current-user to the state, so that the system can log data-changes to this user\n/// </summary>\n[PrivateApi(\"not sure yet what to call this, maybe BlockHost or something\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class BlockBuilder(BlockBuilder.Dependencies services)\n    : ServiceBase<BlockBuilder.Dependencies>(services, \"Sxc.BlkBld\"), IBlockBuilder\n{\n    public record Dependencies(\n        IEngineFactory EngineFactory,\n        Generator<IEnvironmentInstaller> EnvInstGen,\n        Generator<IRenderingHelper> RenderHelpGen,\n        LazySvc<PageChangeSummary> PageChangeSummary,\n        LazySvc<ILicenseService> LicenseService,\n        IModuleHtmlService ModuleHtmlService,\n        CodeInfosInScope CodeInfos,\n        BlockCachingHelper BlockCachingHelper)\n        : DependenciesRecord(connect:\n            [EngineFactory, EnvInstGen, RenderHelpGen, PageChangeSummary, LicenseService, ModuleHtmlService, CodeInfos, BlockCachingHelper]);\n\n    #region Constructor\n\n    public IBlockBuilder Setup(IBlock cb)\n    {\n        var l = Log.Fn<IBlockBuilder>($\"get CmsInstance for a:{cb.AppId} cb:{cb.ContentBlockId}\");\n        // the root block is the main container. If there is none yet, use this, as it will be the root\n        Block = cb;\n        return l.Return(this);\n    }\n\n\n    /// <inheritdoc />\n    public IBlock Block { get; private set; } = null!;\n\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.RenderBlock/BlockBuilder_Render.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing static ToSic.Sxc.Blocks.BlockBuildingConstants;\n\nnamespace ToSic.Sxc.Render.Sys.RenderBlock;\n\npublic partial class BlockBuilder\n{\n    [PrivateApi]\n    public bool WrapInDiv { get; set; } = true;\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    public IRenderingHelper RenderingHelper => field ??= Services.RenderHelpGen.New().Init(Block);\n\n    public IRenderResult Run(bool topLevel, RenderSpecs specs)\n    {\n        // Cache Result in case of multiple runs on the same service instance\n        if (_cached != null)\n            return _cached;\n\n        var l = Log.Fn<IRenderResult>(timer: true);\n        try\n        {\n            var (html, isErr, exceptionsOrNull) = RenderInternal(specs);\n\n            // Caching only allowed if no errors, no exceptions, and the content-block is real (no preview etc.)\n            var canCache = !isErr\n                           && exceptionsOrNull.SafeNone()\n                           && Block.ConfigurationIsReady\n                           && (Block.ContentGroupExists || Block.Configuration.PreviewViewEntity != null);\n\n            // The change summary should only happen at top-level\n            // Because once these properties are picked up, they are flushed\n            // So only the top-level should get them\n            var changeSummary = topLevel\n                ? Services.PageChangeSummary.Value\n                    .FinalizeAndGetAllChanges(Block.ParentId, ((ContextOfBlock)Block.Context).PageServiceShared, specs, Block.Context.Permissions.IsContentAdmin)\n                : new();\n\n\n            var result = changeSummary with\n            {\n                AppId = Block.AppId,        // info for LightSpeedStats\n                Html = html,                // Final HTML to add to page\n                IsError = isErr,            // Error status\n                CanCache = canCache,        // Can this be cached?\n            };\n\n            // If data comes from other apps, ensure that cache-tracking knows to depend on these changes\n            if (Block.DependentApps.Any())\n                result.DependentApps.AddRange(Block.DependentApps);\n\n            // Cache Result in case of multiple runs on the same service instance\n            _cached = result;\n        }\n        catch (Exception ex)\n        {\n            l.A(\"Error!\");\n            l.Ex(ex);\n        }\n\n        // Add information to code changes if relevant\n        Services.CodeInfos.AddContext(() => new SpecsForLogHistory().BuildSpecsForLogHistory(Block));\n\n\n        return l.Return(_cached!);\n    }\n\n\n    private IRenderResult? _cached;\n\n    private (string? Html, bool IsError, List<Exception> exsOrNull) RenderInternal(RenderSpecs specs)\n    {\n        var l = Log.Fn<(string?, bool, List<Exception>)>(timer: true);\n\n        // any errors from dnn requirements check (like missing c# 8.0)\n        var oldExceptions = specs.RenderEngineResult?.ExceptionsOrNull;\n        if (oldExceptions != null)\n            return l.Return((specs.RenderEngineResult!.Html, true, oldExceptions), \"dnn requirements (c# 8.0...) not met\");\n\n        var exceptions = new List<Exception>();\n        try\n        {\n            // Make sure that each block pushes its App dependencies to the root block\n            // for collecting later when it's done.\n            // This way first the top block does this, later on inner-child blocks\n            // will also do it (since this same code is called for them when they render).\n            // Later on we'll collect the result.\n            Services.BlockCachingHelper.PushAppDependenciesToRoot(Block);\n\n            // do pre-check to see if system is stable & ready\n            var (body, err) = GenerateErrorMsgIfInstallationNotOk();\n            var errorCode = err\n                ? ErrorInstallationNotOk\n                : null;\n\n            #region Content-Group Exists\n\n            // If the body is still empty, it can be that there is nothing yet (empty block)\n            // or that something is wrong.\n            // Check if the content-group exists - sometimes the Content-Group it's missing if a site is being imported and the data isn't in yet\n            if (body == null && Block is { ConfigurationIsReady: true, AppIsReady: false })\n            {\n                l.A(\"content-block is missing data - will show error or just stop if not-admin-user\");\n                var blockId = Block.Configuration.BlockIdentifierOrNull;\n                var msg = \"Data is missing. \";\n\n                msg += Block.Context.AppReaderOrNull?.IsHealthy == false\n                    ? \"The app is unhealthy, indicating that data wasn't properly loaded from SQL. \"\n                      + \"This is the message: '\" + Block.Context.AppReaderRequired.HealthMessage + \"'. \"\n                      + \"Please check the insights to see in more detail what happened.\"\n                    : \"This is common when a site is copied \" +\n                      \"but the content / apps have not been imported yet\" +\n                      \" - check 2sxc.org/help?tag=export-import - \";\n                msg += $\" Zone/App: {Block.ZoneId}/{Block.AppId}; App NameId: {blockId?.AppDebugNameId}; ContentBlock GUID: {blockId?.Guid}\";\n\n                var ex = new Exception(msg);\n                exceptions.Add(ex);\n                body = RenderingHelper.DesignErrorMessage(exceptions, true);\n                err = true;\n                errorCode = ErrorDataIsMissing;\n            }\n            #endregion\n\n            #region App is unhealthy\n\n            if (Block.Context.AppReaderOrNull?.IsHealthy == false)\n            {\n                l.A(\"app is unhealthy, show health message\");\n                exceptions.Add(new(AppIsUnhealthy + Block.Context.AppReaderRequired.HealthMessage));\n                body = RenderingHelper.DesignErrorMessage(exceptions, true, AppIsUnhealthy + Render.Sys.RenderingHelper.DefaultVisitorError)\n                       + $\"{body}\";\n                err = true;\n                errorCode = ErrorAppIsUnhealthy;\n            }\n            #endregion\n\n            #region try to render the block or generate the error message\n\n            if (body == null)\n                try\n                {\n                    // If we got nothing, but we had a view, then there must be data missing, so we need to show an error\n                    if (Block.ViewIsReady) // when a content block is still new, there is no definition yet\n                    {\n                        l.A(\"standard case, found template, will render\");\n                        var engine = GetEngine()\n                                     ?? throw new(\"Engine missing, probably no view configured.\");\n                        var renderEngineResult = engine.Render(Block, specs);\n                        body = renderEngineResult.Html;\n                        if (renderEngineResult.ExceptionsOrNull != null)\n                            exceptions.AddRange(renderEngineResult.ExceptionsOrNull);\n                        errorCode = renderEngineResult.ErrorCode ?? errorCode;\n                        if (errorCode == null && body?.Contains(ErrorHtmlMarker) == true) \n                            errorCode = ErrorGeneral;\n\n                        var pageServiceShared = ((ContextOfBlock)Block.Context).PageServiceShared;\n\n                        // Activate-js-api is true, if the html has some <script> tags which tell it to load the 2sxc\n                        // only set if true, because otherwise we may accidentally overwrite the previous setting\n                        if (renderEngineResult.ActivateJsApi)\n                        {\n                            l.A(\"template referenced 2sxc.api JS in script-tag: will enable\");\n                            pageServiceShared.PageFeatures.Activate([SxcPageFeatures.JsCore.NameId]);\n                        }\n\n                        // Put all assets into the global page service for final processing later on\n                        pageServiceShared.AddAssets(renderEngineResult);\n                    }\n                    else body = \"\";\n                }\n                catch (Exception ex)\n                {\n                    exceptions.Add(ex);\n                    body = RenderingHelper.DesignErrorMessage(exceptions, true);\n                    err = true;\n                    errorCode = ErrorRendering;\n                }\n            #endregion\n\n\n            var licenseNotOk = GenerateWarningMsgIfLicenseNotOk();\n            if (licenseNotOk != null)\n                body = licenseNotOk + body;\n\n            #region Wrap it all up into a nice wrapper tag\n\n            // Figure out some if we should add the edit context\n            // by default the editors will get it\n            // in special cases the razor requests it to added as well\n            var addEditCtx = Block.Context.Permissions.IsContentAdmin;\n            var addJsApiOnly = false;\n            if (!addEditCtx && Block.BlockFeatureKeys.Any())\n            {\n                var features = BlockFeaturesHelpers.BlockFeatures(Block, Log);\n                addEditCtx = features.Contains(SxcPageFeatures.ContextModule);\n                addJsApiOnly = features.Contains(SxcPageFeatures.JsApiOnModule);\n            }\n\n            #region Add Custom Tags to the end if provided by the ModuleService - like TurnOn - not ideal yet\n\n            // This is not ideal, because it actually changes what's in the DIV\n            // We would rather add it to the end, but ATM that doesn't trigger turnOn in AJAX reload\n            // Note: DNN implementation will ignore the module ID, but Oqtane needs it\n            var additionalTags = Services.ModuleHtmlService.GetMoreTagsAndFlush(Block.Context.Module.Id);\n\n            var bodyWithAddOns = additionalTags.Any()\n                ? body + \"\\n\" + string.Join(\"\\n\", additionalTags.Select(t => t?.ToString()))\n                : body;\n\n            #endregion\n\n            var stats = new RenderStatistics\n            {\n                RenderMs = l == null ? -1 : (int)l.Timer.ElapsedMilliseconds,\n                UseLightSpeed = specs.UseLightspeed,\n            };\n\n            // Wrap\n            var result = WrapInDiv\n                ? RenderingHelper.WrapInContext(bodyWithAddOns,\n                    instanceId: Block.ParentId,\n                    contentBlockId: Block.ContentBlockId,\n                    editContext: addEditCtx,\n                    jsApiContext: addJsApiOnly,\n                    errorCode: errorCode,\n                    exsOrNull: exceptions,\n                    statistics: stats)\n                : bodyWithAddOns;\n            #endregion\n\n            return l.ReturnAsOk((result, err, exceptions));\n        }\n        catch (Exception ex)\n        {\n            exceptions.Add(ex);\n            return l.ReturnAsError((RenderingHelper.DesignErrorMessage(exceptions, true, addContextWrapper: true), true, exceptions));\n        }\n    }\n\n    /// <summary>\n    /// Cache the installation ok state, because once it's ok, we don't need to re-check\n    /// </summary>\n    internal static bool InstallationOk;\n\n    private (string? Html, bool Error) GenerateErrorMsgIfInstallationNotOk()\n    {\n        if (InstallationOk)\n            return (null, false);\n\n        var installer = Services.EnvInstGen.New();\n        var notReady = installer.UpgradeMessages();\n        if (!string.IsNullOrEmpty(notReady))\n        {\n            Log.A(\"system isn't ready,show upgrade message\");\n            var result = RenderingHelper.DesignErrorMessage([new(notReady)], true, encodeMessage: false); // don't encode, as it contains special links\n            return (result, true);\n        }\n\n        InstallationOk = true;\n        Log.A(\"system is ready, no upgrade-message to show\");\n        return (null, false);\n    }\n\n    /// <summary>\n    /// license ok state\n    /// </summary>\n    protected bool AnyLicenseOk => _licenseOk.Get(() => Services.LicenseService.Value.HaveValidLicense);\n    private readonly GetOnce<bool> _licenseOk = new();\n\n    private string? GenerateWarningMsgIfLicenseNotOk()\n    {\n        if (AnyLicenseOk)\n            return null;\n\n        Log.A(\"none of the licenses are valid\");\n        var warningLink = Tag.A(\"go.2sxc.org/license-warning\").Href(\"https://go.2sxc.org/license-warning\").Target(\"_blank\");\n        var appsManagementLink = Tag.A(\"System-Management\").Href(\"#\").On(\"click\", \"$2sxc(this).cms.run({ action: 'system', params: { newWindow: true }})\");\n        var warningMsg = \"Registration not valid so some features may be disabled. \" +\n                         $\"Please re-register in {appsManagementLink}. \" +\n                         \"<br>\" +\n                         $\"This is common after a major upgrade. See {warningLink}.\";\n        var result = RenderingHelper.DesignWarningForSuperUserOnly(warningMsg, false, encodeMessage: false); // don't encode, as it contains special links\n        return result;\n    }\n\n    /// <summary>\n    /// Get the rendering engine, but avoid double execution.\n    /// In some cases, the engine is needed early on to be sure if we need to do some overrides, but execution should then be later on Render()\n    /// </summary>\n    /// <returns></returns>\n    private IEngine? GetEngine()\n    {\n        var l = Log.Fn<IEngine>(timer: true);\n        if (_engine != null)\n            return l.Return(_engine, \"cached\");\n        // edge case: view hasn't been built/configured yet, so no engine to find/attach\n        if (!Block.ViewIsReady)\n            return l.ReturnNull(\"no data / view\");\n        _engine = Services.EngineFactory.CreateEngine(Block.View);\n        //_engine.Init(Block);\n        return l.Return(_engine, \"created\");\n    }\n    private IEngine? _engine;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.RenderBlock/BlockCachingHelper.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Capabilities.Features;\nusing static ToSic.Sxc.Sys.Configuration.SxcFeatures;\n\nnamespace ToSic.Sxc.Render.Sys.RenderBlock;\npublic class BlockCachingHelper(\n    ISysFeaturesService featuresSvc,\n    LazySvc<IAppsCatalog> appsCatalog,\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    Generator<IAppPathsMicroSvc> appPathsLazy)\n    : ServiceBase(\"Sxc.BlInHl\", connect: [featuresSvc, appsCatalog, appReadersLazy, appPathsLazy])\n{\n    [field: AllowNull, MaybeNull]\n    private LightSpeedConfigHelper LsConfigHelper => field ??= new(Log);\n\n    internal bool PushAppDependenciesToRoot(IBlock? currentBlock)\n    {\n        var l = Log.Fn<bool>();\n        if (currentBlock == null)\n            return l.ReturnFalse(\"no block\");\n\n        var myAppId = currentBlock.AppId;\n        // this is only relevant for the root builder, so we can skip it for child builders\n        if (myAppId == 0)\n            return l.ReturnFalse(\"no app\");\n\n        // make sure we have the app reader\n        var appReader = currentBlock.Context.AppReaderOrNull;\n        // if we don't have an app reader, we can't do anything\n        if (appReader == null)\n            return l.ReturnFalse(\"no app reader\");\n\n        // Cast to current object type to access internal APIs\n        if (currentBlock.RootBlock is not { } rootBlock)\n            return l.ReturnFalse(\"no root block\");\n\n        // add dependent appId only once\n        var rootList = rootBlock.DependentApps;\n        if (rootList.All(a => a.AppId != myAppId))\n        {\n            var decorator = LsConfigHelper.GetLightSpeedConfigOfApp(appReader);\n            var appPathsToMonitor = featuresSvc.IsEnabled(LightSpeedOutputCacheAppFileChanges.NameId)\n                ? AppPaths(appReader, currentBlock.Context.Site)\n                : [];\n\n            rootList.Add(new DependentApp\n            {\n                AppId = myAppId,\n                IsSitePrimaryApp = false,\n                LightSpeedDecorator = decorator,\n                IsEnabled = decorator.IsEnabled,\n                PathsToMonitor = appPathsToMonitor,\n                CacheKeys = [MemoryCacheService.ExpandDependencyId(appReader.GetCache())],\n            });\n        }\n\n        if (appReader.ZoneId >= 0)\n        {\n            l.A(\"dependentAppsStates add\");\n            var primary = appsCatalog.Value.PrimaryAppIdentity(appReader.ZoneId);\n            var primaryReader = appReadersLazy.Value.Get(primary);\n            rootList.Add(new DependentApp\n            {\n                AppId = primaryReader.AppId,\n                IsSitePrimaryApp = true,\n                LightSpeedDecorator = null,\n                IsEnabled = true, // always enabled, since it's the primary app and shouldn't result in disabling LightSpeed\n                PathsToMonitor = [],\n                CacheKeys = [],\n            });\n        }\n\n        return l.ReturnTrue(\"added\");\n    }\n\n\n    /// <summary>\n    /// Get physical paths for parent app and all dependent apps (portal and shared)\n    /// </summary>\n    /// <remarks>\n    /// Note: The App Paths are only the apps in /2sxc (global and per portal)\n    /// ADAM folders are not monitored\n    /// </remarks>\n    /// <returns>list of paths to monitor</returns>\n    private IList<string> AppPaths(IAppReader appState, ISite site)\n    {\n        var paths = new List<string>();\n        var appPaths = appPathsLazy.New().Get(appState, site);\n        if (Directory.Exists(appPaths.PhysicalPath))\n            paths.Add(appPaths.PhysicalPath);\n        if (Directory.Exists(appPaths.PhysicalPathShared))\n            paths.Add(appPaths.PhysicalPathShared);\n\n        return paths;\n    }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.RenderBlock/DependentApp.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Render.Sys.RenderBlock;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DependentApp : IDependentApp\n{\n    public required int AppId { get; init; }\n    public required bool IsSitePrimaryApp { get; init; }\n\n    public LightSpeedDecorator? LightSpeedDecorator { get; init; }\n\n    public required bool IsEnabled { get; init; }\n\n    public required ICollection<string> PathsToMonitor { get; init; }\n\n    public required List<string> CacheKeys { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.RenderBlock/IBlockBuilder.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Render.Sys.Specs;\n\nnamespace ToSic.Sxc.Render.Sys.RenderBlock;\n\n/// <summary>\n/// This is kind of the master-container for a content-management block. It's the wrapper which is in the CMS (DNN), and the module will talk with this\n/// Sxc Block to get everything rendered. \n/// </summary>\n[PrivateApi(\"not sure yet what to call this, or if it should be public\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IBlockBuilder: IHasLog\n{\n    public IBlockBuilder Setup(IBlock cb);\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"topLevel\">\n    ///     This means it's the outer-most render which is happening.\n    ///     This changes if things like header changes, features etc. are picked up - which should only happen at top level\n    /// </param>\n    /// <param name=\"specs\">Data to be added to the model of the main template/razor</param>\n    /// <returns></returns>\n    [PrivateApi]\n    IRenderResult Run(bool topLevel, RenderSpecs specs);\n\n    [PrivateApi]\n    IRenderingHelper RenderingHelper { get; }\n\n    /// <summary>\n    /// The real block / unit of content which will be rendered. \n    /// </summary>\n    IBlock Block { get; }\n\n    /// <summary>\n    /// Determines if the output should be wrapped in a div or not\n    /// </summary>\n    bool WrapInDiv { get; set; }\n\n    ///// <summary>\n    ///// Get the engine which will render a block\n    ///// </summary>\n    ///// <returns></returns>\n    //IEngine? GetEngine();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ResourceExtractor/BlockResourceExtractor.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Sxc.Engines;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Web.Sys.ClientAssets;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing ToSic.Sxc.Web.Sys.HtmlParsing;\nusing static System.StringComparer;\n\nnamespace ToSic.Sxc.Render.Sys.ResourceExtractor;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract partial class BlockResourceExtractor(IPageServiceShared pageServiceShared)\n    : ServiceBase(\"Sxc.AstOpt\"), IBlockResourceExtractor\n{\n    /// <summary>\n    /// List of special attributes like \"src\", \"id\", \"data-enableoptimizations\"\n    /// that we need to skip from adding in general HtmlAttributes dictionary\n    /// because this special attributes are handled in custom way.\n    /// </summary>\n    internal static readonly List<string> SpecialHtmlAttributes =\n    [\n        \"src\",\n        \"id\",\n        ClientAssetConstants.AssetOptimizationsAttributeName,\n        CspConstants.CspWhitelistAttribute\n    ];\n\n    #region Settings\n\n    protected virtual ClientAssetsExtractSettings DefaultSettings => _settings.Get(() => new(\n        extractAll: false\n    ))!;\n    private readonly GetOnce<ClientAssetsExtractSettings> _settings = new();\n\n    #endregion\n\n    /// <summary>\n    /// List of extracted assets - this must be processed later by the caller\n    /// </summary>\n    protected List<ClientAsset> Assets { get; set; } = [];\n\n    public RenderEngineResult Process(string html)\n        => Process(html, DefaultSettings);\n\n    public RenderEngineResult Process(RenderEngineResultRaw resultRaw)\n    {\n        var result = Process(resultRaw.Html ?? \"\");\n        return resultRaw.ExceptionsOrNull != null\n            ? result with\n            {\n                ExceptionsOrNull = result.ExceptionsOrNull,\n            }\n            : result;\n    }\n\n    /// <summary>\n    /// Run the sequence to extract assets\n    /// </summary>\n    /// <returns></returns>\n    public RenderEngineResult Process(string html, ClientAssetsExtractSettings settings)\n    {\n        // Pre-Flush Assets, so each call gets its own list\n        Assets = [];\n        var (template, include2SxcJs) = ExtractFromHtml(html, settings);\n        return new()\n        {\n            Html = template,\n            ActivateJsApi = include2SxcJs,\n            Assets = Assets\n        };\n    }\n\n    protected abstract (string Template, bool Include2sxcJs) ExtractFromHtml(string html, ClientAssetsExtractSettings settings);\n\n\n\n\n    /// <summary>\n    /// Extract dictionary of html attributes\n    /// </summary>\n    /// <param name=\"htmlTag\"></param>\n    /// <returns></returns>\n    public static (IDictionary<string, string?>? Attributes, string? CspCode) GetHtmlAttributes(string htmlTag)\n    {\n        if (string.IsNullOrWhiteSpace(htmlTag))\n            return (null, null);\n\n        var attributesMatch = RegexUtil.AttributesDetection.Value.Matches(htmlTag);\n\n        if (attributesMatch.Count == 0)\n            return (null, null);\n\n        var attributes = new Dictionary<string, string?>(InvariantCultureIgnoreCase);\n        foreach (Match attributeMatch in attributesMatch)\n        {\n            if (!attributeMatch.Success)\n                continue;\n            var key = attributeMatch.Groups[\"Key\"]?.Value.ToLowerInvariant();\n\n            // skip special attributes like \"src\", \"id\", \"data-enableoptimizations\"\n            if (key.IsEmpty() || SpecialHtmlAttributes.Contains(key, InvariantCultureIgnoreCase))\n                continue;\n\n            var value = attributeMatch.Groups[\"Value\"]?.Value;\n\n            attributes[key] = value; // add or update\n        }\n\n        var cspCode = attributesMatch.Cast<Match>()\n            .FirstOrDefault(m =>\n                m.Groups[\"Key\"]?.Value.EqualsInsensitive(CspConstants.CspWhitelistAttribute) == true)\n            ?.Groups[\"Value\"]?.Value;\n        return (attributes, cspCode);\n    }\n\n\n\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <remarks>\n    /// check special case: the 2sxc.api script. only check the first part of the path\n    /// because it could be .min, or have versions etc.\n    /// </remarks>\n    /// <param name=\"url\"></param>\n    /// <returns></returns>\n    private static bool Is2SxcApiJs(string url)\n        => url.ToLowerInvariant()\n            .ForwardSlash()\n            .Contains(\"/js/2sxc.api\");\n\n    /// <summary>\n    /// Because of an issue with spaces, prepend tilde to urls that start at root\n    /// and contain spaces: https://github.com/2sic/2sxc/issues/1566\n    /// </summary>\n    /// <returns></returns>\n    private string FixUrlWithSpaces(string url)\n    {\n        if (!url.Contains(\" \"))\n            return url;\n        if (!url.StartsWith(\"/\") || url.StartsWith(\"//\"))\n            return url;\n        return \"~\" + url;\n    }\n\n\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ResourceExtractor/BlockResourceExtractorUnknown.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Sys.Render.PageContext;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Render.Sys.ResourceExtractor;\n\n// ReSharper disable once UnusedMember.Global\ninternal class BlockResourceExtractorUnknown(WarnUseOfUnknown<BlockResourceExtractorUnknown> _, IPageServiceShared pageServiceShared) : BlockResourceExtractor(pageServiceShared)\n{\n    protected override (string Template, bool Include2sxcJs) ExtractFromHtml(string renderedTemplate, ClientAssetsExtractSettings settings)\n        => (renderedTemplate, false);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ResourceExtractor/BlockResourceExtractorWithInline.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Render.Sys.ResourceExtractor;\n\n/// <summary>\n/// ATM only used in Oqtane, where external and internal scripts must be extracted\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockResourceExtractorWithInline(IPageServiceShared pageServiceShared)\n    : BlockResourceExtractor(pageServiceShared)\n{\n    protected override ClientAssetsExtractSettings DefaultSettings => _settings.Get(() => new(extractAll: true))!;\n    private readonly GetOnce<ClientAssetsExtractSettings> _settings = new();\n\n    protected override (string Template, bool Include2sxcJs) ExtractFromHtml(string html, ClientAssetsExtractSettings settings)\n    {\n        var include2SxcJs = false;\n\n        // Handle Client Dependency injection\n        html = ExtractExternalScripts(html, ref include2SxcJs, settings);\n\n        // Handle inline JS\n        html = ExtractInlineScripts(html);\n\n        // Handle Styles\n        html = ExtractStyles(html, settings);\n\n        // 2025-03-17 optimized to functional - remove comment in a few weeks\n        //Assets.ForEach(a => a.PosInPage = PositionNameUnchanged(a.PosInPage));\n        Assets = Assets\n            .Select(a => a with { PosInPage = PositionNameUnchanged(a.PosInPage) })\n            .ToList();\n\n        return (html, include2SxcJs);\n    }\n\n\n\n    private string PositionNameUnchanged(string position)\n    {\n        position = position.ToLowerInvariant();\n\n        switch (position)\n        {\n            case \"body\":\n            case \"head\":\n                return position;\n            default:\n                return \"body\";\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ResourceExtractor/BlockResourceExtractor_RegEx.cs",
    "content": "﻿//using System.Text.RegularExpressions;\n//using ToSic.Sxc.Utils;\n\n//namespace ToSic.Sxc.Blocks.Output\n//{\n//    public abstract partial class BlockResourceExtractor\n//    {\n//        #region RegEx formulas and static compiled RegEx objects (performance)\n\n//        //private const string TokenPriority = \"Priority\";\n//        private const string TokenPosition = \"Position\";\n\n//        #endregion\n\n//        private int GetPriority(Match optMatch, int defaultPriority)\n//        {\n//            var priority = (optMatch.Groups[RegexUtil.PriorityKey]?.Value ?? \"true\").ToLowerInvariant();\n//            var prio = priority == \"true\" || priority == \"\"\n//                ? defaultPriority\n//                : int.Parse(priority);\n//            return prio;\n//        }\n\n//    }\n//}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ResourceExtractor/BlockResourceExtractor_Scripts.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Web.Sys.HtmlParsing;\nusing static ToSic.Sxc.Render.Sys.Output.ClientAssetConstants;\n\nnamespace ToSic.Sxc.Render.Sys.ResourceExtractor;\n\npublic abstract partial class BlockResourceExtractor\n{\n    protected string ExtractExternalScripts(string renderedTemplate, ref bool include2SxcJs, ClientAssetsExtractSettings settings, bool logDetails = false)\n    {\n        var l = Log.Fn<string>(logDetails ? renderedTemplate : null);\n\n        var scriptMatches = RegexUtil.ScriptSrcDetection.Value.Matches(renderedTemplate);\n        var scriptMatchesToRemove = new List<Match>();\n\n        l.A($\"Found {scriptMatches.Count} external scripts\");\n        foreach (var match in scriptMatches.Cast<Match>())\n        {\n            var before = match.Groups[RegexUtil.SrcKey].Value;\n            var url = FixUrlWithSpaces(before);\n            if (logDetails)\n                l.A($\"Url: '{url}' (before: '{before}'\");\n\n            // always remove 2sxc JS requests from template and ensure it's added the standard way\n            if (Is2SxcApiJs(url))\n            {\n                if (logDetails) l.A($\"Found 2sxc api.js url, will ensure it's added the standard way: {url}\");\n                include2SxcJs = true;\n                scriptMatchesToRemove.Add(match);\n                continue;\n            }\n\n            // Also get the ID (new in v12)\n            var idMatches = RegexUtil.IdDetection.Value.Match(match.Value);\n            var id = idMatches.Success\n                ? idMatches.Groups[\"Id\"].Value\n                : null;\n\n            // todo: ATM the priority and type is only detected in the Regex which expects \"enable-optimizations\"\n            // ...so to improve this code, we would have to use 2 regexs - one for detecting \"enable-optimizations\" \n            // ...and another for the priority etc.\n\n            // skip if not matched and setting only wants matches\n            var jsSettings = settings.Js;\n            var (skip, posInPage, priority) = CheckOptimizationSettings(match.Value, jsSettings);\n            if (skip)\n                continue;\n\n            // get all Attributes\n            var (attributes, cspCode) = GetHtmlAttributes(match.Value);\n            attributes ??= new Dictionary<string, string?>();\n            var forCsp = cspCode == pageServiceShared.CspEphemeralMarker;\n            if (jsSettings.AutoDefer && !attributes.ContainsKey(AttributeDefer))\n                attributes[AttributeDefer] = null;\n            if (jsSettings.AutoAsync && !attributes.ContainsKey(AttributeAsync))\n                attributes[AttributeAsync] = null;\n\n            // Register, then add to remove-queue\n            Assets.Add(new()\n            {\n                Id = id,\n                IsJs = true,\n                PosInPage = posInPage,\n                Priority = priority,\n                Url = url,\n                HtmlAttributes = attributes!,\n                WhitelistInCsp = forCsp,\n            });\n            scriptMatchesToRemove.Add(match);\n        }\n\n        // remove in reverse order, so that the indexes don't change as we remove scripts in the HTML\n        scriptMatchesToRemove.Reverse();\n        renderedTemplate = scriptMatchesToRemove\n            .Aggregate(renderedTemplate, (current, p) => current.Remove(p.Index, p.Length));\n        return l.Return(renderedTemplate);\n    }\n\n    private (bool Skip, string PosInPage, int Priority) CheckOptimizationSettings(string value, ClientAssetExtractSettingsForOneAssetType settings)\n    {\n        // Check if we have the optimize attribute\n        var optMatch = RegexUtil.OptimizeDetection.Value.Match(value);\n        if (!optMatch.Success && !settings.ExtractAll)\n            return (true, settings.Location, settings.Priority);\n\n        var finalPosInPage = (optMatch.Groups[RegexUtil.PositionKey]?.Value).UseFallbackIfNoValue(settings.Location);\n\n        var priority = GetPriority(optMatch, settings.Priority);\n\n        // Return as skip if priority is not known\n        return (priority <= 0, finalPosInPage, priority); // don't register/remove if not within specs\n    }\n\n    private int GetPriority(Match optMatch, int defaultPriority)\n    {\n        var priorityString = (optMatch.Groups[RegexUtil.PriorityKey]?.Value ?? \"true\").ToLowerInvariant();\n        var priority = priorityString is \"true\" or \"\"\n            ? defaultPriority\n            : int.Parse(priorityString);\n        return priority;\n    }\n\n\n    protected string ExtractInlineScripts(string renderedTemplate)\n    {\n        var l = Log.Fn<string>();\n        var scriptMatches = RegexUtil.ScriptContentDetection.Value.Matches(renderedTemplate);\n        var scriptMatchesToRemove = new List<Match>();\n\n        l.A($\"Found {scriptMatches.Count} inline scripts\");\n        var order = 1000;\n        foreach (Match match in scriptMatches)\n        {\n            // Register, then add to remove-queue\n            Assets.Add(new()\n            {\n                IsJs = true,\n                Priority = order++,\n                PosInPage = \"inline\",\n                Content = match.Groups[\"Content\"]?.Value,\n                IsExternal = false,\n            });\n            scriptMatchesToRemove.Add(match);\n        }\n\n        // remove in reverse order, so that the indexes don't change\n        scriptMatchesToRemove.Reverse();\n        scriptMatchesToRemove.ForEach(p => renderedTemplate = renderedTemplate.Remove(p.Index, p.Length));\n        return l.Return(renderedTemplate);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Render/Sys.ResourceExtractor/BlockResourceExtractor_Styles.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Web.Sys.HtmlParsing;\n\nnamespace ToSic.Sxc.Render.Sys.ResourceExtractor;\n\npublic abstract partial class BlockResourceExtractor\n{\n    protected string ExtractStyles(string renderedTemplate, ClientAssetsExtractSettings settings)\n    {\n        var l = Log.Fn<string>();\n        var styleMatches = RegexUtil.StyleDetection.Value.Matches(renderedTemplate);\n        var styleMatchesToRemove = new List<Match>();\n\n        if (styleMatches.Count == 0)\n            return l.Return(renderedTemplate, \"no styles to extract\");\n\n        foreach (Match match in styleMatches)\n        {\n            // Also get the ID (new in v12)\n            var idMatches = RegexUtil.IdDetection.Value.Match(match.Value);\n            var id = idMatches.Success ? idMatches.Groups[\"Id\"].Value : null;\n\n            // todo: ATM the priority and type is only detected in the Regex which expects \"enable-optimizations\"\n            // ...so to improve this code, we would have to use 2 regexs - one for detecting \"enable-optimizations\" \n            // ...and another for the priority etc.\n\n            // skip if not stylesheet\n            if (!RegexUtil.StyleRelDetect.Value.IsMatch(match.Value))\n                continue;\n\n            // skip if not matched and setting only wants matches\n            var (skip, posInPage, priority) = CheckOptimizationSettings(match.Value, settings.Css);\n            if (skip)\n            {\n                if (!settings.Css.ExtractAll)\n                    continue;\n                // if Auto-Optimize, then set these defaults\n                posInPage = ClientAssetConstants.AddToBottom;\n                priority = ClientAssetConstants.CssDefaultPriority;\n            }\n\n\n            // get all Attributes\n            var (_, cspCode) = GetHtmlAttributes(match.Value);\n            var forCsp = cspCode == pageServiceShared.CspEphemeralMarker;\n\n            // Register, then remember to remove later on\n            var url = FixUrlWithSpaces(match.Groups[\"Src\"].Value);\n            Assets.Add(new()\n            {\n                Id = id,\n                IsJs = false,\n                PosInPage = posInPage,\n                Priority = priority,\n                Url = url,\n                WhitelistInCsp = forCsp,\n            });\n            styleMatchesToRemove.Add(match);\n        }\n        \n        // Remove the styles in backward order, so the indexes don't shift as things are removed\n        var shrunkTemplate = renderedTemplate;\n        styleMatchesToRemove.Reverse();\n        styleMatchesToRemove.ForEach(p => shrunkTemplate = shrunkTemplate.Remove(p.Index, p.Length));\n        return l.Return(shrunkTemplate, $\"extracted {styleMatches.Count} styles\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Services/IRenderService.cs",
    "content": "﻿using ToSic.Razor.Markup;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Render.Sys;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Render`](xref:ToSic.Sxc.Services.ServiceKit16.Render) to rendering blocks and delivering HTML for the output.\n/// </summary>\n/// <remarks>\n/// It's used for InnerContent, so that Razor-Code can easily render additional content blocks. <br/>\n/// You can also use it inside Skins/Themes to render content-blocks. <br/>\n/// See also [](xref:Basics.Cms.InnerContent.Index)\n/// \n/// This replaces the now obsolete ToSic.Sxc.Blocks.Render\n///\n/// History\n/// * Introduced in v12.05 but on another namespace which still works for compatibility\n/// * Moved to ToSic.Sxc.Services in v13\n/// </remarks>\n[PublicApi]\npublic interface IRenderService\n{\n    /// <summary>\n    /// Render one content block\n    /// This is accessed through DynamicEntity.Render()\n    /// At the moment it MUST stay internal, as it's not clear what API we want to surface\n    /// </summary>\n    /// <param name=\"parent\">The parent-item containing the content-blocks and providing edit-context</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"item\">The content-block item to render. Optional, by default the same item is used as the context.</param>\n    /// <param name=\"field\">Optional: </param>\n    /// <param name=\"newGuid\">Internal: this is the guid given to the item when being created in this block. Important for the inner-content functionality to work. </param>\n    /// <param name=\"data\">Data to give the Razor as `DynamicModel` - new 15.07</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Changed result object to `IRawHtmlString` in v16.02 from `IHybridHtmlString`\n    /// </remarks>\n    IRawHtmlString One(\n        ICanBeItem parent,\n        NoParamOrder npo = default,\n        ICanBeEntity? item = null,\n        object? data = null,\n        string? field = null,\n        Guid? newGuid = null\n    );\n\n    /// <summary>\n    /// Render content-blocks into a larger html-block containing placeholders\n    /// </summary>\n    /// <param name=\"parent\">The parent-item containing the content-blocks and providing edit-context</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"field\">Required: Field containing the content-blocks. </param>\n    /// <param name=\"max\">BETA / WIP</param>\n    /// <param name=\"merge\">Optional: html-text containing special placeholders.</param>\n    /// <param name=\"apps\">BETA / WIP</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// * Changed result object to `IRawHtmlString` in v16.02 from `IHybridHtmlString`\n    /// </remarks>\n    IRawHtmlString All(\n        ICanBeItem parent,\n        NoParamOrder npo = default,\n        string? field = null,\n        string? apps = null,\n        int max = 100,\n        string? merge = null\n    );\n\n    /// <summary>\n    /// Get a 2sxc module rendered directly. \n    /// </summary>\n    /// <param name=\"pageId\"></param>\n    /// <param name=\"moduleId\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"data\">Data to give the Razor as `DynamicModel` - new 15.07</param>\n    /// <returns>\n    /// An HTML-String which can be added to the output directly.\n    /// The object also has additional information like assets or page changes, which are not applied when using this render command. \n    /// </returns>\n    /// <remarks>New in 2sxc 13.02</remarks>\n    IRenderResult Module(\n        int pageId,\n        int moduleId,\n        NoParamOrder npo = default,\n        object? data = null\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Services/OutputCache/IOutputCacheSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Services.OutputCache;\n\n/// <summary>\n/// This interface is internal, to just ensure that all classes use the same property names.\n/// ATM it's not meant for any kind of public use.\n/// </summary>\ninternal interface IOutputCacheSettings\n{\n    bool IsEnabled { get; }\n    int Duration { get; }\n    int DurationUsers { get; }\n    int DurationEditors { get; }\n    int DurationSystemAdmin { get; }\n    bool ByUrlParameters { get; }\n    bool UrlParametersCaseSensitive { get; }\n    string? UrlParameterNames { get; }\n    bool UrlParametersOthersDisableCache { get; }\n    IReadOnlyCollection<string>? ExternalDependencyKeys { get; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Services/OutputCache/OutputCacheSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Services.OutputCache;\n\n// WIP v19.03.03\n// Not complete. To finish:\n// - Figure out how to best implement the logic for combining settings from different sources\n// - eg. skip zeros when merging, merge booleans if not defined, etc.\n// - also consider adding more dependencies (may mix with the Cache API) to e.g. create a dependency on a data-stream such as cached SharePoint data?\n// - then put on Kit\n// - then document\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic record OutputCacheSettings : IOutputCacheSettings\n{\n    public bool IsEnabled { get; init; } = true;\n\n    public int Duration { get; init; } = 0;\n\n    public int DurationUsers { get; init; }\n\n    public int DurationEditors { get; init; }\n\n    public int DurationSystemAdmin { get; init; }\n\n    public bool ByUrlParameters { get; init; }\n\n    public bool UrlParametersCaseSensitive { get; init; }\n\n    public string? UrlParameterNames { get; init; }\n\n    public bool UrlParametersOthersDisableCache { get; init; }\n\n    public IReadOnlyCollection<string>? ExternalDependencyKeys { get; init; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/StartupSxcRender.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.JsContext;\nusing ToSic.Sxc.Render.Sys.RenderBlock;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing ToSic.Sxc.Web.Sys.PageFeatures;\nusing ToSic.Sxc.Web.Sys.PageService;\nusing ToSic.Sxc.Web.Sys.PageServiceShared;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcRender\n{\n    public static IServiceCollection AddSxcRender(this IServiceCollection services)\n    {\n        services.TryAddTransient<Services.IRenderService, RenderService>();  // new 12.05\n        services.TryAddTransient<RenderService.Dependencies>();\n        services.TryAddTransient<SimpleRenderer>();\n        services.TryAddTransient<InTextContentBlockRenderer>();\n        \n        services.TryAddTransient<IBlockBuilder, BlockBuilder>();\n        services.TryAddTransient<BlockBuilder.Dependencies>();\n\n        services.TryAddTransient<IRenderingHelper, RenderingHelper>();\n\n        // JS UI Context for render\n        services.TryAddTransient<JsContextAll>();\n        services.TryAddTransient<JsContextLanguage>();\n        services.TryAddScoped<JsApiCacheService>(); // v16.01\n\n\n        // Content Security Policies (CSP)\n        services.TryAddTransient<IContentSecurityPolicyService, ContentSecurityPolicyService>();\n        services.TryAddTransient<CspOfApp>();   // must be transient\n        services.TryAddScoped<CspOfModule>();   // important: must be scoped!\n        services.TryAddTransient<CspOfPage>();\n        services.TryAddTransient<CspParameterFinalizer>();\n\n\n        // 2022-02-07 2dm experimental\n        // The PageServiceShared must always be generated from the PageScope\n        // I previously thought the PageServiceShared must be scoped at page level, but this is wrong\n        // Reason is that it seems to collect specs per module, and then actually only flushes it\n        // Because it shouldn't remain in the list for the second module\n        // So it actually looks like it's very module-scoped already, but had workarounds for it.\n        // So I think it really doesn't need to be have workarounds for it\n        services.TryAddScoped<IPageServiceShared, PageServiceShared>();\n        services.TryAddTransient<PageChangeSummary>();\n\n        // Page Features\n        services.TryAddTransient<IPageFeatures, PageFeatures>();\n        services.TryAddTransient<IPageFeaturesManager, PageFeaturesManager>();\n        services.TryAddSingleton<PageFeaturesCatalog>();\n\n        // Info Helpers, mainly to ensure that Output-Caching information works\n        services.TryAddTransient<BlockCachingHelper>();\n\n        // Fallbacks\n        services.AddSxcRenderFallbacks();\n\n        return services;\n    }\n\n    public static IServiceCollection AddSxcRenderFallbacks(this IServiceCollection services)\n    {\n        // v16\n        services.TryAddScoped<IJsApiService, JsApiServiceUnknown>();\n\n        return services;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/ToSic.Sxc.Render.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Render</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Edit\\ToSic.Sxc.Edit.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Engines\\ToSic.Sxc.Engines.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/ToSic.Sxc.Render.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cmodule/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cmodule_002Esys/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/ContentSecurityPolicyService.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Web.Sys.PageServiceShared;\n\nnamespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n/// <summary>\n/// Transient CSP Service.\n/// </summary>\n/// <remarks>\n/// Will pick up the shared page state and make sure that any activity on this is projected to the page.\n/// </remarks>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentSecurityPolicyService : ContentSecurityPolicyServiceBase, IContentSecurityPolicyService\n{\n    public ContentSecurityPolicyService(IPageServiceShared pageServiceShared)\n    {\n        PageCsp = ((IPageServiceSharedInternal)pageServiceShared).Csp;\n\n        // Register this transient copy to the page, so it will pick up any changes made to this\n        // transient instance later on when rendering\n        PageCsp.AddCspService(this);\n    }\n\n    private CspOfModule PageCsp { get; }\n\n    public override bool IsEnforced => PageCsp.IsEnforced;\n\n    public override bool IsEnabled => PageCsp.IsEnabled;\n        \n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/ContentSecurityPolicyServiceBase.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n/// <summary>\n/// Very experimental, do not use\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentSecurityPolicyServiceBase() : ServiceBase($\"{SxcLogName}.CspSvc\"), IContentSecurityPolicyService\n{\n    public CspParameters Policy { get; } = [];\n\n    public virtual bool IsEnforced => false;\n\n    public virtual bool IsEnabled => false;\n\n    public void Add(string name, params string?[]? values)\n    {\n        if (values == null || values.Length == 0)\n            values = [null];\n\n        // Split values, so that each value is standalone - in case future merging requires clean-up\n        var valuesSplit = values.SelectMany(IEnumerable<string?> (v) => v == null ? [null!] : v.Split(' '));\n        foreach (var v in valuesSplit)\n            Policy.Add(name, v);\n    }\n\n    //#region Src commands\n\n    //public void AllSrc(params string[] values) => Add(CspConstants.AllSrcName, values);\n\n    //public void DefaultSrc(params string[] values) => Add(CspConstants.DefaultSrcName, values);\n    //public void ChildSrc(params string[] values) => Add(\"child-src\", values);\n    //public void ConnectSrc(params string[] values) => Add(\"connect-src\", values);\n    //public void FontSrc(params string[] values) => Add(\"font-src\", values);\n    //public void FrameSrc(params string[] values) => Add(\"frame-src\", values);\n    //public void ImgSrc(params string[] values) => Add(\"img-src\", values);\n    //public void ManifestSrc(params string[] values) => Add(\"manifest-src\", values);\n    //public void MediaSrc(params string[] values) => Add(\"media-src\", values);\n    //public void ObjectSrc(params string[] values) => Add(\"object-src\", values);\n    //public void PrefetchSrc(params string[] values) => Add(\"prefetch-src\", values);\n    //public void ScriptSrc(params string[] values) => Add(\"script-src\", values);\n    //public void ScriptSrcElem(params string[] values) => Add(\"script-src-elem\", values);\n    //public void ScriptSrcAttr(params string[] values) => Add(\"script-src-attr\", values);\n    //public void StyleSrc(params string[] values) => Add(\"style-src\", values);\n    //public void StyleSrcElem(params string[] values) => Add(\"style-src-elem\", values);\n    //public void StyleSrcAttr(params string[] values) => Add(\"style-src-attr\", values);\n    //public void WorkerSrc(params string[] values) => Add(\"worker-src\", values);\n    //#endregion\n\n    //#region Other Commands\n    //public void BaseUri(params string[] values) => Add(\"base-uri\", values);\n    //// Deprecated according to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/block-all-mixed-content\n    ////public void BlockAllMixedContent(params string[] values) => Add(\"block-all-mixed-content\", values);\n    //public void FormAction(params string[] values) => Add(\"form-action\", values);\n    //public void FrameAncestors(params string[] values) => Add(\"frame-ancestors\", values);\n    //public void NavigateTo(params string[] values) => Add(\"navigate-to\", values);\n    //// Deprecated https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/plugin-types\n    ////public void plugin-types(params string[] values) => Add(\"plugin-types\", values);\n    //// Deprecated https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/referrer\n    ////public void referrer(params string[] values) => Add(\"referrer\", values);\n    //public void ReportTo(params string[] values) => Add(\"report-to\", values);\n    //// Deprecated https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri\n    ////public void report-uri(params string[] values) => Add(\"report-uri\", values);\n\n    //// Deprecated https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/require-sri-for\n    ////public void require-sri-for(params string[] values) => Add(\"require-sri-for\", values);\n\n    //public void RequireTrustedTypesFor(params string[] values) => Add(\"require-trusted-types-for\", values);\n    //public void Sandbox(params string[] values) => Add(\"sandbox\", values);\n    //public void TrustedTypes(params string[] values) => Add(\"trusted-types\", values);\n\n    //public void UpgradeInsecureRequests() => Add(\"upgrade-insecure-requests\");\n\n    //#endregion\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/CspConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\ninternal class CspConstants\n{\n    public const string LogPrefix = \"Csp\";\n    public const string AllSrcName = \"all-src\";\n    public const string DefaultSrcName = \"default-src\";\n    public const string SuffixSrc = \"-src\";\n\n    public const string CspHeaderNamePolicy = \"Content-Security-Policy\";\n    public const string CspHeaderNameReport = \"Content-Security-Policy-Report-Only\";\n    public const string CspUrlParameter = \"csp\";\n    public const string CspUrlTrue = \"true\";\n    public const string CspUrlDev = \"dev\";\n\n    public const string CspWhitelistAttribute = \"csp-whitelist\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/CspOfApp.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n/// <summary>\n/// This object reads the CSP settings of an app and passes it to the <see cref=\"CspOfModule\"/>.\n/// This is important because a module can have multiple apps in it, so it must merge the Csp Settings\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CspOfApp : ServiceWithContext\n{\n    public int AppId => _appId ??= ExCtx.GetBlock()?.AppId ?? 0;\n    private int? _appId;\n\n    #region Constructor\n\n    public CspOfApp(IUser user, CspOfModule moduleCsp) : base(CspConstants.LogPrefix + \".AppLvl\", connect: [/* nothing everything is already connected */])\n    {\n        _user = user;\n        _moduleCsp = moduleCsp;\n        moduleCsp.RegisterAppCsp(this); // Attach to parent which is scoped for the entire module\n    }\n\n    private readonly IUser _user;\n    private readonly CspOfModule _moduleCsp;\n\n    /// <summary>\n    /// Connect to code root, so page-parameters and settings will be available later on.\n    /// Important: page-parameters etc. are not available at this time, so don't try to get them until needed\n    /// </summary>\n    /// <param name=\"exCtx\"></param>\n    public override void ConnectToRoot(IExecutionContext exCtx)\n    {\n        var l = Log.Fn();\n        base.ConnectToRoot(exCtx);\n        // Also connect upstream CspOfModule in case it's not yet connected\n        _moduleCsp.ConnectToRoot(exCtx);\n        l.Done();\n    }\n\n    #endregion\n\n    #region Read Settings\n\n    public string? AppPolicies => _appPolicies.Get(GetAppPolicies);\n    private readonly GetOnce<string?> _appPolicies = new();\n\n    private string? GetAppPolicies()\n    {\n        var l = Log.Fn<string?>(AppId.ToString());\n\n        // Get Stack\n        if (ExCtxOrNull?.GetDataStack<IDynamicStack>(ExecutionContextStateNames.Settings) is not { } stack) \n            return l.ReturnNull(\"no stack\");\n\n        // Enable this for detailed debugging\n        //stack.Debug = true;\n\n        // Dynamic Stack of the App Settings\n        var appSettings = stack.GetStack(AppStackConstants.PartAppSystem);\n        Log.A($\"has {nameof(appSettings)}: {appSettings != null}\");\n\n        // CSP Settings Reader from Dynamic Entity for the App\n        var cspReader = new CspSettingsReader(appSettings, _user, _moduleCsp.UrlIsDevMode, Log);\n        var policies = cspReader.Policies;\n        return l.ReturnAndLog(policies);\n    }\n    #endregion\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/CspOfModule.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Users;\nusing IFeaturesService = ToSic.Sxc.Services.IFeaturesService;\n\nnamespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CspOfModule(IUser user, IFeaturesService featuresService)\n    : ServiceWithContext($\"{CspConstants.LogPrefix}.ModLvl\")\n{\n    #region App Level CSP Providers\n\n    /// <summary>\n    /// Each App will register itself here to be added to the CSP list\n    /// </summary>\n    private List<CspOfApp> AppCsps { get; }= [];\n\n    internal bool RegisterAppCsp(CspOfApp? appCsp)\n    {\n        var cLog = Log.Fn<bool>(\"appId: not yet known, not yet attached\");\n        if (appCsp == null)\n            return cLog.ReturnFalse(\"null\");\n\n        // Note: We tried not-adding duplicates but this doesn't work\n        // Because at the moment of registration, the AppId is often not known yet\n        // Do not delete this comment, as others will attempt this too\n        //if (AppCsps.Any(a => a.AppId == appCsp.AppId)) \n        //    return cLog.Done($\"app {appCsp.AppId} exists\", false);\n        AppCsps.Add(appCsp);\n        return cLog.ReturnTrue(\"added\");\n    }\n\n    #endregion\n\n    #region Url Parameters to Detect Dev / True\n\n    public bool UrlIsDevMode => _urlDevMode.Get(() => CspUrlParam.EqualsInsensitive(CspConstants.CspUrlDev));\n    private readonly GetOnce<bool> _urlDevMode = new();\n\n    private string? CspUrlParam => _cspUrlParam.Get(Log, () =>\n    {\n        if (!featuresService.IsEnabled(SxcFeatures.ContentSecurityPolicyTestUrl.NameId))\n            return null;\n        var pageParameters = ExCtxOrNull?.GetCmsContext()?.Page?.Parameters;\n        if (pageParameters == null)\n            return null;\n        pageParameters.TryGetValue(CspConstants.CspUrlParameter, out var cspParam);\n        return cspParam;\n    });\n    private readonly GetOnce<string?> _cspUrlParam = new();\n\n    #endregion\n\n    #region Read Settings\n\n    /// <summary>\n    /// CSP Settings Reader from Dynamic Entity for the Site\n    /// </summary>\n    private CspSettingsReader SiteCspSettings => _siteCspSettings.Get(Log, () =>\n    {\n        var pageSettings = ExCtxOrNull?.GetDataStack<IDynamicStack>(ExecutionContextStateNames.Settings)\n            ?.GetStack(AppStackConstants.PartSiteSystem, AppStackConstants.PartGlobalSystem, AppStackConstants.PartPresetSystem);\n        return new CspSettingsReader(pageSettings, user, UrlIsDevMode, Log);\n    })!;\n    private readonly GetOnce<CspSettingsReader> _siteCspSettings = new();\n\n    #endregion\n\n    #region Enabled / Enforced\n\n    /// <summary>\n    /// Enforce?\n    /// </summary>\n    internal bool IsEnforced => _cspReportOnly.Get(Log, () => SiteCspSettings.IsEnforced);\n    private readonly GetOnce<bool> _cspReportOnly = new();\n\n\n    /// <summary>\n    /// Check if enabled based on various criteria like features, url-param, settings etc.\n    /// </summary>\n    internal bool IsEnabled => _enabled.Get(Log, () =>\n    {\n        // Check features\n        if (!featuresService.IsEnabled(SxcFeatures.ContentSecurityPolicy.NameId))\n            return false;\n        if(featuresService.IsEnabled(SxcFeatures.ContentSecurityPolicyEnforceTemp.NameId))\n            return true;\n\n        // Try settings\n        if (SiteCspSettings.IsEnabled) \n            return true;\n\n        // Check URL Parameters - they are null if the feature is not enabled\n        return CspUrlParam.EqualsInsensitive(CspConstants.CspUrlTrue) || UrlIsDevMode;\n    });\n    private readonly GetOnce<bool> _enabled = new();\n\n\n    #endregion\n\n\n    private List<KeyValuePair<string, string>> Policies => _policies.Get(Log, () =>\n    {\n        var sitePolicies = SiteCspSettings.Policies;\n        Log.A($\"Site.Policies: {sitePolicies}\");\n\n        var appPolicies = GetAppPolicies();\n        var merged = $\"{sitePolicies}\\n{appPolicies}\";\n        Log.A($\"Merged: {merged}\");\n        return new CspPolicyTextProcessor(Log).Parse(merged);\n    })!;\n    private readonly GetOnce<List<KeyValuePair<string, string>>> _policies = new();\n\n    private string GetAppPolicies()\n    {\n        var cLog = Log.Fn<string>();\n\n        var deduplicate = AppCsps\n            .GroupBy(ac => ac.AppId)\n            .Select(g => g.First())\n            .ToList();\n\n\n        var appPolicySets = deduplicate\n            .Select(ac =>\n            {\n                var p = ac.AppPolicies;\n                Log.A($\"App[{ac.AppId}]: {p}\");\n                return p.NullIfNoValue();\n            })\n            .Where(p => p.HasValue())\n            .ToList();\n\n        var appPolicies = string.Join(\"\\n\", appPolicySets);\n\n        return cLog.Return(appPolicies, $\"Total: {AppCsps.Count}; Distinct: {deduplicate.Count}; With Value: {appPolicySets.Count}\");\n    }\n\n\n\n    internal void AddCspService(IContentSecurityPolicyService provider) => CspServices.Add(provider);\n    internal readonly List<IContentSecurityPolicyService> CspServices = [];\n\n    public List<CspParameters> CspParameters()\n    {\n        var l = Log.Fn<List<CspParameters>>();\n        if (!IsEnabled)\n            return l.Return([], \"disabled\");\n\n        if (Policies.Any())\n        {\n            Log.A(\"Policies found\");\n            // Create a CspService which just contains these new policies for merging later on\n            var policyCsp = new ContentSecurityPolicyServiceBase();\n            foreach (var policy in Policies)\n                policyCsp.Add(policy.Key, policy.Value);\n            AddCspService(policyCsp);\n        }\n\n        if (!CspServices.Any())\n            return l.Return([], \"no services to add\");\n        var result = CspServices\n            .Select(c => c?.Policy!)\n            .Where(c => c != null)\n            .ToList();\n        return l.ReturnAsOk(result);\n\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/CspOfPage.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CspOfPage(Generator<CspParameterFinalizer> cspParameterFinalizer)\n    : ServiceBase(CspConstants.LogPrefix + \".Page\", connect: [cspParameterFinalizer])\n{\n    public List<CspParameters> CspParameters { get; } = [];\n\n    public void Add(IList<CspParameters> additional)\n        => CspParameters.AddRange(additional);\n\n    /// <summary>\n    /// Name of the CSP header to be added, based on the report-only aspect\n    /// </summary>\n    public string HeaderName(bool isEnforced) => isEnforced\n        ? CspConstants.CspHeaderNamePolicy\n        : CspConstants.CspHeaderNameReport;\n\n\n    public string? CspHttpHeader()\n    {\n        try\n        {\n            var l = Log.Fn<string>();\n            var relevant = CspParameters.Where(cs => cs != null).ToList();\n            if (!relevant.Any())\n                return l.ReturnNull(\"none relevant\");\n            var mergedPolicy = relevant.First();\n\n            var finalizer = cspParameterFinalizer.New();\n\n            if (relevant.Count == 1)\n                return l.Return(finalizer.Finalize(mergedPolicy).ToString(), \"found 1\");\n\n            // Pre-copy, so we never change the original!\n            mergedPolicy = new(mergedPolicy);\n\n            // If many, merge the settings of each additional policy list\n            foreach (var cspS in relevant.Skip(1))\n                mergedPolicy.Add(cspS);\n\n            return l.Return(finalizer.Finalize(mergedPolicy).ToString(), \"merged\");\n        }\n        catch (Exception e)\n        {\n            Console.WriteLine(e);\n            throw;\n        }\n\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/CspParameterFinalizer.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CspParameterFinalizer() : ServiceBase($\"{CspConstants.LogPrefix}.ParFin\")\n{\n    [return: NotNullIfNotNull(nameof(original))]\n    public CspParameters? Finalize(CspParameters? original)\n    {\n        var l = Log.Fn<CspParameters?>();\n        // Empty, skip\n        if (original == null || !original.HasKeys())\n            return l.Return(original, \"none\");\n        var merged = MergedWithAll(original);\n        var deduped = DeduplicateValues(merged);\n        return l.ReturnAsOk(deduped);\n    }\n\n    [return: NotNullIfNotNull(nameof(original))]\n    public CspParameters? MergedWithAll(CspParameters? original)\n    {\n        var l = Log.Fn<CspParameters?>();\n        // Empty, skip\n        if (original == null || !original.HasKeys())\n            return l.Return(original, \"none\");\n            \n        // Create copy and remove the All from it\n        var copy = new CspParameters(original);\n        copy.Remove(CspConstants.AllSrcName);\n\n        // No values, skip\n        var values = original\n            .GetValues(CspConstants.AllSrcName)\n            ?.Where(v => !string.IsNullOrWhiteSpace(v))\n            .ToArray();\n        if (values == null || values.Length == 0) return l.Return(copy, \"no values\");\n\n        // Make sure the default exists, as it must get all values from the all\n        copy.Add(CspConstants.DefaultSrcName, null);\n\n        // Get the keys which should receive the all-src params\n        // Note that most end with -src, but some have -src-elem or something, so we use .Contains\n        var existingSrcKeys = copy.AllKeys\n            .Where(s => s.HasValue() && s.Contains(CspConstants.SuffixSrc));   \n        foreach (var key in existingSrcKeys)\n        foreach (var value in values)\n            copy.Add(key, value);\n        return l.ReturnAsOk(copy);\n    }\n\n    [return: NotNullIfNotNull(nameof(original))]\n    public CspParameters? DeduplicateValues(CspParameters? original)\n    {\n        var l = Log.Fn<CspParameters?>();\n        // Empty, skip\n        if (original == null || !original.HasKeys())\n            return l.Return(original, \"none\");\n        var copy = new CspParameters(original);\n        var keys = copy.AllKeys;\n        var dedupeCount = 0;\n        foreach (var key in keys)\n        {\n            var values = copy.GetValues(key);\n            if (values == null || values.Length == 0) continue;\n            var groupsOfSameValues = values\n                .SelectMany(v => v.Split(' '))\n                .GroupBy(v => v)\n                .ToList();\n\n            // Don't modify if none are duplicate\n            if (!groupsOfSameValues.Any(g => g.Count() > 1)) continue;\n            copy.Remove(key);\n\n            foreach (var value in groupsOfSameValues) \n                copy.Add(key, value.Key);\n            dedupeCount++;\n        }\n\n        return l.Return(copy, $\"deduped {dedupeCount}\");\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/CspParameters.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CspParameters: NameValueCollection\n{\n    public CspParameters() { }\n\n    public CspParameters(NameValueCollection originals) : base(originals) { }\n\n    public override string ToString() =>\n        UrlHelpers.NvcToString(this, \" \", \"; \", \";\", \"\", false, \" \");\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/CspPolicyTextProcessor.cs",
    "content": "﻿\nnamespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CspPolicyTextProcessor(ILog parentLog) : HelperBase(parentLog, $\"{CspConstants.LogPrefix}.TxtPrc\")\n{\n    public List<KeyValuePair<string,string>> Parse(string policyText)\n    {\n        var l = Log.Fn<List<KeyValuePair<string, string>>>();\n\n        var result = new List<KeyValuePair<string,string>>();\n        if (policyText.IsEmpty())\n            return result;\n        var lines = policyText.SplitNewLine()\n            // Remove spaces in front and end, + trailing ';'\n            .Select(line => line.Trim().TrimEnd(';'))\n            // Remove comment lines\n            .Where(line => !line.StartsWith(\"//\"))\n            // Keep only real lines\n            .Where(line => line.HasValue())\n            .ToArray();\n\n        foreach (var line in lines)\n        {\n            var splitIndex = line.IndexOfAny([':', ' ']);\n            if (splitIndex == -1 || splitIndex >= line.Length)\n                continue;\n            var key = line.Substring(0, splitIndex);\n            var value = line.Substring(splitIndex + 1).Trim();\n            result.Add(new(key, value));\n        }\n\n        return l.Return(result, result.Count.ToString());\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/CspSettingsReader.cs",
    "content": "﻿using ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n/// <summary>\n/// Helper class to read the dynamic settings for the current site or global to be used in CSP\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class CspSettingsReader(ICanGetByName? settingsStackOrNull, IUser user, bool devMode, ILog parentLog)\n    : HelperBase(parentLog, $\"{CspConstants.LogPrefix}.Setting\")\n{\n    private const string FieldIsEnabled = \"IsEnabled\";\n    private const string FieldIsEnforced = \"IsEnforced\";\n    private const string FieldPolicies = \"Policies\";\n    private const string FieldContentSecurityPolicies = \"ContentSecurityPolicies\";\n\n    // Enable this for edge cases where we must debug deeply into each settings-stack\n    // if (_settingsOrNull != null) _settingsOrNull.Debug = true;\n\n    public bool IsEnabled => GetFromPreferredOrDefaultSource(FieldIsEnabled) as bool? == true;\n\n    public bool IsEnforced => GetFromPreferredOrDefaultSource(FieldIsEnforced) as bool? == true;\n\n    public string? Policies => GetFromPreferredOrDefaultSource(FieldPolicies) as string;\n\n    /// <summary>\n    /// Get bool / string settings from the preferred settings or the default settings\n    /// </summary>\n    /// <param name=\"field\"></param>\n    /// <returns></returns>\n    private object? GetFromPreferredOrDefaultSource(string field)\n    {\n        var cLog = Log.Fn<object>(field);\n\n        var pref = SettingPreferred;\n        if (pref.Entity?.Get(field) is { } result)\n            return cLog.Return(result, $\"Preferred[{pref.Name}]: {result}\");\n\n        if (SettingsDefault?.Get(field) is { } result2)\n            return cLog.Return(result2, $\"Default Source: {result2}\");\n\n        return cLog.ReturnNull(\"not found\");\n    }\n\n    private (string Name, /*DynamicEntity Setting,*/ IEntity? Entity) SettingPreferred => _preferred.Get(Log, () =>\n    {\n        Log.A($\"Dev: {devMode}; Super: {user.IsSystemAdmin}; Admin: {user.IsSiteAdmin}; Anon: {user.IsAnonymous}\");\n\n        if (devMode)\n            return GetName(\"Dev\");\n        if (user.IsSystemAdmin)\n            return GetName(\"SystemAdmin\");\n        if (user.IsSiteAdmin)\n            return GetName(\"SiteAdmin\");\n        if (user.IsAnonymous)\n            return GetName(\"Anonymous\");\n        return (\"none\", /*null,*/ null);\n\n        (string Name, /*DynamicEntity Setting,*/ IEntity? Entity) GetName(string theName)\n            => (theName, (SettingsRoot?.Get(theName) as ICanBeEntity /*DynamicEntity*/)?.Entity);\n    });\n    private readonly GetOnce<(string Name, /*DynamicEntity Setting,*/ IEntity? Entity)> _preferred = new();\n\n    /// <summary>\n    /// The fallback settings, which will be null if in devMode, because then we shouldn't do a fallback\n    /// </summary>\n    private ICanGetByName? SettingsDefault => devMode\n        ? null\n        : _default.Get(() => SettingsRoot?.Get(\"Default\") as ICanGetByName /*DynamicEntity*/);\n    private readonly GetOnce<ICanGetByName?> _default = new();\n\n    private ICanGetByName? SettingsRoot => _settingsRoot.Get(Log,\n        () => settingsStackOrNull?.Get(FieldContentSecurityPolicies) as ICanGetByName /*DynamicEntity*/\n    );\n    private readonly GetOnce<ICanGetByName?> _settingsRoot = new();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.ContentSecurityPolicy/IContentSecurityPolicyService.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\n[PrivateApi(\"The service isn't publicly documented, as the functionality happens on the IPageService object\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IContentSecurityPolicyService\n{\n    /// <summary>\n    /// You can determine if CSP should report only. You cannot change it in code.\n    ///\n    /// To enable, do this in the settings (Global or Site)\n    /// </summary>\n    bool IsEnforced { get; }\n\n    /// <summary>\n    /// Tells you if CSP is enabled or not. You cannot change it in code.\n    ///\n    /// To enable, do this in the settings (Global or Site)\n    /// </summary>\n    bool IsEnabled { get; }\n\n    CspParameters Policy { get; }\n\n    /// <summary>\n    /// Add a CSP rule where you also specify the name.\n    ///\n    /// Example: `cspService.Add(\"default-src\", \"'self'\")`\n    ///\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"values\"></param>\n    void Add(string name, params string[] values);\n\n    //[PrivateApi]\n    //IHybridHtmlString WhitelistAttribute\n\n    #region Specific Commands, probably not needed - will disable for now while it's not yet a public API\n\n    //void DefaultSrc(params string[] values);\n    //void ChildSrc(params string[] values);\n    //void ConnectSrc(params string[] values);\n    //void FontSrc(params string[] values);\n    //void FrameSrc(params string[] values);\n    //void ImgSrc(params string[] values);\n    //void ManifestSrc(params string[] values);\n    //void MediaSrc(params string[] values);\n    //void ObjectSrc(params string[] values);\n    //void PrefetchSrc(params string[] values);\n    //void ScriptSrc(params string[] values);\n    //void ScriptSrcElem(params string[] values);\n    //void ScriptSrcAttr(params string[] values);\n    //void StyleSrc(params string[] values);\n    //void StyleSrcElem(params string[] values);\n    //void StyleSrcAttr(params string[] values);\n    //void WorkerSrc(params string[] values);\n    //void BaseUri(params string[] values);\n    //void FormAction(params string[] values);\n    //void FrameAncestors(params string[] values);\n    //void NavigateTo(params string[] values);\n    //void ReportTo(params string[] values);\n    //void RequireTrustedTypesFor(params string[] values);\n    //void Sandbox(params string[] values);\n    //void TrustedTypes(params string[] values);\n    //void UpgradeInsecureRequests();\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.HtmlParsing/RegexUtil.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Sxc.Render.Sys.Output;\n\nnamespace ToSic.Sxc.Web.Sys.HtmlParsing;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class RegexUtil\n{\n    /// <summary>\n    /// Used in ScriptSrc and StyleSrc Formulas\n    /// </summary>\n    public const string SrcKey = \"Src\";\n\n    public const string IntegrityKey = \"Integrity\";\n\n    // language=regex\n    private const string AttributesFormula = \"\\\\s(?<Key>[\\\\w-]+(?=[^<]*>))=([\\\"'])(?<Value>.*?[^\\\\1][\\\\s\\\\S]+?)\\\\1|\\\\s(?<Key>[\\\\w-]+(?=.*?))\";\n    // language=regex\n    private const string ImagesWithDataCmsidFormula = \"<img[^>]*data-cmsid=['\\\"](?<cmsid>[^'\\\"]+)['\\\"][^>]*>\";\n    // language=regex\n    private const string ScriptSrcFormula = \"<script\\\\s([^>]*)src=('|\\\")(?<Src>.*?)('|\\\")(([^>]*/>)|[^>]*(>.*?</script>))\";\n    // language=regex\n    private const string IntegrityAttributeFormula = \"(?<Integrity>integrity=('|\\\").*?('|\\\"))\";\n\n    // language=regex\n    private const string ScriptContentFormula = @\"<script[^>]*>(?<Content>(.|\\n)*?)</script[^>]*>\";\n    // language=regex\n    private const string StyleSrcFormula = \"<link\\\\s([^>]*)href=('|\\\")(?<Src>.*?)('|\\\")([^>]*)(>.*?</link>|/?>)\";\n    // language=regex\n    private const string StyleRelFormula = \"('|\\\"|\\\\s)rel=('|\\\")stylesheet('|\\\")\";\n    // language=regex\n    private const string IdFormula = \"('|\\\"|\\\\s)id=('|\\\")(?<Id>.*?)('|\\\")\";\n    // language=regex\n    private const string ClientDependencyRegex =\n        \"\\\\s\" + ClientAssetConstants.AssetOptimizationsAttributeName + \"=('|\\\")(?<Priority>true|[0-9]+)?(?::)?(?<Position>bottom|head|body)?('|\\\")(>|\\\\s)\";\n\n    public const string PriorityKey = \"Priority\";\n    public const string PositionKey = \"Position\";\n\n    public static readonly Lazy<Regex> AttributesDetection = new(() => new(AttributesFormula, RegexOptions.IgnoreCase));\n    public static readonly Lazy<Regex> ImagesDetection = new(() => new(ImagesWithDataCmsidFormula, RegexOptions.IgnoreCase));\n    public static readonly Lazy<Regex> ScriptSrcDetection = new(() => new(ScriptSrcFormula, RegexOptions.IgnoreCase | RegexOptions.Singleline));\n    // note: 2dm created this, because I wasn't sure if changing the original to ML would have side effects\n    public static Regex ScriptSrcDetectionMultiLine = new(ScriptSrcFormula, RegexOptions.IgnoreCase | RegexOptions.Multiline);\n\n    public static readonly Lazy<Regex> ScriptContentDetection = new(() => new(ScriptContentFormula, RegexOptions.IgnoreCase | RegexOptions.Multiline));\n    public static readonly Lazy<Regex> StyleDetection = new(() => new(StyleSrcFormula, RegexOptions.IgnoreCase | RegexOptions.Singleline));\n    // note: 2dm created this, because I wasn't sure if changing the original to ML would have side effects\n    public static Regex StyleDetectionMultiLine = new(StyleSrcFormula, RegexOptions.IgnoreCase | RegexOptions.Multiline);\n    public static Regex IntegrityAttribute = new(IntegrityAttributeFormula, RegexOptions.IgnoreCase | RegexOptions.Singleline);\n    public static readonly Lazy<Regex> StyleRelDetect = new(() => new(StyleRelFormula, RegexOptions.IgnoreCase));\n    public static readonly Lazy<Regex> OptimizeDetection = new(() => new(ClientDependencyRegex, RegexOptions.IgnoreCase));\n    public static readonly Lazy<Regex> IdDetection = new(() => new(IdFormula, RegexOptions.IgnoreCase));\n\n    //// language=regex\n    //private const string WysiwygWidthNumFormula = \"wysiwyg-width(?<num>\\\\d+)of(?<all>\\\\d+)\";\n    //private static readonly Lazy<Regex> WysiwygWidthNumDetectionLazy = new Lazy<Regex>(() => new Regex(WysiwygWidthNumFormula, RegexOptions.IgnoreCase));\n    //public static Regex WysiwygWidthNumDetection => WysiwygWidthNumDetectionLazy.Value;\n\n    // language=regex\n    private const string WysiwygWidthFormula = \"wysiwyg-(?<percent>\\\\d+)\";\n    public static readonly Lazy<Regex> WysiwygWidthLazy = new(() => new(WysiwygWidthFormula, RegexOptions.IgnoreCase));\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageFeatures/IPageFeaturesManager.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageFeatures;\n\nnamespace ToSic.Sxc.Web.Sys.PageFeatures;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPageFeaturesManager\n{\n    IReadOnlyDictionary<string, IPageFeature> Features { get; }\n        \n    List<IPageFeature> GetWithDependents(List<string> keys);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageFeatures/PageFeatures.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\n\nnamespace ToSic.Sxc.Web.Sys.PageFeatures;\n\n[PrivateApi(\"Internal stuff, hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class PageFeatures(IPageFeaturesManager pfm) : IPageFeatures\n{\n    /// <inheritdoc />\n    public IEnumerable<string> Activate(string[] keys)\n    {\n        var realKeys = keys.TrimmedAndWithoutEmpty();\n        FeatureKeysRecent.AddRange(realKeys);\n        return realKeys;\n    }\n\n    /// <summary>\n    /// Must be a real List, because it will be modified.\n    /// </summary>\n    private List<PageFeatureFromSettings> FeaturesFromSettings { get; } = [];\n\n    private List<PageFeatureFromSettings> FeaturesFromSettingsProcessed { get; } = [];\n\n    public void FeaturesFromSettingsAdd(PageFeatureFromSettings newFeature)\n        => FeaturesFromSettings.Add(newFeature);\n\n    /// <summary>\n    /// Get the manual features which were added - skip those which were previously already added\n    /// </summary>\n    /// <param name=\"specs\"></param>\n    /// <param name=\"log\"></param>\n    /// <returns></returns>\n    internal List<PageFeatureFromSettings> FeaturesFromSettingsGetNew(RenderSpecs specs, ILog log)\n    {\n        var l = log.Fn<List<PageFeatureFromSettings>>();\n        // Filter out the ones which were already added in a previous round\n        var newFeatures = FeaturesFromSettings\n            // 2025-08-17 2dm changed detection of already-processed because it resulted in changing the original object which caused problems in caching\n            .Where(f => !FeaturesFromSettingsProcessed.Any(p => ReferenceEquals(p, f))) // only keep the groups which only have false\n            .ToList();\n\n        // Mark the new ones as processed now, so they won't be processed in the future, except for Oqtane where we will keep it all\n        if (!specs.IncludeAllAssetsInOqtane)\n            FeaturesFromSettingsProcessed.AddRange(newFeatures);\n\n        newFeatures = newFeatures\n            // Put duplicates together\n            .GroupBy(f => f.NameId)\n            // Only process the groups which have none that were already processed (old before 2025-08-17)\n            //.Where(g => g.All(f => !f.AlreadyProcessed )) // only keep the groups which only have false\n            // Keep only one of the group to then process\n            .Select(g => g.First())\n            .ToList();\n\n        return l.Return(newFeatures, $\"{newFeatures.Count}\");\n    }\n\n    /// <summary>\n    /// The recently added feature keys.\n    /// Will be flushed regularly, as each module will make sure that it's added to the page.\n    /// </summary>\n    private List<string> FeatureKeysRecent { get; } = [];\n\n\n\n    public List<IPageFeature> GetFeaturesWithDependentsAndFlush(ILog log)\n    {\n        var l = log.Fn<List<IPageFeature>>();\n        var unfolded = GetWithDependents([.. FeatureKeysRecent], log);\n        FeatureKeysRecent.Clear();\n        return l.Return(unfolded);\n    }\n\n    /// <inheritdoc />\n    public List<IPageFeature> GetWithDependents(List<string> features, ILog log)\n    {\n        var l = log.Fn<List<IPageFeature>>($\"Got {features.Count} items\");\n        var unfolded = pfm.GetWithDependents(features);\n        return l.Return(unfolded, $\"Got unfolded features {unfolded.Count}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageFeatures/PageFeaturesCatalog.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sys.Run.GlobalState;\nusing static ToSic.Sxc.Sys.Render.PageFeatures.SxcPageFeatures;\n\nnamespace ToSic.Sxc.Web.Sys.PageFeatures;\n\n/// <summary>\n/// Important: This is a singleton!\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PageFeaturesCatalog: GlobalCatalogBase<IPageFeature>\n{\n    /// <summary>\n    /// Constructor - ATM we'll just add our known services here.\n    ///\n    /// </summary>\n    /// <remarks>\n    /// Important: if you want to add more services in a DI Startup, it must happen at Configure.\n    /// If you do it earlier, the singleton retrieved then will not be the one at runtime.\n    /// </remarks>\n    public PageFeaturesCatalog(ILogStore logStore): base(logStore, SxcLogName + \".PftCat\", new())\n    {\n        Register(\n            JQuery,\n            ContextPage,\n            ContextModule,\n            JsApiOnModule,\n            JsCore,\n            JsCms,\n            JsCmsInternal,\n            Toolbars,\n            ToolbarsInternal,\n            ToolbarsAuto,\n            ToolbarsAutoInternal,\n            TurnOn,\n            CmsWysiwyg,\n            Lightbox,\n            EncryptFormData\n        );\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageFeatures/PageFeaturesManager.cs",
    "content": "﻿\nusing ToSic.Sxc.Sys.Render.PageFeatures;\n\nnamespace ToSic.Sxc.Web.Sys.PageFeatures;\n\n/// <summary>\n/// Constructor - ATM we'll just add our known services here. \n/// </summary>\ninternal class PageFeaturesManager(PageFeaturesCatalog catalog) : IPageFeaturesManager\n{\n    /// <inheritdoc />\n    public IReadOnlyDictionary<string, IPageFeature> Features => catalog.Dictionary;\n\n    public List<IPageFeature> GetWithDependents(List<string> keys)\n    {\n        if (keys == null || !keys.Any()) return [];\n        var collected = Get(keys).Internal;\n\n        var added = collected;\n            \n        // Go max 5 levels deep\n        for (var i = 0; i < 5; i++)\n        {\n            added = GetMissingDependencies(collected, added).Internal;\n            if (!added.Any()) break;\n            collected.AddRange(added);\n        }\n        return collected.Distinct().ToList();\n    }\n\n    private (List<IPageFeature> Internal, List<IPageFeature> External) GetMissingDependencies(IReadOnlyCollection<IPageFeature> target, IEnumerable<IPageFeature> toCheck)\n    {\n        // See what we still need\n        var requiredKeys = toCheck\n            .SelectMany(f => f.Needs)\n            .ToArray();\n            \n        // Skip those already in the target\n        var missing = requiredKeys\n            .Where(si => !target.Any(c => c.NameId.EqualsInsensitive(si)))\n            .ToArray();\n        return Get(missing);\n    }\n\n    private (List<IPageFeature> Internal, List<IPageFeature> External) Get(IEnumerable<string> keys)\n    {\n        //return Features.Values\n        //    .Where(f => keys.Contains(f.NameId, StringComparer.InvariantCultureIgnoreCase))\n        //    .ToList();\n\n        var split = Features.Values\n            .GroupBy(f => keys.Contains(f.NameId, StringComparer.InvariantCultureIgnoreCase))\n            .ToList();\n\n        var result =\n        (\n            split.FirstOrDefault(g => g.Key)?.ToList() ?? [],\n            split.FirstOrDefault(g => !g.Key)?.ToList() ?? []\n        );\n        return result;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageService/PageChangeSummary.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.ModuleHtml;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.ClientAssets;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing ToSic.Sxc.Web.Sys.PageServiceShared;\nusing ToSic.Sys.Requirements;\nusing static ToSic.Sxc.Render.Sys.Output.ClientAssetConstants;\nusing Services_ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Web.Sys.PageService;\n\n/// <summary>\n/// This should bundle all the page changes once a module is done.\n/// Usually used at the top-level of render-result, and in future also on page-level dynamic code\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PageChangeSummary(\n    LazySvc<IBlockResourceExtractor> resourceExtractor,\n    LazySvc<RequirementsService> requirements,\n    IModuleHtmlService moduleHtmlService)\n    : Services_ServiceBase(SxcLogName + \"PgChSm\", connect: [requirements, resourceExtractor, moduleHtmlService])\n{\n    /// <summary>\n    /// Finalize the page and get all changes such as header modifications etc.\n    /// </summary>\n    /// <param name=\"moduleId\">The module ID to check for any output caching instructions; use `0` if it should be ignored.</param>\n    /// <param name=\"pss\"></param>\n    /// <param name=\"specs\"></param>\n    /// <param name=\"enableEdit\"></param>\n    /// <returns></returns>\n    public RenderResult FinalizeAndGetAllChanges(int moduleId, IPageServiceShared pss, RenderSpecs specs, bool enableEdit)\n    {\n        var l = Log.Fn<RenderResult>(timer: true);\n        if (enableEdit)\n            pss.PageFeatures.Activate([\n                SxcPageFeatures.ToolbarsInternal.NameId,\n                SxcPageFeatures.ToolbarsAutoInternal.NameId\n            ]);\n\n        var assets = pss.GetAssetsAndFlush();\n        var newPageFeaturesFromSettings = ((PageFeatures.PageFeatures)pss.PageFeatures).FeaturesFromSettingsGetNew(specs, Log);\n        var (newAssets, rest) = ConvertSettingsAssetsIntoReal(newPageFeaturesFromSettings, specs);\n\n        assets.AddRange(newAssets);\n        assets = [.. assets.OrderBy(a => a.PosInPage)];\n\n        // Collect Warnings of page features which may require other features enabled\n        var features = pss.PageFeatures.GetFeaturesWithDependentsAndFlush(Log);\n\n        var errors = requirements.Value\n            .Check(features)\n            .Select(f => f.Message)\n            .ToList();\n\n        // New beta 2025-03-18 v19.03.03\n        var cacheSettings = moduleId != 0\n            ? ((ModuleHtmlService)moduleHtmlService).GetOutputCache(moduleId)\n            : null;\n\n        var csp = ((IPageServiceSharedInternal)pss).Csp;\n        var result = new RenderResult\n        {\n            Assets = assets,\n            FeaturesFromResources = rest,\n            Features = features,\n            HeadChanges = pss.GetHeadChangesAndFlush(Log),\n            PageChanges = pss.GetPropertyChangesAndFlush(Log),\n\n            HttpStatusCode = pss.HttpStatusCode,\n            HttpStatusMessage = pss.HttpStatusMessage,\n            HttpHeaders = pss.HttpHeaders,\n\n            // CSP settings\n            CspEnabled = csp.IsEnabled,\n            CspEnforced = csp.IsEnforced,\n            CspParameters = csp.CspParameters(),\n            Errors = errors,\n\n            // New 19.03.03\n            ModuleId = moduleId,                    // ModuleId for caching\n            OutputCacheSettings = cacheSettings,    // Additional output-cache settings (often null)\n        };\n\n        // Whitelist any assets which were officially ok, or which were from the settings\n        var additionalCsp = GetCspListFromAssets(assets);\n        if (additionalCsp != null)\n            result.CspParameters.Add(additionalCsp);\n\n        return l.Return(result);\n    }\n\n\n\n    private (List<ClientAsset> newAssets, List<PageFeatureFromSettings> rest) ConvertSettingsAssetsIntoReal(List<PageFeatureFromSettings> featuresFromSettings, RenderSpecs specs)\n    {\n        var l = Log.Fn<(List<ClientAsset> newAssets, List<PageFeatureFromSettings> rest)>($\"{featuresFromSettings.Count}\");\n        var newAssets = new List<ClientAsset>();\n        var withUpdatedHtml = featuresFromSettings\n            .Select(settingFeature =>\n            {\n                var autoOpt = settingFeature.AutoOptimize;\n                var extracted = resourceExtractor.Value.Process(\n                    settingFeature.Html ?? \"\",\n                    new(\n                        css: new(autoOpt, AddToBottom, CssDefaultPriority, false, false),\n                        js: new(autoOpt, AddToBottom, JsDefaultPriority, autoOpt, autoOpt)\n                    )\n                );\n                l.A($\"Feature: {settingFeature.Name} - assets extracted: {extracted.Assets.Count}\");\n                if (!extracted.Assets.Any())\n                    return settingFeature;\n\n                //// todo: If the original settings say we should auto-optimize, do this here\n                //if (settingFeature.AutoOptimize)\n                //    extracted.Assets.ForEach(a =>\n                //    {\n                //        if (!a.IsJs) return;\n                //        a.HtmlAttributes[\"defer\"] = \"test-defer\";\n                //        a.HtmlAttributes[\"async\"] = \"test-async\";\n                //    });\n\n                // All resources from the settings are seen as safe\n                // older code till 2025-03-17, not functional\n                //extracted.Assets.ForEach(a => a.WhitelistInCsp = true);\n                var assetsWithWhitelisting = extracted.Assets\n                    .Select(a => a with { WhitelistInCsp = true });\n\n                newAssets.AddRange(assetsWithWhitelisting);\n\n                // Reset the HTML to what's left after extracting the resources, except for Oqtane where we will keep it all\n                if (!specs.IncludeAllAssetsInOqtane)\n                    return settingFeature with { Html = extracted.Html };\n                return settingFeature;\n            })\n            .ToList();\n\n\n        var featsLeft = withUpdatedHtml\n            .Where(f => !string.IsNullOrWhiteSpace(f.Html))\n            //.Cast<IPageFeature>()\n            .ToList();\n\n        return l.Return((newAssets, featsLeft), $\"New: {newAssets.Count}; Rest: {featsLeft.Count}\");\n    }\n\n    private static CspParameters? GetCspListFromAssets(IReadOnlyCollection<ClientAsset>? assets)\n    {\n        if (assets == null || assets.Count == 0)\n            return null;\n        var toWhitelist = assets\n            .Where(a => a.WhitelistInCsp)\n            .Where(a => !a.Url.NeverNull().StartsWith(\"/\")) // skip local files\n            .ToList();\n        if (!toWhitelist.Any())\n            return null;\n        var whitelist = new CspParameters();\n        foreach (var asset in toWhitelist)\n            whitelist.Add((asset.IsJs ? \"script\" : \"style\") + \"-src\", asset.Url);\n\n        return whitelist;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageServiceShared/IPageServiceSharedInternal.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\nnamespace ToSic.Sxc.Web.Sys.PageServiceShared;\n\ninterface IPageServiceSharedInternal: IPageServiceShared\n{\n    CspOfModule Csp { get; }\n\n    /// <summary>\n    /// WIP v21.06\n    /// </summary>\n    PageUrlSpecs UrlSpecs { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageServiceShared/PageServiceShared.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing IFeaturesService = ToSic.Sxc.Services.IFeaturesService;\n\nnamespace ToSic.Sxc.Web.Sys.PageServiceShared;\n\n/// <summary>\n/// This controller should collect what all the <see cref=\"ToSic.Sxc.Services.IPageService\"/> objects do, for use on the final page\n/// It must be scoped, so that it's the same object across the entire page-lifecycle.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class PageServiceShared(IPageFeatures pageFeatures, IFeaturesService featuresService, CspOfModule csp)\n    : IPageServiceShared, IPageServiceSharedInternal, IChangeQueue\n{\n    internal readonly IFeaturesService FeaturesService = featuresService;\n\n    /// <summary>\n    /// The current page features\n    /// </summary>\n    public IPageFeatures PageFeatures { get; } = pageFeatures;\n\n    public CspOfModule Csp { get; } = csp;\n\n    [field: AllowNull, MaybeNull]\n    public string CspEphemeralMarker => field ??= new Random().Next(100000000, 999999999).ToString();\n\n    /// <summary>\n    /// How the changes given to this object should be processed.\n    /// </summary>\n    [PrivateApi(\"not final yet, will probably change\")]\n    public PageChangeModes ChangeMode { get; set; } = PageChangeModes.Auto;\n\n    [PrivateApi(\"not final yet\")]\n    protected PageChangeModes GetMode(PageChangeModes modeForAuto)\n        => ChangeMode switch\n        {\n            PageChangeModes.Default or PageChangeModes.Auto => modeForAuto,\n            PageChangeModes.Replace or PageChangeModes.Append or PageChangeModes.Prepend => ChangeMode,\n            _ => throw new ArgumentOutOfRangeException(nameof(ChangeMode), ChangeMode, null)\n        };\n\n    /// <summary>\n    /// WIP v21.06\n    /// </summary>\n    public PageUrlSpecs UrlSpecs { get; } = new();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageServiceShared/PageServiceShared_Assets.cs",
    "content": "﻿using ToSic.Sxc.Engines;\nusing ToSic.Sxc.Web.Sys.ClientAssets;\n\nnamespace ToSic.Sxc.Web.Sys.PageServiceShared;\n\npartial class PageServiceShared\n{\n    /// <summary>\n    /// Assets consolidated from all render-results \n    /// </summary>\n    private List<ClientAsset> Assets { get; } = [];\n\n    public List<ClientAsset> GetAssetsAndFlush()\n    {\n        var assets = new List<ClientAsset>(Assets);\n        Assets.Clear();\n        return assets;\n    }\n\n    public void AddAssets(RenderEngineResult result)\n    {\n        if (result?.Assets == null) return;\n        if (!result.Assets.Any()) return;\n        Assets.AddRange(result.Assets);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageServiceShared/PageServiceShared_Headers.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Web.Sys.PageServiceShared;\n\npartial class PageServiceShared\n{\n    /// <summary>\n    /// Must be a real List, since it will be modified.\n    /// </summary>\n    public List<HeadChange> Headers { get; } = [];\n\n    public IList<HeadChange> GetHeadChangesAndFlush(ILog log)\n    {\n        var l = log.Fn<IList<HeadChange>>();\n        var changes = Headers.ToArray().ToList();\n        Headers.Clear();\n        return l.Return(changes, $\"{changes.Count}\");\n    }\n\n\n    public HeadChange? Add(IHtmlTag? tag, string? identifier = null)\n    {\n        if (tag == null)\n            return null;\n        var headChange = new HeadChange\n        {\n            ChangeMode = GetMode(PageChangeModes.Append),\n            Tag = tag,\n            ReplacementIdentifier = identifier,\n        };\n        Headers.Add(headChange);\n        return headChange;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageServiceShared/PageServiceShared_Http.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Web.Sys.PageServiceShared;\n\npartial class PageServiceShared\n{\n    public int? HttpStatusCode { get; set; } = null;\n\n    public string? HttpStatusMessage { get; set; } = null;\n\n\n    #region Headers WIP / BETA\n\n    [PrivateApi]\n    internal void AddToHttp(string name, string value) =>\n        HttpHeaders.Add(new(name, value));\n\n    /// <summary>\n    /// Must be a real List, since it will be modified.\n    /// </summary>\n    [PrivateApi]\n    public List<HttpHeader> HttpHeaders { get; } = [];\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageServiceShared/PageServiceShared_Properties.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Web.Sys.PageServiceShared;\n\npartial class PageServiceShared\n{\n    /// <summary>\n    /// Must be a real List, since it will be modified.\n    /// </summary>\n    internal List<PagePropertyChange> PropertyChanges { get; } = [];\n\n    public IList<PagePropertyChange> GetPropertyChangesAndFlush(ILog log)\n    {\n        var l = log.Fn<IList<PagePropertyChange>>();\n        var changes = PropertyChanges.ToArray().ToList();\n        PropertyChanges.Clear();\n        return l.Return(changes, $\"{changes.Count}\");\n    }\n\n    /// <summary>\n    /// Add something to the queue for setting a page property\n    /// </summary>\n    public PagePropertyChange Queue(PageProperties property, string? value, PageChangeModes change, string? token)\n    {\n        var toAdd = new PagePropertyChange\n        {\n            ChangeMode = GetMode(change),\n            Property = property,\n            Value = value,\n            ReplacementIdentifier = token,\n        };\n        PropertyChanges.Add(toAdd);\n        return toAdd;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageServiceShared/PageUrlSpecs.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Configuration.Sys;\nusing ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Web.Sys.PageServiceShared;\n\npublic class PageUrlSpecs\n{\n\n    internal Dictionary<string, UrlParameterSpecs> Specs { get; } = new(StringComparer.InvariantCultureIgnoreCase);\n\n    public void Set(string key, string? values = null)\n        => Set(key, values?.Split(','));\n\n    public void Set(string key, IEnumerable<string>? values)\n    {\n        if (string.IsNullOrWhiteSpace(key))\n            return;\n\n        foreach (var k in key.CsvToArrayWithoutEmpty())\n            Specs[k] = new(k, values ?? []);\n    }\n\n    public void Add(string key, string? values = null)\n    {\n        if (string.IsNullOrWhiteSpace(key))\n            return;\n\n        // Try to get previous values\n        if (Specs.TryGetValue(key, out var existing))\n        {\n            // If there are existing values, combine them with the new ones\n            var combinedValues = existing.Values\n                .Concat((values ?? \"\").CsvToArrayWithoutEmpty())\n                .Distinct(StringComparer.InvariantCultureIgnoreCase);\n\n            Set(key, combinedValues);\n        }\n        else\n        {\n            // If there are no existing values, just set the new ones\n            Set(key, values);\n        }\n    }\n\n    public void LoadConfiguration(string configuration)\n    {\n        if (string.IsNullOrWhiteSpace(configuration))\n            return;\n\n        //var lines = ConfigStringHelpers.ConfigLinesWithoutComments(configuration);\n        //foreach (var line in lines)\n        //{\n        //    var pair = line.Split('=');\n        //    // it's very important that if there is no \"=\" then we must use null\n        //    // as that specifies that any value is possible, while an empty string would specify that only an empty value is possible\n        //    var value = pair.Length == 2 ? pair[1].Trim() : null;\n        //    Add(pair[0].Trim(), value);\n        //}\n\n        foreach (var line in ConfigStringHelpers.ConfigPairs(configuration))\n            Add(line.Key, line.Values);\n    }\n    \n    public void Remove(string key)\n    {\n        if (string.IsNullOrWhiteSpace(key))\n            return;\n        Specs.Remove(key);\n    }\n\n\n    public bool ContainsKey(string key)\n        => Specs.ContainsKey(key);\n\n    public string Keys() => string.Join(\",\", Specs.Keys);\n\n    public IEnumerable<string> Values(string key) =>\n        Specs.TryGetValue(key, out var value)\n            ? value.Values\n            : [];\n\n    public string? ValuesCsv(string key) =>\n        Specs.TryGetValue(key, out var value) && value.Values.Any()\n            ? string.Join(\",\", value.Values)\n            : null;\n\n    public IParameters GetInvalid(IParameters parameters) =>\n        GetExtract(parameters, true);\n\n    public IParameters GetValid(IParameters parameters) =>\n        GetExtract(parameters, false);\n\n    public IParameters GetExtract(IParameters parameters, bool getInvalid)\n    {\n        // find all parameters which are not in the expected list\n        var unexpected = parameters\n            .Where(pair => IsInvalid(pair.Key, pair.Value) == getInvalid);\n\n        // convert to NameValueCollection and return as IParameters\n        var nvc = new NameValueCollection();\n        foreach (var pair in unexpected)\n            nvc.Add(pair.Key, pair.Value);\n\n        var result = new Context.Sys.Parameters { Nvc = nvc };\n        //var result = (Context.Sys.Parameters)parameters with { Nvc = nvc };\n\n        return result;\n    }\n\n    private bool IsInvalid(string key, string value)\n    {\n        // Check if key exists - if not, it's unexpected\n        if (!Specs.TryGetValue(key, out var spec))\n            return true;\n\n        // Spec found, but name-casing may be off.\n        if (spec.Name != key || !spec.ForceNameLowerCase)\n            return true;\n\n        var values = spec.Values.ToArray();\n\n        // If there are no expected values, then any value is acceptable\n        if (!values.Any())\n            return false;\n\n        // Check if the parameter value is in the expected values\n        var comparer = spec.ValuesCaseVariationAllowed\n            ? StringComparer.InvariantCultureIgnoreCase\n            : StringComparer.InvariantCulture;\n\n        return !values.Contains(value, comparer);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web/Sys.PageServiceShared/UrlParameterSpecs.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.PageServiceShared;\n\npublic record UrlParameterSpecs(string Name, IEnumerable<string>? Values = null, bool ForceNameLowerCase = true, bool ValuesCaseVariationAllowed = false)\n{\n    public IEnumerable<string> Values { get; init; } = Values ?? [];\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web.Sys.LightSpeed/LightSpeedConfigHelper.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\ninternal class LightSpeedConfigHelper(ILog? parentLog) : HelperBase(parentLog, \"Sxc.LsCnRd\")\n{\n\n    public LightSpeedDecorator GetLightSpeedConfigOfApp(IAppReader? appReader)\n    {\n        var l = Log.Fn<LightSpeedDecorator>();\n        var decoFromPiggyBack = LightSpeedDecorator.GetFromAppStatePiggyBack(appReader);\n        return l.Return(decoFromPiggyBack, $\"has decorator: {(decoFromPiggyBack as ICanBeEntity)?.Entity != null!}\");\n    }\n\n    public LightSpeedDecorator? ViewConfigOrNull(IBlock? block)\n    {\n        var l = Log.Fn<LightSpeedDecorator?>();\n        if (block?.ViewIsReady != true)\n            return l.ReturnNull(\"view not ready\");\n            \n        var md = block.View.Metadata.FirstModel<LightSpeedDecorator>();\n\n        return md == null\n            ? l.ReturnNull($\"no view metadata for LightSpeedDecorator; view: {block.View.Id}\")\n            : l.Return(md, $\"entity: {md.Id}; view: {block.View.Id}\");\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Render/Web.Sys.LightSpeed/LightSpeedDecorator.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Services.OutputCache;\n\nnamespace ToSic.Sxc.Web.Sys.LightSpeed;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[ModelSpecs(ContentType = ContentTypeNameId)]\npublic record LightSpeedDecorator : ModelFromEntityBasic, IOutputCacheSettings\n{\n    /// <summary>\n    /// Nice name. If it ever changes, remember to also update UI as it has references to it.\n    /// </summary>\n    public const string ContentTypeName = \"LightSpeedOutputDecorator\";\n    public const string ContentTypeNameId = \"be34f64b-7d1f-4ad0-b488-dabbbb01a186\";\n\n    public bool IsEnabled => GetThis(false);\n\n    public bool? IsEnabledNullable => Get(nameof(IsEnabled), fallback: null as bool?);\n\n    public int Duration => GetThis(0);\n\n    public int DurationUsers => GetThis(0);\n\n    public int DurationEditors => GetThis(0);\n\n    public int DurationSystemAdmin => GetThis(0);\n\n    public bool ByUrlParameters => GetThis(false);\n\n    public bool UrlParametersCaseSensitive => GetThis(false);\n\n    public string UrlParameterNames => GetThis(\"\");\n\n    public bool UrlParametersOthersDisableCache => GetThis(true);\n\n    public IReadOnlyCollection<string> ExternalDependencyKeys => [];\n\n    public string Advanced => GetThis(\"\");\n\n    public static LightSpeedDecorator GetFromAppStatePiggyBack(IAppReader? appReader)\n    {\n        var appState = appReader?.GetCache();\n        var decoFromPiggyBack = appState?.PiggyBack\n            .GetOrGenerate(appState, $\"decorator-{ContentTypeNameId}\", () => appState.Metadata.FirstModel<LightSpeedDecorator>())\n            .Value;\n        return decoFromPiggyBack ?? new LightSpeedDecorator();\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.RenderTests/Configuration.Sys/ConfigStringHelpersTests.cs",
    "content": "﻿namespace ToSic.Sxc.Configuration.Sys;\n\npublic class ConfigStringHelpersTests\n{\n    [Theory]\n    //[InlineData(\"\", \"\")]\n    [InlineData(\"value\", \"value\")]\n    //[InlineData(\"value//comment\", \"value\")]\n    [InlineData(\"value //comment\", \"value\")]\n    [InlineData(\"value  //comment\", \"value\")]\n    [InlineData(\"value,another\", \"value,another\")]\n    [InlineData(\"value\\nanother\", \"value|another\")] // need bar to separate, because comma could be used\n    public void BasicSingleLine(string input, string expected)\n    {\n        var result = ConfigStringHelpers.ConfigLinesWithoutComments(input);\n        //Single(result);\n        Equal(expected.Split('|'), result);\n    }\n\n    [Theory]\n    [InlineData(\"value\\nanother\", \"value,another\")]\n    [InlineData(\"value\\n\\nanother\", \"value,another\")]\n    [InlineData(\"\\nvalue\\nanother\", \"value,another\")]\n    [InlineData(\"\\nvalue\\nanother\\n\", \"value,another\")]\n    [InlineData(\"\\n\\n\\nvalue\\nanother\\n\\n\", \"value,another\")]\n    [InlineData(\"value // comment\\nanother\", \"value,another\")]\n    [InlineData(\"value // comment\\nanother // comment2\", \"value,another\")]\n    [InlineData(\"\\nvalue // comment\\nanother // comment2\\n\", \"value,another\")]\n    public void BasicMultiLine(string input, string expected)\n    {\n        var result = ConfigStringHelpers.ConfigLinesWithoutComments(input);\n        Equal(2, result.Count);\n        Equal(expected.Split(','), result);\n    }\n\n    [Theory]\n    [InlineData(\"key=value\", \"value\")]\n    [InlineData(\"key=value // comment\", \"value\")]\n    [InlineData(\"key=value,value2 // comment\", \"value,value2\")]\n    [InlineData(\"key=value // comment\\nanother\", \"value\")]\n    public void Values(string input, string expected)\n    {\n        var result = ConfigStringHelpers.ConfigPairs(input);\n        Equal(expected, result[0].Values);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.RenderTests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using static Xunit.Assert;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.RenderTests/ToSic.Sxc.RenderTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForTestCode.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.RenderTests/Web.Sys.PageSpecsTests/PageSpecsComparison.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sxc.Web.Sys.PageServiceShared;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.Web.Sys.PageSpecsTests;\n\npublic class PageSpecsComparison(ITestOutputHelper output)\n{\n\n    [Theory]\n    [InlineData(\"id\", \"id\", 0)]\n    [InlineData(\"id\", \"ID\", 1)]\n    [InlineData(\"id\", \"unexpected\", 1)]\n    [InlineData(\"id,id2\", \"id\", 0)]\n    [InlineData(\"id,id2\", \"id2\", 0)]\n    [InlineData(\"id,id2\", \"id,id2\", 0)]\n    [InlineData(\"id,id2\", \"id2,id\", 0)]\n    [InlineData(\"id,id2\", \"id2,unexpected\", 1)]\n    public void CompareWithParameterKeys(string inSpecs, string inParams, int expected)\n    {\n        // Prepare Parameters\n        IParameters pagePars = new Context.Sys.Parameters();\n        pagePars = inParams.Split(',').Aggregate(pagePars, (current, s) => current.Add(s, 42));\n\n        var specs = new PageUrlSpecs();\n        specs.Add(inSpecs);\n\n        var unexpected = specs.GetInvalid(pagePars);\n\n        output.WriteLine($\"allowed: '{specs.Keys()}'\");\n\n        Equal(expected, unexpected.Count());\n    }\n\n    [Theory]\n    [InlineData(\"variant\", \"typed,dyn\", \"dyn\", true)]\n    [InlineData(\"variant\", \"typed,dyn\", \"typed\", true)]\n    [InlineData(\"variant\", \"typed,dyn\", \"TYPED\", false)]\n    [InlineData(\"variant\", \"typed,dyn\", \"unexpected\", false)]\n    public void CompareWithParameterValues(string inSpecs, string inParams, string valueToCheck, bool expected)\n    {\n        // Prepare Parameters\n        var pagePars = new Context.Sys.Parameters()\n            .Add(\"tut\", \"basics-linking\")\n            .Add(inSpecs, valueToCheck);\n\n        var specs = new PageUrlSpecs();\n        specs.Add(\"tut\"); // allow all parameters with name \"tut\"\n        specs.Add(inSpecs, inParams);\n        var unexpected = specs.GetInvalid(pagePars);\n        output.WriteLine($\"allowed: '{specs.Keys()}'\");\n        if (expected)\n            Empty(unexpected);\n        else\n            NotEmpty(unexpected);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.RenderTests/Web.Sys.PageSpecsTests/PageSpecsTests.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.PageServiceShared;\n\nnamespace ToSic.Sxc.Web.Sys.PageSpecsTests;\n\npublic class PageSpecsTests\n{\n    private const string Id = \"id\";\n\n    [Fact]\n    public void InitiallyEmpty()\n    {\n        var c = new PageUrlSpecs();\n        Empty(c.Specs);\n        False(c.ContainsKey(Id));\n        Null(c.ValuesCsv(Id));\n    }\n\n    [Fact]\n    public void SetNull()\n    {\n        var c = new PageUrlSpecs();\n        c.Set(Id);\n        True(c.ContainsKey(Id));\n        Null(c.ValuesCsv(Id));\n    }\n\n    [Fact]\n    public void SetValue()\n    {\n        var c = new PageUrlSpecs();\n        c.Set(Id, \"42\");\n        True(c.ContainsKey(Id));\n        Equal(\"42\", c.ValuesCsv(Id));\n    }\n\n    [Fact]\n    public void SetValues()\n    {\n        var c = new PageUrlSpecs();\n        c.Set(Id, \"param1,param2\");\n        True(c.ContainsKey(Id));\n        Equal(\"param1,param2\", c.ValuesCsv(Id));\n    }\n\n    [Theory]\n    [InlineData(\"42\", \"42\", \"\")]\n    [InlineData(\"42\", \"42\", null)]\n    [InlineData(\"42,43\", \"42\", \"43\")]\n    [InlineData(\"42,43,44\", \"42\", \"43,44\")]\n    [InlineData(\"42,47,43,44\", \"42,47\", \"43,44\")]\n    public void SetAddExtends(string expected, string first, string add)\n    {\n        var c = new PageUrlSpecs();\n        c.Set(Id, first);\n        c.Add(Id, add);\n        True(c.ContainsKey(Id));\n        Equal(expected, c.ValuesCsv(Id));\n    }\n\n    [Fact]\n    public void SetSetReplaces()\n    {\n        var c = new PageUrlSpecs();\n        c.Set(Id, \"42\");\n        c.Set(Id, \"43\");\n        True(c.ContainsKey(Id));\n        Equal(\"43\", c.ValuesCsv(Id));\n    }\n\n    [Theory]\n    [InlineData(\"\", null, null)]\n    [InlineData(\"\", \"\", \"\")]\n    [InlineData(\"\", \"\", null)]\n    [InlineData(\"\", null, \"\")]\n    [InlineData(\"param1\", \"param1\", \"param1\")]\n    [InlineData(\"param1\", \"param1\", \"\")]\n    [InlineData(\"param1\", \"\", \"param1\")]\n    [InlineData(\"param1\", \"param1\", null)]\n    [InlineData(\"param1,param2,param3\", \"param1,param2\", \"param2,param3\")]\n    [InlineData(\"param2,param1,param3\", \"param2,param1\", \"param2,param3\")]\n    public void SetManyKeys(string expected, string keys1, string keys2)\n    {\n        var c = new PageUrlSpecs();\n        c.Set(keys1);\n        c.Add(keys2);\n        //True(c.ContainsKey(AllowedUrlParameters));\n        Equal(expected, c.Keys());\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Code.Razor.Sys/RenderPartialSpecsWithCaching.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys.Specs;\nusing ToSic.Sxc.Services.Cache;\n\nnamespace ToSic.Sxc.Code.Razor.Sys;\n\n/// <summary>\n/// Extends the PartialSpecs with caching capabilities.\n///\n/// It is not quite correct in the Services.dll - but this is the best option since it's accessibly by all code which will need it.\n/// </summary>\npublic record RenderPartialSpecsWithCaching: RenderPartialSpecs\n{\n    /// <summary>\n    /// Cache Specs for the partial render.\n    /// </summary>\n    /// <remarks>\n    /// Must allow set, as it is modified at runtime if the razor requests caching.\n    /// </remarks>\n    public required ICacheSpecs CacheSpecs { get; set; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Demo/ToolbarServiceExtensions.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Demo;\n\n/// <summary>\n/// Demo extensions to help in tutorials with the ToolbarService.\n///\n/// Not meant for production, could change at any time. \n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class ToolbarServiceExtensions\n{\n    /// <summary>\n    /// Internal API for the Tutorials. Sets UI settings - mainly \"show=always\" - to better demonstrate what the toolbar does.\n    /// </summary>\n    /// <param name=\"toolbarService\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"ui\"></param>\n    /// <remarks>\n    /// Created for 14.08, used in the tutorial starting 2022-08-23.\n    /// As of 2025-05-26 it's still used extensively, so we must preserve it as of now.\n    /// </remarks>\n    public static void ActivateDemoMode(this IToolbarService toolbarService, \n        NoParamOrder npo = default,\n        string? ui = null\n    )\n    {\n        if (toolbarService is not ToolbarService typed)\n            return;\n        typed._setDemoDefaults(ui);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Demo/readme.md",
    "content": "﻿# Demo - ToSic.Sxc.Demo\n\nThis contains helper APIs meant purely to activate internal features\nfor demo scenarios. \n\nIt's mainly to help the tutorials behave in special ways which would not normally work. \n\nAnything that's in this namespace is not meant for public use. "
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Wrappers;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Properties/SxcServicesInternalsVisibleTo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n//[assembly: InternalsVisibleTo(\"ToSic.Sxc.Custom\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Code\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.WebApi\")]\n\n//[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.Core\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Oqtane.Server\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.UnitTests\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Various.SystemTests\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/CacheDependencyScopes.cs",
    "content": "namespace ToSic.Sxc.Services.Cache;\n\n/// <summary>\n/// Internal scopes for named cache dependencies.\n/// These keep output-cache markers isolated from future cache consumers which may reuse the same service.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class CacheDependencyScopes\n{\n    public const string OutputCache = \"output-cache\";\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/ICacheService.cs",
    "content": "﻿using ToSic.Sxc.Services.Cache;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Cache`](xref:ToSic.Sxc.Services.ServiceKit16.Cache) to help your code cache data.\n/// </summary>\n/// <remarks>\n/// It does quite a bit of magic, for example:\n///\n/// - scope the cache to the current App, so a key like `main-list` will not bleed to other apps\n/// - help invalidate the cache if the app data changes\n/// - vary the cache by specific parameters such as the `category` in the URL.\n/// - vary the cache by the current user only\n/// - ...and more.\n///\n/// In most cases, you'll\n/// \n/// 1. start by creating <see cref=\"ICacheSpecs\"/> using a call to <see cref=\"CreateSpecs\"/>\n/// 2. use a fluid API on the specs to determine what you want, like <see cref=\"ICacheSpecs.VaryByPageParameters\"/>, <see cref=\"ICacheSpecs.VaryByUser()\"/> <see cref=\"ICacheSpecs.WatchAppData\"/> or just set different expiry options.\n/// 3. Then use these specs to either check if it <see cref=\"Contains\"/> or use <see cref=\"TryGet{T}\"/> or <see cref=\"GetOrSet{T}\"/>\n/// \n/// History\n/// \n/// * Was in internal beta since v17.09\n/// * Released v19.01\n/// * Requires the [SmartDataCache](https://patrons.2sxc.org/features/feat/DataCache) feature (Patron Perfectionist); if not enabled, will work without caching anything.\n/// </remarks>\n[PublicApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ICacheService\n{\n    /// <summary>\n    /// Create cache specs for a specific key and optional segment.\n    /// \n    /// This is used for complex setups where the same specs will be reused for multiple operations.\n    /// </summary>\n    /// <param name=\"key\">The main cache key (name) to use. It will be extended internally, to prevent collisions, so it can be fairly short.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"regionName\">a cache region to segment the cache into multiple regions</param>\n    /// <param name=\"shared\">\n    /// If set to `true` it will make this key available on other apps which access the data with allApps = `true`.\n    /// By default, each app has its own region, preventing key collisions between apps.\n    /// </param>\n    /// <returns></returns>\n    ICacheSpecs CreateSpecs(string key, NoParamOrder npo = default, string? regionName = default, bool? shared = default);\n\n    /// <summary>\n    /// Check if the cache contains data for the given specs.\n    /// </summary>\n    bool Contains(ICacheSpecs specs);\n\n    ///// <summary>\n    ///// Check if the cache contains data for the given key.\n    ///// </summary>\n    //bool Contains(string key);\n\n    /// <summary>\n    /// Check if the cache contains data of specified type for the given specs.\n    /// </summary>\n    bool Contains<T>(ICacheSpecs specs);\n\n    ///// <summary>\n    ///// Check if the cache contains data of specified type for the given key.\n    ///// </summary>\n    //bool Contains<T>(string key);\n\n    /// <summary>\n    /// Get data from the cache of the given type for the given specs, with optional fallback.\n    /// </summary>\n    /// <param name=\"specs\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\"></param>\n    T? Get<T>(ICacheSpecs specs, NoParamOrder npo = default, T? fallback = default);\n\n    ///// <summary>\n    ///// Get data from the cache of the given type for the given key, with optional fallback.\n    ///// </summary>\n    ///// <typeparam name=\"T\"></typeparam>\n    ///// <param name=\"key\"></param>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    ///// <param name=\"fallback\"></param>\n    ///// <returns></returns>\n    //T Get<T>(string key, NoParamOrder npo = default, T fallback = default);\n\n    ///// <summary>\n    ///// Get or set data in the cache for the given key, with optional generation and specs-tweaking.\n    ///// </summary>\n    ///// <typeparam name=\"T\"></typeparam>\n    ///// <param name=\"key\"></param>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    ///// <param name=\"generate\"></param>\n    ///// <returns></returns>\n    //T GetOrSet<T>(string key, NoParamOrder npo = default, Func<T> generate = default);\n\n    /// <summary>\n    /// Get or set data in the cache for the given specs, with optional generation.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"specs\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"generate\"></param>\n    /// <returns></returns>\n    T? GetOrSet<T>(ICacheSpecs specs, NoParamOrder npo = default, Func<T>? generate = default);\n\n    /// <summary>\n    /// Try to get data of the specified type from the cache for the given specs.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"specs\"></param>\n    /// <param name=\"value\"></param>\n    /// <returns>`true` if found, `false` if not found</returns>\n    bool TryGet<T>(ICacheSpecs specs, out T? value);\n\n    ///// <summary>\n    ///// Try to get data of the specified type from the cache for the given key.\n    ///// </summary>\n    ///// <typeparam name=\"T\"></typeparam>\n    ///// <param name=\"key\"></param>\n    ///// <param name=\"value\"></param>\n    ///// <returns>`true` if found, `false` if not found</returns>\n    //bool TryGet<T>(string key, out T value);\n\n    ///// <summary>\n    ///// Remove a cache entry.\n    ///// </summary>\n    ///// <param name=\"key\"></param>\n    ///// <returns>The object if it was in the cache, otherwise null.</returns>\n    //object Remove(string key);\n\n    /// <summary>\n    /// Remove a cache entry.\n    /// </summary>\n    /// <param name=\"key\"></param>\n    /// <returns>The object if it was in the cache, otherwise null.</returns>\n    object? Remove(ICacheSpecs key);\n\n    ///// <summary>\n    ///// Set a value in the cache.\n    ///// </summary>\n    ///// <typeparam name=\"T\"></typeparam>\n    ///// <param name=\"key\"></param>\n    ///// <param name=\"value\"></param>\n    ///// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    //void Set<T>(string key, T value, NoParamOrder npo = default);\n\n    /// <summary>\n    /// Set a value in the cache.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"specs\"></param>\n    /// <param name=\"value\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    void Set<T>(ICacheSpecs specs, T value, NoParamOrder npo = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/ICacheSpecs.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sxc.Services.Cache.Sys.CacheKey;\nusing ToSic.Sys.Caching.Policies;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Services.Cache;\n\n/// <summary>\n/// Cache Specs contain the definition of what the cached data should depend on, how long it should be cached and how the cache key should be generated.\n/// It uses a fluent API to continue adding rules / expirations / dependencies.\n/// Internally this is then used to create a cache policy.\n/// </summary>\n/// <remarks>\n/// * Introduced as experimental in v17.09\n/// * Released in 19.01\n/// * Enhancing with Enable/Disable in v20.01, especially with various user elevations.\n/// </remarks>\n[PublicApi]\npublic interface ICacheSpecs\n{\n    /// <summary>\n    /// The final cache key.\n    /// </summary>\n    /// <remarks>\n    /// This services will always add a prefix to the key, to avoid conflicts with other cache keys.\n    /// The Key itself is only ever needed if you want to see a key manually, mainly for debugging purposes.\n    /// </remarks>\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    string Key { get; }\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    internal IPolicyMaker PolicyMaker { get; }\n\n    /// <summary>\n    /// Determine if caching is enabled. Default is `true`.\n    /// </summary>\n    /// <remarks>\n    /// Internally it will determine if the previously set rules match the current user elevation.\n    /// </remarks>\n    [WorkInProgressApi(\"wip v20.00-05\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    bool IsEnabled { get; }\n\n    public ICacheSpecs Disable();\n\n    public ICacheSpecs Disable(UserElevation elevation);\n\n    /// <summary>\n    /// Disable caching for this data, so it will not be cached. Rarely used. \n    /// </summary>\n    /// <returns></returns>\n    /// <remarks>\n    /// This rarely makes sense, since it's better to just not add something to the cache in the first place.\n    /// \n    /// WIP v20.01: This is a work in progress, and the implementation may change in future versions.\n    /// </remarks>\n    public ICacheSpecs Disable(UserElevation minElevation, UserElevation maxElevation);\n\n    /// <summary>\n    /// Disable caching for this data, so it will not be cached. Rarely used. \n    /// </summary>\n    /// <returns></returns>\n    /// <remarks>\n    /// WIP v20.01: This is a work in progress, and the implementation may change in future versions.\n    /// </remarks>\n    public ICacheSpecs Enable();\n\n    /// <summary>\n    /// Set absolute expiration, alternative is sliding expiration.\n    /// If neither are set, a sliding expiration of 1 hour will be used.\n    /// </summary>\n    /// <param name=\"absoluteExpiration\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// If neither absolute nor sliding are set, a sliding expiration of 1 hour will be used.\n    /// Setting both is invalid and will throw an exception.\n    /// </remarks>\n    ICacheSpecs SetAbsoluteExpiration(DateTimeOffset absoluteExpiration);\n\n    /// <summary>\n    /// Set sliding expiration, alternative is absolute expiration.\n    /// </summary>\n    /// <param name=\"timeSpan\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"seconds\">time in seconds - if specified, takes precedence - new v20.01</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// If neither absolute nor sliding are set, a sliding expiration of 1 hour will be used.\n    /// Setting both is invalid and will throw an exception.\n    /// </remarks>\n    ICacheSpecs SetSlidingExpiration(TimeSpan? timeSpan = default, NoParamOrder npo = default, int? seconds = null);\n\n    /// <summary>\n    /// Depend on the app data, so if any data changes, the cache will be invalidated.\n    /// </summary>\n    /// <returns></returns>\n    ICacheSpecs WatchAppData(NoParamOrder npo = default);\n\n    /// <summary>\n    /// Depend on the app folder, so if any file in the app folder changes, the cache will be invalidated. WIP!\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"withSubfolders\">should it also watch subfolders? default is `true`</param>\n    /// <returns></returns>\n    ICacheSpecs WatchAppFolder(NoParamOrder npo = default, bool? withSubfolders = default);\n\n    ///// <summary>\n    ///// Add files\n    ///// </summary>\n    ///// <param name=\"filePaths\"></param>\n    ///// <returns></returns>\n    //ICacheSpecs WatchFiles(IEnumerable<string> filePaths);\n\n    #region VaryBy\n\n    /// <summary>\n    /// Vary the cache by a specific name and value.\n    /// All cache items where this value is the same, will be considered the same.\n    /// For example, this could be a category name or something where the data for this category is always the same.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"value\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"caseSensitive\"></param>\n    /// <returns></returns>\n    ICacheSpecs VaryBy(string name, string value, NoParamOrder npo = default, bool caseSensitive = false);\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    internal CacheKeyConfig KeyConfig { get; }\n\n    /// <summary>\n    /// Vary the cache by a specific name and value.\n    /// All cache items where this value is the same, will be considered the same.\n    /// For example, this could be a category name or something where the data for this category is always the same.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    ICacheSpecs VaryBy(string name, int value);\n\n    /// <summary>\n    /// Vary the cache by the _current_ module, so that each module has its own cache.\n    /// </summary>\n    ICacheSpecs VaryByModule();\n\n    ///// <summary>\n    ///// Vary the cache by module, so that each module has its own cache.\n    ///// </summary>\n    ///// <param name=\"id\">Module id to use</param>\n    //ICacheSpecs VaryByModule(int id);\n\n    // Note: I don't think there is great value in providing ICms... overloads, so comment out to prevent next person from creating them again\n    ///// <summary>\n    ///// Vary the cache by module, so that each module has its own cache.\n    ///// </summary>\n    ///// <param name=\"module\">module to use</param>\n    //ICacheSpecs VaryByModule(ICmsModule module);\n\n    /// <summary>\n    /// Vary the cache by the _current_ page, so that each page has its own cache.\n    /// </summary>\n    /// <returns></returns>\n    ICacheSpecs VaryByPage();\n\n    /// <summary>\n    /// Vary the cache by the _current_ language/culture, so that each language has its own cache.\n    /// </summary>\n    /// <remarks>\n    /// This uses the CMS context language such as `en-us` or `de-ch`.\n    /// </remarks>\n    ICacheSpecs VaryByLanguage();\n\n    ///// <summary>\n    ///// Vary the cache by page, so that each page has its own cache.\n    ///// By default, it will take the current page, but you can optionally specify a custom page or ID.\n    ///// </summary>\n    ///// <param name=\"id\">page id to use</param>\n    ///// <returns></returns>\n    //ICacheSpecs VaryByPage(int id);\n\n    // Note: I don't think there is great value in providing ICms... overloads, so comment out to prevent next person from creating them again\n    ///// <summary>\n    ///// Vary the cache by page, so that each page has its own cache.\n    ///// By default, it will take the current page, but you can optionally specify a custom page or ID.\n    ///// </summary>\n    ///// <param name=\"page\">page object to use</param>\n    ///// <returns></returns>\n    //ICacheSpecs VaryByPage(ICmsPage page);\n\n    /// <summary>\n    /// Vary the cache by _current_ user, so that each user has its own cache.\n    /// </summary>\n    /// <returns></returns>\n    ICacheSpecs VaryByUser();\n\n    ///// <summary>\n    ///// Vary the cache by user, so that each user has its own cache.\n    ///// </summary>\n    ///// <param name=\"id\">User id to use</param>\n    ///// <returns></returns>\n    //ICacheSpecs VaryByUser(int id);\n\n    // Note: I don't think there is great value in providing ICms... overloads, so comment out to prevent next person from creating them again\n    ///// <summary>\n    ///// Vary the cache by user, so that each user has its own cache.\n    ///// </summary>\n    ///// <param name=\"user\">user object to use</param>\n    ///// <returns></returns>\n    //ICacheSpecs VaryByUser(ICmsUser user);\n\n    /// <summary>\n    /// Vary the cache by one or more specific page parameter, like `?category=1` or `?category=1&amp;sort=asc`.\n    /// Using this method will only vary the cache by the mentioned parameters and ignore the rest.\n    /// </summary>\n    /// <param name=\"names\">Names of one or more parameters, comma-separated. If null, all parameters are used, if `\"\"`, no parameters are used.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"caseSensitive\">Determines if the value should be treated case-sensitive, default is `false`</param>\n    ICacheSpecs VaryByPageParameters(string? names = default, NoParamOrder npo = default, bool caseSensitive = false);\n\n    /// <summary>\n    /// Vary the cache by a custom parameters list.\n    /// </summary>\n    /// <param name=\"parameters\">parameters object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"names\">Names of one or more parameters, comma-separated</param>\n    /// <param name=\"caseSensitive\">Determines if the value should be treated case-sensitive, default is `false`</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// This only makes sense when using with the CacheService, but not in output caching.\n    /// Reason is that in output caching, the pre-flight would not have access to the parameters object and would never result in a cache hit.\n    /// </remarks>\n    ICacheSpecs VaryByParameters(IParameters parameters, NoParamOrder npo = default, string? names = default, bool caseSensitive = false);\n\n    #endregion\n\n    #region Vary By Model EXPERIMENTAL\n\n    /// <summary>\n    /// Vary the cache by values in the model, so that each sample has its own cache. Used in Partial-Caching only. WORK-IN-PROGRESS!\n    /// </summary>\n    /// <param name=\"names\">Names of one or more parameters, comma-separated</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"caseSensitive\">Determines if the value should be treated case-sensitive, default is `false`</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// This is only meant for partial razor caching, since that would have a model available.\n    /// If used elsewhere, it will be ignored.\n    /// \n    /// WIP v20.01\n    /// </remarks>\n    [WorkInProgressApi(\"WIP v20.01\")]\n    ICacheSpecs VaryByModel(string? names = default, NoParamOrder npo = default, bool caseSensitive = false);\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/INamedCacheDependencyService.cs",
    "content": "using ToSic.Sxc.Services.OutputCache;\n\nnamespace ToSic.Sxc.Services.Cache;\n\n/// <summary>\n/// Internal marker service for app-scoped named cache dependencies.\n/// It currently backs <see cref=\"IModuleOutputCacheService\"/> and <see cref=\"IOutputCacheManagementService\"/>,\n/// and is structured so future <c>Kit.Cache</c> APIs can reuse the same invalidation mechanism.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface INamedCacheDependencyService\n{\n    IReadOnlyList<string> GetOrEnsureKeys(string scope, int appId, IEnumerable<string>? names);\n\n    string GetOrEnsureAppKey(string scope, int appId);\n\n    int Touch(string scope, int appId, IEnumerable<string>? names);\n\n    void TouchApp(string scope, int appId);\n\n    IReadOnlyList<string> NormalizeNames(IEnumerable<string>? names);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheKey/CacheKeyConfig.cs",
    "content": "﻿using ToSic.Sys.Memory;\nusing ToSic.Sys.Users;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cache.Sys.CacheKey;\n\n/// <summary>\n/// Internal configuration for the cache which will be relevant for generating the cache key.\n/// </summary>\n/// <remarks>\n/// This is used to determine which parameters will be used to pre-check the cache.\n/// Because of this, it must be a pure, simple record (to allow for easy comparison)\n/// and never contain any objects which are specific to the current request.\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic record CacheKeyConfig(): ICanEstimateSize\n{\n    public const int Disabled = -1;\n    public const int EnabledWithoutTime = 0;\n\n    public CacheKeyConfig(NoParamOrder npo = default, int? seconds = null, string? varyBy = null, string? url = null, string? model = null): this()\n    {\n        if (seconds != null)\n            ForElevation = new() { [UserElevation.All] = seconds.Value };\n\n        foreach (var varyPart in (varyBy?.ToLowerInvariant()).CsvToArrayWithoutEmpty())\n            switch (varyPart)\n            {\n                case \"page\":\n                    ByPage = true;\n                    break;\n                case \"language\":\n                    ByLanguage = true;\n                    break;\n                case \"user\":\n                    ByUser = true;\n                    break;\n                case \"module\":\n                    ByModule = true;\n                    break;\n                default:\n                    throw new ArgumentException($@\"Unknown {nameof(varyBy)} part '{varyPart}'\", nameof(varyBy));\n            }\n\n        if (!string.IsNullOrWhiteSpace(url))\n            ByPageParameters = new()\n            {\n                CaseSensitive = false,\n                Names = url\n            };\n\n        if (!string.IsNullOrWhiteSpace(model))\n            ByModel = new()\n            {\n                CaseSensitive = false,\n                Names = model\n            };\n    }\n\n\n    public bool ByPage { get; init; }\n    public bool ByLanguage { get; init; }\n    public bool ByModule { get; init; }\n    public bool ByUser { get; init; }\n\n    /// <summary>\n    /// this must be tracked in addition to the list page parameters, because even if the parameters are empty, it must still be\n    /// activated on re-checking the cache.\n    /// </summary>\n    public CacheKeyConfigNamed? ByPageParameters { get; init; }\n\n    public CacheKeyConfigNamed? ByModel { get; init; }\n\n    /// <summary>\n    /// Rules per elevation; the value is the sliding expiration in seconds.\n    /// </summary>\n    public Dictionary<UserElevation, int> ForElevation { get; init; } = [];\n\n    SizeEstimate ICanEstimateSize.EstimateSize(ILog? log) => new(\n        sizeof(bool) * 4 // ByPage, ByLanguage, ByModule, ByUser\n        + (ByPageParameters?.Names?.Length ?? 0) // ByParameters\n        + (ByModel?.Names?.Length ?? 0) // ByModel\n    );\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheKey/CacheKeyConfigExtensions.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cache.Sys.CacheKey;\npublic static class CacheKeyConfigExtensions\n{\n    public static CacheKeyConfig Updated(this CacheKeyConfig keyConfig, string name, string? keys, bool caseSensitive) =>\n        name switch\n        {\n            CacheSpecConstants.ByModule => keyConfig with { ByModule = true },\n            CacheSpecConstants.ByPage => keyConfig with { ByPage = true },\n            CacheSpecConstants.ByLanguage => keyConfig with { ByLanguage = true },\n            CacheSpecConstants.ByUser => keyConfig with { ByUser = true },\n            CacheSpecConstants.ByPageParameters when !string.IsNullOrWhiteSpace(keys) => keyConfig with { ByPageParameters = Update(keyConfig.ByPageParameters, keys, caseSensitive) },\n            CacheSpecConstants.ByModel when !string.IsNullOrWhiteSpace(keys) => keyConfig with { ByModel = Update(keyConfig.ByModel, keys, caseSensitive) },\n            _ => keyConfig\n        };\n\n    public static CacheKeyConfigNamed Update(CacheKeyConfigNamed? original, string? newNames, bool caseSensitive)\n    {\n        // merge previous names with new names, ensure no duplicates, order alphabetically\n        var names = (original?.Names + \",\" + newNames).ToLowerInvariant()\n            .CsvToArrayWithoutEmpty()\n            .OrderBy(s => s)\n            .Distinct()\n            .ToArray();\n        \n        return new() { Names = string.Join(\",\", names), CaseSensitive = caseSensitive };\n    }\n\n\n    public static ICacheSpecs RestoreAll(this ICacheSpecs cacheSpecs, CacheKeyConfig keyConfig, CacheWriteConfig writeConfig) =>\n        (CacheSpecs)cacheSpecs with\n        {\n            KeyConfig = keyConfig,\n            WriteConfig = writeConfig,\n            Key = null!,\n            PolicyMaker = null!,\n        };\n\n    /// <summary>\n    /// Restore a cache specs to apply the same logic as was stored here.\n    /// </summary>\n    /// <returns></returns>\n    public static ICacheSpecs RestoreBy(this CacheKeyConfig keyConfig, ICacheSpecs cacheSpecs) =>\n        (CacheSpecs)cacheSpecs with\n        {\n            KeyConfig = keyConfig,\n        };\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheKey/CacheKeyConfigNamed.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Cache.Sys.CacheKey;\n\n/// <summary>\n/// Describes a cache configuration for named parameters.\n/// </summary>\npublic record CacheKeyConfigNamed\n{\n    public required string? Names { get; init; }\n    public required bool CaseSensitive { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheKey/CacheKeyParts.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Cache.Sys.CacheKey;\n\n/// <summary>\n/// The parts which make up a cache key.\n/// Can then be converted to a key using the GetKey() extension method.\n/// </summary>\n[PrivateApi]\npublic record CacheKeyParts\n{\n    /// <summary>\n    /// Special marker to say that the cache should not vary by appId\n    /// </summary>\n    internal const int NoApp = -12345;\n\n    public required int AppId { get; init; }\n\n    public string? RuntimeKey { get; init; }\n\n    public required string Main { get; init; }\n\n    public string? RegionName { get; init; }\n\n    public Dictionary<string, string>? VaryByDic { get; init; }\n\n    /// <summary>\n    /// Override the ToString method to return the key.\n    /// </summary>\n    /// <returns></returns>\n    public override string ToString() => this.GetKey();\n\n    public CacheKeyParts WithUpdatedVaryBy(string name, string value, bool caseSensitive)\n    {\n        var varyByName = \"VaryBy\" + name;\n        var varyByKey = caseSensitive ? varyByName : varyByName.ToLowerInvariant();\n        var valueToUse = caseSensitive ? value : value.ToLowerInvariant();\n\n        return this with\n        {\n            VaryByDic = new(VaryByDic ?? [], StringComparer.InvariantCultureIgnoreCase)\n            {\n                [varyByKey] = valueToUse\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheKey/CacheKeyPartsExtensions.cs",
    "content": "﻿using System.Text;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Services.Cache.Sys.CacheServiceConstants;\n\nnamespace ToSic.Sxc.Services.Cache.Sys.CacheKey;\n\n/// <summary>\n/// Functions to generate the final cache key based on the specifications.\n/// </summary>\n[PrivateApi]\npublic static class CacheKeyPartsExtensions\n{\n    /// <summary>\n    /// Generate the key according to specs.\n    /// </summary>\n    /// <exception cref=\"ArgumentException\"></exception>\n    internal static string GetKey(this CacheKeyParts keyParts)\n    {\n        // Make sure the Main key (prefix) is not empty\n        if (string.IsNullOrWhiteSpace(keyParts.Main))\n            throw new ArgumentException(@\"Key must not be empty\", nameof(keyParts.Main));\n\n        // Prevent accidental adding of the prefix/segment multiple times\n        var mainKey = GetBestKeyBase(keyParts);\n\n        // If no additional keys are specified, exit early.\n        if (keyParts.VaryByDic == null || keyParts.VaryByDic.Count == 0)\n            return mainKey;\n\n        // If there are no new keys, or they are already in the main key, exit early.\n        var varyBy = GetVaryByOfDic(keyParts.VaryByDic);\n        if (string.IsNullOrWhiteSpace(varyBy) || mainKey.EndsWith(varyBy))\n            return mainKey;\n\n        // Combine and return.\n        return $\"{mainKey}{varyBy}\";\n    }\n\n    private static string GetBestKeyBase(CacheKeyParts keyParts)\n    {\n        // Prevent accidental adding of the prefix/segment multiple times\n        if (keyParts.Main.StartsWith(DefaultPrefix))\n            return keyParts.Main;\n\n        var appKey = keyParts.RuntimeKey.HasValue()\n            ? keyParts.RuntimeKey\n            : keyParts.AppId.ToString();\n        var isMagicOverride = keyParts.Main.StartsWith(CacheSpecConstants.PrefixForDontPrefix);\n        var prefix = isMagicOverride\n            ? keyParts.Main.TrimStart('*')\n            : DefaultPrefix +\n              (keyParts.AppId == CacheKeyParts.NoApp ? \"\" : Sep + \"App:\" + appKey) +\n              $\"{Sep}{SegmentPrefix}{keyParts.RegionName.NullIfNoValue() ?? DefaultSegment}{Sep}{keyParts.Main}\";\n\n        return prefix;\n    }\n\n    /// <summary>\n    /// Generate string containing all parameters which should be included in the cache key.\n    /// </summary>\n    internal static string GetVaryByOfDic(Dictionary<string, string> dic)\n    {\n        // Keys must be ordered A-Z so that they are the same, no mater the order of adding\n        var ordered = dic\n            .OrderBy(p => p.Key, comparer: StringComparer.InvariantCultureIgnoreCase)\n            .ThenBy(p => p.Value, comparer: StringComparer.InvariantCultureIgnoreCase)\n            .ToList();\n\n        var sb = new StringBuilder();\n        foreach (var pair in ordered)\n            sb.Append($\"{Sep}{pair.Key}={pair.Value}\");\n        return sb.ToString();\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheKey/ForElevationExtensions.cs",
    "content": "﻿using ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Services.Cache.Sys.CacheKey;\npublic static class ForElevationExtensions\n{\n    //public static int GetSlidingAny(this CacheKeyConfig keyConfig)\n    //    => keyConfig.ForElevation.TryGetValue(UserElevation.Any, out var time) && time > 0 ? time : 0;\n\n    public static Dictionary<UserElevation, int> ResetAll(int seconds) =>\n        new() { [UserElevation.All] = seconds };\n\n    public static Dictionary<UserElevation, int> SetForOneOrAll(this IDictionary<UserElevation, int> dic, UserElevation elevation, int seconds) =>\n        // If not specified, for all, or within the lowest and highest elevation, then disable\n        elevation is UserElevation.Unknown or UserElevation.All\n            ? ResetAll(seconds)\n            : SetOne(dic, elevation, seconds);\n\n    public static Dictionary<UserElevation, int> SetOne(this IDictionary<UserElevation, int> dic, UserElevation elevation, int seconds) =>\n        new(dic)\n        {\n            [elevation] = seconds\n        };\n\n    public static Dictionary<UserElevation, int> SetRange(this IDictionary<UserElevation, int> dic, UserElevation minElevation, UserElevation maxElevation, int seconds)\n    {\n        // If not specified, for all, or within the lowest and highest elevation, then disable\n        if (minElevation is UserElevation.Unknown or UserElevation.All or UserElevation.Anonymous\n            && maxElevation is UserElevation.Unknown or UserElevation.All or UserElevation.SystemAdmin)\n            return ResetAll(CacheKeyConfig.Disabled);\n\n        if (minElevation > maxElevation)\n            throw new ArgumentOutOfRangeException($\"The {nameof(minElevation)} must be lower or equal to the {nameof(maxElevation)}\");\n\n        // Create a list of all elevations which should be disabled\n        var listToDisable = Enum.GetValues(typeof(UserElevation))\n            .Cast<UserElevation>()\n            .Where(e => e >= minElevation && e <= maxElevation)\n            .ToList();\n\n        var toUpdate = new Dictionary<UserElevation, int>(dic);\n        foreach (var elevation in listToDisable)\n            toUpdate[elevation] = CacheKeyConfig.Disabled;\n\n        return toUpdate;\n    }\n\n    public static bool IsEnabledFor(this IDictionary<UserElevation, int> dic, UserElevation elevation) =>\n        IsEnabledForExact(dic, elevation)\n        ?? IsEnabledForExact(dic, UserElevation.All)\n        ?? false;\n\n    public static bool? IsEnabledForExact(this IDictionary<UserElevation, int> dic, UserElevation elevation) =>\n        dic.TryGetValue(elevation, out var time)\n            ? time > CacheKeyConfig.Disabled\n            : null; // true if 0 or greater, false if -1\n\n    public static int SecondsFor(this IDictionary<UserElevation, int> dic, UserElevation elevation)\n        => SecondsForExact(dic, elevation)\n           ?? SecondsForExact(dic, UserElevation.All)\n           ?? 0;\n\n    public static int? SecondsForExact(this IDictionary<UserElevation, int> dic, UserElevation elevation) =>\n        dic.TryGetValue(elevation, out var time) && time > 0\n            ? time\n            : null; // true if 0 or greater, false if -1\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheService.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Services.Cache.Sys.CacheKey;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Caching;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Services.Cache.Sys;\n\n/// <summary>\n/// WIP thoughts...\n/// - policy variants\n/// \n/// Also vary-by variants, like vary\n/// - by culture\n/// - by role\n/// - by device\n/// - by query\n/// - by url\n/// - by page\n/// - by module\n/// - by app, by tenant\n/// - by site\n/// - by domain\n/// - by host\n/// - by path\n/// - by cookie\n/// - by header\n/// - by session, by cache, by request, by response, by server, by client, by browser, by os, by device...\n/// </summary>\n/// <param name=\"cache\"></param>\ninternal class CacheService(\n    MemoryCacheService cache,\n    IRuntimeKeyService runtimeKeyService,\n    LazySvc<IAppsCatalog> appsCatalog,\n    Generator<IAppPathsMicroSvc> appPathsLazy,\n    ISysFeaturesService features\n    ) : ServiceWithContext($\"{SxcLogName}.CchSvc\", connect: [cache, runtimeKeyService, appsCatalog]), ICacheService\n{\n    /// <summary>\n    /// AppId to use in key generation, so it won't collide with other apps.\n    /// </summary>\n    private int AppId => _appId ??= ExCtxOrNull?.GetApp().AppId ?? -1;\n    private int? _appId;\n\n    private string? AppRuntimeKey => _appRuntimeKey ??= ResolveAppRuntimeKey();\n    private string? _appRuntimeKey;\n\n    private bool IsEnabled => _isEnabled ??= features.IsEnabled(SxcFeatures.SmartDataCache);\n    private bool? _isEnabled;\n\n    public ICacheSpecs CreateSpecs(string key, NoParamOrder npo = default, string? regionName = default, bool? shared = default)\n    {\n        var l = Log.Fn<ICacheSpecs>($\"Key: {key} / Segment: {regionName}\");\n        var keySpecs = new CacheKeyParts\n        {\n            AppId = shared == true ? CacheKeyParts.NoApp : AppId,\n            RuntimeKey = shared == true ? null : AppRuntimeKey,\n            Main = key,\n            RegionName = regionName,\n        };\n        var specs = new CacheSpecs(Log)\n        {\n            CacheSpecsContextAndTools = new(Log)\n            {\n                AppPathsLazy = appPathsLazy,\n                ExCtx = ExCtx,\n                BasePolicyMaker = cache.NewPolicyMaker(),\n                BaseKeyParts = keySpecs,\n            },\n            KeyConfig = new()\n            {\n                ForElevation = ForElevationExtensions.ResetAll(0),\n            },\n        };\n        return l.Return(specs);\n    }\n\n    private string? ResolveAppRuntimeKey()\n    {\n        var app = ExCtxOrNull?.GetApp();\n        if (app is IAppWithInternal appWithInternal)\n            return appWithInternal.AppReader.Specs.RuntimeKey;\n\n        if (AppId <= 0)\n            return null;\n\n        try\n        {\n            var identity = appsCatalog.Value.AppIdentity(AppId);\n            return runtimeKeyService.AppRuntimeKey(identity);\n        }\n        catch\n        {\n            return null;\n        }\n    }\n\n    public bool Contains(ICacheSpecs specs)\n        => IsEnabled && cache.Contains(specs.Key);\n\n    public bool Contains<T>(ICacheSpecs specs)\n        => IsEnabled && cache.TryGet<T>(specs.Key, out _);\n\n    public T? Get<T>(ICacheSpecs specs, NoParamOrder npo = default, T? fallback = default) \n        => IsEnabled ? cache.Get(specs.Key, fallback) : fallback;\n\n    public T? GetOrSet<T>(ICacheSpecs specs, NoParamOrder npo = default, Func<T>? generate = default)\n    {\n        if (!IsEnabled)\n            return generate == null ? default : generate();\n        if (cache.TryGet(specs.Key, out T? value))\n            return value;\n        \n        if (generate == null || !specs.IsEnabled)\n            return default;\n        var newValue = generate();\n\n        cache.Set(specs.Key, newValue, specs.PolicyMaker);\n        return newValue;\n    }\n\n    public bool TryGet<T>(ICacheSpecs specs, out T? value)\n    {\n        if (IsEnabled)\n            return cache.TryGet(specs.Key, out value);\n        value = default;\n        return false;\n    }\n\n    //public bool TryGet<T>(string key, out T value)\n    //    => cache.TryGet(new CacheKeySpecs(AppId, key).Key, out value);\n\n    //public object Remove(string key)\n    //    => cache.Remove(new CacheKeySpecs(AppId, key).Key);\n\n    public object? Remove(ICacheSpecs specs)\n        => IsEnabled ? cache.Remove(specs.Key) : null;\n\n    //public void Set<T>(string key, T value, NoParamOrder npo = default)\n    //    => Set(ProcessSpecs(key), value);\n\n    public void Set<T>(ICacheSpecs specs, T value, NoParamOrder npo = default)\n    {\n        if (!IsEnabled || !specs.IsEnabled)\n            return;\n        cache.Set(specs.Key, value, specs.PolicyMaker);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheServiceConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Cache.Sys;\n\ninternal class CacheServiceConstants\n{\n    internal const string Sep = \"|\";\n    internal const string DefaultPrefix = \"Sxc-CacheService\";\n    internal const string SegmentPrefix = \"Seg:\";\n    internal const string DefaultSegment = \"Default\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheSpecConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Cache.Sys;\npublic class CacheSpecConstants\n{\n    public const string ByModule = \"Module\";\n\n    public const string ByPage = \"Page\";\n\n    public const string ByLanguage = \"Language\";\n\n    public const string ByPageParameters = \"PageParameters\";\n\n    public const string ByParameters = \"Parameters\";\n\n    public const string ByUser = \"User\";\n\n    public const string ByModel = \"Model\";\n\n    public const string PrefixForDontPrefix = \"***\";\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheSpecs.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sxc.Services.Cache.Sys.CacheKey;\nusing ToSic.Sys.Caching.Policies;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Services.Cache.Sys;\n\n/// <summary>\n/// This is the \"public API\" for things which setup cache specs.\n/// It does very little, but manage key/write configurations.\n/// In the end it provides both the policy-maker and the key.\n/// </summary>\ninternal record CacheSpecs : HelperRecordBase, ICacheSpecs\n{\n    public CacheSpecs(ILog parentLog) : base(parentLog, \"Sxc.ChKySp\")\n    { }\n\n    #region Internal Bits to make it work\n\n    internal required CacheSpecsContextAndTools CacheSpecsContextAndTools { get; init; }\n\n    public CacheKeyConfig KeyConfig { get; init; } = new();\n\n    public CacheWriteConfig WriteConfig { get; init; } = new();\n\n    // Note: actually internal...\n    [field: AllowNull, MaybeNull]\n    public IPolicyMaker PolicyMaker\n    {\n        // Recreate whenever it is null or was reset previously\n        get => field ??= CacheSpecsContextAndTools.ApplyConfigToPolicy(KeyConfig, WriteConfig);\n        internal init;\n    }\n\n    #endregion\n\n    #region Keys\n\n    /// <inheritdoc />\n    [field: AllowNull, MaybeNull]\n    public string Key\n    {\n        get => field ??= CacheSpecsContextAndTools.ApplyToKeySpecs(KeyConfig, WriteConfig).GetKey();\n        internal init;\n    }\n\n    #endregion\n\n    private CacheSpecs WithChanges(CacheKeyConfig? keyConfig = null, CacheWriteConfig? writeConfig = null) =>\n        this with\n        {\n            Key = null!, // reset key so it will be re-calculated\n            KeyConfig = keyConfig ?? KeyConfig,\n            PolicyMaker = null!, // reset policy-maker so it will be re-calculated\n            WriteConfig = writeConfig ?? WriteConfig,\n        };\n\n    #region Enabled / disabled\n\n    public bool IsEnabled => KeyConfig.ForElevation.IsEnabledFor(CacheSpecsContextAndTools.UserElevation);\n\n    public ICacheSpecs Disable() =>\n        WithChanges(KeyConfig with { ForElevation = ForElevationExtensions.ResetAll(CacheKeyConfig.Disabled), });\n\n    public ICacheSpecs Disable(UserElevation elevation) =>\n        WithChanges(KeyConfig with { ForElevation = KeyConfig.ForElevation.SetForOneOrAll(elevation, CacheKeyConfig.Disabled), });\n\n    public ICacheSpecs Disable(UserElevation minElevation, UserElevation maxElevation) =>\n        WithChanges(KeyConfig with { ForElevation = KeyConfig.ForElevation.SetRange(minElevation, maxElevation, CacheKeyConfig.Disabled), });\n\n    public ICacheSpecs Enable()\n        => WithChanges(KeyConfig with { ForElevation = ForElevationExtensions.ResetAll(CacheKeyConfig.EnabledWithoutTime), });\n\n    public ICacheSpecs Enable(UserElevation elevation) =>\n        WithChanges(KeyConfig with { ForElevation = KeyConfig.ForElevation.SetForOneOrAll(elevation, CacheKeyConfig.EnabledWithoutTime), });\n\n    public ICacheSpecs Enable(UserElevation minElevation, UserElevation maxElevation) =>\n        WithChanges(KeyConfig with { ForElevation = KeyConfig.ForElevation.SetRange(minElevation, maxElevation, CacheKeyConfig.EnabledWithoutTime), });\n\n    #endregion\n\n\n    #region Time Absolute / Sliding\n\n    public ICacheSpecs SetAbsoluteExpiration(DateTimeOffset absoluteExpiration)\n        => WithChanges(writeConfig: WriteConfig with { AbsoluteExpiration = absoluteExpiration });\n\n    public ICacheSpecs SetSlidingExpiration(TimeSpan? timeSpan = null, NoParamOrder npo = default, int? seconds = null) =>\n        WithChanges(keyConfig: KeyConfig with\n        {\n            ForElevation = KeyConfig.ForElevation.SetOne(\n                UserElevation.All,\n                seconds ?? (int)(timeSpan ?? throw new ArgumentException(\"no time specified\")).TotalSeconds\n            ),\n        });\n\n    #endregion\n\n    #region Watch Files / Folders - not yet on the interface, since the standard for paths is not final (eg. full path, relative path, etc.)\n\n    //public ICacheSpecs WatchFile(string filePath)\n    //    => this with { PolicyMaker = PolicyMaker.WatchFiles([filePath]) };\n\n    //public ICacheSpecs WatchFiles(IEnumerable<string> filePaths)\n    //    => this with { PolicyMaker = PolicyMaker.WatchFiles([..filePaths]) };\n\n    //public ICacheSpecs WatchFolder(string folderPath, bool watchSubfolders = false)\n    //    => this with { PolicyMaker = PolicyMaker.WatchFolders(new Dictionary<string, bool> { { folderPath, watchSubfolders } }) };\n\n    //public ICacheSpecs WatchFolders(IDictionary<string, bool> folderPaths)\n    //    => this with { PolicyMaker = PolicyMaker.WatchFolders(folderPaths) };\n\n    //public ICacheSpecs WatchCacheKeys(IEnumerable<string> cacheKeys)\n    //    => this with { PolicyMaker = PolicyMaker.WatchCacheKeys(cacheKeys) };\n\n    #endregion\n\n    #region Watch App Data / Folder\n\n    public ICacheSpecs WatchAppData(NoParamOrder npo = default) =>\n        WithChanges(writeConfig: WriteConfig with { WatchAppData = true, });\n\n    public ICacheSpecs WatchAppFolder(NoParamOrder npo = default, bool? withSubfolders = default) =>\n        WithChanges(writeConfig: WriteConfig with { WatchAppFolder = true, WatchAppSubfolders = withSubfolders ?? true });\n    \n    #endregion\n\n    #region Vary By Value\n\n    //public ICacheSpecs VaryBy(string value, NoParamOrder npo = default, bool caseSensitive = false)\n    //    => Next(value, \"\", caseSensitive: caseSensitive);\n\n    public ICacheSpecs VaryBy(string name, string value, NoParamOrder npo = default, bool caseSensitive = false) =>\n        WithChanges(writeConfig: WriteConfig with\n        {\n            AdditionalValues = [.. WriteConfig.AdditionalValues, (name, value, caseSensitive)]\n        });\n\n    #endregion\n\n    #region Vary-By Custom User, QueryString, etc.\n\n    /// <inheritdoc />\n    public ICacheSpecs VaryByPageParameters(string? names = default, NoParamOrder npo = default, bool caseSensitive = false)\n        => WithChanges(KeyConfig.Updated(CacheSpecConstants.ByPageParameters, names, caseSensitive));\n\n    /// <summary>\n    /// Vary by Parameters is an overload we only use in testing.\n    /// </summary>\n    /// <param name=\"parameters\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"names\"></param>\n    /// <param name=\"caseSensitive\"></param>\n    /// <returns></returns>\n    public ICacheSpecs VaryByParameters(IParameters parameters, NoParamOrder npo = default, string? names = default, bool caseSensitive = false) =>\n        WithChanges(writeConfig: WriteConfig with\n            {\n                AdditionalParameters = [..WriteConfig.AdditionalParameters, (parameters, names, caseSensitive)]\n            });\n\n    #endregion\n\n    #region VaryByModel Experimental\n\n    public ICacheSpecs VaryByModel(string? names = default, NoParamOrder npo = default, bool caseSensitive = false) =>\n        WithChanges(KeyConfig with\n            {\n                ByModel = CacheKeyConfigExtensions.Update(KeyConfig.ByModel, names, caseSensitive)\n            });\n\n    #endregion\n\n    #region VaryBy Int, Page, Language, Module, User\n\n    /// <inheritdoc />\n    public ICacheSpecs VaryBy(string name, int value)\n        => VaryBy(name, value.ToString(), caseSensitive: false);\n\n    ///// <inheritdoc />\n    //public ICacheSpecs VaryByModule(int id)\n    //    => VaryBy(CacheSpecConstants.ByModule, id);\n\n    ///// <inheritdoc />\n    //public ICacheSpecs VaryByModule(ICmsModule module)\n    //    => VaryByModule(module.Id);\n\n    /// <inheritdoc />\n    public ICacheSpecs VaryByModule() =>\n        WithChanges(KeyConfig with { ByModule = true });\n\n    ///// <inheritdoc />\n    //public ICacheSpecs VaryByPage(int id)\n    //    => VaryBy(CacheSpecConstants.ByPage, id);\n\n    ///// <inheritdoc />\n    //public ICacheSpecs VaryByPage(ICmsPage page)\n    //    => VaryByPage(page.Id);\n\n    /// <inheritdoc />\n    public ICacheSpecs VaryByPage() =>\n        WithChanges(KeyConfig with { ByPage = true });\n\n    /// <inheritdoc />\n    public ICacheSpecs VaryByLanguage() =>\n        WithChanges(KeyConfig with { ByLanguage = true });\n\n    ///// <inheritdoc />\n    //public ICacheSpecs VaryByUser(int id)\n    //    => VaryBy(CacheSpecConstants.ByUser, id);\n\n    ///// <inheritdoc />\n    //public ICacheSpecs VaryByUser(ICmsUser user)\n    //    => VaryByUser(user.Id);\n\n    /// <inheritdoc />\n    public ICacheSpecs VaryByUser() =>\n        WithChanges(KeyConfig with { ByUser = true });\n\n    #endregion\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheSpecsContextAndTools.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Services.Cache.Sys.CacheKey;\nusing ToSic.Sxc.Services.Cache.Sys.VaryBy;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Caching.Policies;\nusing ToSic.Sys.Users;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cache.Sys;\n\n/// <summary>\n/// Converts cache configuration to cache-policy maker.\n/// </summary>\ninternal record CacheSpecsContextAndTools : HelperRecordBase\n{\n    public CacheSpecsContextAndTools(ILog parentLog) : base(parentLog, \"Sxc.ChPM\") { }\n\n    #region Internal Bits / Context to make it work\n\n    //internal required CacheKeySpecs KeySpecs { get; init; }\n\n    [field: AllowNull, MaybeNull]\n    internal required IExecutionContext ExCtx\n    {\n        get => field ?? throw new NullReferenceException($\"{nameof(CacheSpecs)}.{nameof(ExCtx)} should never be null at runtime, only during unit tests. Avoid test on aspects which need this.\");\n        init;\n    }\n\n    internal required Generator<IAppPathsMicroSvc> AppPathsLazy { get; init; }\n\n    internal required CacheKeyParts BaseKeyParts { get; init; }\n\n    // Note: actually internal...\n    public required IPolicyMaker BasePolicyMaker { get; internal init; }\n\n    internal IDictionary<string, object?>? Model { get; init; }\n\n    #endregion\n\n    #region Retrieved / Calculated values for Re-Use\n\n    [field: AllowNull, MaybeNull]\n    private ICmsContext Context => field ??= ExCtx.GetCmsContext();\n\n    //[field: AllowNull, MaybeNull]\n    //public ICmsUser User => field ??= ExCtx.GetCmsContext().User;\n\n    //[field: AllowNull, MaybeNull]\n    //public ICmsModule Module => field ??= ExCtx.GetCmsContext().Module;\n\n    //[field: AllowNull, MaybeNull]\n    //public ICmsPage Page => field ??= ExCtx.GetCmsContext().Page;\n\n    //[field: AllowNull, MaybeNull]\n    //public ICmsCulture Culture => field ??= ExCtx.GetCmsContext().Culture;\n\n    public UserElevation UserElevation => _userElevation ??= Context.User.GetElevation(); // ?? UserElevation.Unknown;\n    private UserElevation? _userElevation;\n\n    private ISite? Site => field ??= ExCtx.GetContextOfBlock()?.Site;\n\n    [field: AllowNull, MaybeNull]\n    private IAppReader AppReader => field ??= ExCtx.GetState<IAppReader>();\n\n    #endregion\n\n\n    internal IPolicyMaker ApplyConfigToPolicy(CacheKeyConfig keyConfig, CacheWriteConfig writeConfig)\n    {\n        var policyMaker = BasePolicyMaker;\n        // Only set either the absolute or sliding expiration, never both.\n        policyMaker = writeConfig.AbsoluteExpiration != default\n            ? policyMaker.SetAbsoluteExpiration(writeConfig.AbsoluteExpiration)\n            : ApplySlidingExpiration(policyMaker, keyConfig);\n\n        if (writeConfig.WatchAppData)\n            policyMaker = policyMaker.WatchNotifyKeys([AppReader.GetCache()]);\n\n        if (writeConfig.WatchAppFolder)\n        {\n            var appPaths = AppPathsLazy.New().Get(AppReader, Site);\n            policyMaker = policyMaker.WatchFolders(new Dictionary<string, bool>\n            {\n                [appPaths.PhysicalPath] = writeConfig.WatchAppSubfolders\n            });\n        }\n\n        return policyMaker;\n    }\n\n    private IPolicyMaker ApplySlidingExpiration(IPolicyMaker policyMaker, CacheKeyConfig keyConfig)\n    {\n        var slidingAny = keyConfig.ForElevation.SecondsFor(UserElevation);\n        return slidingAny > 0\n            ? policyMaker.SetSlidingExpiration(slidingAny)\n            : policyMaker;\n    }\n\n    internal CacheKeyParts ApplyToKeySpecs(CacheKeyConfig keyConfig, CacheWriteConfig writeConfig)\n    {\n        var keySpecs = BaseKeyParts;\n        if (keyConfig.ByPageParameters is { } byParameters)\n        {\n            var parameters = Context.Page.Parameters ?? new Parameters { Nvc = [] };\n            var asUrl = CacheVaryByHelper.VaryByParameters(parameters, byParameters.Names);\n            keySpecs = keySpecs.WithUpdatedVaryBy(CacheSpecConstants.ByPageParameters, asUrl, byParameters.CaseSensitive);\n        }\n\n        foreach (var add in writeConfig.AdditionalParameters)\n        {\n            var asUrl = CacheVaryByHelper.VaryByParameters(add.Parameters, add.Names);\n            keySpecs = keySpecs.WithUpdatedVaryBy(CacheSpecConstants.ByParameters, asUrl, add.CaseSensitive);\n        }\n\n        foreach (var add in writeConfig.AdditionalValues)\n            keySpecs = keySpecs.WithUpdatedVaryBy(add.Name, add.Value, caseSensitive: add.CaseSensitive);\n\n        if (keyConfig.ByModel is { } byModel)\n            keySpecs = ReplayByModel(keySpecs, byModel.Names, caseSensitive: byModel.CaseSensitive);\n\n        if (keyConfig.ByUser)\n            keySpecs = Update(keySpecs, CacheSpecConstants.ByUser, Context.User.Id);\n\n        if (keyConfig.ByModule)\n            keySpecs = Update(keySpecs, CacheSpecConstants.ByModule, Context.Module.Id);\n\n        if (keyConfig.ByPage)\n            keySpecs = Update(keySpecs, CacheSpecConstants.ByPage, Context.Page.Id);\n\n        if (keyConfig.ByLanguage)\n            keySpecs = keySpecs.WithUpdatedVaryBy(CacheSpecConstants.ByLanguage, Context.Culture.CurrentCode, caseSensitive: false);\n\n        return keySpecs;\n\n        // Helper Function to update the key specs\n        CacheKeyParts Update(CacheKeyParts tempParts, string name, int? value)\n            => tempParts.WithUpdatedVaryBy(name, (value ?? -1).ToString(), true);\n    }\n\n    private CacheKeyParts ReplayByModel(CacheKeyParts keyParts, string? names, bool caseSensitive)\n    {\n        var l = Log.Fn<CacheKeyParts>($\"{nameof(names)}: '{names}', {nameof(caseSensitive)}: {caseSensitive}\");\n        var model = Model;\n        if (model == null)\n        {\n            // fail silently\n            // Future: option to have aggressive mode or logging - in which case we would use the ExCtx etc. to log this message\n            return l.Return(keyParts, \"no model, unchanged\");\n        }\n\n        var nameList = names.CsvToArrayWithoutEmpty();\n        if (!nameList.Any())\n            return l.Return(keyParts, \"no keys, unchanged\");\n\n        var all = CacheVaryByModelHelper.VaryByModelExtract(model, nameList);\n\n        var asUrl = CacheVaryByHelper.VaryByToUrl(all);\n        keyParts = keyParts.WithUpdatedVaryBy(CacheSpecConstants.ByModel, asUrl, caseSensitive);\n        return l.Return(keyParts, $\"updated; Model had {model.Count}; used: {all.Count}\");\n    }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheSpecsExtensions.cs",
    "content": "﻿using ToSic.Sxc.Services.Cache.Sys.CacheKey;\n\nnamespace ToSic.Sxc.Services.Cache.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class CacheSpecsExtensions\n{\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static ICacheSpecs WithPolicyOf(this ICacheSpecs specs, ICacheSpecs specsWithPolicy) => \n        (CacheSpecs)specs with { PolicyMaker = specsWithPolicy.PolicyMaker };\n\n    /// <summary>\n    /// Give access to internal VaryByList.\n    /// </summary>\n    /// <param name=\"specs\"></param>\n    /// <returns></returns>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static CacheKeyConfig GetConfig(this ICacheSpecs specs)\n        => ((CacheSpecs)specs).KeyConfig;\n\n\n    public static ICacheSpecs AttachModel(this ICacheSpecs specs, IDictionary<string, object?>? model)\n    {\n        var typed = (CacheSpecs)specs;\n        var l = typed.Log.Fn<ICacheSpecs>($\"hasModel: {model != null}; count: {model?.Count}\");\n        return l.ReturnAsOk(typed with\n        {\n            CacheSpecsContextAndTools = typed.CacheSpecsContextAndTools with\n            {\n                Model = model\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/CacheWriteConfig.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cache.Sys;\n\n/// <summary>\n/// Partial Cache configuration information which is only relevant for **writing** to the cache.\n/// </summary>\n/// <remarks>\n/// The object itself will not be serialized or stored in the cache,\n/// but is used to specify how the cache will be set up - for example timeouts or watchers.\n/// \n/// Any information in this object is either\n/// - not relevant for _retrieving_ from the cache\n/// - too complex / changing to be serialized\n/// - would cause trouble if also cached, since it might change fairly randomly\n/// </remarks>\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic record CacheWriteConfig\n{\n    public CacheWriteConfig(NoParamOrder npo = default, string? watch = null)\n    {\n        foreach (var part in watch.CsvToArrayWithoutEmpty())\n            switch (part.ToLowerInvariant())\n            {\n                case \"data\":\n                    WatchAppData = true;\n                    break;\n                // ReSharper disable once StringLiteralTypo\n                case \"folder\":\n                    WatchAppFolder = true;\n                    break;\n                default:\n                    throw new ArgumentException($@\"Unknown {nameof(watch)} part '{part}'\", nameof(watch));\n            }\n    }\n\n    public bool WatchAppData { get; init; }\n    public bool WatchAppFolder { get; init; }\n    public bool WatchAppSubfolders { get; init; }\n\n    public DateTimeOffset AbsoluteExpiration { get; init; }\n\n    public int SlidingExpirationSeconds { get; init; }\n\n    public List<(IParameters Parameters, string? Names, bool CaseSensitive)> AdditionalParameters = [];\n\n    public List<(string Name, string Value, bool CaseSensitive)> AdditionalValues = [];\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/NamedCacheDependencyService.cs",
    "content": "using ToSic.Sys.Caching;\n\nnamespace ToSic.Sxc.Services.Cache.Sys;\n\n/// <summary>\n/// Shared marker service for app-scoped named cache dependencies.\n/// Output cache is the first public consumer, but the service is intentionally generic\n/// so future data-cache APIs can watch and touch the same kind of dependency markers.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class NamedCacheDependencyService(MemoryCacheService memoryCacheService)\n    : ServiceBase($\"{SxcLogName}.NmCacDp\", connect: [memoryCacheService]), INamedCacheDependencyService\n{\n    private const string DependencyRoot = \"Sxc-Dependency.\";\n    private static readonly DateTimeOffset MarkerExpiration = DateTimeOffset.MaxValue;\n\n    public IReadOnlyList<string> GetOrEnsureKeys(string scope, int appId, IEnumerable<string>? names)\n    {\n        // Every scope also has an app-wide marker so callers can invalidate all entries for the app\n        // without needing to enumerate existing cache keys.\n        var appKey = GetOrEnsureAppKey(scope, appId);\n        var normalized = NormalizeNames(names);\n        if (normalized.Count == 0)\n            return [appKey];\n\n        var keys = normalized\n            .Select(name => GetNamedKey(scope, appId, name))\n            .ToArray();\n\n        foreach (var key in keys)\n            EnsureMarker(key);\n\n        return [appKey, .. keys];\n    }\n\n    public string GetOrEnsureAppKey(string scope, int appId)\n    {\n        var key = GetAppKey(scope, appId);\n        EnsureMarker(key);\n        return key;\n    }\n\n    public int Touch(string scope, int appId, IEnumerable<string>? names)\n    {\n        var keys = NormalizeNames(names)\n            .Select(name => GetNamedKey(scope, appId, name))\n            .ToArray();\n\n        foreach (var key in keys)\n            SetMarker(key);\n\n        return keys.Length;\n    }\n\n    public void TouchApp(string scope, int appId)\n        => SetMarker(GetOrEnsureAppKey(scope, appId));\n\n    public IReadOnlyList<string> NormalizeNames(IEnumerable<string>? names)\n    {\n        if (names == null)\n            return [];\n\n        return names\n            .Select(NormalizeName)\n            .Where(name => name != null)\n            .Distinct(StringComparer.OrdinalIgnoreCase)\n            .OrderBy(name => name, StringComparer.Ordinal)\n            .Cast<string>()\n            .ToArray();\n    }\n\n    private static string? NormalizeName(string? name)\n    {\n        if (name == null)\n            return null;\n\n        var trimmed = name.Trim();\n        return trimmed.Length == 0\n            ? null\n            : trimmed.ToLowerInvariant();\n    }\n\n    private static string NormalizeScope(string scope)\n    {\n        if (string.IsNullOrWhiteSpace(scope))\n            throw new ArgumentException(\"Dependency scope must not be empty.\", nameof(scope));\n\n        return scope.Trim().ToLowerInvariant();\n    }\n\n    private static string GetAppKey(string scope, int appId)\n        => $\"{DependencyRoot}s:{NormalizeScope(scope)}.a:{appId}\";\n\n    private static string GetNamedKey(string scope, int appId, string name)\n        => $\"{GetAppKey(scope, appId)}.k:{name}\";\n\n    private void EnsureMarker(string cacheKey)\n    {\n        if (memoryCacheService.TryGet<CacheDependencyMarker>(cacheKey, out _))\n            return;\n\n        SetMarker(cacheKey);\n    }\n\n    private void SetMarker(string cacheKey)\n        => memoryCacheService.Set(\n            cacheKey,\n            new CacheDependencyMarker(),\n            policy => policy.SetAbsoluteExpiration(MarkerExpiration)\n        );\n\n    private sealed class CacheDependencyMarker : ITimestamped\n    {\n        long ITimestamped.CacheTimestamp { get; } = DateTime.UtcNow.Ticks;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/VaryBy/CacheVaryByHelper.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cache.Sys.VaryBy;\ninternal class CacheVaryByHelper\n{\n    internal static string VaryByToUrl(List<KeyValuePair<string, string>> all)\n    {\n        var nvc = all\n            // Keep only relevant\n            .Where(pair => pair.Value.HasValue())\n            // Order so the same keys always result in the same string\n            .OrderBy(pair => pair.Key, comparer: StringComparer.InvariantCultureIgnoreCase)\n            .Aggregate(new NameValueCollection(),\n                (seed, pair) =>\n                {\n                    seed.Add(pair.Key, pair.Value);\n                    return seed;\n                });\n\n        var asUrl = nvc.NvcToString();\n        return asUrl;\n    }\n\n    internal static string VaryByParameters(IParameters parameters, string? names)\n    {\n        var all = parameters\n            .Filter(names)\n            .OrderBy(p => p.Key, comparer: StringComparer.InvariantCultureIgnoreCase)\n            .ToList();\n        return VaryByToUrl(all);\n    }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cache/Sys/VaryBy/CacheVaryByModelHelper.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cache.Sys.VaryBy;\ninternal class CacheVaryByModelHelper\n{\n    internal static List<KeyValuePair<string, string>> VaryByModelExtract(IDictionary<string, object?> model, string[] nameList)\n    {\n        var all = model\n            .Where(pair => nameList.Any(n\n                    => n.EqualsInsensitive(pair.Key)                    // contains key\n                       && IsUsefulForCacheKey(pair.Value)     // is simple value, allowing use in cache key\n            ))\n            .Select(p => new KeyValuePair<string, string>(p.Key, p.Value?.ToString() ?? \"\"))\n            .OrderBy(p => p.Key, comparer: StringComparer.InvariantCultureIgnoreCase)\n            .ToList();\n        return all;\n    }\n\n    internal static bool IsUsefulForCacheKey(object? value)\n    {\n        if (value == null)\n            return false;\n        var type = value.GetType().UnboxIfNullable();\n        return type.IsValueType\n               || type.IsPrimitive\n               || type == typeof(string)\n               || type == typeof(DateTime)\n               || type == typeof(Guid)\n               || type.IsNumeric();\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cms/Sys/CmsProcessed.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Cms.Sys;\n\ninternal class CmsProcessed(bool isProcessed, string? contents, string? classes)\n{\n    public bool IsProcessed { get; set; } = isProcessed;\n\n    public string? Contents { get; set; } = contents;\n    public string? Classes { get; set; } = classes;\n\n    public string DefaultTag { get; set; } = \"div\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cms/Sys/CmsService.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Services.Sys.Cms;\nusing ToSic.Sxc.Services.Tweaks;\nusing ToSic.Sxc.Services.Tweaks.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing InputTypes = ToSic.Sxc.Data.Sys.InputTypes;\n\nnamespace ToSic.Sxc.Services.Cms.Sys;\n\ninternal class CmsService(Generator<CmsServiceStringWysiwyg> stringWysiwyg)\n    : ServiceWithContext($\"{SxcLogName}.CmsSrv\", connect: [stringWysiwyg]), ICmsService\n{\n    [field: AllowNull, MaybeNull]\n    private Generator<CmsServiceStringWysiwyg> StringWysiwygGen => field\n        ??= stringWysiwyg.SetInit(s => s.ConnectToRoot(ExCtx));\n\n    public IHtmlTag Html(\n        object? thing,\n        NoParamOrder npo = default,\n        object? container = default,\n        string? classes = default,\n        bool debug = default,\n        object? imageSettings = default,\n        bool? toolbar = default,\n        Func<ITweakInput<string>, ITweakInput<string>>? tweak = default\n    )\n    {\n        var field = thing as IField;\n        var l = Log.Fn<IHtmlTag>($\"Field: {field?.Name}\");\n        // Initialize the container helper, as we'll use it a few times\n        var cntHelper = new CmsServiceContainerHelper(ExCtx, field, container, classes, toolbar, Log);\n\n        // New v17 - preprocess the tweaks if available\n        // Note that we should use the field if one was found, only use the \"thing\" if there was no field\n        // Otherwise there is the risk that \"Raw\" is null (like new wysiwyg field before adding text)\n        // and it would then revert to showing \"ToSic.Sxc.Data.Internal.Field\"\n        var value = field != null\n            ? field.Raw?.ToString()\n            : thing?.ToString();\n        value = ProcessTweaks(tweak, value, l);\n\n        // If it's not a field, we cannot find out more about the object\n        // In that case, just wrap the result in the container and return it\n        if (field is null)\n            return l.Return(cntHelper.Wrap(value ?? thing, defaultToolbar: false), \"No field, will just treat as value\");\n\n        // Get Content type and field information; if not found, exit early\n        var contentType = field.Parent.Entity?.Type; // Entity can be null on mock data\n        if (contentType == null)\n            return l.Return(cntHelper.Wrap(value, defaultToolbar: false), \"can't find content-type, treat as value\");\n\n        // Get Attribute information; if not found, exit early\n        var attribute = contentType[field.Name];\n        if (attribute == null)\n            return l.Return(cntHelper.Wrap(value, defaultToolbar: false), \"no attribute info, treat as value\");\n\n        // Now we handle all kinds of known special treatments\n        // Start with strings...\n        if (attribute.Type == ValueTypes.String)\n            return l.Return(HtmlString(contentType, attribute, field, value, imageSettings, cntHelper, debug), \"string\");\n\n        // Fallback...\n        return l.Return(cntHelper.Wrap(value, defaultToolbar: false), \"nothing else hit, will treat as value\");\n    }\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= ExCtx.GetCdf();\n\n\n    private IHtmlTag HtmlString(IContentType contentType, IContentTypeAttribute attribute, IField field, string? value, object? imageSettings, CmsServiceContainerHelper cntHelper, bool debug)\n    {\n        var l = Log.Fn<IHtmlTag>($\"Attribute: {attribute.Name}\");\n        var inputType = attribute.InputType;\n        if (debug) l.A($\"Field type is: {ValueTypes.String}:{inputType}\");\n\n        // Not WYSIWYG = normal string, no toolbar by default\n        if (inputType != InputTypes.InputTypeWysiwyg)\n            return l.Return(cntHelper.Wrap(value, defaultToolbar: false), \"string, default no toolbar\");\n\n        // WYSIWYG\n        var fieldAdam = Cdf.Folder(field.Parent, field.Name, field);\n        var htmlResult = StringWysiwygGen.New()\n            .Init(field, contentType, attribute, fieldAdam, debug, imageSettings)\n            .HtmlForStringAndWysiwyg(value);\n\n        return htmlResult.IsProcessed\n            ? l.Return(cntHelper.Wrap(htmlResult, defaultToolbar: true), \"wysiwyg, default w/toolbar\")\n            : l.Return(cntHelper.Wrap(value, defaultToolbar: true), \"wysiwyg, not converted, w/toolbar\");\n    }\n\n    private static string? ProcessTweaks(Func<ITweakInput<string>, ITweakInput<string>>? tweak, string? value, ILog? log)\n    {\n        var l = log.Fn<string?>();\n        if (tweak == null)\n            return l.Return(value, \"no tweaks\");\n\n        try\n        {\n            var tweakHtml = (TweakInput<string>)tweak(new TweakInput<string>());\n            var valueTweak = tweakHtml.Tweaks.Preprocess(value);\n            return l.Return(valueTweak.Value, \"tweaked\");\n        }\n        catch (Exception e)\n        {\n            var ex = new Exception($\"Error in processing {nameof(tweak)}\", e);\n            throw l.Ex(ex);\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cms/Sys/CmsServiceContainerHelper.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cms.Sys;\n\ninternal class CmsServiceContainerHelper(\n    IExecutionContext executionContext,\n    IField? entityField,\n    object? container,\n    string? classes,\n    bool? toolbar,\n    ILog parentLog)\n    : HelperBase(parentLog, \"Cms.SvcCnt\")\n{\n    private string? Classes { get; set; } = classes;\n\n    [field: AllowNull, MaybeNull]\n    private IToolbarService Toolbar => field ??= executionContext.GetService<IToolbarService>(reuse: true);\n    \n\n    public IHtmlTag Wrap(CmsProcessed result, bool defaultToolbar)\n    {\n        Classes = string.Join(\" \", new[] { Classes, result.Classes }.Where(x => x.HasValue()));\n        return Wrap(result.Contents, defaultToolbar: defaultToolbar);\n    }\n\n    public IHtmlTag Wrap(object? contents, bool defaultToolbar)\n    {\n        var l = Log.Fn<IHtmlTag>($\"{nameof(defaultToolbar)}: {defaultToolbar}\");\n        var tag = GetContainer(container);\n        tag = tag.Wrap(contents);\n        // If tag is not a real tag (no name) then it also can't have classes or toolbars; just finish and return\n        if (!tag.TagName.HasValue())\n            return l.Return(tag, \"no wrapper tag, stop here\");\n\n        // Add classes if we can\n        if (Classes.HasValue())\n            tag = tag.Class(Classes);\n\n        // quick exit if no entity field\n        if (entityField == null)\n            return l.Return(tag, \"no entity field, so no toolbar or edit icon added\");\n\n        // Add Toolbar if relevant\n        if (entityField.Parent.IsDemoItem)\n            return l.Return(tag, \"demo-item, so no toolbar\");\n\n        if (entityField.Parent.Entity.DisableInlineEditSafe())\n            return l.Return(tag, \"decorator no-edit\");\n\n        var toolbar1 = toolbar ?? defaultToolbar;\n        if (!toolbar1)\n            return l.Return(tag, \"no toolbar added\");\n\n        l.A(\"Will add toolbar\");\n        if (Toolbar != null)\n            tag = tag.Attr(Toolbar.Empty()\n                .Edit(entityField.Parent, tweak: b => b\n                    .Icon(EditFieldIcon)\n                    .UiFields(entityField.Name)\n                )\n            );\n        return l.Return(tag, \"added toolbar\");\n\n    }\n\n    private const string EditFieldIcon =\n        \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" height=\\\"48\\\" viewBox=\\\"0 96 960 960\\\" width=\\\"48\\\"><path d=\\\"M180 1044q-24 0-42-18t-18-42V384q0-24 18-42t42-18h405l-60 60H180v600h600V636l60-60v408q0 24-18 42t-42 18H180Zm300-360Zm182-352 43 42-285 284v86h85l286-286 42 42-303 304H360V634l302-302Zm171 168L662 332l100-100q17-17 42.311-17T847 233l84 85q17 18 17 42.472T930 402l-97 98Z\\\"/></svg>\";\n\n    private IHtmlTag GetContainer(object? cont)\n    {\n        var l = Log.Fn<IHtmlTag>();\n        return cont switch\n        {\n            // Already an ITag\n            IHtmlTag iTagContainer => l.Return(iTagContainer, \"container is pre-built RazorBlade tag\"),\n            string tagName when tagName.IsEmpty() => l.Return(Tag.RawHtml(), \"no container, return empty tag\"),\n            string tagName when !tagName.Contains(\" \") => l.Return(Tag.Custom(tagName), \"was a tag name, created tag\"),\n            string tagName => throw l.Done(new ArgumentException(\n                $@\"Must be a tag name like 'div' or a RazorBlade Html Tag object but got '{tagName}'\", nameof(cont))),\n            _ => l.Return(Tag.Div(), \"no container, return div tag\")\n        };\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cms/Sys/CmsServiceImageExtractor.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Web.Sys.HtmlParsing;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cms.Sys;\n\ninternal class CmsServiceImageExtractor() : ServiceBase(\"Sxc.ImgExt\")\n{\n    internal const string WysiwygLightboxClass = \"wysiwyg-lightbox\";\n\n    internal ImagePropertiesExtracted ExtractImageProperties(string imgTag, IFolder folder)\n    {\n        var l = Log.Fn<ImagePropertiesExtracted>($\"old: '{imgTag}'\");\n        string? src = null;\n        string? factor = null;\n        object? width = default;\n        string? imgAlt = null;\n        string? imgClasses = null;\n        string? picClasses = null;\n        var otherAttributes = new Dictionary<string, string?>();\n        IFile? file = null;\n\n        var files = folder.Files.ToList();\n\n        // get all attributes\n        var attributes = RegexUtil.AttributesDetection.Value.Matches(imgTag);\n        foreach (Match attributeMatch in attributes)\n        {\n            var key = attributeMatch.Groups[\"Key\"].Value;\n            var value = attributeMatch.Groups[\"Value\"].Value;\n            switch (key.ToLowerInvariant())\n            {\n                case \"data-cmsid\":\n                    var parts = new LinkParts(value, true);\n                    src = parts.IsMatch ? $\"{folder.Url}{parts.Name}\" : value;\n                    try\n                    {\n                        file = files.FirstOrDefault(f => f.FullName.EqualsInsensitive(parts.Name));\n                    }\n                    catch (Exception ex)\n                    {\n                        Log.Ex(ex, \"Error while trying to get file from Adam\");\n                    }\n                    break;\n                case \"src\":\n                    src ??= value; // should not overwrite data-cmsid\n                    break;\n                case \"width\":\n                    width = value;\n                    break;\n                case \"alt\":\n                    imgAlt = value;\n                    break;\n                case \"class\": // specially look at the classes\n                    imgClasses = value; // add it as class\n                    factor = GetImgServiceResizeFactor(value); // use the \"#/#\" as the `factor` parameter\n                    picClasses = GetPictureClasses(value);\n                    break;\n                default:\n                    // store alt-attribute, class etc. from the original if it had it (to re-attach latter)\n                    otherAttributes[key] = value.NullIfNoValue();\n                    break;\n            }\n        }\n\n        var result = new ImagePropertiesExtracted\n        {\n            File = file,\n            Src = src,\n            Factor = factor,\n            ImgAlt = imgAlt,\n            ImgClasses = imgClasses,\n            PicClasses = picClasses,\n            Width = width,\n            OtherAttributes = otherAttributes\n        };\n        return l.Return(result, $\"src:{src}\");\n    }\n\n    /// <summary>\n    /// NOT DONE YET: the Picture tag should only preserve the wysiwyg-* classes\n    /// </summary>\n    /// <param name=\"classes\"></param>\n    /// <returns></returns>\n    internal static string GetPictureClasses(string classes)\n    {\n        // TODO: filter to only return wysiwyg-* classes\n        return classes;\n    }\n\n    /// <summary>\n    /// ATM not used at all, only tested. Idea was that there would be a class to mark it for lightbox,\n    /// but the decision was made to use image settings instead.\n    /// </summary>\n    /// <param name=\"classes\"></param>\n    /// <returns></returns>\n    internal static bool UseLightbox(string? classes)\n        => classes?.Contains(WysiwygLightboxClass) ?? false;\n\n    internal static string? GetImgServiceResizeFactor(string value)\n    {\n        // check if we can find something like \"wysiwyg-width#of#\" - this is for resize ratios\n        var widthMatch = RegexUtil.WysiwygWidthLazy.Value.Match(value);\n\n        // convert to a format like \"#/#\"\n        if (!widthMatch.Success)\n            return null;\n\n        var numString = widthMatch.Groups[\"percent\"].Value;\n        // We want to return a nice factor, in case the rules have optimized values\n        return numString switch\n        {\n            \"100\" => \"1\",\n            \"50\" => \"1/2\",\n            \"33\" => \"1/3\",\n            \"66\" => \"2/3\",\n            \"25\" => \"1/4\",\n            \"75\" => \"3/4\",\n            _ => numString\n        };\n    }\n\n    internal class ImagePropertiesExtracted\n    {\n        public IFile? File { get; init; }\n        public string? Src { get; init; }\n        public string? Factor { get; init; }\n        public string? ImgAlt { get; init; }\n        public string? ImgClasses { get; init; }\n        public string? PicClasses { get; init; }\n        public object? Width { get; init; }\n        public required Dictionary<string, string?> OtherAttributes { get; init; }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cms/Sys/CmsServiceStringWysiwyg.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Services.CmsService;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.HtmlParsing;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cms.Sys;\n\ninternal class CmsServiceStringWysiwyg()\n    : ServiceWithContext(\"Cms.StrWys\", connect: [])\n{\n    #region Sub-Services which should come from the same Code context\n\n    [field: AllowNull, MaybeNull]\n    private IPageService PageService => field ??= ExCtx.GetService<IPageService>(reuse: true);\n\n    [field: AllowNull, MaybeNull]\n    private HtmlImgToPictureHelper HtmlImgToPictureHelper => field ??= ExCtx.GetService<HtmlImgToPictureHelper>();\n\n    [field: AllowNull, MaybeNull]\n    private HtmlInnerContentHelper HtmlInnerContentHelper => field ??= ExCtx.GetService<HtmlInnerContentHelper>();\n\n    #endregion\n\n    #region Init\n\n    public CmsServiceStringWysiwyg Init(IField field, IContentType contentType, IContentTypeAttribute attribute, IFolder folder, bool debug, object? imageSettings)\n    {\n        var l = Log.Fn<CmsServiceStringWysiwyg>();\n        Field = field;\n        ContentType = contentType;\n        Folder = folder;\n        Attribute = attribute;\n        Debug = debug;\n        ImageSettings = imageSettings;\n        return l.ReturnAsOk(this);\n    }\n\n    /// <summary>FYI: is never allowed to be null.</summary>\n    protected IField Field = null!;\n    /// <summary>FYI: is never allowed to be null.</summary>\n    protected IContentType ContentType = null!;\n    /// <summary>FYI: is never allowed to be null.</summary>\n    protected IContentTypeAttribute Attribute = null!;\n    /// <summary>FYI: could be null.</summary>\n    protected object? ImageSettings;\n    /// <summary>FYI: is never allowed to be null.</summary>\n    protected IFolder Folder = null!;\n\n    #endregion\n\n\n    /// <summary>\n    /// Note: very expressive name for logs\n    /// </summary>\n    /// <param name=\"value\"></param>\n    internal CmsProcessed HtmlForStringAndWysiwyg(string? value)\n    {\n        var l = Log.Fn<CmsProcessed>();\n        var html = value ?? Field.Raw as string;\n        if (html.IsEmptyOrWs())\n            return l.Return(new(false, null, null), \"no html, treat as unknown, return null to let parent do wrapping with original\");\n\n        // 1. We got HTML, so first we must ensure the feature is activated\n        PageService.Activate(SxcPageFeatures.CmsWysiwyg.NameId);\n\n        // 2. Check Inner Content\n        html = HtmlInnerContentHelper.ProcessInnerContent(html, ContentType, Attribute, Field);\n\n        // prepare classes to add\n        var classes = WysiwygConstants.WysiwygContainerClass + (Debug ? $\" {WysiwygConstants.WysiwygDebugClass}\" : \"\");\n\n        // 3. Check Responsive Images\n        // extract img tags from html using regex case insensitive\n        // and check if we have an img tags with data-cmsid=\"file:...\" attributes\n        var imgTags = RegexUtil.ImagesDetection.Value.Matches(html);\n        if (imgTags.Count == 0)\n            return l.Return(new(true, html, classes), \"can't find img tags with data-cmsid, done\");\n\n        // check if field metadata specifies alternate Lightbox or image resize settings\n\n        var fieldMd = ImageDecorator.GetOrNull(Attribute, [null]);\n\n        // Assume fallback-image settings to be the specified or \"Wysiwyg\"\n        var defaultImageSettings = fieldMd?.ResizeSettings ?? ImageSettings ?? \"Wysiwyg\";\n\n        l.A($\"Found {imgTags.Count} images to process with default {defaultImageSettings}\");\n\n        foreach (var imgTag in imgTags.Cast<Match>())\n        {\n            var originalImgTag = imgTag.ToString();\n\n            var picture = HtmlImgToPictureHelper.ConvertImgToPicture(originalImgTag, Folder, defaultImageSettings);\n\n            // replace the old img tag with the new one\n            html = html.Replace(originalImgTag, picture.ToString());\n        }\n\n        // reconstruct the original html and return wrapped in the realContainer\n        return l.Return(new(true, html, classes), \"wysiwyg changed with images\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cms/Sys/HtmlImgToPictureHelper.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cms.Sys;\n\ninternal class HtmlImgToPictureHelper(CmsServiceImageExtractor imageExtractor)\n    : ServiceWithContext(\"Cms.StrWys\", connect: [imageExtractor])\n{\n    [field: AllowNull, MaybeNull]\n    internal IImageService ImageService => field\n        ??= ExCtx.GetService<IImageService>(reuse: true);\n\n\n    public IResponsivePicture ConvertImgToPicture(string originalImgTag, IFolder folder, object? defaultImageSettings)\n    {\n        var imgProps = imageExtractor.ExtractImageProperties(originalImgTag, folder);\n\n        // if we have a real file, pre-get the inner parameters as we would want to use it for resize-settings\n        var preparedImgParams = imgProps.File.NullOrGetWith(ResponsiveSpecsOfTarget.ExtractSpecs);\n\n        // if the file itself specifies a resize settings, use it, otherwise use the default settings\n        var imgSettings = preparedImgParams?.ImgDecoratorOrNull?.ResizeSettings ?? defaultImageSettings;\n\n        // In most cases use the preparedImgParams, but if it's null, use the src attribute\n        var target = (object?)preparedImgParams ?? imgProps.Src;\n\n        // use the IImageService to create Picture tags for it\n        var picture = ImageService.Picture(link: target, settings: imgSettings, factor: imgProps.Factor, width: imgProps.Width,\n            imgAlt: imgProps.ImgAlt, imgClass: imgProps.ImgClasses, imgAttributes: imgProps.OtherAttributes,\n            pictureClass: imgProps.PicClasses);\n        return picture;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cms/Sys/HtmlInnerContentHelper.cs",
    "content": "﻿using ToSic.Sxc.Blocks;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Cms.Sys;\n\ninternal class HtmlInnerContentHelper()\n    : ServiceWithContext(\"Cms.StrWys\", connect: [])\n{\n    [field: AllowNull, MaybeNull]\n    private IRenderService RenderService => field\n        ??= ExCtx.GetService<IRenderService>(reuse: true);\n\n    public string ProcessInnerContent(string html, IContentType contentType, IContentTypeAttribute attribute, IField field)\n    {\n        var l = Log.Fn<string>();\n\n        // Find out if \"next\" field has inner-content. For that, sort attributes in the order they will be in\n        var sortedFields = contentType.Attributes\n            .OrderBy(a => a.SortOrder)\n            .ToList();\n        var index = sortedFields.IndexOf(attribute);\n        if (index == -1 || sortedFields.Count <= index + 1)\n            return l.Return(html, \"can't check next attribute for content-blocks\");\n\n        var nextField = sortedFields[index + 1];\n        var nextIsEntityField = nextField.Type == ValueTypes.Entity;\n        var nextInputType = nextField.InputType;\n        var nextHasContentBlocks = nextInputType.EqualsInsensitive(BlockBuildingConstants.InputTypeForContentBlocksField);\n\n        // Next ist not inner content, exit early\n        if (!nextIsEntityField || !nextHasContentBlocks)\n            return l.Return(html, \"no inner content; next field is not content-block\");\n\n        html = RenderService\n            .All(field.Parent, field: nextField.Name, merge: html)\n            .ToString() ?? \"\";\n\n        return l.ReturnAsOk(html);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Cms/WysiwygConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Services.CmsService;\n\ninternal class WysiwygConstants\n{\n    /// <summary>\n    /// The container Class - must usually be assigned, so that CSS inside it works\n    /// </summary>\n    internal const string WysiwygContainerClass = \"wysiwyg-container\";\n\n    /// <summary>\n    /// Debug class to show debug borders etc. with CSS\n    /// </summary>\n    internal const string WysiwygDebugClass = \"wysiwyg-debug\";\n\n    internal const string WysiwygCssPrefix = \"wysiwyg\";  // not used ATM\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Convert/ConvertService.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys.ConvertService;\nusing ToSic.Sys.Utils;\n\n// ReSharper disable MethodOverloadWithOptionalParameter\n\nnamespace ToSic.Sxc.Services;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ConvertService(\n    ConvertValueService cnvSvc,\n    LazySvc<ConvertForCodeService> code,\n    LazySvc<IJsonService> json)\n    : ServiceBase(\"Sxc.CnvSrv\", connect: [cnvSvc, code, json]), IConvertService\n{\n    public bool OptimizeNumbers => true;\n\n    public bool OptimizeBoolean => true;\n\n\n    public T? To<T>(object value)\n        => value.ConvertOrDefault<T>(numeric: OptimizeNumbers, truthy: OptimizeBoolean);\n\n    public T? To<T>(object value, NoParamOrder npo = default, T? fallback = default)\n        => cnvSvc.To(value, npo, fallback);\n\n\n    public int ToInt(object value)\n        => cnvSvc.To<int>(value);\n\n    public int ToInt(object value, int fallback = 0)\n        => cnvSvc.To(value, fallback: fallback);\n\n\n    public Guid ToGuid(object value)\n        => cnvSvc.To<Guid>(value);\n\n    public Guid ToGuid(object value, Guid fallback = default)\n        => cnvSvc.To(value, fallback: fallback);\n\n\n    public float ToFloat(object value)\n        => cnvSvc.To<float>(value);\n    public float ToFloat(object value, float fallback = default)\n        => cnvSvc.To(value, fallback: fallback);\n\n\n    public decimal ToDecimal(object value)\n        => cnvSvc.To<decimal>(value);\n\n    public decimal ToDecimal(object value, decimal fallback = default)\n        => cnvSvc.To(value, fallback: fallback);\n\n\n    public double ToDouble(object value)\n        => cnvSvc.To<double>(value);\n    public double ToDouble(object value, double fallback = default)\n        => cnvSvc.To(value, fallback: fallback);\n\n\n    public bool ToBool(object value)\n        => cnvSvc.To<bool>(value);\n\n    public bool ToBool(object value, bool fallback = false)\n        => cnvSvc.To(value, fallback: fallback);\n        \n\n    public string? ToString(object value)\n        => cnvSvc.To<string>(value);\n\n    public string? ToString(object value, string? fallback = null, NoParamOrder npo = default, bool fallbackOnNull = true) \n        => cnvSvc.ToString(value, npo, fallback, fallbackOnNull);\n\n\n    public string? ForCode(object value)\n        => code.Value.ForCode(value);\n\n    public string? ForCode(object value, string? fallback = default)\n        => code.Value.ForCode(value, fallback: fallback);\n        \n\n    public IJsonService Json => json.Value;\n\n    #region Invisible Converts for backward compatibility\n\n    public int ToInt32(object value)\n        => ToInt(value);\n\n    public float ToSingle(object value)\n        => ToFloat(value);\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Convert/ConvertService16.cs",
    "content": "﻿using ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Services.Sys.ConvertService;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Services;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ConvertService16(\n    ConvertValueService cnvSvc,\n    LazySvc<ConvertForCodeService> code,\n    LazySvc<IJsonService> json)\n    : ServiceWithContext(\"Sxc.CnvSrv\", connect: [cnvSvc, code, json]), IConvertService16\n{\n\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= ExCtx.GetCdf();\n\n    #region ToMock() new v21\n\n    ITypedItem IConvertService16.ToMockItem(object data, NoParamOrder npo, bool? propsRequired)\n        => Cdf.AsItem(data, new() { ItemIsStrict = true, UseMock = true})!;\n\n    T IConvertService16.ToMock<T>(object data, NoParamOrder npo, bool? propsRequired)\n        => Cdf.AsCustom<T>(source: data, mock: true);\n\n    #endregion\n\n    #region New v17 As conversions - used in Content App etc.\n\n    /// <inheritdoc/>\n    T IConvertService16.As<T>(ICanBeEntity source, NoParamOrder npo)\n        => Cdf.AsCustom<T>(source: source, npo: npo)!;\n\n    /// <inheritdoc/>\n    IEnumerable<T> IConvertService16.AsList<T>(IEnumerable<ICanBeEntity> source, NoParamOrder npo, bool nullIfNull)\n        => Cdf.AsCustomList<T>(source: source, npo: npo, nullIfNull: nullIfNull);\n\n    #endregion\n\n    //public bool OptimizeNumbers => true;\n\n    //public bool OptimizeBoolean => true;\n\n\n    public T? To<T>(object value, NoParamOrder npo = default, T? fallback = default)\n        => cnvSvc.To(value, npo, fallback);\n\n    public int ToInt(object value, NoParamOrder npo = default, int fallback = 0)\n        => cnvSvc.To(value, fallback: fallback);\n\n    public Guid ToGuid(object value, NoParamOrder npo = default, Guid fallback = default)\n        => cnvSvc.To(value, fallback: fallback);\n\n    public float ToFloat(object value, NoParamOrder npo = default, float fallback = default)\n        => cnvSvc.To(value, fallback: fallback);\n\n    public decimal ToDecimal(object value, NoParamOrder npo = default, decimal fallback = default)\n        => cnvSvc.To(value, fallback: fallback);\n\n    public double ToDouble(object value, NoParamOrder npo = default, double fallback = default)\n        => cnvSvc.To(value, fallback: fallback);\n\n    public bool ToBool(object value, NoParamOrder npo = default, bool fallback = false)\n        => cnvSvc.To(value, fallback: fallback);\n        \n\n    public string? ToString(object value, NoParamOrder npo = default, string? fallback = default, bool fallbackOnNull = true) \n        => cnvSvc.ToString(value, npo, fallback, fallbackOnNull);\n\n    public string? ForCode(object value, NoParamOrder npo = default, string? fallback = default)\n        => code.Value.ForCode(value, npo, fallback);\n        \n\n    public IJsonService Json => json.Value;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Convert/IConvertService.cs",
    "content": "﻿\n\n// ReSharper disable MethodOverloadWithOptionalParameter\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Conversion helper for things which are very common in web-code like Razor and WebAPIs.\n/// </summary>\n/// <remarks>\n/// It's mainly a safe conversion from anything to a target-type.\n/// \n/// Some special things it does:\n/// * Strings like \"4.2\" reliably get converted to int 4 which would otherwise return 0\n/// * Numbers like 42 reliably converts to bool true which would otherwise return false\n/// * Numbers like 42.5 reliably convert to strings \"42.5\" instead of \"42,5\" in certain cultures\n/// \n/// History: New in v12.05\n/// </remarks>\n[PublicApi]\npublic interface IConvertService\n{\n    // Important internal information\n    // Most of our APIs have a pleaseNameParams parameter very early on\n    // But these don't enforce that for the second fallback parameter.\n    // The reason is that they are very common, and if people would try\n    // ToInt(value, 27) they would always get a\n    // \"second parameter is not a string\" - which is hard for people to figure out why this happens\n\n\n    ///// <summary>\n    ///// If set to true (default) will optimize converting numbers.\n    ///// For example, a string like \"4.2\" will properly convert to an int of 4.\n    ///// If set to false, this optimization doesn't happen and a string \"4.2\" would result in a 0 int\n    ///// </summary>\n    //[PrivateApi(\"Set to private in 16.03 as it was never communicated and it's read-only anyhow, so it can't be in use\")]\n    //bool OptimizeNumbers { get; }\n\n    ///// <summary>\n    ///// If set to true, will treat a number like 2 or -1 and strings like \"2\" as true.\n    ///// If set to false, only 1 will be true, other numbers will be false.\n    ///// </summary>\n    //[PrivateApi(\"Set to private in 16.03 as it was never communicated and it's read-only anyhow, so it can't be in use\")]\n    //bool OptimizeBoolean { get; }\n\n    /// <summary>\n    /// Convert any object safely to the desired type T.\n    /// If conversion fails, it will return `default(T)`, which is 0 for most numbers, `false` for boolean or `null` for strings or objects.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    T? To<T>(object value);\n\n    /// <summary>\n    /// Convert any object safely to the desired type T.\n    /// If conversion fails, it will return the `fallback` parameter as given.\n    /// Since the fallback is typed, you can usually call this method without specifying T explicitly, so this should work:\n    /// \n    /// ```\n    /// var c1 = Convert.To(\"5\", 100); // will return 5\n    /// var c2 = Convert.To(\"\", 100);  // will return 100\n    /// ```\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"value\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails.</param>\n    /// <returns></returns>\n    T? To<T>(object value,\n        NoParamOrder npo = default,\n        T? fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to bool.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    ///\n    /// _Note that it's called ToBool, not ToBoolean, because the core type is also called bool, not boolean. This is different from `System.Convert.ToBoolean(...)`_\n    /// </summary>\n    bool ToBool(object value);\n\n    /// <summary>\n    /// Convert any object safely to bool, or if that fails, return the fallback value.\n    /// \n    /// _Note that it's called ToBool, not ToBoolean, because the core type is also called bool, not boolean. This is different from `System.Convert.ToBoolean(...)`_\n    /// </summary>\n    /// <param name=\"value\"></param>\n    /// <param name=\"fallback\"></param>\n    /// <returns></returns>\n    bool ToBool(object value, bool fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to decimal.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    decimal ToDecimal(object value);\n\n    /// <summary>\n    /// Convert any object safely to decimal, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    decimal ToDecimal(object value, decimal fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to double.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    double ToDouble(object value);\n\n    /// <summary>\n    /// Convert any object safely to double, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    double ToDouble(object value, double fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to float.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    ///\n    /// _Note that it's called ToFloat, not ToSingle, because the core type is also called float, not single. This is different from `System.Convert.ToSingle(...)`_\n    /// </summary>\n    float ToFloat(object value);\n\n    /// <summary>\n    /// Convert any object safely to float, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    ///\n    /// _Note that it's called ToFloat, not ToSingle, because the core type is also called float, not single. This is different from `System.Convert.ToSingle(...)`_\n    /// </summary>\n    float ToFloat(object value, float fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to standard int.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    int ToInt(object value);\n\n    /// <summary>\n    /// Convert any object safely to standard int, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    int ToInt(object value, int fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to a Guid\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    Guid ToGuid(object value);\n\n    /// <summary>\n    /// Convert any object safely to standard guid, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    Guid ToGuid(object value, Guid fallback = default);\n\n\n\n    /// <summary>\n    /// Convert any object safely to string.\n    /// This does the same as <see cref=\"To{T}(object)\"/> but this is easier to type in Razor.\n    /// </summary>\n    string? ToString(object value);\n\n    /// <summary>\n    /// Convert any object safely to string - or if that fails, return the fallback value.\n    /// \n    /// This does **NOT** do the same as <see cref=\"To{T}(object, NoParamOrder, T)\"/>.\n    /// In the standard implementation would only give you the fallback, if conversion failed.\n    /// But this ToString will also give you the fallback, if the result is null. \n    /// </summary>\n    /// <param name=\"value\">The value to convert</param>\n    /// <param name=\"fallback\">Fallback in case conversion fails or result is null</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallbackOnNull\">Determine that nulls should also fallback, default is `true`</param>\n    string? ToString(object value,\n        string? fallback = default,\n        NoParamOrder npo = default,\n        bool fallbackOnNull = true);\n\n    /// <summary>\n    /// Convert any object safely to string to put into source code like HTML-attributes, inline-JavaScript or similar.\n    /// This is usually used to ensure numbers, booleans and dates are in a format which works.\n    /// Especially useful when giving data to a JavaScript, Json-Fragment or an Html Attribute.\n    ///\n    /// * booleans will be `true` or `false` (not `True` or `False`)\n    /// * numbers will have a . notation and never a comma (like in de-DE cultures)\n    /// * dates will convert to ISO format without time zone\n    /// </summary>\n    string? ForCode(object value);\n\n    /// <summary>\n    /// Same as <see cref=\"ForCode(object)\"/>, but with fallback, in case the conversion fails.\n    /// </summary>\n    /// <returns></returns>\n    string? ForCode(object value, string? fallback = default);\n\n    /// <summary>\n    /// Sub-Service to convert JSON\n    /// </summary>\n    IJsonService Json { get; }\n\n    #region Invisible Converts for backward compatibility\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    int ToInt32(object value);\n\n    [PrivateApi]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    float ToSingle(object value);\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Convert/IConvertService16.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Sxc.Data;\n\n// 2024-01-22 2dm\n// Remove all convert methods which are just missing the optional parameters, to make the API smaller.\n// Assume it has no side effects, must watch.\n// Remove this note 2024-Q3 (ca. July)\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Helper on [`Kit.Convert`](xref:ToSic.Sxc.Services.ServiceKit16.Convert) for common conversions in web-code like Razor and WebAPIs.\n/// </summary>\n/// <remarks>\n/// It's mainly a safe conversion from anything to a target-type.\n/// \n/// Some special things it does:\n/// * Strings like \"4.2\" reliably get converted to int 4 which would otherwise return 0\n/// * Numbers like 42 reliably converts to bool true which would otherwise return false\n/// * Numbers like 42.5 reliably convert to strings \"42.5\" instead of \"42,5\" in certain cultures\n/// \n/// History\n/// \n/// * New in v16.03\n/// * Difference to <see cref=\"IConvertService\"/> is that the param `fallback` must always be named\n/// </remarks>\n[PublicApi]\npublic interface IConvertService16\n{\n    /// <summary>\n    /// Convert any object safely to the desired type.\n    /// If conversion fails, it will return the `fallback` parameter as given, or `default(T)`.\n    /// Since the fallback is typed, you can usually call this method without specifying T explicitly, so this should work:\n    /// \n    /// ```\n    /// var c1 = Convert.To(\"5\", fallback: 100); // will return 5\n    /// var c2 = Convert.To(\"\", fallback: 100);  // will return 100\n    /// var c1 = Convert.To(\"\"); // will return 0\n    /// ```\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"value\">value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails. If not specified, will use `default(T)`</param>\n    /// <returns></returns>\n    T? To<T>(object value, NoParamOrder npo = default, T? fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to bool, or if that fails, return the fallback value.\n    /// \n    /// _Note that it's called ToBool, not ToBoolean, because the core type is also called bool, not boolean. This is different from `System.Convert.ToBoolean(...)`_\n    /// </summary>\n    /// <param name=\"value\">value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails. Defaults to `false`.</param>\n    /// <returns></returns>\n    bool ToBool(object value, NoParamOrder npo = default, bool fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to decimal, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object, NoParamOrder, T)\"/> but this is easier to type in Razor.\n    /// </summary>\n    /// <param name=\"value\">value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails. Defaults to `0`.</param>\n    decimal ToDecimal(object value, NoParamOrder npo = default, decimal fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to double, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object, NoParamOrder, T)\"/> but this is easier to type in Razor.\n    /// </summary>\n    /// <param name=\"value\">value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails. Defaults to `0`.</param>\n    double ToDouble(object value, NoParamOrder npo = default, double fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to float, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object, NoParamOrder, T)\"/> but this is easier to type in Razor.\n    ///\n    /// _Note that it's called ToFloat, not ToSingle, because the core type is also called float, not single. This is different from `System.Convert.ToSingle(...)`_\n    /// </summary>\n    /// <param name=\"value\">value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails. Defaults to `0`.</param>\n    float ToFloat(object value, NoParamOrder npo = default, float fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to standard int, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object, NoParamOrder, T)\"/> but this is easier to type in Razor.\n    /// </summary>\n    /// <param name=\"value\">value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails. Defaults to `0`.</param>\n    int ToInt(object value, NoParamOrder npo = default, int fallback = default);\n\n    /// <summary>\n    /// Convert any object safely to standard guid, or if that fails, return the fallback value.\n    /// This does the same as <see cref=\"To{T}(object, NoParamOrder, T)\"/> but this is easier to type in Razor.\n    /// </summary>\n    /// <param name=\"value\">value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails. Defaults to `Guid.Empty`.</param>\n    Guid ToGuid(object value, NoParamOrder npo = default, Guid fallback = default);\n\n\n    /// <summary>\n    /// Convert any object safely to string - or if that fails, return the fallback value.\n    /// \n    /// This does **NOT** do the same as <see cref=\"To{T}(object, NoParamOrder, T)\"/>.\n    /// In the standard implementation would only give you the fallback, if conversion failed.\n    /// But this ToString will also give you the fallback, if the result is null. \n    /// </summary>\n    /// <param name=\"value\">The value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">Fallback in case conversion fails or result is null. Defaults to `null`.</param>\n    /// <param name=\"fallbackOnNull\">Determine that nulls should also fallback, default is `true`</param>\n    string? ToString(object value,\n        NoParamOrder npo = default,\n        string? fallback = default,\n        bool fallbackOnNull = true);\n\n    /// <summary>\n    /// Convert any object safely to string to put into source code like HTML-attributes, inline-JavaScript or similar.\n    /// This is usually used to ensure numbers, booleans and dates are in a format which works.\n    /// Especially useful when giving data to a JavaScript, Json-Fragment or an Html Attribute.\n    ///\n    /// * booleans will be `true` or `false` (not `True` or `False`)\n    /// * numbers will have a . notation and never a comma (like in de-DE cultures)\n    /// * dates will convert to ISO format without time zone\n    /// \n    /// Optionally also allows a `fallback` to use instead of the defaults above.\n    /// </summary>\n    /// <returns></returns>\n    /// <param name=\"value\">value to convert</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"fallback\">The value used if conversion fails. Defaults to `null`.</param>\n    string? ForCode(object value, NoParamOrder npo = default, string? fallback = default);\n\n    /// <summary>\n    /// Sub-Service to convert JSON\n    /// </summary>\n    IJsonService Json { get; }\n\n    #region New v17 As conversions - used in Content App etc.\n\n    /// <inheritdoc cref=\"ITypedApi.As{T}\"/>\n    T As<T>(ICanBeEntity source, NoParamOrder npo = default)\n        where T : class, IModelFromData;\n    \n    /// <inheritdoc cref=\"ITypedApi.AsList{T}\"/>\n    IEnumerable<T> AsList<T>(IEnumerable<ICanBeEntity> source, NoParamOrder npo = default, bool nullIfNull = default)\n        where T : class, IModelFromData;\n\n    #endregion\n\n    #region ToMock - new v21\n\n    /// <summary>\n    /// Convert anonymous objects to be a mock TypedItem - for fallback when some original data may be missing.\n    /// </summary>\n    /// <param name=\"data\">The data, usually an anonymous object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"propsRequired\">make the resulting object [strict](xref:NetCode.Conventions.PropertiesRequired), default `true`</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New v21; replaces older ToItem(..., mock: true)\n    /// </remarks>\n    public ITypedItem ToMockItem(object data, NoParamOrder npo = default, bool? propsRequired = default);\n\n    /// <summary>\n    /// Convert anonymous objects to be a mock item/model of your choice - for fallback when some original data may be missing.\n    /// </summary>\n    /// <typeparam name=\"T\">the target type</typeparam>\n    /// <param name=\"data\">The data, usually an anonymous object</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"propsRequired\">make the resulting object [strict](xref:NetCode.Conventions.PropertiesRequired), default `true`</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New v21; replaces older ToItem(..., mock: true)\n    /// </remarks>\n    T ToMock<T>(object data, NoParamOrder npo = default, bool? propsRequired = default)\n        where T : class, IModelFromData;\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Data.Sys/DataService.cs",
    "content": "﻿using ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.DataSource.Sys.Catalog;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Eav.Services;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Services.Sys.DataService;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Users;\n\n// TODO: MAKE PRIVATE AGAIN AFTER MOVING TO ToSic.Sxc.Custom\n\nnamespace ToSic.Sxc.Services.Data.Sys;\n\n[PrivateApi(\"hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class DataService(\n    LazySvc<IDataSourcesService> dataSources,\n    LazySvc<DataSourceCatalog> catalog,\n    LazySvc<IAppsCatalog> appsCatalog,\n    LazySvc<QueryManager<Query>> queryManager,\n    IUser user)\n    : ServiceWithContext(\"Sxc.DatSvc\", connect: [user, dataSources, catalog, appsCatalog, queryManager]),\n        IDataService,\n        IServiceWithSetup<DataService.Options>\n{\n    public record Options(IAppIdentity? AppIdentity, Func<ILookUpEngine?>? GetLookup);\n\n    public override void ConnectToRoot(IExecutionContext exCtx)\n    {\n        base.ConnectToRoot(exCtx);\n        Setup(new(exCtx.GetState<Sxc.Apps.IApp>(), () => (exCtx as IExCtxLookUpEngine)?.LookUpForDataSources));\n    }\n\n    public void Setup(Options opts)\n    {\n        _appIdentity = opts.AppIdentity ?? _appIdentity;\n        _getLookup = opts.GetLookup ?? _getLookup;\n\n    }\n    private IAppIdentity? _appIdentity;\n\n    //// TODO: MAKE PRIVATE AGAIN AFTER MOVING TO ToSic.Sxc.Custom\n    //public IDataService SetupOld(IAppIdentity? appIdentity, Func<ILookUpEngine?>? getLookup)\n    //{\n    //    _appIdentity = appIdentity ?? _appIdentity;\n    //    _getLookup = getLookup ?? _getLookup;\n    //    return this;\n    //}\n\n\n    public IDataService SpawnNew(NoParamOrder npo = default, IAppIdentity? appIdentity = default, int zoneId = default, int appId = default)\n    {\n        // Make sure we have an AppIdentity if possible - or reuse the existing, though it could be null\n        if (appIdentity == default)\n        {\n            if (appId != default)\n                appIdentity = zoneId == default\n                    ? appsCatalog.Value.AppIdentity(appId)\n                    : new AppIdentity(zoneId, appId);\n            else\n                appIdentity = _appIdentity;\n        }\n\n        var newDs = new DataService(dataSources, catalog, appsCatalog, queryManager, user);\n        if (ExCtxOrNull != null)\n        {\n            newDs.ConnectToRoot(ExCtxOrNull);\n            newDs.Setup(new(appIdentity, null));\n        }\n        else\n        {\n            newDs.Setup(new(appIdentity, _getLookup));\n        }\n        return newDs;\n    }\n\n    private DataSourceOptionsMs OptionsMs => _optionsHandler.Get(() => new(_appIdentity, _getLookup))!;\n    private readonly GetOnce<DataSourceOptionsMs> _optionsHandler = new();\n\n    private Func<ILookUpEngine?>? _getLookup;\n\n\n    public IDataSource GetAppSource(NoParamOrder npo = default, object? parameters = default, object? options = default)\n    {\n        var l = Log.Fn<IDataSource>($\"{nameof(options)}: {options}\");\n        var fullOptions = OptionsMs.SafeOptions(parameters, options: options, identityRequired: true);\n        var appSource = dataSources.Value.CreateDefault(fullOptions);\n        return l.Return(appSource);\n    }\n\n\n    #region GetQuery\n\n    public IDataSource? GetQuery(string? name = default,\n        NoParamOrder npo = default,\n        IDataSourceLinkable? attach = default,\n        object? parameters = default)\n        => new GetQueryMs<Query>(queryManager, OptionsMs, Log).GetQuery(name, npo, attach, parameters);\n\n    #endregion\n\n    #region Linking\n\n    public IDataSourceLink CreateLink(IDataSourceLinkable source,\n        NoParamOrder npo = default,\n        string? inName = default,\n        string? outName = default\n    )\n    {\n        var link = source.GetLink();\n        return inName != default || outName != default\n            ? link.WithRename(outName: outName, inName: inName)\n            : link;\n    }\n\n    public IDataSourceLink CombineLinks(params IDataSourceLinkable[] sources)\n    {\n        if (sources.Length == 0)\n            throw new ArgumentException(@\"At least one source must be provided\", nameof(sources));\n\n        var first = sources[0].GetLink();\n        return sources.Length == 1\n            ? first\n            : first.WithMore(sources.Skip(1).ToArray());\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Data.Sys/DataService_GetSource.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Sys.Errors;\nusing ToSic.Sys.Exceptions;\nusing ToSic.Sys.Users;\nusing ToSic.Sys.Utils;\nusing static ToSic.Eav.Data.Sys.DataConstants;\n\n\nnamespace ToSic.Sxc.Services.Data.Sys;\npartial class DataService\n{\n\n    // IMPORTANT - this is different! from the _DynCodeRoot - as it should NOT auto attach!\n    public T GetSource<T>(\n        NoParamOrder npo = default,\n        IDataSourceLinkable? attach = default,\n        object? parameters = default,\n        object? options = default) where T : IDataSource\n    {\n        var l = Log.Fn<T>($\"{nameof(attach)}: {attach}, {nameof(options)}: {options}\");\n\n        // If no in-source was provided, make sure that we create one from the current app\n        var fullOptions = DataSourceOptionsExtensions.WithAttach(OptionsMs.SafeOptions(parameters, options: options), attach);\n        var ds = dataSources.Value.Create<T>(/*attach: attach,*/ options: fullOptions);\n\n        return l.Return(ds);\n    }\n\n    public IDataSource GetSource(\n        NoParamOrder npo = default,\n        string? name = null,\n        IDataSourceLinkable? attach = null,\n        object? parameters = default,\n        object? options = null,\n        bool? debug = default\n    )\n    {\n        var l = Log.Fn<IDataSource>($\"{nameof(name)}: {name}, {nameof(attach)}: {attach}, {nameof(options)}: {options}\");\n\n        // Do this first, to ensure AppIdentity is really known/set\n        var safeOptions = DataSourceOptionsExtensions.WithAttach(OptionsMs.SafeOptions(parameters, options: options), attach);\n        var appId = safeOptions.AppIdentityOrReader!.AppId;\n\n        var dsInfo = name.IsEmptyOrWs()\n            ? null\n            : catalog.Value.FindDataSourceInfo(name, appId);\n        if (dsInfo == null)\n            throw new ArgumentException($\"Tried to create DataSource with name '{name}' but it was not found. \" +\n                                        \"Either you a) mis-typed it, \" +\n                                        $\"b) it's not located in the 'DataSources' folder of the app '{appId}', \" +\n                                        $\"c) the class name is not 'public class {name}', \" +\n                                        $\"d) the file name is not 'DataSources/{name}.cs'. \");\n\n        // Decide if we should show errors or not\n        var showErrors = debug == true || (user.IsSystemAdmin && debug != false);\n        if (dsInfo.ErrorOrNull != null && showErrors)\n            throw l.Done(DevException(name, \"a compile error\",\n                \"It could also be that the file name and class names don't match. \\n\" +\n                $\"Title: '{dsInfo.ErrorOrNull.Title}'; \\n\" +\n                $\"Message: {dsInfo.ErrorOrNull.Message}; \\n\" +\n                $\"Debug Info: {ErrorDebugMessage}\"));\n\n        var ds = dataSources.Value.Create(dsInfo.Type, /*attach: attach,*/ options: safeOptions);\n\n        // If it's the superuser (often developing the DS) we should show errors instead of letting it just happen\n        if (!showErrors || !ErrorExtensions.IsError((IDataSource)ds))\n            return l.Return(ds);\n\n        // Work out more information about the error\n        var errEntity = Enumerable.First<IEntity>(ds.List);\n        var message = $\"Title: '{errEntity.Get<string>(ErrorFieldTitle)}'; \\n\" +\n                      $\"Message: {errEntity.Get<string>(ErrorFieldMessage)}; \\n\" +\n                      $\"Debug Info: {errEntity.Get<string>(ErrorFieldDebugNotes)}\";\n        throw l.Done(DevException(name, \"a bug in the code\", message));\n\n    }\n\n    private static Exception DevException(string? name, string reason, string? more = default)\n    {\n        var intro =  $\"The DataSource {name} threw an error. Probably: '{reason}'. \" +\n                     \"Normally this would be invisible and just return a first item with the error message, \" +\n                     $\"but because you are logged in as {nameof(IUser.IsSystemAdmin)} the error is shown directly. \" +\n                     \"If you wish to disable this, set 'debug: false'. \" +\n                     \"These are the error details: \\n\" +\n                     more;\n        return new ExceptionSuperUserOnly(new(intro));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Features/FeaturesService.cs",
    "content": "﻿using ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Services;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class FeaturesService(ISysFeaturesService sysFeaturesSvc)\n    : ServiceBase($\"{SxcLogName}.FeatSv\"), IFeaturesService, ICanDebug\n{\n    public bool IsEnabled(params string[] nameIds)\n    {\n        var result = sysFeaturesSvc.IsEnabled(nameIds);\n        if (!Debug) return result;\n        var l = Log.Fn<bool>(string.Join(\",\", nameIds ?? []));\n        return l.Return(result, $\"{result}\");\n    }\n\n    public bool Debug { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/HttpCtx/HttpContextService.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\n#if !NETFRAMEWORK\nusing Microsoft.AspNetCore.Http;\n#endif\n\n// Important: the namespace cannot be \"HttpContext\" because that would cause a conflict with the System.Web.HttpContext class in .net framework\n// which is used in the implementation. So we use \"HttpCtx\" instead.\nnamespace ToSic.Sxc.Services.HttpCtx;\n\n#if NETFRAMEWORK\ninternal class HttpContextService(): ServiceWithContext(\"Sxc.HttpCx\"), IHttpContextService\n#else\ninternal class HttpContextService(IHttpContextAccessor httpContextAccessor): ServiceWithContext(\"Sxc.HttpCx\", connect: [httpContextAccessor]), IHttpContextService\n#endif\n{\n    public void Redirect301(string url) => Redirect(url, 301);\n\n    public void Redirect302(string url) => Redirect(url, 302);\n\n\n    public void Redirect(string url, int statusCode)\n    {\n#if NETFRAMEWORK\n        // The .net framework implementation uses the \"global\" HttpContext, which isn't perfect, but that's how it works in DNN.\n        var response = System.Web.HttpContext.Current.Response;\n\n        // Clear any previous headers/content\n        response.Clear();\n\n        // Manually set the 301 status code - defaults to 302 if not specified\n        response.StatusCode = statusCode;\n        response.StatusDescription = StatusDescriptions.TryGetValue(statusCode, out var description)\n            ? description\n            : \"Unknown Status\";\n\n        // Set the destination\n        response.AddHeader(\"Location\", url);\n\n        // End the response to prevent further processing\n        response.End();\n#else\n        // Resolve HttpContext once to avoid repeated property access on the accessor\n        var httpContext = httpContextAccessor.HttpContext;\n        if (httpContext is null)\n        {\n            Log.A($\"Can't redirect to '{url}' because there is no current HttpContext.\");\n            return;\n        }\n\n        var response = httpContext.Response;\n        if (response.HasStarted)\n        {\n            Log.A($\"Can't redirect to '{url}' because the response has already started.\");\n            return;\n        }\n\n        // ASP.NET Core doesn't support StatusDescription, so just set the code and location.\n        response.Clear();\n        response.StatusCode = statusCode;\n        response.Headers[\"Location\"] = url;\n        response.ContentLength = 0;\n#endif\n\n    }\n\n    /// <summary>\n    /// 300-level status codes and their descriptions for reference. This can be expanded as needed.\n    /// https://developer.att.com/video-optimizer/docs/best-practices/http-300-status-codes\n    /// </summary>\n    private static readonly Dictionary<int, string> StatusDescriptions = new()\n    {\n        { 301, \"Moved Permanently\" },\n        { 302, \"Found\" },\n        { 303, \"See Other\" },\n        { 304, \"Not Modified\" },\n        { 305, \"Use Proxy\" },\n        { 306, \"obsolete status code - not used\" },\n        { 307, \"Temporary Redirect\" },\n        { 308, \"Permanent Redirect\" }\n    };\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/HttpCtx/IHttpContextService.cs",
    "content": "﻿#pragma warning disable IDE0130\nnamespace ToSic.Sxc.Services;\n#pragma warning restore IDE0130\n\n/// <summary>\n/// Internal service for now, not for public use.\n/// Later we'll probably create a different API to make this more generic for .net framework and .net core,\n/// and it will probably not be called HttpContext.\n/// </summary>\n[PrivateApi(\"WIP 21.06, not for public use, internal only\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IHttpContextService\n{\n    /// <summary>\n    /// Do a redirect to a url with a custom status code.\n    /// </summary>\n    /// <remarks>\n    /// This is a low-level method, and the status code should be a 300-level code for redirection.\n    /// For common use cases, consider using the Redirect301 or Redirect302 methods which are more straightforward and set the appropriate status codes automatically.\n    /// </remarks>\n    /// <param name=\"url\">url to redirect to.</param>\n    /// <param name=\"statusCode\">The HTTP status code to use for the redirect. Cannot be null or empty.</param>\n    void Redirect(string url, int statusCode);\n\n    /// <summary>\n    /// Performs a permanent HTTP 301 redirect to the specified URL.\n    /// </summary>\n    /// <remarks>\n    /// Use this method to indicate that a resource has been permanently moved to a new location.\n    /// Clients and search engines will update their references to the new URL. Ensure that the specified URL is valid\n    /// and accessible.\n    /// </remarks>\n    /// <param name=\"url\">The destination URL to which the client is permanently redirected. Cannot be null or empty.</param>\n    void Redirect301(string url);\n\n    /// <summary>\n    /// Performs a temporary HTTP 302 redirect to the specified URL.\n    /// </summary>\n    /// <remarks>\n    /// Use this method to indicate that a resource has been temporarily moved to a new location.\n    /// Clients and search engines will continue to use the original URL for future requests.\n    /// </remarks>\n    /// <param name=\"url\">The destination URL to which the client is temporarily redirected. Cannot be null or empty.</param>\n    void Redirect302(string url);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Json/JsonService.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.DynamicJacket;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing static ToSic.Eav.Serialization.Sys.Json.JsonOptions;\n\nnamespace ToSic.Sxc.Services;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class JsonService(Generator<CodeJsonWrapper> wrapJsonGenerator)\n    : ServiceBase(\"Sxc.JsnSvc\", connect: [wrapJsonGenerator]), IJsonService\n{\n    /// <inheritdoc />\n    public T? To<T>(string json) \n        => JsonSerializer.Deserialize<T>(json, SafeJsonForHtmlAttributes);\n\n    /// <inheritdoc />\n    public object? ToObject(string json)\n        => JsonSerializer.Deserialize<object>(json, SafeJsonForHtmlAttributes);\n\n    /// <inheritdoc />\n    public string ToJson(object item)\n        => JsonSerializer.Serialize(item, SafeJsonForHtmlAttributes);\n\n    /// <inheritdoc />\n    public string ToJson(object item, int indentation)\n        => JsonSerializer.Serialize(item, SafeJsonForHtmlAttributes);\n\n    /// <inheritdoc />\n    public ITyped? ToTyped(string json, NoParamOrder npo = default, string? fallback = default, bool? propsRequired = default)\n        => wrapJsonGenerator.New()\n            .Setup(WrapperSettings.Typed(true, true, propsRequired: propsRequired ?? true))\n            .JsonToTyped(json, npo, fallback);\n\n\n    /// <inheritdoc />\n    public IEnumerable<ITyped>? ToTypedList(string json, NoParamOrder npo = default, string? fallback = default, bool? propsRequired = default)\n        => wrapJsonGenerator.New()\n            .Setup(WrapperSettings.Typed(true, true, propsRequired: propsRequired ?? true))\n            .JsonToTypedList(json, npo, fallback);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/KeyService/KeyService.cs",
    "content": "﻿namespace ToSic.Sxc.Services;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class KeyService : IKeyService\n{\n    private UniqueKeysServices UniqueKeysSvc => field ??= new();\n\n    /// <inheritdoc cref=\"IKeyService.UniqueKey\"/>\n    public string UniqueKey => UniqueKeysSvc.UniqueKey;\n\n    /// <inheritdoc cref=\"IKeyService.UniqueKeyOf\"/>\n    public string UniqueKeyOf(object data) => UniqueKeysServices.UniqueKeyOf(data);\n\n    /// <inheritdoc cref=\"IKeyService.UniqueKeyWith\"/>\n    public string UniqueKeyWith(params object[] partners) => UniqueKeysSvc.UniqueKeyWithGen(partners);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/KeyService/UniqueKeysServices.cs",
    "content": "﻿using ToSic.Eav.Identity;\n\nusing ToSic.Sxc.Adam;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class UniqueKeysServices\n{\n    internal const int UniqueKeyLength = 8;\n    internal const string NullValue = \"null\";\n    internal const string PfxBool = \"b\";\n    internal const string PfxNum = \"n\";\n    internal const string PfxString = \"s\";\n    internal const string PfxHash = \"hash\";\n    internal const string PfxEntity = \"eid\";\n    internal const string PfxDate = \"d\";\n    internal const string PfxGuid = \"g\";\n    internal const string PfxUrl = \"u\";\n\n    /// <summary>\n    /// A unique, random key for the current module.\n    /// It's recommended for giving DOM elements a unique id for scripts to then access them.\n    /// \n    /// It's generated for every content-block, and more reliable than `Module.Id`\n    /// since that sometimes results in duplicate keys, if the many blocks are used inside each other.\n    ///\n    /// It's generated using a GUID and converted/shortened. \n    /// In the current version it's 8 characters long, so it has 10^14 combinations, making collisions extremely unlikely.\n    /// (currently 8 characters)\n    /// </summary>\n    [PrivateApi]\n    public string UniqueKey => field ??= UniqueKeyGen();\n\n\n    [PrivateApi]\n    internal static string UniqueKeyGen() => Guid2UniqueKey(Guid.NewGuid());\n\n\n    [PrivateApi]\n    internal string UniqueKeyWithGen(object[] partners) => $\"{UniqueKey}-{UniqueKeysOf(partners)}\";\n\n    internal static string UniqueKeysOf(params object[] data) => \n        data.SafeNone() ? NullValue : string.Join(\"-\", data.Select(UniqueKeyOf));\n\n    [PrivateApi]\n    internal static string UniqueKeyOf(object data)\n    {\n        // Handle some initial basic cases\n        switch (data)\n        {\n            case null: return NullValue;\n            case bool b: return $\"{PfxBool}{(b ? \"true\" : \"false\")}\";\n            case string s: return $\"{PfxString}{s.GetHashCode()}\";\n            case DateTime d: return $\"{PfxDate}{d.ToString(\"O\").RemoveAll(':', '-', 'T', 'Z', '.').TrimEnd('0')}\";\n            case Guid guid: return $\"{PfxGuid}{Guid2UniqueKey(guid)}\";\n            case ICanBeEntity canBeEntity:\n                var entity = canBeEntity.Entity;\n                if (entity == null! /* paranoid */)\n                    return $\"{PfxEntity}{Obj2HashKey(canBeEntity)}\";\n                if (entity.EntityGuid != Guid.Empty)\n                    return $\"{PfxEntity}{Guid2UniqueKey(entity.EntityGuid)}\";\n                if (entity.EntityId > 0)\n                    return $\"{PfxEntity}{entity.EntityId}\";\n                return Obj2HashKey(entity);\n            case IAsset asset:\n                return $\"{PfxUrl}{asset.Url?.GetHashCode()}\";\n        }\n\n        // handle numbers etc.\n        if (data.IsNumeric()) //.GetType().UnboxIfNullable().IsNumeric())\n            return PfxNum + data.ConvertOrFallback(\"convert-num-to-string-failed\", numeric: true).Replace(\".\", \"_\");\n\n        return Obj2HashKey(data);\n    }\n\n    private static string Guid2UniqueKey(Guid guid) => guid.GuidCompress().Substring(0, UniqueKeyLength);\n\n    private static string Obj2HashKey(object obj) => $\"{PfxHash}{obj.GetHashCode()}\";\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Kits/IKeyService.cs",
    "content": "﻿using ToSic.Sxc.Adam;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Key`](xref:ToSic.Sxc.Services.ServiceKit16.Key) to generate module/block level unique keys.\n/// </summary>\n/// <remarks>\n/// Rarely used, as the RazorTyped has a UniqueKey property which comes from this service.\n/// You only need this service, if you need to create combined keys (like with an entity).\n/// \n/// History: Introduced v16.04\n/// </remarks>\n[PublicApi]\npublic interface IKeyService\n{\n    /// <summary>\n    /// A unique, random key for the current module.\n    /// It's recommended for giving DOM elements a unique id for scripts to then access them.\n    /// \n    /// It's generated for every content-block, and more reliable than `Module.Id`\n    /// since that sometimes results in duplicate keys, if the many blocks are used inside each other.\n    ///\n    /// It's generated using a GUID and converted/shortened. \n    /// In the current version it's 8 characters long, so it has 10^14 combinations, making collisions extremely unlikely.\n    /// (currently 8 characters)\n    ///\n    /// > [!TIP]\n    /// > To get a unique key which is based on additional objects such as Entities,\n    /// > use the <see cref=\"UniqueKeyWith\"/> method.\n    /// </summary>\n    /// <remarks>\n    /// If you get a fresh <see cref=\"IKeyService\"/> it will also create a new UniqueKey.\n    /// So your code should usually use the built-in property `UniqueKey` which comes from the shared ServiceKit <see cref=\"ServiceKit16.Key\"/>.\n    /// </remarks>\n    string UniqueKey { get; }\n\n    [PrivateApi(\"not yet sure if we should publish this\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    string UniqueKeyOf(object data);\n\n    /// <summary>\n    /// Generate a unique key based on the <see cref=\"UniqueKey\"/> and additional objects.\n    ///\n    /// It has a special mechanisms for creating unique keys for specific data types such as entities,\n    /// so calling this multiple times with the same objects will still result in the same key being generated.\n    ///\n    /// Special behaviors:\n    ///\n    /// * Strings will use the HashCode\n    /// * Entities and similar will use a shortened unique string based on the GUID\n    /// * Assets (files, folders) will use the HashCode of their <see cref=\"IAsset.Url\"/>\n    /// * Dates are converted to a safe string and trimmed for all trailing zeros\n    /// * Most key parts will receive a simple prefix making debugging easier\n    /// </summary>\n    /// <param name=\"partners\"></param>\n    /// <returns></returns>\n    string UniqueKeyWith(params object[] partners);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Kits/ServiceKit14.cs",
    "content": "﻿using Connect.Koi;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Services.PageShield;\nusing ToSic.Sxc.Services.Sys;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Default ServiceKit for 2sxc v14.\n/// Provided in Razor and WebApi as `Kit`.\n/// </summary>\n/// <remarks>\n/// * History: Added v14.04\n/// </remarks>\n[PublicApi]\n[method: PrivateApi(\"Public constructor for DI\")]\npublic class ServiceKit14() : ServiceKit(\"Sxc.Kit14\") // , IServiceKitForTypedData /* probably not needed, since typed data is always newer base classes */\n{\n    /// <summary>\n    /// The ADAM Service, used to retrieve files and maybe more. \n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IAdamService Adam => field ??= GetKitService<IAdamService>();\n\n    // 2025-05-11 2dm commented out, previous was internal / marked obsolete\n    ///// <summary>\n    ///// The CMS Service - not for use\n    ///// </summary>\n    //[PrivateApi(\"Was never public but could be in use\")]\n    //[Obsolete(\"This API was never published, do not use.\")]\n    //[ShowApiWhenReleased(ShowApiMode.Never)]\n    //internal ICmsService Cms => field ??= GetKitService<ICmsService>();\n\n    ///// <summary>\n    ///// Access for TypedData when using this service kit with the interface.\n    ///// New & internal v20.\n    ///// </summary>\n    //ICmsService IServiceKitForTypedData.Cms => Cms;\n\n    /// <summary>\n    /// The Convert Service, used to convert any kind of data type to another data type\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IConvertService Convert => field ??= GetKitService<IConvertService>();\n\n    /// <summary>\n    /// The Koi CSS Service, used to detect the current CSS framework and other features.\n    /// See [ICss](xref:Connect.Koi.ICss)\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public ICss Css => field ??= GetKitService<ICss>();\n\n\n    /// <summary>\n    /// The Data service to get DataSources and similar.\n    /// </summary>\n    /// <remarks>\n    /// * added in v15.06\n    /// </remarks>\n    [field: AllowNull, MaybeNull]\n    public IDataService Data => field ??= GetKitService<IDataService>();\n\n    /// <summary>\n    /// The Edit service, same as the main Edit service\n    /// </summary>\n    // Important: must share the Edit from the _DynCodeRoot for scenarios where Enable was set manually\n    [field: AllowNull, MaybeNull]\n    public IEditService Edit => field ??= GetKitService<IEditService>();\n\n\n    /// <summary>\n    /// The Features service, used to check if features are enabled\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IFeaturesService Feature => field ??= GetKitService<IFeaturesService>();\n\n    /// <summary>\n    /// The Razor Blade 4 HtmlTags service, to fluidly create Tags.\n    /// See [](xref:ToSic.Razor.Blade.IHtmlTagsService).\n    ///\n    /// > [!IMPORTANT]\n    /// > This is _similar but different_ to the [Razor.Blade.Tag](https://razor-blade.net/api/ToSic.Razor.Blade.Tag.html).\n    /// > The [](xref:ToSic.Razor.Blade.IHtmlTag) objects returned here are _immutable_.\n    /// > This means that chained commands like `...HtmlTags.Div().Id(...).Class(...)`\n    /// > all return new objects and don't modify the previous one.\n    /// >\n    /// > The older `Tag` helper created mutable objects where chaining always modified the original and returned it again.\n    /// </summary>\n    /// <remarks>Added in v15</remarks>\n    [field: AllowNull, MaybeNull]\n    public IHtmlTagsService HtmlTags => field ??= GetKitService<IHtmlTagsService>();\n\n    /// <summary>\n    /// The Images service, used to create `img` and `picture` tags\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IImageService Image => field ??= GetKitService<IImageService>();\n\n\n    /// <summary>\n    /// The JSON service, used to convert data to-and-from JSON\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IJsonService Json => field ??= GetKitService<IJsonService>();\n\n\n    /// <inheritdoc cref=\"IDynamicCodeDocs.Link\" />\n    [field: AllowNull, MaybeNull]\n    public ILinkService Link => field ??= GetKitService<ILinkService>();\n\n    /// <summary>\n    /// The System Log service, used to add log messages to the system (Dnn/Oqtane)\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public ISystemLogService SystemLog => field ??= GetKitService<ISystemLogService>();\n\n    /// <summary>\n    /// Note that this was used in Mobius / Events in a few releases, so we can't just change it.\n    /// If we create a Kit15, this should be removed\n    /// </summary>\n    [PrivateApi(\"was the official name before v15.06, probably never used publicly, but should stay in for a while\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public new ISystemLogService Log => SystemLog;\n\n\n    /// <summary>\n    /// The Mail service, used to send mails\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IMailService Mail => field ??= GetKitService<IMailService>();\n\n\n    /// <summary>\n    /// The Page service, used to set headers, activate features etc.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IPageService Page => field ??= GetKitService<IPageService>();\n\n\n    /// <summary>\n    /// The Render service, used to render one or more dynamic content within other content\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IRenderService Render => field ??= GetKitService<IRenderService>();\n\n    /// <summary>\n    /// The Secure Data service - mainly for reading / decrypting secrets. \n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public ISecureDataService SecureData => field ??= GetKitService<ISecureDataService>();\n\n    /// <summary>\n    /// The Razor-Blade Scrub service, used to clean up HTML.\n    /// See [](xref:ToSic.Razor.Blade.IScrub)\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IScrub Scrub => field ??= GetKitService<IScrub>();\n\n\n    /// <summary>\n    /// The toolbar service, used to generate advanced toolbars\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IToolbarService Toolbar => field ??= GetKitService<IToolbarService>();\n\n\n    #region Late addition v21.06 - added because much old code may not be able to quickly upgrade\n\n    /// <summary>\n    /// Output cache management service, used to invalidate LightSpeed output-cache markers for a specific app.\n    /// </summary>\n    [PrivateApi(\"Still internal v21.06\")]\n    [field: AllowNull, MaybeNull]\n    public IPageShield PageShield => field ??= GetKitService<IPageShield>();\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Kits/ServiceKit16.cs",
    "content": "﻿using Connect.Koi;\nusing ToSic.Razor.Blade;\nusing ToSic.Razor.Html5;\nusing ToSic.Sxc.Services.OutputCache;\nusing ToSic.Sxc.Services.PageShield;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Services.Sys.Cms;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Default ServiceKit for 2sxc v16.\n/// Provided in Razor and WebApi as `Kit`.\n/// </summary>\n/// <remarks>\n/// This is the service kit you get on `Hybrid.RazorTyped`, `AppCode.Razor.AppRazor` or `Hybrid.ApiTyped`.\n/// \n/// History\n/// * New in v16 for Typed Razor / WebApi\n/// * Added Key service in v16.04\n/// * Added Template service in v18.00\n/// * Added Cache service in v19.00\n/// * Added User service in v19.02\n/// </remarks>\n[PublicApi]\n[method: PrivateApi(\"Public constructor for DI\")]\npublic class ServiceKit16() : ServiceKit(\"Sxc.Kit16\")\n{\n    #region Same as v14\n\n    /// <inheritdoc cref=\"ServiceKit14.Adam\"/>\n    [field: AllowNull, MaybeNull]\n    public IAdamService Adam => field ??= GetKitService<IAdamService>();\n\n    /// <summary>\n    /// The CMS Service - WIP\n    /// </summary>\n    [PrivateApi(\"Not yet for public use, as API is not yet public\")]\n    [field: AllowNull, MaybeNull]\n    private ICmsService Cms => field ??= GetKitService<ICmsService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Convert\"/>\n    [field: AllowNull, MaybeNull]\n    public IConvertService16 Convert => field ??= GetKitService<IConvertService16>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Css\"/>\n    [field: AllowNull, MaybeNull]\n    public ICss Css => field ??= GetKitService<ICss>();\n\n\n    /// <inheritdoc cref=\"ServiceKit14.Data\"/>\n    [field: AllowNull, MaybeNull]\n    public IDataService Data => field ??= GetKitService<IDataService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Edit\"/>\n    [field: AllowNull, MaybeNull]\n    public IEditService Edit => field ??= GetKitService<IEditService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Feature\"/>\n    [field: AllowNull, MaybeNull]\n    public IFeaturesService Feature => field ??= GetKitService<IFeaturesService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.HtmlTags\"/>\n    [field: AllowNull, MaybeNull]\n    public IHtmlTagsService HtmlTags => field ??= GetKitService<IHtmlTagsService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Image\"/>\n    [field: AllowNull, MaybeNull]\n    public IImageService Image => field ??= GetKitService<IImageService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Json\"/>\n    [field: AllowNull, MaybeNull]\n    public IJsonService Json => field ??= GetKitService<IJsonService>();\n\n    /// <inheritdoc cref=\"Razor.Html5.Link\" />\n    [field: AllowNull, MaybeNull]\n    public ILinkService Link => field ??= GetKitService<ILinkService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.SystemLog\"/>\n    [field: AllowNull, MaybeNull]\n    public ISystemLogService SystemLog => field ??= GetKitService<ISystemLogService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Mail\"/>\n    [field: AllowNull, MaybeNull]\n    public IMailService Mail => field ??= GetKitService<IMailService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Page\"/>\n    [field: AllowNull, MaybeNull]\n    public IPageService Page => field ??= GetKitService<IPageService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Render\"/>\n    [field: AllowNull, MaybeNull]\n    public IRenderService Render => field ??= GetKitService<IRenderService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.SecureData\"/>\n    [field: AllowNull, MaybeNull]\n    public ISecureDataService SecureData => field ??= GetKitService<ISecureDataService>();\n\n    /// <inheritdoc cref=\"ServiceKit14.Scrub\"/>\n    [field: AllowNull, MaybeNull]\n    public IScrub Scrub => field ??= GetKitService<IScrub>();\n\n\n    /// <inheritdoc cref=\"ServiceKit14.Toolbar\"/>\n    [field: AllowNull, MaybeNull]\n    public IToolbarService Toolbar => field ??= GetKitService<IToolbarService>();\n\n    #endregion\n\n    #region Existed in v14 but Removed in v16\n\n    // Removed for v16\n    //public new ISystemLogService Log => SystemLog;\n\n    #endregion\n\n    #region Added to v16 only\n\n    /// <summary>\n    /// The User service, used to get user and role information.\n    /// </summary>\n    /// <remarks>\n    /// History: released in 19.02 (started in v15.03 but was never public)\n    /// </remarks>\n    [field: AllowNull, MaybeNull]\n    public IUserService User => field ??= GetKitService<IUserService>();\n\n    /// <summary>\n    /// Key service.\n    /// Rarely used, as the RazorTyped has a UniqueKey property which comes from this service.\n    /// You only need this service, if you need to create combined keys (like with an entity)\n    /// </summary>\n    /// <remarks>\n    /// * New in v16.04\n    /// </remarks>\n    [field: AllowNull, MaybeNull]\n    public IKeyService Key => field ??= GetKitService<IKeyService>(); // new KeyService();\n\n    /// <summary>\n    /// Templates service, which can parse strings containing placeholders.\n    /// </summary>\n    /// <remarks>\n    /// History: introduced in v18.00\n    /// </remarks>\n    [field: AllowNull, MaybeNull]\n    public ITemplateService Template => field ??= GetKitService<ITemplateService>();\n\n    /// <summary>\n    /// Cache service, used to cache data.\n    /// </summary>\n    /// <remarks>\n    /// Used to cache data, specifically to ensure it is refreshed when certain events happen,\n    /// such as data in the App changes.\n    ///\n    /// History: introduced in v19.00\n    /// </remarks>\n    [field: AllowNull, MaybeNull]\n    public ICacheService Cache => field ??= GetKitService<ICacheService>();\n\n    /// <summary>\n    /// Output cache service, used to influence LightSpeed output-cache behavior for the current render.\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public IModuleOutputCacheService OutputCache => field ??= GetKitService<IModuleOutputCacheService>();\n\n    /// <summary>\n    /// Output cache management service, used to invalidate LightSpeed output-cache markers for a specific app.\n    /// </summary>\n    [PrivateApi(\"Still internal v21.06\")]\n    [field: AllowNull, MaybeNull]\n    public IOutputCacheManagementService OutputCacheManagement => field ??= GetKitService<IOutputCacheManagementService>();\n\n    /// <summary>\n    /// Output cache management service, used to invalidate LightSpeed output-cache markers for a specific app.\n    /// </summary>\n    [PrivateApi(\"Still internal v21.06\")]\n    [field: AllowNull, MaybeNull]\n    public IPageShield PageShield => field ??= GetKitService<IPageShield>();\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Kits/Sys/IHasKit.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Sys;\n\n[PrivateApi(\"v14\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IHasKit<out TServiceKit> where TServiceKit : ServiceKit\n{\n    /// <summary>\n    /// The Service Kit containing all kinds of services which are commonly used.\n    /// The services on the Kit are context-aware, so they know what App is currently being used etc.\n    /// </summary>\n    TServiceKit Kit { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Kits/Sys/IHasKitExtensions.cs",
    "content": "﻿using ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Services.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class IHasKitExtensions\n{\n    // 2026-02-20 2dm - seems unused...\n    //internal static TServiceKit GetKit<TServiceKit>(IExecutionContext exCtx)\n    //    where TServiceKit : ServiceKit =>\n    //    exCtx switch\n    //    {\n    //        // if it has the exact kit version, return it\n    //        IHasKit<TServiceKit> { Kit: not null } withKit => withKit.Kit,\n\n    //        // Situation where the IHasKit would have a different version of the service kit...\n    //        ICanGetService cgs => cgs.GetService<TServiceKit>(),\n\n    //        _ => throw new($\"GetKit: {exCtx.GetType().Name} doesn't implement IHasKit or IExCtxGetKit\")\n    //    };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Kits/Sys/ServiceKit.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Sys;\n\n/// <summary>\n/// Root / base class for **ServiceKits**.\n/// ServiceKits are a bundle of services which are quickly available when you need them.\n/// </summary>\n/// <remarks>\n/// * History: Added v14.04\n/// * Everything that needs a ServiceKit will have a \"where TKit : <see cref=\"ServiceKit14\"/>\"\n/// * It's not abstract, so that you can use it as the placeholder in cases where you don't need a real kit (like in DynamicCodeRoot generic types)\n/// </remarks>\n[PrivateApi(\"Hidden in v17.02, previously public, but no good reason for it.\")]\n// #NoEditorBrowsableBecauseOfInheritance\n// 2025-05-11 re-enabled, since it shouldn't matter anymore with the new setup\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ServiceKit(string logName = \"Sxc.Kit\") : ServiceWithContext(logName)\n{\n\n    /// <summary>\n    /// All the services provided by this kit must come from the code root, so they are properly initialized.\n    ///\n    /// Will first try to use the GetService method to ensure that changes in the Kit (like 16/14) still return\n    /// the identical sub-services.\n    /// </summary>\n    /// <typeparam name=\"TService\"></typeparam>\n    /// <returns></returns>\n    [PrivateApi]\n    protected TService GetKitService<TService>() where TService : class\n        => ExCtx.GetService<TService>(reuse: true);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Link/ILinkService.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\n#pragma warning disable CS0108, CS0114\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Helper on [`Kit.Link`](xref:ToSic.Sxc.Services.ServiceKit16.Link) to create links to pages, APIs and images.\n/// </summary>\n/// <remarks>\n/// It is usually also available as a `Link` object in every Razor and WebApi file.\n/// \n/// This helps create links to:\n/// \n/// - Pages\n/// - APIs\n/// - Images\n///\n/// As well as create base-tag links (important for SPAs)\n///\n/// You will never create this yourself, as get this automatically in Razor or WebAPIs on an object called `Link`.\n/// \n/// History\n/// \n/// - Created ca. v2 as `ToSic.Sxc.Web.ILinkHelper`\n/// - Moved to this new `Services.ILinkService` in v13.05. The previous name will continue to work, but newer features will be missing on that interface. \n/// </remarks>\n[PublicApi]\npublic interface ILinkService: /*INeedsCodeApiService,*/ ICanDebug\n{\n    /// <summary>\n    /// returns a link to the current page with parameters resolved in a way that DNN wants it\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"pageId\">optional page ID (TabId) - if not supplied, will use current page</param>\n    /// <param name=\"api\">optional api url \"api/name/method?id=something\"</param>\n    /// <param name=\"parameters\">\n    ///     - the parameters either as `id=47&amp;name=daniel` (Dnn also supports `/id/47/name/daniel`)\n    ///     - in 2sxc 12.05+ it can also be an <see cref=\"Context.IParameters\"/>\n    /// </param>\n    /// <param name=\"type\">\n    ///     Optional type changes how the link is generated. Possible values are:\n    /// \n    ///     - null / not specified / empty = return link as is generated\n    ///     - `\"full\"` return link with protocol and domain. If that was missing before, it will add current protocol/domain if possible, but not on relative `./` or `../` links\n    ///     - `\"//\"` return link with `//domain`. If that was missing before, will add current domain if possible, but not on relative `./` or `../` links\n    /// </param>\n    /// <param name=\"language\">\n    /// - If not set, `null` or empty `\"\"` will use the specified pageId (pageIds can be language specific); api would always be the current language\n    /// - If set to `\"current\"` will adjust pageId to use the language of the current language. API will be as before, as it was already `current`\n    /// - future _(not implemented yet)_ `\"primary\"` would link to primary language\n    /// - future _(not implemented yet)_ `\"en\"` or `\"en-us\"` would link to that specific language (page and API)\n    /// </param>\n    /// <returns></returns>\n    /// <remarks>\n    /// History\n    /// * v12 added the api parameter for liking APIs of the current app\n    /// * In v12.05 the type of parameters was changed from string to object, to allow <see cref=\"Context.IParameters\"/> as well\n    /// * In v13.02 introduced language with \"current\"\n    /// </remarks>\n    string To(\n        NoParamOrder npo = default,\n        int? pageId = null,\n        string? api = null,\n        object? parameters = null,\n        string? type = null,\n        string? language = null\n    );\n        \n    /// <summary>\n    /// A base url for the current page, for use in html-base tags\n    /// </summary>\n    /// <returns></returns>\n    string Base();\n\n    /// <summary>\n    /// Generate an Image-Resizing link base on presets or custom parameters.  \n    /// It will also ensure that the final url is safe, so it will encode umlauts, spaces etc.\n    /// \n    /// Note that you can basically just use presets, or set every parameter manually.\n    /// \n    /// - All params are optional.\n    /// - Some combinations are not valid - like setting a factor and a width doesn't make sense and will throw an error\n    /// - Most parameters if set to 0 will cause a reset so that this aspect is not in the URL\n    /// </summary>\n    /// <param name=\"url\">The image url. Use an empty string if you want to just get the params for re-use.</param>\n    /// <param name=\"settings\">\n    /// - A settings name such as \"Content\", \"Lightbox\" etc. (new 17.06)\n    /// - A standardized Image-Settings object like Settings.Images.Content - see https://go.2sxc.org/settings\n    /// - An anonymous objects with properties such as `width`, `height`, `quality`, `resizeMode`, `scaleMode`, `format`, `aspectRatio` etc. like `new { width = 100, height = 100 }` (new v19.03.03)\n    /// - Or a dynamic object containing settings properties (this can also be a merged custom + standard settings)\n    /// - Or a specially prepared <see cref=\"Images.IResizeSettings\"/> object containing all settings.\n    ///   If this is provided, only `factor` will still be respected, all other settings like `width` on this command will be ignored.\n    /// </param>\n    /// <param name=\"factor\">A multiplier, usually used to create urls which resize to a part of the default content-size. Like 0.5.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"field\">WIP v13.04 - not final yet</param>\n    /// <param name=\"width\">Optional width parameter. Usually takes the default from the `settings`.</param>\n    /// <param name=\"height\">Optional height parameter. Usually takes the default from the `settings`.</param>\n    /// <param name=\"quality\">Optional quality parameter. Usually takes the default from the `settings`.</param>\n    /// <param name=\"resizeMode\">Optional resize-mode, like `crop` or `max`. Usually takes the default from the `settings`.</param>\n    /// <param name=\"scaleMode\">Optional scale-mode to allow up-scaling images like `up` or `both`. Usually takes the default from the `settings`.</param>\n    /// <param name=\"format\">Optional file format like `jpg` or `png`</param>\n    /// <param name=\"aspectRatio\">Aspect Ratio width/height, only relevant if a `width` is supplied. Can't be used together with height. Usually takes default from the `settings` or is ignored. </param>\n    /// <param name=\"type\">\n    ///     Optional type changes how the link is generated. Possible values are:\n    /// \n    ///     - null / not specified / empty = return link as is generated\n    ///     - `\"full\"` return link with protocol and domain. If that was missing before, it will add current protocol/domain if possible, but not on relative `./` or `../` links\n    ///     - `\"//\"` return link with `//domain`. If that was missing before, will add current domain if possible, but not on relative `./` or `../` links\n    /// </param>\n    /// <param name=\"parameters\">\n    ///     - the parameters either as `id=47&amp;name=daniel` (Dnn also supports `/id/47/name/daniel`)\n    ///     - in 2sxc 12.05+ it can also be an <see cref=\"Context.IParameters\"/>\n    /// </param>\n    /// <remarks>\n    /// Usually a factor is applied to create a link which is possibly 50% of the content-width or similar.\n    /// In these cases the height is not applied but the aspectRatio is used, which usually comes from `settings` if any were provided.\n    /// \n    /// History\n    /// - New in 2sxc 12.03\n    /// - type added ca. v12.08\n    /// - Option to use <see cref=\"Images.IResizeSettings\"/> added in v13.03\n    /// - `factor` originally didn't influence width/height if provided here, updated it v13.03 to influence that as well\n    /// - `field` being added in 13.04, not ready yet\n    /// - `settings` enhanced to also support simple anonymous objects in v19.03.03\n    /// </remarks>\n    /// <returns></returns>\n    // Test comments, probably remove soon as this was never implemented like this\n    ///// <param name=\"part\">\n    ///// _This is a proposal, it's not final yet_\n    ///// - null/empty/default means that the link is returned as given - as provided by the 'url' parameter. if none was provided, it's a root-absolute link like `/xyz/abc?stuff#stuff`\n    ///// - `full` means full protocol, domain and everything - like https://2sxc.org/dnn-tutorials/page/subpage/?product=27&filter=42#test=42\n    /////     - if a url is provided without protocol, it's assumed that it's on the current site, so the current domain/protocol are added\n    /////     - when no url or params was provided would just result in the domain + link to the current page as is\n    /////     - if the url seems invalid (like `hello:there` or an invalid `file:593902` reference) nothing is added\n    ///// - `protocol` would just return the \"http\", \"https\" or whatever.\n    /////     - if no url was provided, it will assume that the current page is to be used\n    /////     - if a url was provided and it has no protocol, then the current protocol is used\n    /////     - if a url was provided with protocol, it would return that\n    ///// - `domain` would just return the full domain like `2sxc.org`, `www.2sxc.org` or `gettingstarted.2sxc.org`\n    /////     - if no url was provided, then the domain of the current page\n    /////     - if the url contains a domain, then that domain\n    ///// - `hash` would just return the part after the `#` (without the `#`) - if not provided, empty string\n    ///// - `query` would return the part after the `?` (without the `?`- if not provided, empty string\n    /////     - if no url was provided and there are magical query params (like in DNN), these would not be returned, but not dnn-internals like tabid or language\n    ///// - `suffix` would return the entire suffix starting from the `?` _including_ the `?` or `#` - if nothing is there, empty string\n    ///// </param>        [PrivateApi]\n    string? Image(\n        string? url = default,\n        object? settings = default,\n        object? factor = default,\n        NoParamOrder npo = default,\n        IField? field = default,\n        object? width = default,\n        object? height = default,\n        object? quality = default,\n        string? resizeMode = default,\n        string? scaleMode = default,\n        string? format = default,\n        object? aspectRatio = default,\n        string? type = default,\n        object? parameters = default\n    );\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Link/Sys/ILinkServiceIntegration.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Link.Sys;\n\n/// <summary>\n/// Not yet used - idea is to make the LinkService more composition instead of inheritance.\n/// 2024-05-14 it's difficult though, because the inner workings need the _CodeApiService, which is not available in the interface.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ILinkServiceIntegration\n{\n    string ToApi(string api, string? parameters = default);\n\n    string ToPage(int? pageId, string? parameters = default, string? language = default);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Link/Sys/LinkServiceBase.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Link.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class LinkServiceBase(ImgResizeLinker imgLinker, LazySvc<ILinkPaths> linkPathsLazy, object[]? connect = default)\n    : ServiceWithContext($\"{SxcLogName}.LnkHlp\", connect: [..connect ?? [], linkPathsLazy, imgLinker]), ILinkService\n{\n    [PrivateApi]\n    protected ILinkPaths LinkPaths => linkPathsLazy.Value;\n\n    [PrivateApi]\n    [field: AllowNull, MaybeNull]\n    protected string AppFolder => field\n        ??= ExCtx.GetApp().Folder;\n\n\n    /// <inheritdoc />\n    public string To(\n        NoParamOrder npo = default,\n        int? pageId = null,\n        string? api = null,\n        object? parameters = null,\n        string? type = null,\n        string? language = null\n    )\n    {\n        var l = (Debug ? Log : null).Fn<string>($\"pid:{pageId},api:{api},t:{type},l:{language}\");\n\n        // Check initial conflicting values.\n        if (pageId != null && api != null)\n            throw new ArgumentException($\"Only one of the parameters '{nameof(api)}' or '{nameof(pageId)}' can have a value.\");\n\n        var strParams = ParametersToString(parameters);\n        l.A($\"parameters:{strParams}\");\n \n        // TODO: unclear what would happen if a new parameter would replace an existing - would it just append? that wouldn't be good\n        var url = api == null\n            ? ToPage(pageId, strParams, language)\n            : ToApi(api, strParams);\n        l.A($\"url:{url}\");\n\n        var processed = ExpandUrlIfNecessary(type, url);\n        l.A($\"expandUrl:{processed}, t:{type}\");\n\n        return l.ReturnAsOk(Tags.SafeUrl(processed).ToString());\n    }\n\n    private string? ExpandUrlIfNecessary(string? type, string? url)\n    {\n        if (url == null)\n            return null;\n\n        // Short-Circuit to really not do anything if the type isn't specified\n        if (type.IsEmpty())\n            return url;\n\n        var parts = new UrlParts(url);\n        switch (type.ToLowerInvariant())\n        {\n            case \"full\":\n                if (!parts.IsAbsolute)\n                    parts.ReplaceRoot(LinkPaths.GetCurrentRequestUrl());\n                return parts.ToLink(\"full\");\n            case \"//\":\n                if (!parts.IsAbsolute)\n                    parts.ReplaceRoot(LinkPaths.GetCurrentRequestUrl());\n                return parts.ToLink(\"//\");\n            case \"/\": // note: \"/\" isn't officially supported\n                return parts.ToLink(\"/\");\n            default:\n                return url;\n        }\n    }\n     \n\n    protected abstract string ToApi(string api, string? parameters = null);\n\n    protected abstract string ToPage(int? pageId, string? parameters = null, string? language = null);\n\n    protected static string? ParametersToString(object? parameters)\n        => parameters switch\n        {\n            null => null,\n            string strParameters => strParameters.TrimStart(['?', '&']),\n            IParameters paramDic => paramDic.ToString(),\n            _ => null // Fallback / default\n        };\n\n\n    /// <inheritdoc />\n    public virtual string Base()\n    {\n        // helper to generate a base path which is also valid on home (special DNN behaviour)\n        const string randomxyz = \"this-should-never-exist-in-the-url\";\n        var basePath = To(parameters: randomxyz + \"=1\");\n        return basePath.Substring(0, basePath.IndexOf(randomxyz, StringComparison.InvariantCultureIgnoreCase));\n    }\n\n    /// <inheritdoc />\n    public string? Image(\n        string? url = default,\n        object? settings = default,\n        object? factor = default,\n        NoParamOrder npo = default,\n        IField? field = default,\n        object? width = default,\n        object? height = default,\n        object? quality = default,\n        string? resizeMode = default,\n        string? scaleMode = default,\n        string? format = default,\n        object? aspectRatio = default,\n        string? type = default,\n        object? parameters = default\n    )\n    {\n        // If params were given, ensure it can be used as string, as it could also be a params-object\n        var strParams = ParametersToString(parameters);\n\n        // If the url should be expanded to have a full root or something, do this first\n        url ??= field?.Parent.Url(field.Name);\n        var expandedUrl = ExpandUrlIfNecessary(type, url);\n\n        // Get the image-url(s) as needed\n        // Note that srcset is false, so it won't generate a bunch of sources, just one - which is how the API works\n        // Anybody that wants a srcset must use the new IImageService for that\n        var imageUrl = imgLinker.ImageUrl(url: expandedUrl, settings: settings, field: field, factor: factor, width: width, height: height, quality: quality, resizeMode: resizeMode,\n            scaleMode: scaleMode, format: format, aspectRatio: aspectRatio, parameters: strParams,\n            executionContext: ExCtxOrNull);\n\n        return imageUrl;\n    }\n\n    /// <inheritdoc />\n    public override bool Debug\n    {\n        get => base.Debug;\n        set\n        {\n            base.Debug = value;\n            imgLinker.Debug = value;\n        }\n    }\n\n    /// <summary>\n    /// Combine api with query string.\n    /// </summary>\n    public static string CombineApiWithQueryString(string api, string? queryString)\n    {\n        queryString = queryString?.TrimStart(['?', '&']);\n\n        // combine api with query string\n        return string.IsNullOrEmpty(queryString)\n            ? api\n            : api?.IndexOf(\"?\") > 0\n                ? $\"{api}&{queryString}\"\n                : $\"{api}?{queryString}\";\n    }\n\n    internal static string CurrentPageUrlWithEventualHashError(int? pageId, string currentPageUrl) \n        => !pageId.HasValue ? currentPageUrl : $\"{currentPageUrl}#error-unknown-pageid-{pageId}\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Link/Sys/LinkServiceUnknown.cs",
    "content": "﻿using ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Sys.Integration.Paths;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Link.Sys;\n\n[PrivateApi(\"for testing / un-implemented use\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n#pragma warning disable CS9113 // Parameter is unread.\ninternal class LinkServiceUnknown(ImgResizeLinker imgLinker, LazySvc<ILinkPaths> linkPathsLazy, WarnUseOfUnknown<LinkServiceUnknown> _)\n#pragma warning restore CS9113 // Parameter is unread.\n    : LinkServiceBase(imgLinker, linkPathsLazy), IIsUnknown\n{\n    public const string DefDomain = \"unknown.2sxc.org\";\n    public const string DefProtocol = \"https\";\n    public const string DefRoot = DefProtocol +\"://\" + DefDomain;\n    public const string NiceCurrentPath = \"/folder/sub-folder/\";\n    public const string NiceCurrentPage = \"current-page\";\n    public const string NiceCurrentRelative = NiceCurrentPath + NiceCurrentPage;\n\n    public const string NiceCurrentUrlRoot = DefRoot + NiceCurrentRelative;\n    public const string NiceCurrentUrl = NiceCurrentUrlRoot;\n\n    public const string UglyAnyQuery = \"tabId={0}\";\n    public const string UglyCurrentQuery = \"tabId=27\";\n    public const string UglyCurrentPage = \"default.aspx?\" + UglyCurrentQuery;\n    public const string UglyAnyPage = \"default.aspx?\" + UglyAnyQuery;\n    public const string UglyCurrentUrl = DefRoot + \"/\" + UglyCurrentPage;\n    public const string UglyAnyPageUrl = DefRoot + \"/\" + UglyAnyPage;\n\n    public const string NiceAnyRelative = \"/page{0}\";\n    public static string NiceAnyPageUrl = DefRoot + NiceAnyRelative;\n\n    internal static string CurrentPageUrl = NiceCurrentUrl;\n    internal static string AnyPageUrl = NiceAnyPageUrl;\n\n    protected override string ToApi(string api, string? parameters = null) => $\"{api}{Parameters(parameters)}\";\n\n    protected override string ToPage(int? pageId, string? parameters = null, string? language = null) =>\n        // Page or Api?\n        pageId != null\n            ? string.Format(AnyPageUrl, pageId) + Parameters(parameters)\n            : $\"{CurrentPageUrl}{Parameters(parameters)}\";\n\n    private static string? Parameters(string? parameters)\n        => parameters.IsEmpty() ? parameters : $\"?{parameters}\";\n\n\n    public static void SwitchModeToUgly(bool uglyOn)\n    {\n        CurrentPageUrl = uglyOn ? UglyCurrentUrl : NiceCurrentUrl;\n        AnyPageUrl = uglyOn ? UglyAnyPageUrl : NiceAnyPageUrl;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Mail/IMailService.cs",
    "content": "﻿using System.Net.Mail;\nusing System.Text;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Mail`](xref:ToSic.Sxc.Services.ServiceKit16.Mail) to send mail messages cross-platform.\n/// </summary>\n/// <remarks>\n/// History: New in 2sxc 12.05\n/// </remarks>\n[PublicApi]\npublic interface IMailService: INeedsExecutionContext\n{\n    /// <summary>\n    /// Quickly create a MailMessage object for further modification and then sending using <see cref=\"Send(MailMessage)\"/>\n    /// If you don't want to modify the resulting object, skip this and use the direct-send method. \n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"from\">\n    ///     sender e-mail address in one of the following formats\n    ///     * An e-mail string like \"info@somwhere.com\"\n    ///     * An e-mail with name and address like \"iJungleboy &lt;ijungleboy@2sxc.org&gt;\"\n    ///     * A single System.Net.Mail.MailAddress object\n    /// </param>\n    /// <param name=\"to\">\n    ///     Main recipient(s) of the mail in one of the following formats\n    ///     * all the formats as available in `from`\n    ///     * a CSV of such addresses like \"info@a.com, info@b.com\"\n    ///     * An Array/List/IEnumerable of such strings\n    ///     * An Array/List/IEnumerable of System.Net.Mail.MailAddress objects\n    /// </param>\n    /// <param name=\"cc\">CC recipient(s) of the mail, in the same format as `to`</param>\n    /// <param name=\"bcc\">BCC recipient(s) of the mail, in the same format as `to`</param>\n    /// <param name=\"replyTo\">ReplyTo address(es) in the same format as `to`</param>\n    /// <param name=\"subject\">The main subject</param>\n    /// <param name=\"body\">The body / contents of the e-mail - can be text or HTML</param>\n    /// <param name=\"isHtml\">Set the body to be HTML - if not set, will auto-detect</param>\n    /// <param name=\"encoding\">\n    ///     Encoding of subject and body - if not set, will default to UTF8.\n    ///     If you need different encodings on subject and body, set it on the resulting object. \n    /// </param>\n    /// <param name=\"attachments\">\n    ///     One or more attachments to include. Could be any of the following\n    ///     - A System.Net.Mail.Attachment object\n    ///     - An <see cref=\"Adam.IFile\"/> or an <see cref=\"Eav.Apps.Assets.IFile\"/> object\n    ///     - An Array/IEnumerable of these \n    /// </param>\n    /// <returns>The newly created `MailMessage` object</returns>\n    MailMessage Create(\n        NoParamOrder npo = default,\n        object? from = null,\n        object? to = null,\n        object? cc = null,\n        object? bcc = null,\n        object? replyTo = null,\n        string? subject = null,\n        string? body = null,\n        bool? isHtml = null,\n        Encoding? encoding = null,\n        object? attachments = null);\n\n    /// <summary>\n    /// Send a .net `MailMessage` object using the settings configured in Dnn or Oqtane.\n    /// </summary>\n    /// <param name=\"message\">A prepared .net MailMessage object</param>\n    /// <returns></returns>\n    void Send(MailMessage message);\n\n    /// <summary>\n    /// Quickly create and send an E-Mail.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"from\">\n    ///     sender e-mail address in one of the following formats\n    ///     * An e-mail string like \"info@somwhere.com\"\n    ///     * An e-mail with name and address like \"iJungleboy &lt;ijungleboy@2sxc.org&gt;\"\n    ///     * A single System.Net.Mail.MailAddress object\n    /// </param>\n    /// <param name=\"to\">\n    ///     Main recipient(s) of the mail in one of the following formats\n    ///     * all the formats as available in `from`\n    ///     * a CSV of such addresses like \"info@a.com, info@b.com\"\n    ///     * An Array/List/IEnumerable of such strings\n    ///     * An Array/List/IEnumerable of System.Net.Mail.MailAddress objects\n    /// </param>\n    /// <param name=\"cc\">CC recipient(s) of the mail, in the same format as `to`</param>\n    /// <param name=\"bcc\">BCC recipient(s) of the mail, in the same format as `to`</param>\n    /// <param name=\"replyTo\">ReplyTo address(es) in the same format as `to`</param>\n    /// <param name=\"subject\">The main subject</param>\n    /// <param name=\"body\">The body / contents of the e-mail - can be text or HTML</param>\n    /// <param name=\"isHtml\">Set the body to be HTML - if not set, will auto-detect</param>\n    /// <param name=\"encoding\">\n    ///     Encoding of subject and body - if not set, will default to UTF8.\n    ///     If you need different encodings on subject and body, set it on the resulting object. \n    /// </param>\n    /// <param name=\"attachments\">\n    ///     One or more attachments to include. Could be any of the following\n    ///     - A System.Net.Mail.Attachment object\n    ///     - An <see cref=\"ToSic.Sxc.Adam.IFile\"/> or an <see cref=\"ToSic.Eav.Apps.Assets.IFile\"/> object\n    ///     - An Array/IEnumerable of these \n    /// </param>\n    /// <returns>void</returns>\n    void Send(\n        NoParamOrder npo = default,\n        object? from = null,\n        object? to = null,\n        object? cc = null,\n        object? bcc = null,\n        object? replyTo = null,\n        string? subject = null,\n        string? body = null,\n        bool? isHtml = null,\n        Encoding? encoding = null,\n        object? attachments = null\n    );\n\n    // 2024-01-10 2dm internalized - doesn't seem in use, and also not clear why we would have this\n    // was probably an experiment from STV during dev, but we shouldn't keep it in the interface\n    //[PrivateApi] MailAddress MailAddress(string addressType, object mailAddress);\n\n    // 2024-01-10 2dm internalized - doesn't seem in use, and also not clear why we would have this\n    // was probably an experiment from STV during dev, but we shouldn't keep it in the interface\n    //[PrivateApi] bool AddMailAddresses(string addressType, MailAddressCollection targetMails, object mailAddresses);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Mail/Sys/MailServiceBase.cs",
    "content": "﻿using System.Net.Mail;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing ToSic.Eav.Apps.Assets;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sys.Users;\nusing ToSic.Sys.Utils;\nusing MailMessage = System.Net.Mail.MailMessage;\n\nnamespace ToSic.Sxc.Services.Mail.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class MailServiceBase(LazySvc<IUser> userLazy, object[]? connect = default)\n    : ServiceWithContext($\"{SxcLogName}.MailSrv\", connect: [..connect ?? [], userLazy]), IMailService\n{\n    private static readonly Regex HtmlDetectionRegex = new(\"<(.*\\\\s*)>\", RegexOptions.Compiled);\n    \n    protected abstract SmtpClient SmtpClient();\n\n    /// <inheritdoc />\n    public void Send(MailMessage message)\n    {\n        var l = Log.Fn();\n        try\n        {\n            using var client = SmtpClient();\n            client.Send(message);\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            if (userLazy.Value.IsSystemAdmin)\n                throw;\n            throw new(\"SMTP configuration problem.\");\n        }\n\n        l.Done();\n    }\n\n    /// <inheritdoc />\n    public MailMessage Create(\n        NoParamOrder npo = default,\n        object? from = null,\n        object? to = null,\n        object? cc = null,\n        object? bcc = null,\n        object? replyTo = null,\n        string? subject = null,\n        string? body = null,\n        bool? isHtml = null,\n        Encoding? encoding = null,\n        object? attachments = null)\n    {\n        var l = Log.Fn<MailMessage>(\n            parameters: $\"{nameof(from)}: {from}, {nameof(to)}: {to}, {nameof(cc)}: {cc}, {nameof(bcc)}: {bcc}, {nameof(replyTo)}: {replyTo}, \" +\n                        $\"{nameof(subject)}: {subject}, {nameof(body)}: {body}, {nameof(isHtml)}: {isHtml}, {nameof(encoding)}: {encoding}, \" +\n                        $\"{nameof(attachments)}: {attachments}\");\n\n        // prevent incorrect use without named parameters\n\n        var mailMessage = new MailMessage();\n            \n        if (from != null) mailMessage.From = MailAddress(nameof(from), from);\n        AddMailAddresses(nameof(to), mailMessage.To, to);\n        AddMailAddresses(nameof(cc), mailMessage.CC, cc);\n        AddMailAddresses(nameof(bcc), mailMessage.Bcc, bcc);\n        AddMailAddresses(nameof(replyTo), mailMessage.ReplyToList, replyTo);\n\n        mailMessage.Subject = subject;\n        mailMessage.SubjectEncoding = encoding ?? Encoding.UTF8;\n        mailMessage.IsBodyHtml = isHtml ?? AutoDetectHtml(body);\n        mailMessage.BodyEncoding = encoding ?? Encoding.UTF8;\n        mailMessage.Body = body;\n\n        AddAttachments(mailMessage.Attachments, attachments);\n\n        return l.Return(mailMessage, \"done\");\n    }\n\n    [PrivateApi] \n    public static bool AutoDetectHtml(string? body)\n    {\n        return !string.IsNullOrEmpty(body) && HtmlDetectionRegex.IsMatch(body);\n    }\n\n    /// <inheritdoc />\n    public void Send(\n        NoParamOrder npo = default,\n        object? from = null,\n        object? to = null,\n        object? cc = null,\n        object? bcc = null,\n        object? replyTo = null,\n        string? subject = null,\n        string? body = null,\n        bool? isHtml = null,\n        Encoding? encoding = null,\n        object? attachments = null)\n    {\n        var l = Log.Fn();\n        // Note: don't log all the parameters here, because we'll do it again on the Create-call\n        var mailMessage = Create(\n            from: from,\n            to: to,\n            cc: cc,\n            bcc: bcc,\n            replyTo: replyTo,\n            subject: subject,\n            body: body,\n            isHtml: isHtml, encoding: encoding, attachments: attachments);\n\n        Send(mailMessage);\n        l.Done();\n    }\n\n    // 2024-01-10 2dm internalized - doesn't seem in use, and also not clear why we would have this\n    // was probably an experiment from STV during dev, but we shouldn't keep it in the interface\n    internal MailAddress MailAddress(string addressType, object mailAddress)\n    {\n        switch (mailAddress)\n        {\n            case MailAddress fromMailAddress:\n                return fromMailAddress;\n            case string fromString:\n                return new(fromString);\n            default:\n                throw new ArgumentException($\"Trying to parse e-mails for {addressType} but got unknown type for {nameof(mailAddress)}\");\n        }\n    }\n\n    // 2024-01-10 2dm internalized - doesn't seem in use, and also not clear why we would have this\n    // was probably an experiment from STV during dev, but we shouldn't keep it in the interface\n    internal bool AddMailAddresses(string addressType, MailAddressCollection targetMails, object? mailAddresses)\n    {\n        var l = Log.Fn<bool>(); // return a bool just to make return-statements easier later on\n\n        switch (mailAddresses)\n        {\n            case MailAddressCollection inputMailAddressCollection:\n                foreach (var mailAddress in inputMailAddressCollection) \n                    targetMails.Add(mailAddress);\n                return l.ReturnTrue(nameof(MailAddressCollection));\n\n            case IEnumerable<MailAddress> inputMailAddressesArray:\n                foreach (var mailAddress in inputMailAddressesArray) \n                    targetMails.Add(mailAddress);\n                return l.ReturnTrue(nameof(IEnumerable<MailAddress>));\n\n            case IEnumerable<string> inputStringArray:\n                foreach (var emailAddress in inputStringArray)\n                    if (!string.IsNullOrEmpty(emailAddress))\n                        targetMails.Add(emailAddress);\n                return l.ReturnTrue(nameof(IEnumerable<string>));\n\n            case string inputString: \n                if (!string.IsNullOrEmpty(inputString)) \n                    targetMails.Add(NormalizeEmailSeparators(inputString));\n                return l.ReturnTrue(\"string\");\n\n            case null:\n                return l.ReturnTrue(\"null\");\n\n            default:\n                throw new ArgumentException($\"Trying to parse e-mails for {addressType} but got unknown type for {nameof(mailAddresses)}\");\n        }\n    }\n\n    [PrivateApi]\n    [return: NotNullIfNotNull(nameof(input))]\n    public static string? NormalizeEmailSeparators(string? input)\n        => input.IsEmpty() ? null : input.Replace(\";\", \",\");\n\n    public bool AddAttachments(AttachmentCollection targetAttachments, object? attachments)\n    {\n        var l = Log.Fn<bool>(); // return a bool just to make return-statements easier later on\n        switch (attachments)\n        {\n            case Attachment inputAttachment:\n                targetAttachments.Add(inputAttachment);\n                return l.ReturnTrue(nameof(Attachment));\n\n            case AttachmentCollection attachmentCollection:\n                foreach (var attachment in attachmentCollection) \n                    targetAttachments.Add(attachment);\n                return l.ReturnTrue(nameof(AttachmentCollection));\n\n            case IEnumerable<Attachment> inputAttachmentsArray:\n                foreach (var attachment in inputAttachmentsArray) \n                    targetAttachments.Add(attachment);\n                return l.ReturnTrue(nameof(IEnumerable<Attachment>));\n\n            case IFile inputFile:\n                targetAttachments.Add(new(\n                    new FileStream(inputFile.PhysicalPath, FileMode.Open, FileAccess.Read, FileShare.Read),\n                    inputFile.FullName));\n                return l.ReturnTrue(nameof(IFile));\n\n            case IEnumerable<IFile> inputFiles:\n                foreach (var file in inputFiles)\n                    targetAttachments.Add(new(\n                        new FileStream(file.PhysicalPath, FileMode.Open, FileAccess.Read, FileShare.Read),\n                        file.FullName));\n                return l.ReturnTrue(nameof(IEnumerable<IFile>));\n\n            default:\n                throw new ArgumentException($\"Unknown type for {nameof(attachments)}\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Mail/Sys/MailServiceUnknown.cs",
    "content": "﻿using System.Net.Mail;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Services.Mail.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class MailServiceUnknown : MailServiceBase\n{\n    public MailServiceUnknown(WarnUseOfUnknown<MailServiceUnknown> _, LazySvc<IUser> userLazy) : base(userLazy)\n    { }\n\n    protected override SmtpClient SmtpClient()\n    {\n        throw new System.NotImplementedException();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/OutputCache/IModuleOutputCacheService.cs",
    "content": "﻿namespace ToSic.Sxc.Services.OutputCache;\n\n/// <summary>\n/// Service to influence LightSpeed output caching for the current module render.\n/// To be used within Razor templates to control caching behavior of the current module output,\n/// while keeping cache invalidation and other app-level management operations on a separate service.\n/// </summary>\n/// <remarks>\n/// It allows enabling/disabling the cache, configuring cache settings, and adding named dependencies\n/// that LightSpeed should watch for this render.\n/// </remarks>\npublic interface IModuleOutputCacheService\n{\n    /// <summary>\n    /// The current module ID\n    /// </summary>\n    [PrivateApi(\"for internal use only\")]\n    internal int ModuleId { get; set; }\n\n    /// <summary>\n    /// Set the configuration of the output cache for the current module.\n    /// </summary>\n    /// <remarks>\n    /// If only some settings are provided, the others will be filled with default values or values derived from the provided settings.\n    /// This means that you can specify only the settings you want to change, and the service will ensure that all necessary settings have valid values.\n    /// For example, if Duration is set but DurationUsers is not, then DurationUsers will be set to the same value as Duration.\n    /// This allows for flexible configuration while ensuring that all necessary settings have valid values.\n    /// </remarks>\n    /// <param name=\"settings\"></param>\n    /// <returns></returns>\n    string Configure(OutputCacheSettings settings);\n\n    /// <summary>\n    /// Explicitly disable the output cache for the current module.\n    /// This will override any other cache settings and ensure that the module's output is not cached.\n    /// </summary>\n    /// <returns></returns>\n    string Disable();\n\n    /// <summary>\n    /// Add a named external dependency that the output cache should depend on.\n    /// When the specified dependency changes, the current app's cached output will be invalidated and refreshed.\n    /// </summary>\n    /// <remarks>\n    /// This currently affects output caching only.\n    /// Internally the dependency is tracked through a shared named-marker service so future <c>Kit.Cache</c>\n    /// APIs can reuse the same invalidation mechanism without inventing a second dependency system.\n    /// </remarks>\n    /// <param name=\"key\"></param>\n    /// <returns></returns>\n    string DependOn(string key);\n    // TODO: unclear where / how to add such dependencies, that they are properly tracked and trigger cache invalidation when they change.\n    // Maybe we need a more generic API for this, that can be used not only for output cache but also for data caching?\n\n    /// <summary>\n    /// Explicitly enable (or disable) the output cache for the current module.\n    /// </summary>\n    /// <param name=\"enable\"></param>\n    /// <returns></returns>\n    string Enable(bool enable = true);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/OutputCache/IOutputCacheManagementService.cs",
    "content": "namespace ToSic.Sxc.Services.OutputCache;\n\n/// <summary>\n/// Service on <c>Kit.OutputCacheManagement</c> to invalidate LightSpeed output-cache markers for a specific app.\n/// </summary>\n/// <remarks>\n/// This is intentionally separate from <see cref=\"IModuleOutputCacheService\"/>, which only affects the\n/// current render. Management operations require the target <paramref name=\"appId\"/> explicitly, so they do not\n/// depend on ambient execution context.\n/// </remarks>\n[WorkInProgressApi(\"Still WIP v21.06\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IOutputCacheManagementService\n{\n    /// <summary>\n    /// Flush output-cache entries for a specific app.\n    /// </summary>\n    /// <param name=\"appId\">The app whose output-cache markers should be touched.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"dependencies\">\n    /// Optional named dependencies to flush selectively.\n    /// If omitted or empty after normalization, the app-wide output-cache marker is touched.\n    /// </param>\n    /// <returns>\n    /// The number of normalized named dependency markers that were touched.\n    /// Returns <c>0</c> when the app-wide flush path is used.\n    /// </returns>\n    int Flush(int appId, NoParamOrder npo = default, IEnumerable<string>? dependencies = null);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/OutputCache/ModuleOutputCacheService.cs",
    "content": "using ToSic.Sxc.Render.Sys.ModuleHtml;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.Services.OutputCache;\n\n// Note 2dm 2025-06 - this doesn't seem to be in use anywhere!\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ModuleOutputCacheService(IModuleHtmlService moduleHtmlService)\n    : ServiceWithContext(\"Sxc.OutCac\", connect: [moduleHtmlService]), IModuleOutputCacheService\n{\n    [PrivateApi(\"internal use only, external API should not know about this.\")]\n    public int ModuleId\n    {\n        get => _moduleId ??= ExCtxOrNull?.GetBlock()?.Context?.Module?.Id ?? 0;\n        set => _moduleId = value;\n    }\n    private int? _moduleId;\n\n    public string Disable()\n        => Configure(new() { IsEnabled = false });\n\n    public string Enable(bool enable = true)\n        => Configure(new() { IsEnabled = enable });\n\n    public string DependOn(string key)\n    {\n        if (string.IsNullOrWhiteSpace(key))\n            throw new ArgumentException(\"Dependency key must not be empty.\", nameof(key));\n\n        ((ModuleHtmlService)moduleHtmlService).AddOutputCacheDependency(ModuleId, key);\n        return \"\";\n    }\n\n    public string Configure(OutputCacheSettings settings)\n    {\n        ((ModuleHtmlService)moduleHtmlService).ConfigureOutputCache(ModuleId, settings);\n        return \"\";\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/OutputCache/OutputCacheManagementService.cs",
    "content": "using ToSic.Sxc.Services.Cache;\n\nnamespace ToSic.Sxc.Services.OutputCache;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class OutputCacheManagementService(INamedCacheDependencyService cacheDependenciesSvc)\n    : ServiceBase(\"Sxc.OutCacMng\", connect: [cacheDependenciesSvc]), IOutputCacheManagementService\n{\n    public int Flush(int appId, NoParamOrder npo = default, IEnumerable<string>? dependencies = null)\n    {\n        var l = Log.Fn<int>($\"Flush appId: {appId}, dependencies: {string.Join(\", \", dependencies ?? [])}\");\n\n        if (appId <= 0)\n            throw l.Ex(new ArgumentOutOfRangeException(nameof(appId), appId, \"App id must be greater than zero.\"));\n\n        var normalized = cacheDependenciesSvc.NormalizeNames(dependencies);\n        if (normalized.Count == 0)\n        {\n            cacheDependenciesSvc.TouchApp(CacheDependencyScopes.OutputCache, appId);\n            return l.Return(0, \"flushed, no dependencies\");\n        }\n\n        var count = cacheDependenciesSvc.Touch(CacheDependencyScopes.OutputCache, appId, normalized);\n        return l.Return(count, \"flushed, with dependencies\");\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageChangeListenerWip.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\npublic class PageChangeListenerManagerWip\n{\n    public List<RenderResult> RenderListeners = [];\n\n    public RenderResult CreateRenderListener()\n    {\n        var listener = new RenderResult\n        {\n            Features = [],\n            FeaturesFromResources = [],\n            PartialActivateWip = [],\n            PartialModuleTags = [],\n            HeadChanges = [],\n            PageChanges = [],\n        };\n        RenderListeners.Add(listener);\n        return listener;\n    }\n\n    public void RemoveListener(RenderResult listener)\n        => RenderListeners.Remove(listener);\n\n    public void Activate(string[] keys)\n    {\n        foreach (var renderListener in RenderListeners)\n            renderListener.PartialActivateWip!.AddRange(keys);\n    }\n\n    public void AddResource(PageFeatureFromSettings feature)\n    {\n        foreach (var renderListener in RenderListeners)\n            renderListener.FeaturesFromResources!.Add(feature with { }); // clone to avoid modifying the original, which is cached\n    }\n\n    public void AddPartialModuleTag(IHtmlTag tag, bool noDuplicates)\n    {\n        foreach (var renderListener in RenderListeners)\n            renderListener.PartialModuleTags!.Add((tag, noDuplicates));\n    }\n\n    public void AddToHead(HeadChange headChange)\n    {\n        foreach (var renderListener in RenderListeners)\n            renderListener.HeadChanges!.Add(headChange);\n    }\n\n    public void AddToPageChangeQueue(PagePropertyChange result)\n    {\n        foreach (var renderListener in RenderListeners)\n            renderListener.PageChanges!.Add(result);\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.ModuleHtml;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Services.TurnOn.Sys;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing ToSic.Sxc.Web.Sys.PageServiceShared;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class PageService(\n    IPageServiceShared pageServiceShared,\n    LazySvc<IContentSecurityPolicyService> cspServiceLazy,\n    LazySvc<IHtmlTagsService> htmlTagsLazy,\n    LazySvc<ITurnOnService> turnOn,\n    LazySvc<IModuleHtmlService> moduleService,\n    LazySvc<IFeaturesService> featuresSvc)\n    : ServiceWithContext(\"2sxc.PgeSrv\",\n            connect: [cspServiceLazy, htmlTagsLazy, moduleService, turnOn, pageServiceShared, featuresSvc]),\n        IPageService // Important: Write with namespace, because it's easy to confuse with IPageService it supports\n{\n    public IPageServiceShared PageServiceShared { get; } = pageServiceShared;\n\n    ///// <summary>\n    ///// How the changes given to this object should be processed.\n    ///// </summary>\n    //[PrivateApi(\"not final yet, will probably change\")]\n    //public PageChangeModes ChangeMode { get; set; } = PageChangeModes.Auto;\n\n\n    public bool CspIsEnabled => cspServiceLazy.Value.IsEnabled;\n\n    public bool CspIsEnforced => cspServiceLazy.Value.IsEnforced;\n\n    public string AddCsp(string name, params string[] values)\n    {\n        cspServiceLazy.Value.Add(name, values);\n        return \"\";\n    }\n\n    #region Experimental Listeners\n\n    /// <summary>\n    /// Listeners are added / removed through the depth of render-in-render,\n    /// so that certain segments can detect what was modified for them and things underneath.\n    /// This is to cache changes for replace later on without re-running the razor render.\n    /// </summary>\n    public PageChangeListenerManagerWip Listeners { get; } = new();\n\n    #endregion\n\n    /// <summary>\n    /// Re-apply cached changes from a render result.\n    /// </summary>\n    /// <param name=\"renderResult\"></param>\n    /// <remarks>\n    /// It's implemented on the PageService because it needs some private properties/methods.\n    /// </remarks>\n    public void ReplayCachedChanges(RenderResult renderResult)\n    {\n        var l = Log.Fn();\n        if (renderResult.PartialActivateWip?.Any() == true)\n            Activate(renderResult.PartialActivateWip.ToArray());\n\n        foreach (var ffs in renderResult.FeaturesFromResources ?? [])\n            PageServiceShared.PageFeatures.FeaturesFromSettingsAdd(ffs);\n\n        foreach (var tagSet in renderResult.PartialModuleTags ?? [])\n            moduleService.Value.AddTag(tagSet.Tag, moduleId: ModuleId, noDuplicates: tagSet.NoDuplicates);\n\n        if (renderResult.HeadChanges != null)\n            PageServiceShared.Headers.AddRange(renderResult.HeadChanges);\n\n        if (renderResult.PageChanges != null)\n            ((PageServiceShared)PageServiceShared).PropertyChanges.AddRange(renderResult.PageChanges);\n\n        l.Done();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService_Assets.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Razor.Markup;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\nusing Attribute = ToSic.Razor.Markup.Attribute;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\npartial class PageService\n{\n    public Attribute? CspWhitelistAttribute() => CspIsEnabled\n        ? Tag.Attr(CspConstants.CspWhitelistAttribute, PageServiceShared.CspEphemeralMarker)\n        : null;\n\n    public IRawHtmlString AssetAttributes(NoParamOrder npo = default, bool optimize = true, int priority = 0, string? position = null, bool whitelist = true)\n    {\n        var attributes = new List<string>();\n        if (optimize)\n        {\n            var strPriority = priority > 100 ? priority.ToString() : \"true\";\n            var strPos = position != null ? \":\" + position : null;\n            var optAttr = Tag.Attr(ClientAssetConstants.AssetOptimizationsAttributeName, strPriority + strPos);\n            attributes.Add(optAttr.ToString());\n        }\n\n        if (whitelist)\n        {\n            var cspAttr = CspWhitelistAttribute();\n            if (cspAttr != null)\n                attributes.Add(cspAttr.ToString());\n        }\n\n        var result = string.Join(\" \", attributes);\n\n        return new RawHtmlString(result);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService_Features.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys;\nusing ToSic.Sxc.Data.Sys.DynamicStack;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Web.Sys.WebResources.WebResourceConstants;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\npartial class PageService\n{\n    /// <summary>\n    /// Test code to modify the CDN source, not for public use\n    /// </summary>\n    /// <param name=\"cdnSource\"></param>\n    public void TestCdn(string cdnSource)\n    {\n        _overrideCdnSource = cdnSource;\n    }\n    private string? _overrideCdnSource;\n\n    /// <inheritdoc />\n    public string Activate(params string[] keys)\n    {\n        keys ??= [];\n        var l = Log.Fn<string>($\"{nameof(keys)}: '{string.Join(\",\", keys)}'\");\n        FeatureKeysAdded.AddRange(keys);\n\n        // #PartialCaching must know about all activated features\n        var doFirst = false;\n        if (doFirst)\n            Listeners.Activate(keys);\n\n        // 1. Try to add manual resources from WebResources\n        // This must happen in the IPageService which is per-module\n        // The PageServiceShared cannot do this, because it doesn't have the WebResources which vary by module\n        // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract\n        if (WebResources is not null /* paranoid */) // important: DynamicEntity null-compare isn't quite right, **do not** use `!=`\n            keys = AddResourcesFromSettings(keys);\n\n        // 2. If any keys are left, they are probably preconfigured keys, so add them now\n        if (!keys.Any())\n            return l.ReturnAsOk(\"\");\n\n        l.A($\"Remaining keys: {string.Join(\",\", keys)}\");\n        var added = PageServiceShared.PageFeatures.Activate(keys).ToArray();\n\n        // WIP #PartialCaching\n        if (!doFirst)\n            Listeners.Activate(added);\n\n        // also add to this specific module, as we need a few module-level features to activate in case...\n        ExCtxOrNull?.GetBlock()?.BlockFeatureKeys.AddRange(added);\n\n        return l.ReturnAsOk(\"\"); // empty string, just so it can be used as `@Kit.Page.Activate(...)` and not produce anything\n    }\n\n    /// <inheritdoc />\n    public string? Activate(\n        NoParamOrder npo = default,\n        bool condition = true,\n        params string[] features)\n    {\n        var l = Log.Fn<string>();\n\n        // Check condition - default is true - so if it's false, this overload was called\n        return !condition\n            ? l.ReturnNull(\"condition false\")\n            : l.Return(Activate(features), \"condition true, added\");\n    }\n\n    private string[] AddResourcesFromSettings(string[] keys)\n    {\n        var l = Log.Fn<string[]>();\n        var keysToRemove = new List<string>();\n        var processor = new WebResourceProcessor(featuresSvc.Value, _overrideCdnSource ?? CdnSource, Log);\n        foreach (var key in keys)\n        {\n            l.A($\"Key: {key}\");\n            if (WebResources.Get(key) is not DynamicEntity webRes) // special problem: DynamicEntity null-compare isn't quite right, don't! use ==\n                continue;\n\n            // Found - make sure we remove the key, no matter what decisions are made below\n            keysToRemove.Add(key);\n\n            var pageFeature = processor.Process(key, webRes);\n            if (pageFeature == null)\n                continue;\n\n            l.A(\"Found html and everything, will register\");\n            // all ok so far\n            PageServiceShared.PageFeatures.FeaturesFromSettingsAdd(pageFeature);\n\n            // Wip #PartialCaching\n            Listeners.AddResource(pageFeature);\n        }\n\n        // drop keys which were already taken care of\n        keys = keys.Where(k => !keysToRemove.Contains(k)).ToArray();\n        return l.Return(keys);\n    }\n\n    /// <summary>\n    /// List of all feature keys which were ever added. Will never be cleared.\n    /// </summary>\n    public List<string> FeatureKeysAdded { get; } = [];\n\n    public bool HasFeature(string featureKey)\n        => FeatureKeysAdded.Any(f => f.EqualsInsensitive(featureKey));\n\n\n    private string? CdnSource => _cdnSource.Get(() => WebResources.Get<string>(CdnSourcePublicField));\n    private readonly GetOnce<string?> _cdnSource = new();\n\n    private DynamicEntity WebResources => _webResources.Get(() => (DynamicEntity)Settings.Get(WebResourcesNode)!)!;\n    private readonly GetOnce<DynamicEntity> _webResources = new();\n\n    private DynamicStack Settings => _settings.Get(() => (ExCtx.GetDataStack<IDynamicStack>(ExecutionContextStateNames.Settings) as DynamicStack)!)!;\n    private readonly GetOnce<DynamicStack> _settings = new();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService_Headers.cs",
    "content": "﻿using ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\npartial class PageService\n{\n\n    /// <inheritdoc />\n    public string AddToHead(IHtmlTag tag)\n    {\n        var added = PageServiceShared.Add(tag);\n        if (added != null)\n            Listeners.AddToHead(added.Value); // no duplicates, because this is a new tag\n        return \"\";\n    }\n\n    /// <inheritdoc />\n    public string AddToHead(string html)\n    {\n        if (string.IsNullOrWhiteSpace(html))\n            return \"\";\n        AddToHead(Tag.Custom(html));\n        return \"\";\n    }\n\n    /// <inheritdoc />\n    public string AddMeta(string name, string content)\n        => AddToHead(htmlTagsLazy.Value.Meta().Name(name).Content(content));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService_Icons.cs",
    "content": "﻿using ToSic.Razor.Html5;\nusing ToSic.Razor.Internals.Page;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\npartial class PageService\n{\n    /// <inheritdoc />\n    public string AddIcon(string path,\n        NoParamOrder npo = default,\n        string rel = \"\",\n        int size = 0, string? type = null)\n    {\n        AddToHead(new Icon(path, rel, size, type));\n        return \"\";\n    }\n\n    /// <inheritdoc />\n    public string AddIconSet(string path,\n        NoParamOrder npo = default,\n        object? favicon = null, IEnumerable<string>? rels = null, IEnumerable<int>? sizes = null)\n    {\n        foreach (var s in IconSet.GenerateIconSet(path, favicon, rels, sizes))\n            AddToHead(s);\n        return \"\";\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService_JsonLd.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Page.Sys;\n\npartial class PageService\n{\n    /// <inheritdoc />\n    public string AddJsonLd(string jsonString)\n        => AddToHead(htmlTagsLazy.Value.ScriptJsonLd(jsonString));\n\n    /// <inheritdoc />\n    public string AddJsonLd(object jsonObject)\n        => AddToHead(htmlTagsLazy.Value.ScriptJsonLd(jsonObject));\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService_OpenGraph.cs",
    "content": "﻿using ToSic.Razor.Html5;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\npartial class PageService\n{\n    /// <inheritdoc />\n    public string AddOpenGraph(string property, string content)\n        => AddToHead(new MetaOg(property, content));\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService_Properties.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\npartial class PageService\n{\n    /// <inheritdoc />\n    public string SetTitle(string value, string? placeholder = null)\n        => AddToQueue(PageProperties.Title, value, PageChangeModes.Prepend, placeholder);\n\n    /// <inheritdoc />\n    public string SetDescription(string value, string? placeholder = null)\n        => AddToQueue(PageProperties.Description, value, PageChangeModes.Prepend, placeholder);\n\n    /// <inheritdoc />\n    public string SetKeywords(string value, string? placeholder = null)\n        => AddToQueue(PageProperties.Keywords, value, PageChangeModes.Prepend, placeholder);\n\n    /// <inheritdoc />\n    public string SetHttpStatus(int statusCode, string? message = null)\n    {\n        PageServiceShared.HttpStatusCode = statusCode;\n        PageServiceShared.HttpStatusMessage = message;\n        return \"\";\n    }\n\n    /// <inheritdoc />\n    public string SetBase(string? url)\n        => AddToQueue(PageProperties.Base, url, PageChangeModes.Replace, null);\n\n    private string AddToQueue(PageProperties property, string? value, PageChangeModes change, string? token)\n    {\n        var result = PageServiceShared.Queue(property, value, change, token);\n        Listeners.AddToPageChangeQueue(result);\n        return \"\"; // empty so it can be used directly in razor.\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/PageService_turnOn.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\npartial class PageService\n{\n    /// <inheritdoc />\n    public string? TurnOn(object runOrSpecs,\n        NoParamOrder npo = default,\n        object? require = default,\n        object? data = default,\n        IEnumerable<object>? args = default,\n        bool condition = true,\n        bool? noDuplicates = default,\n        string? addContext = default\n    )\n    {\n        var l = Log.Fn<string?>($\"{runOrSpecs}: {runOrSpecs}; {require}; {data}\");\n\n        // Check condition - default is true - so if it's false, this overload was called\n        if (!condition)\n            return l.ReturnNull(\"condition false\");\n\n        // first activate the page feature\n        Activate(SxcPageFeatures.TurnOn.NameId);\n\n        // then generate the turn-on and add to module state\n        var tag = turnOn.Value.Run(runOrSpecs, require: require, data: data, args: args, addContext: addContext);\n\n        var reallyNoDuplicates = noDuplicates == true;\n\n        // In the Oqtane Interactive Server, the Dependency Injection (DI) session scope is bound to the first HTTP request of the user's browser session,\n        // and it does not change during subsequent SignalR communications (until a full page reload).\n        // As a result, scoped services have the same instance for all 2sxc module instances across all pages during a user's browser session.\n        // To prevent conflicts, we need to add the ModuleId to the ModuleService to scope its functionality to each module rendering.\n        // Note: in DNN, the ModuleId will be ignored.\n        var added = moduleService.Value.AddTag(tag, moduleId: ModuleId, noDuplicates: reallyNoDuplicates);\n\n        if (added != null)\n            Listeners.AddPartialModuleTag(added, reallyNoDuplicates);\n\n        // Then return empty string for usage as @Kit.Page.TurnOn(...)\n        return l.ReturnNull(\"ok\");\n    }\n\n    private int ModuleId => _moduleId ??= ExCtx.GetCmsContext().Module.Id;\n    private int? _moduleId;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Page/Sys/WebResourceProcessor.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Sxc.Data.Sys;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.HtmlParsing;\nusing ToSic.Sxc.Web.Sys.WebResources;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Page.Sys;\n\ninternal class WebResourceProcessor(IFeaturesService features, string? cdnSource, ILog parentLog)\n    : HelperBase(parentLog, \"Sxc.WebRHl\")\n{\n    #region Constants\n\n\n    private const string WebResHtmlField = \"Html\";\n\n    private const string WebResEnabledField = \"Enabled\";\n\n    private const string WebResAutoOptimizeField = \"AutoOptimize\";\n\n    #endregion\n\n    #region Constructor\n\n    public string? CdnSource { get; } = cdnSource;\n\n    #endregion\n\n    public PageFeatureFromSettings? Process(string key, DynamicEntity webRes)\n    {\n        var l = Log.Fn<PageFeatureFromSettings>(key);\n\n        // Check if it's enabled\n        if (webRes.Get(WebResEnabledField) as bool? == false)\n            return l.ReturnNull(\"not enabled\");\n\n        // Check if we really have HTML to use\n        if (webRes.Get(WebResHtmlField) is not string html || html.IsEmpty())\n            return l.ReturnNull(\"no html\");\n\n        // TODO: HANDLE AUTO-ENABLE-OPTIMIZATIONS\n        var autoOptimize = webRes.Get(WebResAutoOptimizeField, fallback: false);\n\n        if (!CdnSource.HasValue() || CdnSource == WebResourceConstants.CdnDefault)\n            return l.Return(new() { NameId = key, Html = html, AutoOptimize = autoOptimize }, \"ok, using built-in cdn-path\");\n\n        // check if feature is enabled\n        if (!features.IsEnabled(SxcFeatures.CdnSourcePublic.NameId))\n            return l.Return(new() { NameId = key, Html = html, AutoOptimize = autoOptimize }, \"ok, cdn-swap feature not enabled\");\n\n        // Set new root based on CdnSource settings\n        var newRoot = CdnSource + WebResourceConstants.VersionSuffix;\n\n        // Replacements will be delayed until preparing to generate the final HTML\n        // to be sure we only replace things in the url.\n        var srcMatches = RegexUtil.ScriptSrcDetectionMultiLine.Matches(html)\n            .Cast<Match>()\n            .Concat(RegexUtil.StyleDetectionMultiLine.Matches(html).Cast<Match>());\n        foreach (var match in srcMatches)\n        {\n            var orig = match.Groups[RegexUtil.SrcKey].Value;\n            var thirdSlash = orig.GetNthIndex('/', 3); // all paths start with \"https://xxx/\" - which we want to truncate\n            var updated = thirdSlash == -1\n                ? \"error-path-should-have-at-least-3-slashes\"\n                : newRoot + orig\n                    .Substring(thirdSlash)\n                    .Replace(\"@\", \"-\"); // not underscore, because this fails on github cdn where folders starting with underscore are hidden?\n            html = html.Replace(orig, updated);\n        }\n\n        // When going local, drop integrity property because ATM DNN changes it, and we would need to ensure it's not changed\n        // TODO: ideally we only do this, if we don't have another CDN - or make it optional... ? - where would the setting be?\n        var integrityMatches = RegexUtil.IntegrityAttribute.Matches(html);\n        foreach (Match match in integrityMatches)\n        {\n            var orig = match.Groups[RegexUtil.IntegrityKey].Value;\n            html = html.Replace(orig, \"\");\n        }\n\n        return l.Return(new() { NameId = key, Html = html, AutoOptimize = autoOptimize }, $\"ok; root now {newRoot}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/PageShield/IPageShield.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Services.PageShield;\n\n[PrivateApi]\npublic interface IPageShield\n{\n    /// <summary>\n    /// Add a url-parameter to the allowed list, optionally with specific values which are allowed.\n    /// </summary>\n    /// <remarks>\n    /// * If values are not specified, any value is allowed for the parameter.\n    /// * This is used to prevent bots from accessing the page with invalid parameters, which could lead to performance issues or security vulnerabilities.\n    /// </remarks>\n    /// <param name=\"keys\"></param>\n    /// <param name=\"values\"></param>\n    /// <returns></returns>\n    public string Allow(string keys, string? values = null);\n\n    //string? ParametersAllowed { get; }\n    //IParameters ParametersUnexpected { get; }\n    IParameters Parameters { get; }\n\n    //bool ParametersAreValid { get; }\n    [Obsolete(\"will be removed in v21.07\")]\n    IHtmlTag? Enforce(ILinkService link, string? prioritize = null);\n\n    /// <summary>\n    /// WIP - load a configuration text similar to LightSpeed, ATM just used for the tutorial, not sure if this should be public.\n    /// </summary>\n    /// <param name=\"configuration\"></param>\n    /// <returns></returns>\n    [PrivateApi]\n    string LoadConfiguration(string configuration);\n\n    /// <summary>\n    /// Enforce Page Shield - especially Flood Gates - by checking the parameters and returning a tag to be rendered if the parameters are not valid.\n    /// This is used to prevent bots from accessing the page with invalid parameters, which could lead to performance issues or security vulnerabilities.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"prioritizeParameters\">\n    /// Specify the url parameters to prioritize in the order of the final url, comma separated.\n    /// Optional. All other allowed params will be sorted A-Z.\n    /// </param>\n    /// <returns></returns>\n    IHtmlTag? Enforce(NoParamOrder npo = default, string? prioritizeParameters = null);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/PageShield/PageShield.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.Sys.Render.PageContext;\nusing ToSic.Sxc.Web.Sys.PageServiceShared;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Services.PageShield;\n\ninternal class PageShield(IPageServiceShared pageServiceShared, IUser user, IHttpContextService httpContextService, ISysFeaturesService features)\n    : ServiceWithContext(\"Sxc.OutCac\", connect: [pageServiceShared, httpContextService, features]), IPageShield\n{\n\n    private IPageServiceSharedInternal PssInternal => (IPageServiceSharedInternal)pageServiceShared;\n\n    private ILinkService LinkSvc => field ??= ExCtx.GetService<ILinkService>(reuse: true);\n\n    public string Allow(string keys, string? values = null)\n    {\n        PssInternal.UrlSpecs.Add(keys, values);\n        return \"\";\n    }\n\n    public string LoadConfiguration(string configuration)\n    {\n        PssInternal.UrlSpecs.LoadConfiguration(configuration);\n        return \"\";\n    }\n\n    public string ParametersAllowed =>\n        PssInternal.UrlSpecs.Keys() ?? \"\";\n\n    public bool ParametersAreValid =>\n        ParametersUnexpected.Count == 0;\n\n    public IParameters ParametersUnexpected =>\n        PssInternal.UrlSpecs.GetInvalid(PageParametersSafe);\n\n    public IParameters Parameters =>\n        PssInternal.UrlSpecs.GetValid(PageParametersSafe);\n\n    private IParameters PageParametersSafe =>\n        ExCtxOrNull?.GetBlock().Context.Page.Parameters ?? new Context.Sys.Parameters();\n\n    [Obsolete]\n    public IHtmlTag? Enforce(ILinkService link, string? prioritize = null) =>\n        Enforce(prioritizeParameters: prioritize);\n\n    public IHtmlTag? Enforce(NoParamOrder npo = default, string? prioritizeParameters = null)\n    {\n        var l = Log.Fn<IHtmlTag?>($\"{nameof(prioritizeParameters)}:'{prioritizeParameters}'\");\n\n        if (!features.IsEnabled(SxcFeatures.PageShieldFloodGates))\n            return l.ReturnNull(\"feature not enabled\");\n\n        if (ParametersAreValid)\n            return l.ReturnNull(\"parameters are valid\");\n\n        if (user.IsContentEditor)\n        {\n            var result = Tag.Div().Class(\"alert alert-danger\").Wrap(\n                Tag.H4(\"Warning: Unexpected URL Parameters Detected\"),\n                Tag.P(\n                    \"\"\"\n                    The URL contains parameters which are not expected on this page, and may cause problems. \n                    If you are not logged it, this will trigger a redirect. \n                    \"\"\",\n                    Tag.Br(),\n                    \"\"\"\n                    Please check the URL and remove any parameters which are not expected, \n                    or update the configuration to expect these parameters.\n                    \"\"\"\n                ),\n                Tag.Ol().Wrap(\n                    Tag.Li(Tag.Strong(\"Expected\"), \": \", Tag.Code(Parameters + \"\")),\n                    Tag.Li(Tag.Strong(\"Actual\"), \": \", Tag.Code(PageParametersSafe + \"\")),\n                    Tag.Li(Tag.Strong(\"Unexpected\"), \": \", Tag.Code(ParametersUnexpected + \"\"))\n                )\n            );\n            return l.Return(result, \"showing warning\");\n        }\n\n\n        var parameters = Parameters;\n        if (prioritizeParameters != null)\n            parameters = parameters.Prioritize(prioritizeParameters);\n\n        l.A($\"Not editor, will enforce redirect to: {parameters}\");\n\n        httpContextService.Redirect301(LinkSvc.To(parameters: parameters));\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/SecureData/ISecureDataService.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.SecureData`](xref:ToSic.Sxc.Services.ServiceKit16.SecureData) to work with secure / encrypted data. \n/// </summary>\n/// <remarks>\n/// History\n/// * Added in 2sxc 12.05\n/// </remarks>\n[PublicApi]\npublic interface ISecureDataService: IHasLog, ICanDebug\n{\n    /// <summary>\n    /// Read an input value and return a secure data object.\n    /// This will contain the readable value and additional information if it was encrypted or not, etc.\n    /// </summary>\n    /// <param name=\"value\"></param>\n    /// <returns></returns>\n    ISecureData<string> Parse(string value);\n\n    //[PrivateApi(\"WIP v15.01\")]\n    //string Create(string value);\n\n    /// <summary>\n    /// Hash a value using SHA256, using a FIPS compliant provider.\n    /// </summary>\n    /// <param name=\"value\">value to hash, `null` will be treated as empty string</param>\n    /// <returns>the hash as a ???</returns>\n    /// <remarks>Added v17.08</remarks>\n    string HashSha256(string value); //, NoParamOrder npo = default, string salt = default);\n\n    /// <summary>\n    /// Hash a value using SHA512, using a FIPS compliant provider.\n    /// </summary>\n    /// <param name=\"value\">value to hash, `null` will be treated as empty string</param>\n    /// <returns>the hash as a ???</returns>\n    /// <remarks>Added v17.08</remarks>\n    string HashSha512(string value); //, NoParamOrder npo = default, string salt = default);\n\n    // Note to my future self: HashSha3_256 and HashSha3_512 are not implemented yet\n    // reason is that they are not FIPS compliant until .net 8 according to \n    // https://docs.microsoft.com/en-us/dotnet/standard/security/cryptographic-services#hash-algorithms\n    // https://stackoverflow.com/questions/47679476/how-to-generate-sha3-256-in-net-core\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/SecureData/SecureDataService.cs",
    "content": "﻿using ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Secret;\nusing ToSic.Sys.Security.Encryption;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Note: this is still a very temporary implementation, WIP\n///\n/// For now we have a super-trivial encryption for keys which are not really critical,\n/// but only 2sxc distributions actually encrypt stuff. So it's not for any other use yet.\n///\n/// To encrypt other values, use the SecureDataTest.DumpEncryptedValue() code and get the encrypted value from the Trace\n/// </summary>\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class SecureDataService(AesCryptographyService aes)\n    : ServiceBase($\"{SxcLogName}.SecDtS\"), ISecureDataService\n{\n    public readonly AesCryptographyService Aes = aes;\n\n    public const string PrefixSecure = \"secure:\";\n    public const string PrefixIv = \"iv:\";\n    public const char ValueSeparator = ';';\n\n    public ISecureData<string> Parse(string value)\n    {\n        var l = Log.Fn<ISecureData<string>>(enabled: Debug);\n        if (string.IsNullOrWhiteSpace(value))\n            return l.Return(new SecureData<string>(value, false), $\"{nameof(value)} null/empty\");\n\n        // remove prefix which should be required, but ATM not enforced\n        if (!value.StartsWith(PrefixSecure, InvariantCultureIgnoreCase))\n            return l.Return(new SecureData<string>(value, false), $\"not secured, missing prefix {PrefixSecure}\");\n            \n        var probablySecure = value.Substring(PrefixSecure.Length);\n        var parts = probablySecure.Split(ValueSeparator);\n        var toDecrypt = parts[0];\n        var iv = parts.Length <= 1 \n            ? null \n            : parts[1].StartsWith(PrefixIv, InvariantCultureIgnoreCase)\n                ? parts[1].Substring(PrefixIv.Length)\n                : null;\n\n        try\n        {\n            // will return null if it fails\n            var decrypted = Aes.DecryptFromBase64(toDecrypt, new() { InitializationVector64 = iv });\n            return decrypted == null \n                ? l.Return(new SecureData<string>(value, false), $\"{nameof(decrypted)} null/empty\")\n                : l.Return(new SecureData<string>(decrypted, true), \"decrypted\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            // if all fails, return the original\n            return l.Return(new SecureData<string>(value, false), \"error decrypting\");\n        }\n    }\n\n    public string? Create(string value)\n    {\n        var l = Log.Fn<string>(enabled: Debug);\n        if (string.IsNullOrWhiteSpace(value))\n            return l.ReturnNull(\"null/empty\");\n\n        try\n        {\n            // will return null if it fails\n            var encrypt64 = Aes.EncryptToBase64(value);\n            if (encrypt64.Value == null! /* paranoid */)\n                return l.Return(\"\", \"empty encryption\");\n            var final = PrefixSecure + encrypt64.Value + ValueSeparator + PrefixIv + encrypt64.Iv;\n            return l.Return(final, \"encrypted\");\n\n        }\n        catch (Exception ex)\n        {\n            l.Done(ex);\n            throw;\n        }\n    }\n\n    public string HashSha256(string value)\n    {\n        var l = Log.Fn<string>(enabled: Debug);\n        return l.Return(Sha256.Hash(value ?? \"\"));\n    }\n\n    public string HashSha512(string value)\n    {\n        var l = Log.Fn<string>(enabled: Debug);\n        return l.Return(Sha512.Hash(value ?? \"\"));\n    }\n\n    public bool Debug { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/SystemLog/ILogService.cs",
    "content": "﻿namespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.SystemLog`](xref:ToSic.Sxc.Services.ServiceKit16.SystemLog) to add messages to the global (system) log in any platform Dnn/Oqtane.\n/// </summary>\n/// <remarks>\n/// As of now this service is still very simple, later we may add methods like `Warn()` or `Error()` but let's wait and see what's needed\n/// </remarks>\n[PublicApi]\npublic interface ISystemLogService\n{\n    /// <summary>\n    /// Add a general message to the log.\n    /// </summary>\n    /// <param name=\"title\"></param>\n    /// <param name=\"message\"></param>\n    void Add(string title, string message);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/SystemLog/LogServiceUnknown.cs",
    "content": "﻿#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Services;\n\n[PrivateApi(\"Mock / Unknown implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class SystemLogServiceUnknown(WarnUseOfUnknown<SystemLogServiceUnknown> _) : ISystemLogService\n{\n    public void Add(string title, string message)\n    {\n        // ignore\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Templates/ITemplateEngine.cs",
    "content": "﻿using ToSic.Eav.LookUp;\nusing ToSic.Sxc.Services.Templates;\n\n// TODO: unclear if the namespace is correct, feels a bit off...\n\nnamespace ToSic.Sxc.Services.Template;\n\n/// <summary>\n/// Engine which parses a template containing placeholders and replaces them with values from sources.\n/// </summary>\n/// <remarks>\n/// Released in 18.03\n/// </remarks>\n[WorkInProgressApi(\"namespace not final\")]\npublic interface ITemplateEngine\n{\n    /// <summary>\n    /// Get a list of underlying sources, mainly for debugging.\n    /// </summary>\n    /// <returns></returns>\n    public IEnumerable<ILookUp> GetSources(NoParamOrder npo = default, int depth = 0);\n\n    /// <summary>\n    /// Basic Parse functionality.\n    /// This is the variant without parameters, which should be used in basic cases and also\n    /// for passing into function calls, like into CMS HTML Tweaks.\n    /// </summary>\n    /// <param name=\"template\">The string containing the token placeholders like `Hello [User:FirstName]`</param>\n    /// <returns></returns>\n    string Parse(string template);\n\n    /// <summary>\n    /// Basic Parse functionality with more options.\n    /// </summary>\n    /// <param name=\"template\">The string containing the token placeholders like `Hello [User:FirstName]`</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"allowHtml\">allow adding html to the string - if false (default) will html encode anything found for safety before replacing something</param>\n    /// <param name=\"sources\">A list of sources to use for this parse - otherwise use the sources provided on creation of the template engine</param>\n    /// <param name=\"recursions\">\n    /// Recursion depth for tokens-in-tokens.\n    /// Could leak unexpected information, if a token contains user provided data or url-parameters so _use with caution_.\n    /// Defaults to `0` for safety, added v20.09\n    /// </param>\n    // ReSharper disable once MethodOverloadWithOptionalParameter\n    string Parse(string template, NoParamOrder npo = default, bool allowHtml = false, IEnumerable<ILookUp>? sources = default, int recursions = TemplateEngineTokens.MaxDepth);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Templates/ITemplateService.cs",
    "content": "﻿using ToSic.Eav.LookUp;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services.Template;\nusing ToSic.Sxc.Services.Templates;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.Template`](xref:ToSic.Sxc.Services.ServiceKit16.Template) to help parse token-based templates.\n/// </summary>\n/// <remarks>\n/// Released in 18.03\n/// </remarks>\n[PublicApi]\npublic interface ITemplateService\n{\n    /// <summary>\n    /// Start with the default engine, which already has lookups for QueryString and similar sources.\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"sources\">optional _additional_ sources</param>\n    /// <returns></returns>\n    ITemplateEngine Default(NoParamOrder npo = default, IEnumerable<ILookUp>? sources = null);\n\n    /// <summary>\n    /// Start with an empty engine.\n    /// This usually only makes sense, if you provide custom sources. \n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"sources\">optional sources, but without them this engine won't do much</param>\n    /// <returns></returns>\n    ITemplateEngine Empty(NoParamOrder npo = default, IEnumerable<ILookUp>? sources = null);\n\n    /// <summary>\n    /// Get a built-in source by name.\n    /// This is usually used when you want to create a template-engine with some specific sources,\n    /// and you explicitly need for example the QueryString source as well.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <returns>The source if found, otherwise null</returns>\n    ILookUp? GetSource(string name);\n\n    /// <summary>\n    /// Create a source based on a dictionary.\n    /// Lookup will be case-insensitive.\n    /// </summary>\n    /// <param name=\"name\">The source name, basically the first part of the token eg: [Name:Value]</param>\n    /// <param name=\"values\"></param>\n    /// <returns></returns>\n    ILookUp CreateSource(string name, IDictionary<string, string> values);\n\n    /// <summary>\n    /// Create a source based on another source.\n    /// This is mainly used to give a source another name.\n    /// </summary>\n    /// <param name=\"name\">The source name, basically the first part of the token eg: [Name:Value]</param>\n    /// <param name=\"original\"></param>\n    /// <returns></returns>\n    ILookUp CreateSource(string name, ILookUp original);\n\n    /// <summary>\n    /// Create a source using an entity (or entity-like thing such as an ITypedItem) as the source.\n    /// </summary>\n    /// <param name=\"name\">The source name, basically the first part of the token eg: [Name:Value]</param>\n    /// <param name=\"item\">An <see cref=\"IEntity\"/>, <see cref=\"ITypedItem\"/> or similar object.</param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"dimensions\">optional array of languages to use when looking for the value - if the data is multi-language. Default to current languages.</param>\n    /// <returns></returns>\n    ILookUp CreateSource(string name, ICanBeEntity item, NoParamOrder npo = default, string[]? dimensions = default);\n\n    /// <summary>\n    /// Create a source using a function, basically a very custom source. \n    /// </summary>\n    /// <param name=\"name\">The source name, basically the first part of the token eg: [Name:Value]</param>\n    /// <param name=\"getter\">The function which uses the key to retrieve a value. It will be case-sensitive/-insensitive based on your code.</param>\n    /// <returns></returns>\n    ILookUp CreateSource(string name, Func<string, string> getter);\n\n    /// <summary>\n    /// Create a source using a function, basically a very custom source.\n    /// This variant has 2 string parameters - the key and the format-string.\n    /// </summary>\n    /// <param name=\"name\">The source name, basically the first part of the token eg: [Name:Value]</param>\n    /// <param name=\"getter\"></param>\n    /// <returns></returns>\n    ILookUp CreateSource(string name, Func<string, string, string> getter);\n\n    /// <summary>\n    /// Merge multiple sources into one.\n    /// </summary>\n    /// <param name=\"name\"></param>\n    /// <param name=\"sources\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Added v17.09\n    /// </remarks>\n    ILookUp MergeSources(string name, IEnumerable<ILookUp> sources);\n\n    /// <summary>\n    /// Quick parse a template using the default engine, and optional sources.\n    /// </summary>\n    /// <param name=\"template\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"allowHtml\">allow adding html to the string - if false (default) will html encode anything found for safety before replacing something</param>\n    /// <param name=\"sources\"></param>\n    /// <param name=\"recursions\">\n    /// Recursion depth for tokens-in-tokens.\n    /// Could leak unexpected information, if a token contains user provided data or url-parameters so _use with caution_.\n    /// Defaults to `0`, added v20.09\n    /// </param>\n    /// <returns></returns>\n    string Parse(string template, NoParamOrder npo = default, bool allowHtml = false, IEnumerable<ILookUp>? sources = default, int recursions = TemplateEngineTokens.MaxDepth);\n\n\n    /// <summary>\n    /// Take an entity, TypedItem or similar object, and return a TypedItem which will run its values through the parser.\n    /// </summary>\n    /// <param name=\"original\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"allowHtml\">allow adding html to the string - if false (default) will html encode anything found for safety before replacing something</param>\n    /// <param name=\"parser\">A prepared parser - takes preference over `sources`</param>\n    /// <param name=\"sources\">A list of sources to create a parser</param>\n    /// <param name=\"recursions\">\n    /// Recursion depth for tokens-in-tokens.\n    /// Could leak unexpected information, if a token contains user provided data or url-parameters so _use with caution_.\n    /// Defaults to `0` for safety.\n    /// </param>\n    /// <returns>An ITypedItem to be used with `.String(\"name\")` etc.</returns>\n    /// <remarks>\n    /// WIP v20.09\n    ///\n    /// If neither parser nor sources are provided, an empty parser will be used, resulting in no changes to the original values.\n    /// </remarks>\n    ITypedItem ParseAsItem(ICanBeEntity original, NoParamOrder npo = default, bool allowHtml = false, ITemplateEngine? parser = null, IEnumerable<ILookUp>? sources = null, int recursions = TemplateEngineTokens.MaxDepth);\n\n    /// <summary>\n    /// Take an entity, TypedItem or similar object, and return a type `T` which will run its values through the parser.\n    /// </summary>\n    /// <param name=\"original\"></param>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"allowHtml\">allow adding html to the string - if false (default) will html encode anything found for safety before replacing something</param>\n    /// <param name=\"parser\">A prepared parser - takes preference over `sources`</param>\n    /// <param name=\"sources\">A list of sources to create a parser</param>\n    /// <param name=\"recursions\">\n    /// Recursion depth for tokens-in-tokens.\n    /// Could leak unexpected information, if a token contains user provided data or url-parameters so _use with caution_.\n    /// Defaults to `0` for safety.\n    /// </param>\n    /// <returns>A TypedItem of specified type `T`</returns>\n    /// <remarks>\n    /// WIP v20.09\n    ///\n    /// If neither parser nor sources are provided, an empty parser will be used, resulting in no changes to the original values.\n    /// </remarks>\n    T ParseAs<T>(ICanBeEntity original, NoParamOrder npo = default, bool allowHtml = false, ITemplateEngine? parser = null, IEnumerable<ILookUp>? sources = null, int recursions = TemplateEngineTokens.MaxDepth)\n        where T : class, IModelFromData;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Templates/LookUpWithFunction.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sources;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Templates;\n\ninternal class LookUpWithFunction(string name, Func<string,string> getter): LookUpBase(name, \"LookUp using simple function\")\n{\n    public override string Get(string key, string format)\n    {\n        var result = getter(key);\n        return format.IsEmptyOrWs() \n            ? result \n            : string.Format(format, result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Templates/LookUpWithFunctionAndFormat.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sources;\n\nnamespace ToSic.Sxc.Services.Templates;\n\ninternal class LookUpWithFunctionAndFormat(string name, Func<string,string,string> getter): LookUpBase(name, \"LookUp using Function which also handles format\")\n{\n    public override string Get(string key, string format) \n        => getter(key,format);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Templates/TemplateEngineTokens.cs",
    "content": "﻿using ToSic.Eav.LookUp;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Services.Template;\n\nnamespace ToSic.Sxc.Services.Templates;\n\ninternal class TemplateEngineTokens(ILookUpEngine original): ITemplateEngine, IWrapper<ILookUpEngine>\n{\n\n    private const string TemplateKey = \"Template\";\n\n    /// <summary>\n    /// it's important to use depth 0 to prevent things such as query-string parameters providing new tokens\n    /// otherwise you could have a [QueryString:Id] but the url being ?id=[page:id] or of course worse\n    /// </summary>\n    internal const int MaxDepth = 0;\n\n    IEnumerable<ILookUp> ITemplateEngine.GetSources(NoParamOrder npo, int depth)\n    {\n        if (depth == 0)\n            return original.Sources;\n\n        // loop through depth to get all underlying sources\n        var current = original;\n        var sources = current.Sources;\n        for (var i = 0; i < depth; i++)\n        {\n            if (current.Downstream == null) break;\n            current = current.Downstream;\n            sources = sources.Concat(current.Sources);\n        }\n        return sources.ToList();\n    }\n\n    string ITemplateEngine.Parse(string template)\n        => ((ITemplateEngine)this).Parse(template, npo: default, sources: null);\n\n    string ITemplateEngine.Parse(string template, NoParamOrder npo, bool allowHtml, IEnumerable<ILookUp>? sources, int recursions)\n    {\n        var dic = new Dictionary<string, string>\n        {\n            [TemplateKey] = template\n        };\n        var result = original.LookUp(dic, overrides: sources, depth: MaxDepth, tweak: t =>\n        {\n            if (allowHtml) return t;\n            return t.PostProcess(s =>\n                !string.IsNullOrEmpty(s) && (s.Contains(\"<\") || s.Contains(\"&\") || s.Contains(\">\"))\n                    ? Razor.Blade.Tags.Encode(s)\n                    : s\n            );\n        });\n        var raw = result[TemplateKey];\n        return raw;\n        //if (raw is null) return null;\n\n        //var hasHtml = raw.Contains(\"<\") || raw.Contains(\"&\") || raw.Contains(\">\");\n        //return allowHtml || !hasHtml\n        //    ? raw\n        //    : ToSic.Razor.Blade.Tags.Encode(raw);\n    }\n\n    /// <summary>\n    /// For now just on explicit implementation, for debug, without enlarging the public API\n    /// </summary>\n    /// <returns></returns>\n    ILookUpEngine IWrapper<ILookUpEngine>.GetContents() => original;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Templates/TemplateService.cs",
    "content": "﻿using ToSic.Eav.LookUp;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Typed;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Services.Template;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services.Templates;\n\ninternal class TemplateService(LazySvc<ILookUpEngineResolver> getLookupsLazy) : ServiceWithContext($\"{SxcLogName}.LUpSvc\"), ITemplateService\n{\n    #region Get Engine Default / Empty\n\n    public ITemplateEngine Default(NoParamOrder npo = default, IEnumerable<ILookUp>? sources = default)\n    {\n        var sourcesList = sources?.ToList();\n        var noSources = sourcesList == null || sourcesList.Count == 0;\n        if (_default != null && noSources)\n            return _default;\n\n        // in some cases, like when testing, the _CodeApiSvc is not available\n        // then it should still work, but of course not know about the app's sources\n        var original = ((IExCtxLookUpEngine?)ExCtxOrNull)?.LookUpForDataSources // #DropAppConfigurationProvider ((Apps.App?)ExCtxOrNull?.GetApp())?.ConfigurationProvider\n            ?? getLookupsLazy.Value.GetLookUpEngine(ExCtxOrNull?.GetBlock()?.Context?.Module?.Id ?? 0);\n        \n        return noSources\n            ? _default = new TemplateEngineTokens(original)\n            : new TemplateEngineTokens(new LookUpEngine(original, Log, sources: sourcesList));\n    }\n\n    private ITemplateEngine? _default;\n\n    public ITemplateEngine Empty(NoParamOrder npo = default, IEnumerable<ILookUp>? sources = null)\n    {\n        var sourcesList = sources?.ToList();\n        var noSources = sourcesList == null || sourcesList.Count == 0;\n        if (_empty != null && noSources)\n            return _empty;\n\n        ILookUpEngine originalEngine = new LookUpEngine(Log, sources: sourcesList);\n        \n        return noSources\n            ? _empty ??= new TemplateEngineTokens(originalEngine)\n            : new TemplateEngineTokens(originalEngine);\n    }\n    private ITemplateEngine? _empty;\n\n    #endregion\n\n    #region GetSource\n\n    public ILookUp? GetSource(string name)\n        => Default().GetSources(depth: 10).FirstOrDefault(s => s.Name.EqualsInsensitive(name));\n\n\n    #endregion\n\n    #region Quick Parse\n\n    [field: AllowNull, MaybeNull]\n    private ITemplateEngine Engine => field ??= Default();\n\n\n    string ITemplateService.Parse(string template, NoParamOrder npo, bool allowHtml, IEnumerable<ILookUp>? sources, int recursions)\n        => Engine.Parse(template, npo, allowHtml: allowHtml, sources: sources, recursions: recursions);\n\n    #endregion\n\n    #region Create Sources\n\n    public ILookUp CreateSource(string name, IDictionary<string, string> values) \n        => new LookUpInDictionary(NameOrErrorIfBad(name), values);\n\n    public ILookUp CreateSource(string name, ILookUp original)\n        => new LookUpInLookUps(NameOrErrorIfBad(name), [original]);\n\n    public ILookUp CreateSource(string name, Func<string, string> getter)\n        => new LookUpWithFunction(NameOrErrorIfBad(name), getter);\n\n    public ILookUp CreateSource(string name, Func<string, string, string> getter)\n        => new LookUpWithFunctionAndFormat(NameOrErrorIfBad(name), getter);\n\n    [field: AllowNull, MaybeNull]\n    private ICodeDataFactory Cdf => field ??= ExCtx.GetCdf();\n\n    public ILookUp CreateSource(string name, ICanBeEntity item, NoParamOrder npo = default, string[]? dimensions = default) \n        => new LookUpInEntity(name, item.Entity, dimensions: dimensions ?? Cdf.Dimensions);\n\n    public ILookUp MergeSources(string name, IEnumerable<ILookUp>? sources)\n    {\n        var sourceList = sources\n                             ?.ToList()\n                         ?? throw new ArgumentNullException(nameof(sources), @\"Sources must not be null\");\n\n        if (!sourceList.Any())\n            throw new ArgumentException(@\"Sources must not be empty\", nameof(sources));\n\n        return new LookUpInLookUps(name, sourceList);\n    }\n\n    private string NameOrErrorIfBad(string name)\n        => string.IsNullOrWhiteSpace(name)\n            ? throw new ArgumentException(@\"Name must not be empty\", nameof(name))\n            : name.ToLowerInvariant();\n\n    #endregion\n\n    #region Create Templated Entity\n\n    ITypedItem ITemplateService.ParseAsItem(ICanBeEntity original, NoParamOrder npo,\n        bool allowHtml,\n        ITemplateEngine? parser, \n        IEnumerable<ILookUp>? sources,\n        int recursions\n    )\n    {\n        var entity = original.Entity;\n        if (entity == null)\n            throw new ArgumentException(@\"The original item must have an entity\", nameof(original));\n\n        parser ??= Empty(sources: sources);\n\n        var templated = new TypedItemOfEntity(entity, Cdf, true, overrider: new ValueTemplateParser(parser, null));\n        return templated;\n    }\n\n    T ITemplateService.ParseAs<T>(ICanBeEntity original, NoParamOrder npo,\n        bool allowHtml,\n        ITemplateEngine? parser,\n        IEnumerable<ILookUp>? sources,\n        int recursions\n    )\n    {\n        var templated = ((ITemplateService)this).ParseAsItem(original, npo, allowHtml, parser, sources, recursions: recursions);\n        return Cdf.AsCustom<T>(source: templated);\n    }\n\n\n    private class ValueTemplateParser(ITemplateEngine? parser, ILookUp? overrides, bool allowHtml = false) : IValueOverrider\n    {\n        #region Experiment - but decided for now that it's too much compute for something which is extremely rarely used, and can be done with an if-statement in the code\n        //public object? OverrideRaw(string name)\n        //{\n        //    if (overrides == null)\n        //        return null;\n        //    var found = overrides.Get(name);\n        //    return string.IsNullOrEmpty(found) ? null : found;\n        //}\n\n        //public T? OverrideRaw<T>(string name)\n        //{\n        //    if (overrides == null)\n        //        return default;\n        //    if (overrides is IWrapper<IEntity> entityLookUp)\n        //    {\n        //        var entity = entityLookUp.GetContents();\n        //        if (entity != null)\n        //            return entity.Get<T>(name);\n        //    }\n        //    var found = overrides.Get(name);\n        //    return found.ConvertOrDefault<T>();\n        //}\n        #endregion\n\n        public string? ProcessString(string name, string? originalValue)\n            => originalValue == null || parser == null\n                ? null\n                : parser.Parse(originalValue, allowHtml: allowHtml);\n    }\n    #endregion\n\n\n}\n\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Toolbars/ToolbarService.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Services;\n\n[PrivateApi(\"Hide implementation\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class ToolbarService(Generator<IToolbarBuilder> toolbarGenerator)\n    : ServiceWithContext($\"{SxcLogName}.TlbSvc\", connect: [toolbarGenerator]), IToolbarService\n{\n\n    /// <inheritdoc />\n    public IToolbarBuilder Default(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null\n    ) => ToolbarBuilder(npo: npo, tweak: tweak, toolbarTemplate: ToolbarRuleToolbar.Default, ui: ui, parameters: parameters, prefill: prefill, context: null, target: target);\n\n\n    /// <inheritdoc />\n    public IToolbarBuilder Empty(\n        object? target = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null\n    ) => ToolbarBuilder(npo: npo, tweak: tweak, toolbarTemplate: ToolbarRuleToolbar.Empty, ui: ui, parameters: parameters, prefill: prefill, context: null, target: target);\n\n\n    /// <inheritdoc />\n    public IToolbarBuilder Metadata(\n        object target,\n        string? contentTypes = null,\n        NoParamOrder npo = default,\n        Func<ITweakButton, ITweakButton>? tweak = default,\n        object? ui = null,\n        object? parameters = null,\n        object? prefill = null,\n        string? context = null\n    ) => Empty().Metadata(target: target, contentTypes: contentTypes, npo: npo, tweak: tweak, ui: ui, parameters: parameters, prefill: prefill, context: context);\n\n    public IToolbarBuilder Edit(object target, NoParamOrder npo = default, Func<ITweakButton, ITweakButton>? tweak = default)\n        => Empty().Edit(target: target, npo: npo, tweak: tweak);\n\n\n\n    private IToolbarBuilder ToolbarBuilder(\n        NoParamOrder npo,\n        string toolbarTemplate,\n        Func<ITweakButton, ITweakButton>? tweak,\n        object? ui,\n        object? parameters,\n        object? prefill,\n        string? context,\n        object? target)\n    {\n        var l = Log.Fn<IToolbarBuilder>($\"{nameof(toolbarTemplate)}:{toolbarTemplate}\");\n        \n        // The following lines must be just as this, because it's a functional object, where each call may return a new copy\n        var tlb = (ToolbarBuilder)toolbarGenerator.New();\n        tlb.ConnectToRoot(ExCtxOrNull);\n\n        tlb = (ToolbarBuilder)tlb\n            .Toolbar(toolbarTemplate: toolbarTemplate, target: target, tweak: tweak, ui: ui, parameters: parameters, prefill: prefill);\n\n        if (_defaultUi.HasValue())\n            tlb = (ToolbarBuilder)tlb.Settings(ui: _defaultUi);\n\n        if (context.HasValue())\n            tlb = tlb.AddInternal([new ToolbarRuleGeneric($\"context?{context}\")]);\n\n        return l.Return(tlb);\n    }\n\n\n    internal void _setDemoDefaults(string? defaultUi)\n        => _defaultUi = defaultUi;\n    private string? _defaultUi;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/TurnOn/Sys/ITurnOnService.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing Attribute = ToSic.Razor.Markup.Attribute;\n\nnamespace ToSic.Sxc.Services.TurnOn.Sys;\n\n/// <summary>\n/// turnOn Service helps initialize / boot JavaScripts when all requirements (usually dependencies) are ready.\n/// </summary>\n[PrivateApi(\"Don't publish yet - the functionality is surfaced on the PageService!\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ITurnOnService: IHasLog\n{\n\n    Attribute Attribute(object runOrSpecs,\n        NoParamOrder npo = default,\n        object? require = null,\n        object? data = null);\n\n    IHtmlTag Run(object runOrSpecs,\n        NoParamOrder npo = default,\n        object? require = null,\n        object? data = null,\n        IEnumerable<object>? args = default,\n        string? addContext = default\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/TurnOn/Sys/TurnOnSpecs.cs",
    "content": "﻿using System.Text.Json.Serialization;\n\nnamespace ToSic.Sxc.Services.TurnOn.Sys;\n\ninternal class TurnOnSpecs\n{\n    [JsonPropertyName(\"run\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Run { get; init; }\n\n    [JsonPropertyName(\"require\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public object? Require { get; init; }\n\n    [JsonPropertyName(\"data\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public object? Data { get; init; }\n\n    [JsonPropertyName(\"args\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public IEnumerable<object>? Args { get; init; }\n\n    [JsonPropertyName(\"addContext\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? AddContext { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/TurnOn/TurnOnService.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Services.TurnOn.Sys;\nusing Attribute = ToSic.Razor.Markup.Attribute;\n\nnamespace ToSic.Sxc.Services;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class TurnOnService(LazySvc<IHtmlTagsService> htmlTagsService)\n    : ServiceBase(SxcLogName + \".TrnOnS\", connect: [htmlTagsService]), ITurnOnService\n{\n    protected virtual string TagName => \"turnOn\";\n    private const string AttributeName = \"turn-on\";\n\n    // TODO:\n    // - TEST\n    // - CREATE LOG INTERCEPT - probably only exist on the FN method right now?\n\n    public Attribute Attribute(\n        object runOrSpecs,\n        NoParamOrder npo = default,\n        object? require = default,\n        object? data = default\n    )\n    {\n        var l = Log.Fn<Attribute>();\n        var specs = PickOrBuildSpecs(runOrSpecs: runOrSpecs, require: require, data: data, args: null, addContext: null);\n        var attr = htmlTagsService.Value.Attr(AttributeName, specs);\n        return l.ReturnAsOk(attr);\n    }\n\n    public IHtmlTag Run(\n        object runOrSpecs,\n        NoParamOrder npo = default,\n        object? require = default,\n        object? data = default,\n        IEnumerable<object>? args = default,\n        string? addContext = default\n    )\n    {\n        var l = Log.Fn<IHtmlTag>();\n        var specs = PickOrBuildSpecs(runOrSpecs: runOrSpecs, require: require, data: data, args: args, addContext: addContext);\n        var tag = htmlTagsService.Value.Custom(TagName).Attr(AttributeName, specs);\n        return l.ReturnAsOk(tag);\n    }\n\n    internal static object PickOrBuildSpecs(object runOrSpecs, object? require, object? data, IEnumerable<object>? args, string? addContext)\n        => runOrSpecs is not string run\n            // if we already have a full configuration, just return it\n            ? runOrSpecs\n            // otherwise build a new one\n            : new TurnOnSpecs\n            {\n                Args = args,\n                AddContext = addContext,\n                Data = data,\n                Require = require,\n                Run = run,\n            };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Tweaks.Sys/ITweakData.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks.Sys;\n\n/// <summary>\n/// Container for a value (data) to tweak.\n/// As of now just contains the value in a property, but will be extended in the future.\n/// So in future it could have more context information etc.\n/// </summary>\n/// <remarks>New in v17 - NOT YET IN USE IN PUBLIC APIs</remarks>\n/// <typeparam name=\"TValue\"></typeparam>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal interface ITweakData<out TValue>\n{\n    /// <summary>\n    /// Current value before tweaking.\n    /// </summary>\n    TValue? Value { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Tweaks.Sys/TweakConfig.T.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks.Sys;\n\ninternal record TweakConfig<T>(string NameId)\n    : TweakConfig(NameId)\n{\n    public required T Tweak { get; init; }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Tweaks.Sys/TweakConfig.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks.Sys;\n\n/// <summary>\n/// A tweak configuration, describing what to tweak - usually for workflow-style tweaks which execute at certain steps.\n/// </summary>\ninternal record TweakConfig(string NameId)\n{\n    public const string StepDefault = \"default\";\n    public const string TargetDefault = \"value\";\n\n    /// <summary>\n    /// Identifier of this configuration\n    /// </summary>\n    public string NameId { get; init; } = NameId;\n\n    /// <summary>\n    /// Name of the target which will be modified, like `Value`\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public string Target\n    {\n        get => field ??= TargetDefault;\n        init;\n    }\n\n    /// <summary>\n    /// Step of the tweak, like a workflow step. like `Result`\n    /// </summary>\n    [field: AllowNull, MaybeNull]\n    public string Step\n    {\n        get => field ??= StepDefault;\n        init;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Tweaks.Sys/TweakConfigConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks.Sys;\n\ninternal class TweakConfigConstants\n{\n    public const string NameDefault = \"default\";\n    public const string StepBefore = \"before\";\n    public const string StepAfter = \"after\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Tweaks.Sys/TweakConfigListExtensions.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks.Sys;\ninternal static class TweakConfigListExtensions\n{\n    #region Clone Helpers - maybe centralize to ToSic.Sys some day?\n\n    public static List<T> CloneAndAddNonNull<T>(this IEnumerable<T>? listToClone, T? additional = default)\n    {\n        var newList = listToClone == null ? [] : new List<T>(listToClone);\n        if (additional != null)\n            newList.Add(additional);\n        return newList;\n    }\n\n    #endregion\n\n    #region Get Tweaks by Step / Name\n\n    internal static List<TweakConfig> GetTweaksByStep(this IList<TweakConfig> list, string step)\n        => list.Where(t => t.Step == step).ToList();\n\n    internal static List<TweakConfig> GetTweaksByName(this IList<TweakConfig> list, string nameId)\n        => list.Where(t => t.NameId == nameId).ToList();\n\n    #endregion\n\n    #region Process / PreProcess\n\n    internal static ITweakData<TInput> Preprocess<TInput>(this IList<TweakConfig> list, TInput? value, string name = TweakConfigConstants.NameDefault)\n        => list.Process(value, name, TweakConfigConstants.StepBefore);\n\n    internal static ITweakData<TInput> Process<TInput>(this IList<TweakConfig> list, TInput? value, string? name, string step)\n    {\n        // Find all relevant tweaks for this step\n        var tweaks = list.GetTweaksByStep(step)\n            .Select(t => t as TweakConfig<Func<ITweakData<TInput>, int, ITweakData<TInput>>>)\n            .Where(t => t != null)\n            .Select((tweak, id) => new { tweak, id })\n            .ToList();\n\n        ITweakData<TInput> start = new TweakData<TInput>(value, name, step, 0);\n        return tweaks.Aggregate(start, (current, tweak) =>\n        {\n            try\n            {\n                return tweak.tweak!.Tweak(current, tweak.id);\n            }\n            catch (Exception e)\n            {\n                var exMore = new Exception($\"Error in tweak #{tweak.id} '{tweak.tweak!.NameId}' at step '{tweak.tweak.Step}' for target '{tweak.tweak.Target}'\", e);\n                throw exMore;\n            }\n        });\n    }\n\n    #endregion\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Tweaks.Sys/TweakConfigWithFunction.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks.Sys;\ninternal static class TweakConfigWithFunction\n{\n    internal static TweakConfig<Func<ITweakData<TInput>, int, ITweakData<TInput>>>\n        CreateTweak<TInput>(Func<ITweakData<TInput>, TInput> changeFunc, string? nameId = null, string? step = null, string? target = null)\n        => new(nameId ?? TweakConfigConstants.NameDefault)\n        {\n            Step = step ?? TweakConfigConstants.StepBefore,\n            Tweak = (v, index) => new TweakData<TInput>(v, changeFunc(v), index),\n            Target = target ?? TweakConfig.TargetDefault,\n        };\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Tweaks.Sys/TweakData.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks.Sys;\n\n/// <summary>\n/// WIP 16.08 Helper to let a tweak operation modify a value\n/// </summary>\n/// <typeparam name=\"TValue\"></typeparam>\n[PrivateApi(\"WIP v17\")]\ninternal record TweakData<TValue>: ITweakData<TValue>\n{\n    internal TweakData(TValue? initial, string? name, string step, int stepIndex)\n    {\n        Name = name;\n        Step = step;\n        Value = initial;\n        StepIndex = stepIndex;\n    }\n\n    internal TweakData(ITweakData<TValue> original, TValue value, int stepIndex)\n    {\n        var otw = original as TweakData<TValue>;\n        Name = otw?.Name;\n        Step = otw?.Step;\n        Value = value;\n        StepIndex = stepIndex;\n    }\n\n    /// <summary>\n    /// Name of the value which will be modified, like `FirstName`\n    /// </summary>\n    public string? Name { get; init; }\n\n    /// <summary>\n    /// Step of the tweak, like a workflow step. like `before`\n    /// </summary>\n    public string? Step { get; init; }\n\n    public int StepIndex { get; init; }\n\n    /// <inheritdoc />\n    public TValue? Value { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/Tweaks.Sys/TweakInput.cs",
    "content": "﻿namespace ToSic.Sxc.Services.Tweaks.Sys;\n\ninternal class TweakInput<TInput>\n    : ITweakInput<TInput>\n{\n    public List<TweakConfig> Tweaks { get; init; } = [];\n\n    [PublicApi]\n    public ITweakInput<TInput> Input(TInput replace, NoParamOrder npo = default)\n        => CloneWith(_ => replace);\n\n    [PublicApi]\n    public ITweakInput<TInput> Input(Func<TInput> func, NoParamOrder npo = default)\n        => CloneWith(_ => func());\n\n    [PublicApi]\n    public ITweakInput<TInput> Input(Func<TInput, TInput> func, NoParamOrder npo = default)\n        => CloneWith(tv => func(tv.Value!));\n\n    /// <summary>\n    /// Create new TweakInput with added tweak\n    /// </summary>\n    /// <returns></returns>\n    internal TweakInput<TInput> CloneWith(Func<ITweakData<TInput>, TInput> changeFunc, string? nameId = default, string? step = default, string? target = default)\n        => new()\n        {\n            // Create new tweak config to add\n            Tweaks = Tweaks.CloneAndAddNonNull(TweakConfigWithFunction.CreateTweak(changeFunc, nameId, step, target))\n        };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/User/IUserService.cs",
    "content": "﻿using ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Services;\n\n/// <summary>\n/// Service on [`Kit.User`](xref:ToSic.Sxc.Services.ServiceKit16.User) to get users and roles of the platform.\n/// </summary>\n/// <remarks>\n/// History: Released in 19.02 after being internal since 15.03.\n/// </remarks>\n[PublicApi]\npublic interface IUserService: INeedsExecutionContext\n{\n    /// <summary>\n    /// Get current user.\n    /// </summary>\n    /// <returns>\n    /// The current user or a default anonymous user if not logged in.\n    /// </returns>\n    /// <remarks>\n    /// New v20\n    /// </remarks>\n    public IUserModel GetCurrentUser();\n\n\n    /// <summary>\n    /// Get a user by id.\n    /// </summary>\n    /// <param name=\"id\">the user id</param>\n    /// <returns>\n    /// If found, a user model containing the user specs.\n    /// If not found, a user model containing the unknown user specs.\n    /// </returns>\n    IUserModel GetUser(int id);\n\n    /// <summary>\n    /// Get a user by nameId.\n    /// </summary>\n    /// <param name=\"nameId\">The nameID which is the identity token like `dnn:42`.</param>\n    /// <returns>\n    /// If found, a user model containing the user specs.\n    /// If not found, a user model containing the unknown user specs.\n    /// </returns>\n    IUserModel GetUser(string nameId);\n\n    /// <summary>\n    /// Get all users.\n    /// </summary>\n    /// <returns></returns>\n    IEnumerable<IUserModel> GetUsers();\n\n    /// <summary>\n    /// Get all user roles.\n    /// </summary>\n    /// <returns></returns>\n    IEnumerable<IUserRoleModel> GetRoles();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Services/User/Sys/UserService.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.DataSources;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sys.Utils;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Services.User.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class UserService(LazySvc<IContextOfSite> context, LazySvc<IUsersProvider> usersSvc, LazySvc<IUserRolesProvider> rolesSvc)\n    : ServiceWithContext($\"{SxcLogName}.UsrSrv\", connect: [context, usersSvc]), IUserService\n{\n    #region GetCurrentUser\n\n    public IUserModel GetCurrentUser()\n    {\n        var l = Log.Fn<IUserModel>();\n        var user = context.Value.User;\n        if (user == null! /* paranoid */ || user.IsAnonymous)\n            return l.Return(UserConstants.AnonymousUser, \"no user/anonymous\");\n\n        var model = GetUser(user.Id);\n        return l.Return(model, $\"got user {model.Id}\");\n    }\n\n    #endregion\n\n    #region GetUser\n\n    // FYI: PublicApi\n    public IUserModel GetUser(string nameId)\n    {\n        var l = Log.Fn<IUserModel>($\"token:{nameId}\");\n\n        var userId = UserId(nameId);\n\n        return userId.SpecialUser != null\n            ? l.Return(userId.SpecialUser, \"special user\")\n            : l.Return(GetUser(userId.UserId));\n    }\n\n    // FYI: PublicApi\n    public IUserModel GetUser(int userId) \n    {\n        var l = Log.Fn<IUserModel>($\"id:{userId}\");\n\n        var unknown = UserConstants.UnknownUser;\n        var anon = UserConstants.AnonymousUser;\n        if (userId == anon.Id)\n            return l.Return(anon, \"anonymous\");\n\n        if (userId == unknown.Id)\n            return l.Return(unknown, \"unknown\");\n\n        var userDto = usersSvc.Value.GetUser(userId, context.Value.Site.Id);\n\n        return userDto != null\n            ? l.ReturnAsOk(userDto)\n            : l.Return(unknown, \"err\");\n    }\n\n    /// <summary>\n    /// Helper method to parse UserID from user identity token.\n    /// </summary>\n    /// <param name=\"identityToken\"></param>\n    /// <returns></returns>\n    private (IUserModel? SpecialUser, int UserId) UserId(string identityToken) \n    {\n        var l = Log.Fn<(IUserModel?, int)>($\"token:{identityToken}\");\n\n        var unknown = UserConstants.UnknownUser;\n        var anon = UserConstants.AnonymousUser;\n        if (string.IsNullOrWhiteSpace(identityToken))\n            return l.Return((unknown, unknown.Id), \"empty identity token\");\n\n        if (identityToken.EqualsInsensitive(SxcUserConstants.Anonymous))\n            return l.Return((anon, anon.Id), \"ok (anonymous)\");\n\n        var prefix = usersSvc.Value.PlatformIdentityTokenPrefix;\n        if (identityToken.StartsWith(prefix, InvariantCultureIgnoreCase))\n            identityToken = identityToken.Substring(prefix.Length);\n\n        return int.TryParse(identityToken, out var userId)\n            ? l.Return((null, userId), $\"ok (u:{userId})\")\n            : l.Return((unknown, unknown.Id), \"err\");\n    }\n\n    #endregion\n\n    #region Get Users\n\n    // FYI: PublicApi\n    public IEnumerable<IUserModel> GetUsers()\n        => usersSvc.Value.GetUsers(new());\n\n    // FYI: PublicApi\n    public IEnumerable<IUserRoleModel> GetRoles()\n        => rolesSvc.Value.GetRoles();\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/StartupSxcServices.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Sxc.Render.Sys.ModuleHtml;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Cache;\nusing ToSic.Sxc.Services.Cache.Sys;\nusing ToSic.Sxc.Services.Cms.Sys;\nusing ToSic.Sxc.Services.Data.Sys;\nusing ToSic.Sxc.Services.HttpCtx;\nusing ToSic.Sxc.Services.Link.Sys;\nusing ToSic.Sxc.Services.Mail.Sys;\nusing ToSic.Sxc.Services.OutputCache;\nusing ToSic.Sxc.Services.Page.Sys;\nusing ToSic.Sxc.Services.PageShield;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Services.Sys.Cms;\nusing ToSic.Sxc.Services.Sys.ConvertService;\nusing ToSic.Sxc.Services.Templates;\nusing ToSic.Sxc.Services.TurnOn.Sys;\nusing ToSic.Sxc.Services.User.Sys;\nusing ToSic.Sxc.Web;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcServices\n{\n    public static IServiceCollection AddSxcServices(this IServiceCollection services)\n    {\n        // new in v12.02 - PageService & Page Features\n        services.TryAddTransient<Services.IPageService, PageService>();  // must be unique per module where it's used\n\n        // WIP 12.05 - json converter\n        services.TryAddTransient<IJsonService, JsonService>();\n        services.TryAddTransient<ConvertValueService>();\n        services.TryAddTransient<ConvertForCodeService>();\n        services.TryAddTransient<IConvertService, ConvertService>();\n        services.TryAddTransient<IConvertService16, ConvertService16>();\n\n        // New 12.05: SecureData\n        services.TryAddTransient<ISecureDataService, SecureDataService>();\n\n        // 13 - ToolbarService & IFeaturesService\n        services.TryAddTransient<IToolbarService, ToolbarService>();    // New 13.00\n        services.TryAddTransient<IFeaturesService, FeaturesService>();  // New 13.01\n\n        // V15\n        services.TryAddScoped<IModuleHtmlService, ModuleHtmlService>(); // Must be scoped & shared on the module\n        services.TryAddTransient<ITurnOnService, TurnOnService>();\n        services.TryAddTransient<ICmsService, CmsService>();\n        services.TryAddTransient<CmsServiceStringWysiwyg>();\n        services.TryAddTransient<CmsServiceImageExtractor>();\n        services.TryAddTransient<IDataService, DataService>();\n\n        // 19.03.03 - CmsService improving SoC\n        services.TryAddTransient<HtmlImgToPictureHelper>();\n        services.TryAddTransient<HtmlInnerContentHelper>();\n        services.TryAddTransient<IModuleOutputCacheService, ModuleOutputCacheService>();    // WIP v19.03.03, not official ATM\n        services.TryAddTransient<ModuleOutputCacheService>();                         // WIP v19.03.03, not official ATM\n        services.TryAddTransient<IOutputCacheManagementService, OutputCacheManagementService>(); // v21.06.00\n\n        // Kits v14 - v16\n        services.TryAddTransient<ServiceKit>();\n        services.TryAddTransient<ServiceKit14>();\n        services.TryAddTransient<ServiceKit16>();\n\n        // Lookup Service - WIP v17\n        services.TryAddTransient<ITemplateService, TemplateService>();\n\n        // Cache Service - WIP v17\n        services.TryAddTransient<ICacheService, CacheService>();\n        services.TryAddTransient<INamedCacheDependencyService, NamedCacheDependencyService>();\n\n        // v17.01\n        services.TryAddTransient<IUserService, UserService>();\n\n        services.TryAddTransient<IKeyService, KeyService>();\n\n        services.AddSxcServicesFallbacks();\n        services.ExternalConfig();\n\n        // v21.06\n        services.TryAddTransient<IPageShield, PageShield>();\n        services.TryAddTransient<IHttpContextService, HttpContextService>();\n\n        return services;\n    }\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static IServiceCollection ExternalConfig(this IServiceCollection services)\n    {\n        // new v15 - disabled v21\n        // services.TryAddTransient<GoogleMapsSettings>();\n        return services;\n    }\n\n\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static IServiceCollection AddSxcServicesFallbacks(this IServiceCollection services)\n    {\n        // v12.05 - LinkServiceUnknown - for testing etc.\n        services.TryAddTransient<ILinkService, LinkServiceUnknown>();\n\n        // v12.05\n        services.TryAddTransient<ISystemLogService, SystemLogServiceUnknown>();\n\n        // v12.05\n        services.TryAddTransient<IMailService, MailServiceUnknown>();\n\n        return services;\n    }\n\n#pragma warning disable CS0612 // Type or member is obsolete\n#pragma warning disable CS0618 // Type or member is obsolete\n    public static IServiceCollection AddSxcServicesObsolete(this IServiceCollection services)\n    {\n        // Obsolete version, needed to keep old Apps working which used this\n        services.TryAddTransient<Web.IPageService, WebPageServiceObsolete>();\n        return services;\n    }\n#pragma warning restore CS0618 // Type or member is obsolete\n#pragma warning restore CS0618 // Type or member is obsolete\n\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Sys.ExecutionContext/IExCtxGetKit.cs",
    "content": "﻿using ToSic.Sxc.Services.Sys;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IExCtxGetKit\n{\n    TKit GetKit<TKit>() where TKit : ServiceKit;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Sys.ExecutionContext/IExCtxLookUpEngine.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sys.Engines;\n\nnamespace ToSic.Sxc.Sys.ExecutionContext;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IExCtxLookUpEngine\n{\n    ILookUpEngine LookUpForDataSources { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/ToSic.Sxc.Services.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Services</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Cms\\ToSic.Sxc.Cms.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Data\\ToSic.Sxc.Data.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Edit\\ToSic.Sxc.Edit.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Images\\ToSic.Sxc.Images.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n  </ItemGroup>\n\n  <!-- Include Connect.Koi -->\n  <ItemGroup>\n    <Reference Include=\"Connect.Koi\">\n      <HintPath>..\\..\\..\\Dependencies\\Koi\\netstandard2.0\\Connect.Koi.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/ToSic.Sxc.Services.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cconvert/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Ckits/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Csecuredata/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Ctoolbars/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Ctoolbarservice/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cuser/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cusers/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Web/IPageService.Obsolete.cs",
    "content": "﻿using ToSic.Razor.Blade;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Web;\n\n// Important: There is a critical bug in Razor that methods which an interface inherits\n// Will fail when called using dynamic parameters. \n// https://stackoverflow.com/questions/3071634/strange-behaviour-when-using-dynamic-types-as-method-parameters\n// Because of this,\n// - ToSic.Sxc.Web.IPageService.SetTitle(\"ok\") works\n// - ToSic.Sxc.Web.IPageService.SetTitle(dynEntity.Title) fails!!!\n// This is why each method on the underlying interface must be repeated here :(\n//\n// We suggest that we won't do this for new commands, but all commands that were in 12.08 must be repeated here\n// like Blog 06.00.01 which was still around early 2023 uses this, so it could also be used in Oqtane\n\n/// <summary>\n/// Old name for the IPageService, it's in use in some v12 App templates so we must keep it working.\n/// Will continue to work, but shouldn't be used. Please use <see cref=\"ToSic.Sxc.Services.IPageService\"/>  instead\n/// </summary>\n[PrivateApi]\n[Obsolete(\"Use ToSic.Sxc.Services.IPageService instead\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPageService // : ToSic.Sxc.Services.IPageService\n{\n    // This repeats the definition on the IPage Service\n    // For reasons we cannot explain, Razor sometimes otherwise complains\n    // that a GetService<ToSic.Sxc.Web.IPageService>()\n    // Doesn't contain this command\n    // We don't know why - once this is added here everything works\n    // So for now we just leave it in\n\n#pragma warning disable CS0108, CS0114\n    string SetBase(string? url = null);\n    string SetTitle(string value, string? placeholder = null);\n    string SetDescription(string value, string? placeholder = null);\n    string SetKeywords(string value, string? placeholder = null);\n    string SetHttpStatus(int statusCode, string? message = null);\n    string AddToHead(string tag);\n    string AddToHead(IHtmlTag tag);\n    string AddMeta(string name, string content);\n    string AddOpenGraph(string property, string content);\n    string AddJsonLd(string jsonString);\n    string AddJsonLd(object jsonObject);\n    string AddIcon(string path, NoParamOrder npo = default,\n        string rel = \"\", int size = 0, string? type = null);\n    string AddIconSet(string path, NoParamOrder npo = default,\n        object? favicon = null, IEnumerable<string>? rels = null, IEnumerable<int>? sizes = null);\n    string Activate(params string[] keys);\n#pragma warning restore CS0108, CS0114\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Services/Web/Web.PageServiceObsolete.cs",
    "content": "﻿using ToSic.Razor.Blade;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Web;\n\n/// <summary>\n/// This is the obsolete version of the PageService, which is needed to keep old Apps working which used this.\n/// The apps will get it using `var page = GetService{ToSic.Sxc.Web.IPageService}()` or similar.\n/// </summary>\n[Obsolete]\ninternal class WebPageServiceObsolete(Services.IPageService pageServiceImplementation)\n    : IPageService, INeedsExecutionContext\n{\n    /// <summary>\n    /// Forward execution context to the actual implementation.\n    /// \n    /// Fixes bug https://github.com/2sic/2sxc/issues/3424\n    /// </summary>\n    /// <param name=\"exCtx\"></param>\n    public void ConnectToRoot(IExecutionContext exCtx)\n    {\n        (pageServiceImplementation as INeedsExecutionContext)?.ConnectToRoot(exCtx);\n    }\n\n    public string SetBase(string? url = null)\n    {\n        return pageServiceImplementation.SetBase(url);\n    }\n\n    public string SetTitle(string value, string? placeholder = null)\n    {\n        return pageServiceImplementation.SetTitle(value, placeholder);\n    }\n\n    public string SetDescription(string value, string? placeholder = null)\n    {\n        return pageServiceImplementation.SetDescription(value, placeholder);\n    }\n\n    public string SetKeywords(string value, string? placeholder = null)\n    {\n        return pageServiceImplementation.SetKeywords(value, placeholder);\n    }\n\n    public string SetHttpStatus(int statusCode, string? message = null)\n    {\n        return pageServiceImplementation.SetHttpStatus(statusCode, message);\n    }\n\n    public string AddToHead(string tag)\n    {\n        return pageServiceImplementation.AddToHead(tag);\n    }\n\n    public string AddToHead(IHtmlTag tag)\n    {\n        return pageServiceImplementation.AddToHead(tag);\n    }\n\n    public string AddMeta(string name, string content)\n    {\n        return pageServiceImplementation.AddMeta(name, content);\n    }\n\n    public string AddOpenGraph(string property, string content)\n    {\n        return pageServiceImplementation.AddOpenGraph(property, content);\n    }\n\n    public string AddJsonLd(string jsonString)\n    {\n        return pageServiceImplementation.AddJsonLd(jsonString);\n    }\n\n    public string AddJsonLd(object jsonObject)\n    {\n        return pageServiceImplementation.AddJsonLd(jsonObject);\n    }\n\n    public string AddIcon(string path, NoParamOrder npo = default, string rel = \"\", int size = 0,\n        string? type = null)\n    {\n        return pageServiceImplementation.AddIcon(path, npo, rel, size, type);\n    }\n\n    public string AddIconSet(string path, NoParamOrder npo = default, object? favicon = null,\n        IEnumerable<string>? rels = null,\n        IEnumerable<int>? sizes = null)\n    {\n        return pageServiceImplementation.AddIconSet(path, npo, favicon, rels, sizes);\n    }\n\n    public string Activate(params string[] keys)\n    {\n        return pageServiceImplementation.Activate(keys) ?? \"\";\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.TemplateProject/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Lib.Coding;\nglobal using ToSic.Lib.Documentation;\nglobal using ToSic.Lib.Logging;\nglobal using static ToSic.Sxc.Internal.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.TemplateProject/SxcEditStartup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class SxcEditStartup\n{\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    public static IServiceCollection AddSxcEdit(this IServiceCollection services)\n    {\n        \n\n        return services;\n    }\n\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.TemplateProject/ToSic.Sxc.Edit.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\n  <PropertyGroup>\n    <TargetFrameworks>net472;net9.0;</TargetFrameworks>\n    <RootNamespace>ToSic.Sxc</RootNamespace>\n    <AssemblyName>ToSic.Sxc.Edit</AssemblyName>\n    <Deterministic>true</Deterministic>\n    <!--<FileAlignment>512</FileAlignment>-->\n    <NoWarn>7035;CS1591</NoWarn>\n    <Configurations>Debug;Release;DebugOqtane;DebugDnn</Configurations>\n    <AutoGenerateBindingRedirects>False</AutoGenerateBindingRedirects>\n    <!-- Don't generate assembly properties from this XML which should come from the core file, like version - these lines must be in sync in all ToSic.Eav.*.csproj files -->\n    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>\n    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>\n    <GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>\n    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>\n    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>\n    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>\n    <LangVersion>preview</LangVersion>\n    <!-- end: Don't generate... -->\n  </PropertyGroup>\n\n  <!--<PropertyGroup>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>-->\n\n  <!-- Import common files which change how the project compiles; AssemblyInfo from 2sxc; rest form Lib.Imports -->\n  <ItemGroup>\n    <Compile Include=\"..\\..\\Sxc\\ToSic.Sxc\\Properties\\SxcSharedAssemblyInfo.cs\" Link=\"Properties\\SxcSharedAssemblyInfo.cs\" />\n    <Compile Include=\"..\\..\\..\\..\\eav-server\\ToSic.Lib.Imports\\System.Runtime.CompilerServices.cs\" Link=\"Properties\\System.Runtime.CompilerServices.cs\" />\n    <Compile Include=\"..\\..\\..\\..\\eav-server\\ToSic.Lib.Imports\\HideInternalApisOnReleaseOnly.cs\" Link=\"Properties\\HideInternalApisOnReleaseOnly.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc\\ToSic.Sxc.csproj\" />\n  </ItemGroup>\n\n\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net472'\">\n    <!--<Reference Include=\"System.Runtime.Caching\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Net.Http.WebRequest\" />-->\n    <!--<Reference Include=\"System.Web\" />-->\n    <!--<Reference Include=\"System.Web.Http\">\n      <HintPath>..\\..\\..\\Dependencies\\System.Web\\System.Web.Http.dll</HintPath>\n      <SpecificVersion>False</SpecificVersion>\n      <Private>False</Private>\n    </Reference>-->\n    <!--<Reference Include=\"ToSic.Razor\">\n      <HintPath>..\\..\\..\\Dependencies\\RazorBlade\\Release\\net472\\ToSic.Razor.dll</HintPath>\n    </Reference>-->\n    <!--<Reference Include=\"Microsoft.CSharp\" />-->\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <!--<PackageReference Include=\"Microsoft.CodeAnalysis.Common\" Version=\"4.8.0\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Compilers\" Version=\"4.8.0\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp\" Version=\"4.8.0\" />\n    <PackageReference Include=\"System.Runtime.Caching\" Version=\"9.0.0\" />\n    <PackageReference Include=\"System.Runtime.Loader\" Version=\"4.3.0\" />\n    <PackageReference Include=\"Microsoft.CSharp\" Version=\"4.7.0\" />-->\n\n    <!--<Reference Include=\"ToSic.Razor\">\n      <HintPath>..\\..\\..\\Dependencies\\RazorBlade\\Release\\net6.0\\ToSic.Razor.dll</HintPath>\n    </Reference>-->\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ConfigurationTests/VerifyPatronsHelper.cs",
    "content": "﻿using ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Capabilities.Licenses;\n\nnamespace ToSic.Sxc.ConfigurationTests;\n\npublic class VerifyPatronsHelper(ILicenseService licenses, ISysFeaturesService features)\n{\n    /// <summary>\n    /// A specific amount of licenses should be enabled.\n    /// If the number changes, this test may need update.\n    /// </summary>\n    /// <param name=\"expected\"></param>\n    public void VerifyEnabledLicenses(int expected)\n        => Equal(expected, licenses.Enabled.Count);\n\n\n    public void VerifyPatronPerfectionistsActive(bool expected)\n    {\n        var result = licenses.IsEnabled(BuiltInLicenses.PatronPerfectionist);\n\n        // Our current test enables 6 packages, so the service should report so many active licenses\n        Equal(expected, result);//, \"Patron Perfectionist should be enabled?\");\n    }\n\n    public void VerifyImageFormats(bool expected)\n    {\n        var result = features.IsEnabled(SxcFeatures.ImageServiceMultiFormat);\n\n        // Our current test enables 6 packages, so the service should report so many active licenses\n        Equal(expected, result);//, \"Patron Perfectionist should be enabled\");\n    }\n    \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ConfigurationTests/VerifyScenarioNoPatronsPerfectionist.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.ConfigurationTests;\n\npublic class VerifyScenarioNoPatronsPerfectionist(VerifyPatronsHelper patronsHelper) : IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n    // Start the test with a platform-info that has a patron\n    public class Startup : StartupSxcWithDbBasic\n    {\n        public override void ConfigureServices(IServiceCollection services) =>\n            base.ConfigureServices(\n                services\n                    .AddTransient<VerifyPatronsHelper>()\n                    //.AddTransient<IPlatformInfo, TestPlatformNotPatron>()\n            );\n    }\n\n    // Our current test only has 3 auto-enabled packages, so the service should report so many active licenses\n    [Fact] public void VerifyPackageOk() =>\n        patronsHelper.VerifyEnabledLicenses(3 /* auto-enabled only */);\n\n    [Fact] public void VerifyPatronPerfectionistsActive() =>\n        patronsHelper.VerifyPatronPerfectionistsActive(false);\n\n    [Fact] public void VerifyImageFormats() =>\n        patronsHelper\n            .VerifyImageFormats(false);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ConfigurationTests/VerifyScenarioPatronsPerfectionist.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.ConfigurationTests;\n\npublic class VerifyScenarioPatronsPerfectionist(VerifyPatronsHelper patronsHelper)\n    : IClassFixture<DoFixtureStartup<ScenarioFullPatronsWithDb>>\n{\n    // Start the test with a platform-info that has a patron\n    public class Startup : StartupSxcWithDb\n    {\n        public override void ConfigureServices(IServiceCollection services)\n        {\n            // Services just for this test\n            services.AddTransient<VerifyPatronsHelper>();\n\n            // Tried to reduce the dependencies, but not successful\n            // appears the DB must somehow be loaded for this test to work, not sure why\n            //services\n            //    .AddFixtureHelpers() // Needed to get the paths etc. for all the config files\n            //    .AddSxcCoreNew() // Register all features which we'll test here\n            //    .AddAppStateFromFolder()\n            //    .AddEavCore() // For the loader and everything it needs\n            //    .AddLibFeatSys()\n            //    .AddLibCore()\n            //    .AddTransient<IPlatformInfo, TestPlatformPatronPerfectionist>();\n\n\n            base.ConfigureServices(services);\n        }\n    }\n\n    // Our current test enables 6 packages, so the service should report so many active licenses\n    [Fact] public void VerifyPackageOk() =>\n        patronsHelper.VerifyEnabledLicenses(17); // 17 as of v20\n\n    [Fact] public void VerifyPatronPerfectionistsActive() =>\n        patronsHelper.VerifyPatronPerfectionistsActive(true);\n\n    [Fact] public void VerifyImageFormats() =>\n        patronsHelper.VerifyImageFormats(true);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataForImageTests/ResizeRecipesData.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sxc.Images;\n\nnamespace ToSic.Sxc.DataForImageTests;\n\ninternal class ResizeRecipesData\n{\n    public const int W100 = 990;\n    public const int W75 = 700;\n    public const int W75ImgOnly777 = 777;\n    public const int W75CssUnknown = 678;\n    public const int W50 = 450;\n    public const int W25 = 200;\n\n    public const string CssNone = null;\n    public const string CssUnknown = \"unk\";\n    private static Dictionary<string, object> Attributes75MixIn = new()\n    {\n        { \"loading\", \"lazy\" },\n        { \"toReset\", \"parent\" }\n    };\n    private static Dictionary<string, object> Attributes75 = new()\n    {\n        { \"class\", \"img-fluid\" },\n        { \"test\", \"value\" },\n        { \"toReset\", null! } // null will reset the originally set attribute by the parent\n    };\n\n    public static AdvancedSettings TestRecipeSet() =>\n        new(new(recipes:\n        [\n            new(forFactor: \"1\", width: W100),\n            new(forFactor: \"3/4\", width: W75, attributes: Attributes75MixIn, recipes:\n            [\n                new(forTag: \"img\", width: W75CssUnknown, forCss: CssUnknown, attributes: Attributes75),\n                new(forTag: \"img\", width: W75ImgOnly777, attributes: Attributes75)\n            ]),\n            new(forFactor: \"1:2\", width: W50),\n            new(forFactor: \"0.25\", width: W25)\n        ]));\n\n    public static AdvancedSettings TestRecipeSetFromJson => AdvancedSettings.FromJson(JsonRecipe());\n\n    // ReSharper disable once FieldCanBeMadeReadOnly.Local\n    private static object JsonAttributes75MixIn = new { loading = \"lazy\", toReset = \"parent\" };\n    // ReSharper disable once FieldCanBeMadeReadOnly.Local\n    private static object JsonAttributes75 = new { @class = \"img-fluid\", test = \"value\", toReset = (string?)null };\n\n    private static string JsonRecipe()\n    {\n        var adv = new\n        {\n            recipe = new\n            {\n                recipes = new object[]\n                {\n                    new { forFactor = \"1\", width = W100 },\n                    new\n                    {\n                        forFactor = \"3/4\", width = W75, attributes = JsonAttributes75MixIn, recipes = new object[]\n                        {\n                            new { forTag = \"img\", width = W75CssUnknown, forCss = CssUnknown, attributes = JsonAttributes75 },\n                            new { forTag = \"img\", width = W75ImgOnly777, attributes = JsonAttributes75 }\n                        }\n                    },\n                    new { forFactor = \"1:2\", width = W50 },\n                    new { forFactor = \"0.25\", width = W25 }\n                }\n\n            }\n        };\n\n        return JsonSerializer.Serialize(adv, JsonOptions.UnsafeJsonWithoutEncodingHtml);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataSources/MockUserRolesProvider.cs",
    "content": "﻿using ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.DataSources;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Tests.DataSources;\n\n/// <summary>\n/// Mock a list of roles\n/// </summary>\npublic class MockUserRolesProvider() : ServiceBase(\"DS.MockRoles\"), IUserRolesProvider\n{\n    public IEnumerable<UserRoleModel> GetRoles()\n    {\n        var l = Log.Fn<IEnumerable<UserRoleModel>>();\n        const int siteId = 0;\n        l.A($\"Mock Portal Id {siteId}\");\n\n        var roles = new List<UserRoleModel>();\n        for (var i = 1; i <= 10; i++)\n        {\n            roles.Add(new()\n            {\n                Id = i,\n                Name = $\"[role_name_{i}]\",\n                Created = DateTime.Today,\n                Modified = DateTime.Now,\n            });\n        }\n\n        return l.Return(roles, $\"mock: {roles.Count}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataSources/MockUsersProvider.cs",
    "content": "﻿using ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Cms.Users.Sys;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.DataSources;\n\n/// <summary>\n/// Mock list of users\n/// </summary>\npublic class MockUsersProvider() : ServiceBase(\"DS.MockUsers\"), IUsersProvider\n{\n    public const int GenerateSuperUsers = 3;\n    public const int GenerateUsersWithRoles2And3AndOwn = 7;\n    public const int GenerateUsersWithRoles9And10 = 10;\n    public const int GenerateTotal = GenerateSuperUsers + GenerateUsersWithRoles2And3AndOwn + GenerateUsersWithRoles9And10;\n\n    public string PlatformIdentityTokenPrefix => throw new NotImplementedException();\n\n    public IUserModel GetUser(int userId, int siteId) => throw new NotImplementedException();\n\n    public IEnumerable<UserModel> GetUsers(UsersGetSpecs specs)\n    {\n        var l = Log.Fn<IEnumerable<UserModel>>();\n        var siteId = 0;\n        l.A($\"Portal Id {siteId}\");\n        var users = new List<UserModel>();\n\n        l.A($\"mock {GenerateSuperUsers} super users and admins with one role [1-3]\");\n        for (var i = 1; i <= GenerateSuperUsers; i++)\n        {\n            users.Add(new()\n            {\n                Id = i,\n                Guid = new($\"00000000-0000-0000-0000-{i:d12}\"),\n                NameId = $\"mock:{i}\",\n                Roles = [new UserRoleModel { Id = i, Name = $\"Role{i}\" }],\n                IsSystemAdmin = true,\n                IsSiteAdmin = true,\n                //IsDesigner = false,\n                IsAnonymous = false,\n                Created = DateTime.Today,\n                Modified = DateTime.Now,\n                //\n                Username = $\"superuser{i}\",\n                Email = $\"superuser{i}@email.com\",\n                Name = $\"DNSuperuser{i}\"\n            });\n        }\n\n\n        l.A($\"mock 7 normal users with 3 roles [ 2, 3, 4-10]\");\n        var start = GenerateSuperUsers + 1;\n        for (var i = start; i <= GenerateUsersWithRoles2And3AndOwn + start - 1; i++)\n        {\n            users.Add(new()\n            {\n                Id = i,\n                Guid = new($\"00000000-0000-0000-0000-{i:d12}\"),\n                NameId = $\"mock:{i}\",\n                Roles =\n                [\n                    new UserRoleModel { Id = 2, Name = \"Role2\" },\n                    new UserRoleModel { Id = 3, Name = \"Role3\" },\n                    new UserRoleModel { Id = i, Name = $\"Role{i}\" }\n                ],\n                IsSystemAdmin = false,\n                IsSiteAdmin = false,\n                //IsDesigner = false,\n                IsAnonymous = false,\n                Created = DateTime.Today,\n                Modified = DateTime.Now,\n                //\n                Username = $\"username{i}\",\n                Email = $\"username{i}@email.com\",\n                Name = $\"Displayname{i}\"\n            });\n        }\n\n        l.A($\"mock 10 normal users with 2 roles [9, 10]\");\n        start = GenerateUsersWithRoles2And3AndOwn + start;\n        for (var i = start; i <= GenerateUsersWithRoles9And10 + start -1; i++)\n        {\n            users.Add(new()\n            {\n                Id = i,\n                Guid = new($\"00000000-0000-0000-0000-{i:d12}\"),\n                NameId = $\"mock:{i}\",\n                Roles =\n                [\n                    new UserRoleModel { Id = 9, Name = \"Role9\" },\n                    new UserRoleModel { Id = 10, Name = \"Role10\" }\n                ],\n                IsSystemAdmin = false,\n                IsSiteAdmin = false,\n                //IsDesigner = false,\n                IsAnonymous = false,\n                Created = DateTime.Today,\n                Modified = DateTime.Now,\n                //\n                Username = $\"username{i}\",\n                Email = $\"username{i}@email.com\",\n                Name = $\"Displayname{i}\"\n            });\n        }\n\n        return l.Return(users, $\"mock: {users.Count}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataSources/RolesDataSourceTests.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp;\nusing ToSic.Sxc.DataSources;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Tests.DataSources;\n\npublic class RolesDataSourceTests(DataSourcesTstBuilder dsSvc, LookUpTestData lookUp) : IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n    public class Startup: StartupSxcWithDb\n    {\n        public override void ConfigureServices(IServiceCollection services) => \n            base.ConfigureServices(services.AddTransient<IUserRolesProvider, MockUserRolesProvider>());\n    }\n\n    [Fact]\n    public void RolesDefault()\n    {\n        var rolesDataSource = GenerateRolesDataSourceDataSource();\n        Equal(10, rolesDataSource.List.ToList().Count);\n    }\n\n    [Theory]\n    [InlineData(\"\", 10)]\n    [InlineData(\"not-a-integer,-1\", 0)]\n    [InlineData(\"1\", 1)]\n    [InlineData(\"2,3\", 2)]\n    [InlineData(\"a,b,c,-2,-1,4,4,5,6,4\", 3)]\n    public void RolesWithIncludeFilter(string includeRolesFilter, int expected)\n    {\n        var rolesDataSource = GenerateRolesDataSourceDataSource(new\n        {\n            RoleIds = includeRolesFilter\n        });\n        //rolesDataSource.RoleIds = includeRolesFilter;\n        Equal(expected, rolesDataSource.List.ToList().Count);\n    }\n\n    [Theory]\n    [InlineData(\"\", 10)]\n    [InlineData(\"not-a-integer,-1\", 10)]\n    [InlineData(\"1\", 9)]\n    [InlineData(\"2,3\", 8)]\n    [InlineData(\"a,b,c,-2,-1,4,4,5,6,4\", 7)]\n    public void RolesWithExcludeFilter(string excludeRolesFilter, int expected)\n    {\n        var rolesDataSource = GenerateRolesDataSourceDataSource(new\n        {\n            ExcludeRoleIds = excludeRolesFilter\n        });\n        //rolesDataSource.ExcludeRoleIds = excludeRolesFilter;\n        Equal(expected, rolesDataSource.List.ToList().Count);\n    }\n\n    [Theory]\n    [InlineData(\"\", \"\", 10)]\n    [InlineData(\"not-a-integer,-1\", \"not-a-integer,-1\", 0)]\n    [InlineData(\"3,4,5\", \"1,2,3\", 2)]\n    public void RolesWithIncludeExcludeFilter(string includeRolesFilter, string excludeRolesFilter, int expected)\n    {\n        var rolesDataSource = GenerateRolesDataSourceDataSource(new\n        {\n            RoleIds = includeRolesFilter,\n            ExcludeRoleIds = excludeRolesFilter\n        });\n        //rolesDataSource.RoleIds = includeRolesFilter;\n        //rolesDataSource.ExcludeRoleIds = excludeRolesFilter;\n        Equal(expected, rolesDataSource.List.ToList().Count);\n    }\n\n    private UserRoles GenerateRolesDataSourceDataSource(object? options = default) \n        => dsSvc.CreateDataSourceNew<UserRoles>(new DataSourceOptionConverter()\n            .Create(new DataSourceOptions\n            {\n                AppIdentityOrReader = new AppIdentity(0, 0),\n                LookUp = lookUp.AppSetAndRes()\n            }, options));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataSources/UsersDataSourceTests.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.LookUp;\nusing ToSic.Sxc.Cms.Users.Sys;\n\nnamespace ToSic.Sxc.DataSources;\n\n// Note: most of these tests are useless ATM\n// Reason is that previously the filtering for superusers etc. happened in the UserDataSource\n// But it was then moved to a provider model.\n// But it doesn't make sense to have a mock provider with these filters, and test for that,\n// since that code would never be used in production.\n// So for now, most of the tests are disabled\n//\n// In the future, we should find a way to system-test DNN DBs with real data, to make sure the filters work\n\npublic class UsersDataSourceTests(DataSourcesTstBuilder DsSvc, LookUpTestData lookUpTestData) : IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n    public class Startup : StartupSxcWithDb\n    {\n        public override void ConfigureServices(IServiceCollection services) =>\n            base.ConfigureServices(services.AddTransient<IUsersProvider, MockUsersProvider>());\n    }\n\n    [Fact]\n    public void UsersDefault()\n    {\n        var usersDataSource = GenerateUsersDataSource();\n        Equal(MockUsersProvider.GenerateTotal, usersDataSource.List.ToList().Count);\n    }\n\n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"\", 17)]\n    [InlineData(\"not-a-integer, -1\", 17)]\n    [InlineData(\"1\", 0)]\n    [InlineData(\"1,2,3,4,5,6,7,8,9,10\", 7)]\n    [InlineData(\"a,b,c,-2,-1,4,4,5,6,4\", 3)]\n    public void UsersWithIncludeUserIdsFilter(string includeUsersFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            UserIds = includeUsersFilter,\n        });\n        //usersDataSource.UserIds = includeUsersFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"\", 17)]\n    [InlineData(\"not-a-guid, 00000000-0000-0000-0000-000000000000\", 17)]\n    [InlineData(\"00000000-0000-0000-0000-000000000005\", 1)]\n    [InlineData(\"00000000-0000-0000-0000-000000000006,00000000-0000-0000-0000-000000000007\", 2)]\n    [InlineData(\"a,b,c,10,1,00000000-0000-0000-0000-000000000004,00000000-0000-0000-0000-000000000004,00000000-0000-0000-0000-000000000005,00000000-0000-0000-0000-000000000006,00000000-0000-0000-0000-000000000004\", 4)]\n    public void UsersWithIncludeUserGuidsFilter(string includeUsersFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            UserIds = includeUsersFilter,\n        });\n        //usersDataSource.UserIds = includeUsersFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    \n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"\", 17)]\n    [InlineData(\"not-a-integer,-1\", 17)]\n    [InlineData(\"10\", 16)]\n    [InlineData(\"2,3,4,5\", 15)]\n    [InlineData(\"a,b,c,-2,-1,4,4,5,6,4\", 14)]\n    public void UsersWithExcludeUserIdsFilter(string excludeUsersFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            ExcludeUserIds = excludeUsersFilter,\n        });\n        //usersDataSource.ExcludeUserIds = excludeUsersFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    \n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"\", 17)]\n    [InlineData(\"not-a-guid, 00000000-0000-0000-0000-000000000000\", 17)]\n    [InlineData(\"00000000-0000-0000-0000-000000000009\", 16)]\n    [InlineData(\"00000000-0000-0000-0000-000000000003,00000000-0000-0000-0000-000000000004\", 16)]\n    [InlineData(\"a,b,c,-2,-1,00000000-0000-0000-0000-000000000004,00000000-0000-0000-0000-000000000004,00000000-0000-0000-0000-000000000005,00000000-0000-0000-0000-000000000006,00000000-0000-0000-0000-000000000004\", 14)]\n    public void UsersWithExcludeUserGuidsFilter(string excludeUsersFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            ExcludeUserIds = excludeUsersFilter,\n        });\n        //usersDataSource.ExcludeUserIds = excludeUsersFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    \n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"not-a-guid, 00000000-0000-0000-0000-000000000000\", \"not-a-integer,-1\", 17)]\n    [InlineData(\"3,4,5\", \"00000000-0000-0000-0000-000000000001, 00000000-0000-0000-0000-000000000003, 00000000-0000-0000-0000-000000000004\", 1)]\n    [InlineData(\"00000000-0000-0000-0000-000000000007, 00000000-0000-0000-0000-000000000008,00000000-0000-0000-0000-000000000009\", \"7\", 2)]\n    public void UsersWithIncludeExcludeUsersFilter(string includeUsersFilter, string excludeUsersFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            UserIds = includeUsersFilter,\n            ExcludeUsersFilter = excludeUsersFilter\n        });\n        //usersDataSource.UserIds = includeUsersFilter;\n        //usersDataSource.ExcludeUserIds = excludeUsersFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    \n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"\", 17)]\n    [InlineData(\"not-a-integer,-1,3\", 7)]\n    [InlineData(\"9\", 11)]\n    [InlineData(\"1,2\", 7)]\n    [InlineData(\"a,b,c,-2,-1,4,4,5,6,4\", 3)]\n    public void UsersWithIncludeRolesFilter(string includeRolesFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            RoleIds = includeRolesFilter\n        });\n        //usersDataSource.RoleIds = includeRolesFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    \n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"\", 17)]\n    [InlineData(\"not-a-integer,-1,2\", 10)]\n    [InlineData(\"9\", 6)]\n    [InlineData(\"3,10\", 0)]\n    [InlineData(\"a,b,c,-2,-1,4,4,5,6,4\", 14)]\n    public void UsersWithExcludeRolesFilter(string excludeRolesFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            ExcludeRoleIds = excludeRolesFilter,\n        });\n        //usersDataSource.ExcludeRoleIds = excludeRolesFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    \n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"2,10\", \"3\", 10)]\n    public void UsersWithIncludeExcludeRolesFilter(string includeRolesFilter, string excludeRolesFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            RoleIds = includeRolesFilter,\n            ExcludeRoleIds = excludeRolesFilter\n        });\n        //usersDataSource.RoleIds = includeRolesFilter;\n        //usersDataSource.ExcludeRoleIds = excludeRolesFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    \n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"\", 17)]\n    [InlineData(\"not-a-bool\", 17)]\n    [InlineData(\"true\", 20)]\n    [InlineData(\"false\", 17)]\n    [InlineData(\"TRue\", 20)]\n    [InlineData(\"   false   \", 17)]\n    [InlineData(\"1\", 17)]\n    [InlineData(\"0\", 17)]\n    [InlineData(\"-1\", 17)]\n    [InlineData(\"-100\", 17)]\n    [InlineData(\"yes\", 17)]\n    [InlineData(\"no\", 17)]\n    [InlineData(\"on\", 17)]\n    [InlineData(\"off\", 17)]\n    public void UsersWithSuperUserFilter(string superUserFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            IncludeSystemAdmins = superUserFilter\n        });\n        //usersDataSource.IncludeSystemAdmins = superUserFilter;\n        //usersDataSource.Configuration.Values[nameof(usersDataSource.IncludeSystemAdmins)] = superUserFilter;\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    \n    [Theory(Skip = \"not in use ATM because of changes in the mechanims\")]\n    [InlineData(\"1,2,3,4,5,6,7,8,9,10\", \"00000000-0000-0000-0000-000000000002, 00000000-0000-0000-0000-000000000003\", \"2\", \"9\", true, 6)]\n    // TODO: this test doesn't seem to do much different than the first?\n    [InlineData(\"1,2,3,4,5,6,7,8,9,10\", \"00000000-0000-0000-0000-000000000002, 00000000-0000-0000-0000-000000000003\", \"1,2\", \"9\", false, 6)]\n    public void UsersWithAllFilters(string includeUsersFilter, string excludeUsersFilter, string includeRolesFilter, string excludeRolesFilter, bool superUserFilter, int expected)\n    {\n        var usersDataSource = GenerateUsersDataSource(new\n        {\n            UserIds = includeUsersFilter,\n            ExcludeUserIds = excludeUsersFilter,\n            RoleIds = includeRolesFilter,\n            ExcludeRoleIds = excludeRolesFilter,\n            IncludeSystemAdmins = superUserFilter.ToString(),\n        });\n        //usersDataSource.UserIds = includeUsersFilter;\n        //usersDataSource.ExcludeUserIds = excludeUsersFilter;\n        //usersDataSource.RoleIds = includeRolesFilter;\n        //usersDataSource.ExcludeRoleIds = excludeRolesFilter;\n        //usersDataSource.IncludeSystemAdmins = superUserFilter.ToString();\n        Equal(expected, usersDataSource.List.ToList().Count);\n    }\n\n    private Users GenerateUsersDataSource(object? options = default)\n        => DsSvc.CreateDataSourceNew<Users>(new DataSourceOptionConverter()\n            .Create(new DataSourceOptions\n            {\n                AppIdentityOrReader = new AppIdentity(0, 0),\n                LookUp = lookUpTestData.AppSetAndRes(),\n            }, options));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/CodeDataConverterTestAccessors.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.DataTests;\n\ninternal static class CodeDataConverterTestAccessors\n{\n    public static ITypedItem? AsItemTac(this ICodeDataFactory cdf, object data, NoParamOrder npo = default, bool? required = default, ITypedItem? fallback = default, bool? propsRequired = default, bool? mock = default)\n        => cdf.AsItem(data, new() { ItemIsStrict = propsRequired ?? true, UseMock = mock == true, EntryPropIsRequired = required != false }, npo, fallback);\n\n    public static IEntity FakeEntityTac(this ICodeDataFactory cdf, int? appId)\n        => cdf.FakeEntity(appId ?? 0);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynAndTypedTestHelper.cs",
    "content": "﻿using ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.DynamicJacket;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing static System.Text.Json.JsonSerializer;\n\nnamespace ToSic.Sxc.DataTests;\n\n\npublic class DynAndTypedTestHelper(ICodeDataFactory factory, ICodeDataPoCoWrapperService wrapper, Generator<CodeJsonWrapper> codeJsonGenerator)\n{\n    #region Helper / Factories\n\n    public ICodeDataFactory Factory => factory;\n\n    public ICodeDataPoCoWrapperService Wrapper => wrapper;\n\n    public CodeJsonWrapper JsonWrapper => codeJsonGenerator.New();\n\n    #endregion\n\n    public object Json2Jacket(string jsonString) => Factory.Json2Jacket(jsonString);\n\n    public dynamic Json2Dyn(string jsonString) => Json2Jacket(jsonString);\n\n    public dynamic Obj2Json2Dyn(object obj) => Json2Jacket(JsonSerialize(obj));\n\n    public string JsonSerialize(object obj) => Serialize(obj, JsonOptions.UnsafeJsonWithoutEncodingHtml);\n\n    public (dynamic Dyn, string Json, T Original) DynJsonAndOriginal<T>(T original)\n    {\n        var json = JsonSerialize(original);\n        return (Json2Dyn(json), json, original);\n    }\n\n\n    public  object Obj2WrapObj(object data, bool wrapChildren = true, bool realObjectsToo = true)\n        => Wrapper.DynamicFromObject(data, WrapperSettings.Dyn(children: wrapChildren, realObjectsToo: realObjectsToo));\n\n    public dynamic Obj2WrapObjAsDyn(object data) => Obj2WrapObj(data);\n\n    public ITypedItem Obj2Item(object data, WrapperSettings? reWrap = null)\n        => Wrapper.TypedItemFromObject(data, reWrap ?? WrapperSettings.Typed(true, true));\n\n    #region To Json Wrappers\n\n    public ITyped Obj2Typed(object data, WrapperSettings? reWrap = null)\n        => Wrapper.TypedFromObject(data, reWrap ?? WrapperSettings.Typed(true, true));\n\n    public ITyped Obj2Json2TypedStrict(object data)\n        => Obj2Json2Typed(data, WrapperSettings.Typed(true, true, propsRequired: true));\n\n    public ITyped Obj2Json2TypedLoose(object data)\n        => Obj2Json2Typed(data, WrapperSettings.Typed(true, true, propsRequired: false));\n\n    private ITyped Obj2Json2Typed(object data, WrapperSettings settings) \n        => JsonWrapper.Setup(settings).JsonToTyped(JsonSerialize(data));\n\n\n    public IEnumerable<ITyped> Obj2Json2TypedListStrict(object data)\n        => Obj2Json2TypedList(data, WrapperSettings.Typed(true, true, propsRequired: true));\n\n    private IEnumerable<ITyped> Obj2Json2TypedList(object data, WrapperSettings settings) \n        => JsonWrapper.Setup(settings).JsonToTypedList(JsonSerialize(data));\n    #endregion\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynConverterTests/AsConverterAsItem.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.DataTests.DynConverterTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class AsConverterAsItem(ICodeDataFactory cdf)\n{\n    [Fact]\n    public void AsItemWithFakeOk()\n    {\n        var item = cdf.AsItemTac(cdf.FakeEntityTac(0), propsRequired: true);\n        NotNull(item);\n    }\n\n    [Fact]\n    public void AsItemWithAnonFail()\n    {\n        var data = new\n        {\n            Title = \"This is a title\",\n            Birthday = new DateTime(2012, 02, 07)\n        };\n\n        Throws<ArgumentException>(() =>\n        {\n            var item = cdf.AsItemTac(data, propsRequired: true);\n        });\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynConverterTests/AsConverterFakeTests.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\nusing ToSic.Sxc.Data.Sys.Factory;\n\nnamespace ToSic.Sxc.DataTests.DynConverterTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class AsConverterFakeTests(ICodeDataFactory cdf)\n{\n    [Fact]\n    public void EntityFake()\n    {\n        var fake = cdf.FakeEntityTac(0);\n        NotNull(fake);\n        Equal(DataConstants.DataFactoryDefaultEntityId, fake.EntityId);\n        Equal(DataConstants.DataFactoryDefaultEntityId, fake.RepositoryId);\n    }\n\n    [Fact]\n    public void ItemFake()\n    {\n        var fake = cdf.AsItem(cdf.FakeEntityTac(0), new() { ItemIsStrict = false });\n        NotNull(fake);\n        Null(fake.String(\"some-field\"));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynJson/Startup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.DataTests.DynJson;\n\npublic class Startup: StartupSxcCoreOnly\n{\n    public override void ConfigureServices(IServiceCollection services) =>\n        base.ConfigureServices(services.AddTransient<DynAndTypedTestHelper>());\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynJson/WrapAllGps.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynJson;\n\n\npublic class WrapAllGps(DynAndTypedTestHelper helper)\n{\n    public static double GpsDataLat = 43.508075;\n    public static double GpsDataLong = 16.4665157;\n    public static object GpsDataAnon = new { Lat = GpsDataLat, Long = GpsDataLong };\n    public dynamic GpsDataDyn => helper.Obj2Json2Dyn(GpsDataAnon);\n    public ITyped GpsDataJsonTyped => helper.Obj2Json2TypedStrict(GpsDataAnon);\n    public ITyped GpsDataObjTyped => helper.Obj2Typed(GpsDataAnon);\n\n    [Fact]\n    public void GpsDynProperties()\n    {\n        Equal<double>(GpsDataLat, GpsDataDyn.Lat);\n        Equal<double>(GpsDataLong, GpsDataDyn.Long);\n    }\n\n    [Fact] public void Gps_TypedJson() => GpsTypedProperties(GpsDataJsonTyped);\n    [Fact] public void Gps_TypedFromObject() => GpsTypedProperties(GpsDataObjTyped);\n\n    public void GpsTypedProperties(ITyped typed)\n    {\n        Equal<double>(GpsDataLat, typed.Double(\"Lat\"));\n        Equal<double>(GpsDataLong, typed.Double(\"Long\"));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynJson/WrapAllKeys.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynJson;\n\n\npublic class WrapAllKeys(DynAndTypedTestHelper helper)\n{\n    /// <summary>\n    /// Base object for many tests - as an anonymous object.\n    /// </summary>\n    public static readonly object TestDataAnonObject = new\n    {\n        TrueBoolType = true,\n        FalseBoolType = false,\n        TrueString = \"true\",\n        FalseString = \"false\",\n        TrueNumber = 1,\n        FalseNumber = 0,\n        TrueNumberBig = 27,\n        TrueNumberNegative = -1,    \n    };\n        \n    /// <summary>\n    /// Description of various properties and what they represent (or even if they don't exist)\n    /// </summary>\n    private static readonly List<PropInfo> BoolKeyTests =\n    [\n        new(\"TrueBoolType\", true, true, true),\n        new(\"TrueBoolTYPE\", true, true, true),\n        new(\"FalseBoolType\", true, true, false),\n        new(\"TrueString\", true, true, true),\n        new(\"FalseString\", true, true, false),\n        new(\"TrueNumber\", true, true, true),\n        new(\"FalseNumber\", true, true, false),\n        new(\"TrueNumberBig\", true, true, true),\n        new(\"TrueNumberNegative\", true, true, true),\n        new(\"Something\", false, note: \"key which doesn't exist\"),\n        new(\"Dummy\", false, note: \"key which doesn't exist\"),\n        new(\"Part1\", false, note: \"key which doesn't exist\"),\n        new(\"Dummy.SubDummy\", false, note: \"key which doesn't exist\"),\n        new(\"TrueString.SubDummy\", false, note: \"key which doesn't exist\")\n    ];\n\n    public static TheoryData<PropInfo> BoolKeysInfo => [..BoolKeyTests];\n\n    private ITyped BoolTestDataStrict => _boolTestDataStrict ??= helper.Obj2Json2TypedStrict(TestDataAnonObject);\n    private static ITyped? _boolTestDataStrict;\n    private ITyped BoolTestDataLoose => _boolTestDataLoose ??= helper.Obj2Json2TypedLoose(TestDataAnonObject);\n    private static ITyped? _boolTestDataLoose;\n\n        \n    [Theory]\n    [MemberData(nameof(BoolKeysInfo))]\n    public void JsonBoolPropertyKeys_Typed(PropInfo pti) => Equal(pti.Exists, BoolTestDataStrict.TestContainsKey(pti.Name));\n\n    public static TheoryData<PropInfo> BoolKeysExist => [..BoolKeyTests.Where(bk => bk.Exists)];\n\n    [Theory]\n    [MemberData(nameof(BoolKeysExist))]\n    public void JsonBoolPropertyKeys_Bool(PropInfo pti) =>\n        Equal((bool)pti.Value, BoolTestDataStrict.Bool(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(BoolKeysInfo))]\n    public void IsEmptyBoolData_Json(PropInfo info) =>\n        Equal(info.HasData, BoolTestDataStrict.IsNotEmpty(info.Name));//, info.Name);\n\n\n    #region Test Invalid Keys in different scenarios Typed, Loose, required: false, etc.\n\n    public static TheoryData<PropInfo> BoolInvalidKeys => [..BoolKeyTests.Where(bk => !bk.Exists)];\n        \n    [Theory]\n    [MemberData(nameof(BoolInvalidKeys))]\n    public void StrictExceptions_Typed_ShouldError(PropInfo pti) =>\n        Throws<ArgumentException>(() => (BoolTestDataStrict.Bool(pti.Name)));\n\n    [Theory]\n    [MemberData(nameof(BoolInvalidKeys))]\n    public void StrictExceptions_Loose_ShouldRetFalse(PropInfo pti)\n        => False(BoolTestDataLoose.Bool(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(BoolInvalidKeys))]\n    public void StrictExceptions_TypedReqFalse_ShouldRetFalse(PropInfo pti)\n        => False(BoolTestDataStrict.Bool(pti.Name, required: false));\n\n    [Theory]\n    [MemberData(nameof(BoolInvalidKeys))]\n    public void StrictExceptions_TypedReqFalseFallback_ShouldRetFallback(PropInfo pti)\n        => True(BoolTestDataStrict.Bool(pti.Name, required: false, fallback: true));\n\n    #endregion\n\n    #region Keys Data Deep\n\n    private static readonly object KeysDataDeepAnon = new\n    {\n        Key1 = \"hello\",\n        Key2 = \"goodbye\",\n        SubObject = new\n        {\n            SubTitle = \"hello\",\n            SubSub = new\n            {\n                SubSubTitle = \"hello sub-sub title\",\n            }\n        },\n        SubEmpty = new\n        {\n\n        }\n    };\n\n    /// <summary>\n    /// Description of various properties and what they represent (or even if they don't exist)\n    /// </summary>\n    public static List<PropInfo> KeysDataDeepProps =\n    [\n        new(\"Key1\", true, true, \"hello\"),\n        new(\"Key2\", true, true, \"goodbye\"),\n        new(\"Dummy\", false, note: \"key which doesn't exist\"),\n        new(\"SubObject\", true, true),\n        new(\"SubObject.SubTitle\", true, true, value: \"hello\"),\n        new(\"SubObject.SubSub\", true, true),\n        new(\"SubObject.SubSub.SubSubTitle\", true, true, \"hello sub-sub title\"),\n        new(\"SubObject.SubTitle.Dummy\", false),\n        new(\"SubObject.Dummy\", false),\n        new(\"SubObject.Dummy.Dummy\", false),\n        new(\"SubEmpty\", true, hasData: true)\n    ];\n        \n    private ITyped KeysDataObjJsonTyped => helper.Obj2Json2TypedStrict(KeysDataDeepAnon);\n\n    private ITyped KeysDataObjTyped => helper.Obj2Typed(KeysDataDeepAnon);\n\n    #endregion\n\n    #region Tests Data Deep\n\n    [Fact]\n    public void KeysCountAny() => True(KeysDataObjJsonTyped.TestKeys().Any());\n\n    [Fact]\n    public void KeysCount() => Equal(4, KeysDataObjJsonTyped.TestKeys().Count());\n\n    [Fact]\n    public void KeysCountOnlySpecific1() => Equal(1, KeysDataObjJsonTyped.TestKeys(only: [\"Key1\"]).Count());\n\n    [Fact]\n    public void KeysCountOnlySpecific2() => Equal(2, KeysDataObjJsonTyped.TestKeys(only: [\"Key1\", \"Key2\"]).Count());\n\n    [Fact]\n    public void KeysCountOnlySpecific1of2() => Single(KeysDataObjJsonTyped.TestKeys(only: [\"Key1\", \"KeyNonExisting\"]));\n\n    [Fact]\n    public void KeysCountOnlySpecific0() => Empty(KeysDataObjJsonTyped.TestKeys(only: [\"Nonexisting\"]));\n\n\n    public static TheoryData<PropInfo> KeysDataProps => [..KeysDataDeepProps];\n    public static TheoryData<PropInfo> KeysDataPropsExist => [..KeysDataDeepProps.Where(bk => bk.Exists)];\n\n    [Theory]\n    [MemberData(nameof(KeysDataPropsExist))]\n    public void KeysDataDeepOJT_GetNotNull(PropInfo pti) => NotNull(KeysDataObjJsonTyped.Get(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(KeysDataPropsExist))]\n    public void KeysDataDeepOT_GetNotNull(PropInfo pti) => NotNull(KeysDataObjTyped.Get(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(KeysDataProps))]\n    public void KeysDataDeepOJT_ContainsKey(PropInfo pti) => Equal(pti.Exists, KeysDataObjJsonTyped.ContainsKey(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(KeysDataProps))]\n    public void KeysDataDeepOT_ContainsKey(PropInfo pti) => Equal(pti.Exists, KeysDataObjTyped.ContainsKey(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(KeysDataProps))]\n    public void KeysDataDeepOJT_IsEmpty(PropInfo pti) => Equal(!pti.HasData, KeysDataObjJsonTyped.IsEmpty(pti.Name));\n        \n    [Theory]\n    [MemberData(nameof(KeysDataProps))]\n    public void KeysDataDeepOT_IsEmpty(PropInfo pti) => Equal(!pti.HasData, KeysDataObjTyped.IsEmpty(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(KeysDataProps))]\n    public void KeysDataDeepOJT_IsNotEmpty(PropInfo pti) => Equal(pti.HasData, KeysDataObjJsonTyped.IsNotEmpty(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(KeysDataProps))]\n    public void KeysDataDeepOT_IsNotEmpty(PropInfo pti) => Equal(pti.HasData, KeysDataObjTyped.IsNotEmpty(pti.Name));\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynJson/WrapAllSerialize.cs",
    "content": "﻿using ToSic.Sxc.DataTests.DynWrappers;\nusing static System.Text.Json.JsonSerializer;\n\nnamespace ToSic.Sxc.DataTests.DynJson;\n\n\npublic class WrapAllSerialize(DynAndTypedTestHelper helper)\n{\n    [Fact]\n    public void AnonToObjSerialize()\n    {\n        var data = WrapObjBasic.Data;\n        var anon = new { data.Name, data.Description, data.Founded, data.Birthday, data.Truthy };\n        var typed = helper.Obj2Typed(anon);\n        dynamic dynAnon = helper.Obj2WrapObj(anon, false, false);\n\n        var jsonTyped = Serialize(typed);\n        var jsonAnon = Serialize(anon);\n        var jsonDyn = Serialize(dynAnon);\n\n        Equal(jsonTyped, jsonDyn);\n        Equal(jsonTyped, jsonAnon);\n    }\n\n\n    [Fact]\n    public void AnonToJsonToWrapperSerialize()\n    {\n        var data = WrapObjBasic.Data;\n        var anon = new\n        {\n            data.Name,\n            data.Description,\n            data.Founded,\n            // Birthday not used in this test, because the initial default serializer\n            // will not use \"Z\" time, so it will be a bit different.\n            //data.Birthday, \n            data.Truthy,\n            subData = new { }, // empty sub object\n            subFilled = new\n            {\n                something = \"iJungleboy\",\n                number = 7,\n            }\n        };\n        var jsonAnon = Serialize(anon);\n\n\n        var typed = helper.Obj2Json2TypedStrict(anon);\n        var dynAnon = helper.Obj2Json2Dyn(anon);\n\n        var jsonTyped = Serialize(typed);\n        var jsonDyn = Serialize(dynAnon);\n\n        Equal(jsonAnon, jsonTyped);\n        Equal(jsonAnon, jsonDyn);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynJson/WrapJsonArray.cs",
    "content": "﻿using System.Collections;\nusing System.Text.Json.Nodes;\nusing ToSic.Sxc.Data.Sys.DynamicJacket;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.DataTests.DynJson;\n\n\npublic class WrapJsonArray(DynAndTypedTestHelper helper)\n{\n    private (dynamic Dyn, string Json, string[] Original) StringArrayPrepare() => helper.DynJsonAndOriginal(new[]\n    {\n        \"val1\",\n        \"val2\",\n        \"val3\"\n    });\n\n    [Fact]\n    public void StringArray_Dyn()\n    {\n        var (dyn, _, original) = StringArrayPrepare();\n        True(dyn.IsList);\n        Equal(original[0], dyn[0]);\n        Equal(original[1], dyn[1]);\n        Equal(original[2], dyn[2]);\n        NotEqual(original[0], original[1]);\n    }\n\n    [Fact]\n    public void StringArrayCount_Dyn()\n    {\n        var (dyn, _, original) = StringArrayPrepare();\n        Equal(original.Length, dyn.Count);\n    }\n\n    [Fact]\n    public void StringArrayIterate_Dyn()\n    {\n        var (dyn, _, _) = StringArrayPrepare();\n        foreach (var strItem in dyn) NotNull(strItem);\n    }\n\n    [Fact]\n    public void StringArrayNonExistingProperty_Dyn()\n    {\n        var test = StringArrayPrepare();\n        Null(test.Dyn.NonExistingProperty);\n    }\n\n    [Fact]\n    public void Test()\n    {\n        var anon = new[] { \"test\", \"test2\", \"test3\" };\n        var json = helper.JsonSerialize(anon);\n\n        var jsonNode = JsonNode.Parse(json);\n        var isArray = jsonNode is JsonArray;\n        True(isArray);\n        NotNull(jsonNode.AsArray());\n    }\n\n    public static IEnumerable<object[]> DetectJsonType => new List<object[]>\n    {\n        new object[] { true, false, new { something = \"hello\" } },\n        new object[] { true, false, new { } },\n        new object[] { true, true, new[] { \"hello\", \"there\" } },\n        new object[] { true, true, new[] { 1, 2, 3 } },\n        new object[] { false, false, \"just a string\" },\n        new object[] { false, false, 27 },\n    };\n\n    [Theory]\n    [MemberData(nameof(DetectJsonType))]\n    public void DetectJsonComplexOfObject(bool expComplex, bool expArray, object value, string? testName = default)\n    {\n        var json = helper.JsonSerialize(value);\n        var (isComplex, isArray) = JsonProcessingHelpers.AnalyzeJson(json);\n        Equal(expComplex, isComplex);//, testName + \":\" + value + \"; json: \" + json);\n        Equal(expArray, isArray);//, testName + \":\" + value + \"; json: \" + json);\n    }\n\n    [Fact]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void WrapArrayToStrictShouldFail() =>\n        Throws<ArgumentException>(() => helper.Obj2Json2TypedStrict(new[] { 1, 2, 3 }));\n\n    [Fact]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void WrapArrayValuesToStrictListShouldFail() =>\n        Throws<ArgumentException>(() => helper.Obj2Json2TypedListStrict(new[] { 1, 2, 3 }));\n\n    [Fact]\n    public void WrapArrayToStrictListShouldBeOk()\n    {\n        var list = helper.Obj2Json2TypedListStrict(new object[] { new { a = 7 }, new { b = 27 } });\n        NotNull(list);\n        Equal(2, list.Count());\n    }\n\n    [Fact]\n    public void ArrayPropertyShouldWork()\n    {\n        var anon = new\n        {\n            items = new[] { 14, 27, 33 }\n        };\n        var typed = helper.Obj2Json2TypedStrict(anon);\n        NotNull(typed);\n        var items = typed.Get(nameof(anon.items));\n        NotNull(items);\n        var itemList = items as IEnumerable;\n        NotNull(itemList);\n        Equal(3, itemList.Cast<object>().Count());\n        Equal(14, itemList.Cast<object>().FirstOrDefault());\n    }\n\n    [Fact]\n    public void TestJsonValueBehavior()\n    {\n        var anon = new { x = 27, y = 203.02003050 };\n        var json = JsonNode.Parse(helper.JsonSerialize(anon));\n        IsType<JsonObject>(json);\n        var xPropExists = json.AsObject().TryGetPropertyValue(nameof(anon.x), out var xProp);\n        True(xPropExists);\n\n        var asVal = xProp.AsValue();\n        IsAssignableFrom<JsonValue>(asVal);\n        var data = asVal.GetValue<int>();\n        IsType<int>(data);\n\n        var maybeInt = JsonProcessingHelpers.JsonValueGetContents(asVal);\n        IsType<int>(maybeInt);\n        Equal(27, maybeInt);\n\n        var yPropExists = json.AsObject().TryGetPropertyValue(nameof(anon.y), out var yProp);\n        asVal = yProp.AsValue();\n        var maybeDouble = JsonProcessingHelpers.JsonValueGetContents(asVal);\n        IsType<double>(maybeDouble);\n        IsNotType<int>(maybeDouble);\n        Equal(203.02003050, maybeDouble);\n    }\n\n\n    private (dynamic Dyn, string Json, string[][] Original) StringArray2dPrepare() => helper.DynJsonAndOriginal(new[]\n    {\n        new[] {\"0-0\", \"0-1\", \"0-2\"},\n        new[] {\"1-0\", \"1-1\"},\n        new[] {\"2-0\", \"2-1\", \"2-2\", \"2-3\"},\n    });\n\n    [Fact]\n    public void StringArray2D()\n    {\n        var test = StringArray2dPrepare();\n        Equal(test.Original[0][0], test.Dyn[0][0]);\n        Equal(test.Original[2][3], test.Dyn[2][3]);\n    }\n    [Fact]\n    public void StringArray2DNonExistingProperty()\n    {\n        var (dyn, _, _) = StringArray2dPrepare();\n        Null(dyn.NonExisting);\n        Null(dyn[0].NonExisting);\n    }\n\n    [Fact]\n    public void StringArray2DCount()\n    {\n        var test = StringArray2dPrepare();\n        Equal(test.Original[0].Length, test.Dyn[0].Count);\n    }\n\n    private class MiniObj\n    {\n        public string Name;\n        public int Age;\n    }\n\n    private (dynamic Dyn, string Json, MiniObj[] Original) ObjectArrayPrepare() => helper.DynJsonAndOriginal(new[]\n    {\n        new MiniObj { Name = \"T1\", Age = 11 },\n        new MiniObj { Name = \"t2\", Age = 22 },\n        new MiniObj { Name = \"TTT3\", Age = 3 }\n    });\n\n    [Fact]\n    public void ObjectArray()\n    {\n        var test = ObjectArrayPrepare();\n        Equal(test.Original[0].Name, (string)test.Dyn[0].Name);\n        NotEqual<object>(test.Original[0].Name, test.Dyn[0].Age);\n    }\n\n    [Fact]\n    public void ObjectArrayNonExistingProperties()\n    {\n        var test = ObjectArrayPrepare();\n        Null(test.Dyn.Something);\n        Null(test.Dyn[0].NonExisting);\n    }\n\n\n    [Fact]\n    public void MixedArrays2D()\n    {\n        var (dyn, json, original) = helper.DynJsonAndOriginal(new object[]\n        {\n            new string[] {\"a1\"},\n            new object[] { 1, \"b2\"},\n            new object[] { true, 2, \"c3\"}\n        });\n\n        var expectedType = typeof(DynamicJacketList);\n\n        True(dyn.IsList);\n\n        IsType(expectedType, dyn[2]);\n\n        Equal<string>(\"a1\", dyn[0][0]);\n        Equal<int>(1, dyn[1][0]);\n        True(dyn[2][0]);\n    }\n\n    [Fact(Skip = \"2023-08-23 2dm - This test can't work - json Arrays don't support keys; may need to re-write the test or delete\")]\n    public void Keys()\n    {\n        var anon = new[]\n        {\n            \"hello\",\n            \"goodbye\"\n        };\n        var typed = helper.Obj2Json2TypedStrict(anon);\n        True(typed.TestContainsKey(\"1\"));\n        False(typed.TestContainsKey(\"3\"));\n        True(typed.TestKeys().Any());\n        Equal(2, typed.TestKeys().Count());\n        Equal(1, typed.TestKeys(only: [\"1\"]).Count());\n        Equal(0, typed.TestKeys(only: [\"3\"]).Count());\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynJson/WrapJsonDeep.cs",
    "content": "﻿using ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.DynamicJacket;\nusing ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.DataTests.DynJson;\n\n\npublic class WrapJsonDeep(DynAndTypedTestHelper helper)\n{\n    private static object DeepData = new\n    {\n        TopLevelNumber = 27,\n        ObjectProperty = new\n        {\n            StringProperty = \"test\",\n            ObjectProperty = new\n            {\n                NumberProperty = 1,\n                ObjectProperty = new\n                {\n                    BoolProperty = true\n                }\n            }\n        },\n        Array = new object[]\n        {\n            new { name = \"zeroth\" },\n            new { Name = \"first\" },\n            new { Name = \"second\" }\n        }\n    };\n\n    private ITyped DataTyped => _dataTyped ??= helper.Obj2Json2TypedStrict(DeepData);\n    private ITyped _dataTyped;\n\n    [Fact]\n    public void DeepValueAndCasingWithDyn()\n    {\n        var dyn = helper.Obj2Json2Dyn(DeepData);\n        Equal<int>(27, dyn.TopLevelNumber);\n        Equal<int>(27, dyn.TopLevelNUMBER);\n        Equal<string>(\"test\", dyn.OBJECTPROPERTY.stringproperty);\n        Equal<int>(1, dyn.ObjectProperty.ObjectProperty.NumberProperty);\n        Equal<bool>(true, dyn.ObjectProperty.ObjectProperty.ObjectProperty.BoolProperty);\n    }\n\n    [Fact]\n    public void DeepValueAndCasingWithTyped()\n    {\n        Equal(27, DataTyped.Get(\"TopLevelNumber\"));\n        Equal<int>(27, DataTyped.Int(\"TopLevelNumber\"));\n        Equal(27, DataTyped.Get(\"TopLevelNUMBER\"));\n        Equal<int>(27, DataTyped.Int(\"TopLevelNUMBER\"));\n        Equal(\"test\", (DataTyped.Get(\"OBJECTPROPERTY\") as ITyped).Get(\"stringproperty\"));\n        Equal(1, DataTyped.Get(\"ObjectProperty.ObjectProperty.NumberProperty\"));\n        Equal<int>(1, DataTyped.Int(\"ObjectProperty.ObjectProperty.NumberProperty\"));\n        Equal<bool>(true, DataTyped.Bool(\"ObjectProperty.ObjectProperty.ObjectProperty.BoolProperty\"));\n    }\n\n    [Fact]\n    public void DeepObjectIsNotList()\n    {\n        var dyn = helper.Obj2Json2Dyn(DeepData);\n        False(dyn.IsList);\n    }\n\n    [Fact]\n    public void DeepTypeCheckDyn()\n    {\n        var dyn = helper.Obj2Json2Dyn(DeepData);\n        var expectedType = typeof(DynamicJacket);\n        IsType(expectedType, dyn.ObjectProperty);\n        IsType(expectedType, dyn.ObjectProperty.ObjectProperty);\n        IsType(expectedType, dyn.ObjectProperty.ObjectProperty.ObjectPROPERTY);\n        Null(dyn.ObjectProperty.ObjectProperty.ObjectIncorrect);\n    }\n\n    [Fact]\n    public void DeepTypeCheckTyped()\n    {\n        //var dyn = Obj2Json2Typed(DeepData);\n        var expectedType = typeof(WrapObjectTyped);\n        IsType(expectedType, DataTyped.Get(\"ObjectProperty\"));\n        Null(DataTyped.Get(\"ObjectPropertyNonExisting\", required: false));\n        IsType(expectedType, (DataTyped.Get(\"ObjectProperty\") as ITyped).Get(\"ObjectProperty\"));\n        IsType(expectedType, DataTyped.Get(\"ObjectProperty.ObjectProperty\"));\n        //IsType(dyn.ObjectProperty.ObjectProperty.ObjectPROPERTY, expectedType);\n        // TODO!\n        //Null(dyn.ObjectProperty.ObjectProperty.ObjectIncorrect);\n    }\n\n    [Fact]\n    public void UsePropertyIndexersAndCasing()\n    {\n        var dyn = helper.Obj2Json2Dyn(DeepData);\n        Equal<string>(\"test\", dyn[\"objectproperty\"][\"STRINGPROPERTY\"]);\n        // 2023-08-17 2dm disabled the two-property indexer\n        //Equal<string>(\"test\", test.Dyn[\"ObjectProperty\", true][\"StringProperty\", true]);\n    }\n\n    private const string ReSerializeExpected = @\"{\n  \"\"TopLevelNumber\"\": 27,\n  \"\"ObjectProperty\"\": {\n    \"\"StringProperty\"\": \"\"test\"\",\n    \"\"ObjectProperty\"\": {\n      \"\"NumberProperty\"\": 1,\n      \"\"ObjectProperty\"\": {\n        \"\"BoolProperty\"\": true\n      }\n    }\n  },\n  \"\"Array\"\": [\n    {\n      \"\"name\"\": \"\"zeroth\"\"\n    },\n    {\n      \"\"Name\"\": \"\"first\"\"\n    },\n    {\n      \"\"Name\"\": \"\"second\"\"\n    }\n  ]\n}\";\n\n    private const string ReSerializeObjectProperty = @\"{\n  \"\"StringProperty\"\": \"\"test\"\",\n  \"\"ObjectProperty\"\": {\n    \"\"NumberProperty\"\": 1,\n    \"\"ObjectProperty\"\": {\n      \"\"BoolProperty\"\": true\n    }\n  }\n}\";\n\n    [Fact]\n    public void ToStringAll_Dyn()\n    {\n        var dyn = helper.Obj2Json2Dyn(DeepData);\n        Equal(ReSerializeExpected, dyn.ToString());\n    }\n    [Fact]\n    public void ToStringAll_Typed()\n    {\n        var dyn = helper.Obj2Json2TypedStrict(DeepData);\n        Equal(ReSerializeExpected, dyn.ToString());\n    }\n\n    [Fact]\n    public void ToStringTopLevelNumber_Dyn()\n    {\n        var dyn = helper.Obj2Json2Dyn(DeepData);\n        Equal(\"27\", dyn.TopLevelNumber.ToString());\n    }\n    [Fact]\n    public void ToStringTopLevelNumber_Typed()\n    {\n        var dyn = helper.Obj2Json2TypedStrict(DeepData);\n        Equal(\"27\", dyn.Get(\"TopLevelNumber\").ToString());\n    }\n\n    [Fact]\n    public void ToStringObjectProperty_Dyn()\n    {\n        var dyn = helper.Obj2Json2Dyn(DeepData);\n        Equal(ReSerializeObjectProperty, dyn.ObjectProperty.ToString());\n    }\n    [Fact]\n    public void ToStringObjectProperty_Typed()\n    {\n        var dyn = helper.Obj2Json2TypedStrict(DeepData);\n        Equal(ReSerializeObjectProperty, dyn.Get(\"ObjectProperty\").ToString());\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynJson/WrapJsonMixed.cs",
    "content": "﻿namespace ToSic.Sxc.DataTests.DynJson;\n\n\npublic class WrapJsonMixed(DynAndTypedTestHelper helper)\n{\n    [Fact]\n    public void ObjectWithStringProperty()\n    {\n        var test = helper.DynJsonAndOriginal( new { FirstName = \"test\" });\n        Equal<string>(\"test\", test.Dyn.FirstName);\n    }\n\n    [Fact]\n    public void ArrayOfObjectsWithStringProperty()\n    {\n        var test = helper.DynJsonAndOriginal(new object[]\n        {\n            new { FirstName = \"test\" }, \n            new { FirstName = \"fn2\" }\n        });\n        Equal<string>(\"test\", test.Dyn[0].FirstName);\n    }\n\n    [Fact]\n    public void ObjectWithArrayPropertyOfObjectsWithStringProperty()\n    {\n        var test = helper.DynJsonAndOriginal(new\n        {\n            a = new object[]\n            {\n                new { FirstName = \"test\" }, \n                new { FirstName = \"fn2\" }\n            }\n        });\n        Equal<string>(\"test\", test.Dyn.a[0].FirstName);\n    }\n\n    [Fact]\n    public void ObjectWithArrayPropertyWithObjectWithStringArrayProperty()\n    {\n        var test = helper.DynJsonAndOriginal(new\n        {\n            a = new object[]\n            {\n                new { p1 = \"fn1\", p2 = new [] { \"test\", \"a2\" } },\n                new { p1 = \"fn2\", p2 = new [] { \"b1\", \"b2\" } },\n            }\n        });\n        Equal<string>(\"test\", test.Dyn.a[0].p2[0]);\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynJson/WrapJsonValues.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynJson;\n\n\npublic class WrapJsonValues(DynAndTypedTestHelper helper)\n{\n    private dynamic BoolDataDynLoose => _dynBool ??= helper.Obj2Json2Dyn(WrapAllKeys.TestDataAnonObject);\n    private static object? _dynBool;\n\n    private ITyped BoolTestDataStrict => _boolTestDataStrict ??= helper.Obj2Json2TypedStrict(WrapAllKeys.TestDataAnonObject);\n    private static ITyped? _boolTestDataStrict;\n    private ITyped BoolTestDataLoose => _boolTestDataLoose ??= helper.Obj2Json2TypedLoose(WrapAllKeys.TestDataAnonObject);\n    private static ITyped? _boolTestDataLoose;\n\n    [Fact]\n    public void JsonBool_Dyn()\n    {\n        True(BoolDataDynLoose.TrueBoolType);\n        False(BoolDataDynLoose.FalseBoolType);\n        Null(BoolDataDynLoose.something);\n    }\n\n    [Theory]\n    [InlineData(true, \"TrueBoolType\")]\n    [InlineData(false, \"FalseBoolType\")]\n    [InlineData(true, \"TrueString\")]\n    [InlineData(false, \"FalseString\")]\n    [InlineData(true, \"TrueNumber\")]\n    [InlineData(true, \"TrueNumberBig\")]\n    [InlineData(false, \"FalseNumber\")]\n    [InlineData(true, \"TrueNumberNegative\")]\n    public void JsonBoolProperty_Typed(bool expected, string key) \n        => Equal(expected, BoolTestDataStrict.Bool(key));\n\n\n\n\n\n    [Fact]\n    public void JsonNumberProperty()\n    {\n        var (dyn, _, original) = helper.DynJsonAndOriginal(new \n        {\n            IntType = 32,\n            BigIntType = 9007199254740991,\n            DoubleType = 0.333333333333333314829616256247390992939472198486328125,\n        });\n        Equal<int>(original.IntType, dyn.IntType);\n        Equal<long>(original.BigIntType, dyn.BigIntType);\n        Equal<double>(original.DoubleType,dyn.DoubleType);\n    }\n\n    [Fact]\n    public void ExpectCountOfPropertiesOnNonArray()\n    {\n        var test = helper.DynJsonAndOriginal(new { Name = \"Test\" });\n        Equal(1, test.Dyn.Count);\n\n        var test2 = helper.DynJsonAndOriginal(new { Name = \"Test\", Age = 3, Birthday = new DateTime(2022, 1, 1) });\n        Equal(3, test2.Dyn.Count);\n    }\n\n    [Fact]\n    public void EnumerateProperties()\n    {\n        var test = helper.DynJsonAndOriginal(new { Name = \"Test\" });\n        var testList = (test.Dyn as IEnumerable<object>).ToList();\n        Equal(1, testList.Count);\n        Equal(\"Name\", testList.First().ToString());\n\n        var test2 = helper.DynJsonAndOriginal(new { Name = \"Test\", Age = 3, Birthday = new DateTime(2022, 1, 1) });\n        var testList2 = (test2.Dyn as IEnumerable<object>).ToList();\n        Equal(3, testList2.Count);\n        True(testList2.Contains(\"Name\"));\n        True(testList2.Contains(\"Birthday\"));\n    }\n\n\n    [Fact]\n    public void ObjectWithStringProperty()\n    {\n        var jsonString = @\"{ \n                \"\"StringType\"\": \"\"stringValue\"\", \n                \"\"GuidType\"\": \"\"00000000-0000-0000-0000-000000000000\"\",\n            }\";\n        Equal<string>(\"stringValue\", helper.Json2Dyn(jsonString).StringType);\n        Equal<string>(\"00000000-0000-0000-0000-000000000000\", helper.Json2Dyn(jsonString).GuidType);\n    }\n\n    [Fact]\n    public void ObjectWithDateTimeProperty()\n    {\n        var jsonString = @\"{ \n                \"\"DateTimeType\"\": \"\"2022-11-09T23:00:00.000\"\", \n                \"\"ZuluTimeType\"\": \"\"2021-04-15T21:01:00.000Z\"\", \n            }\";\n        Equal<DateTime>(new DateTime(2022,11,9, 23,0,0), helper.Json2Dyn(jsonString).DateTimeType);\n        Equal<DateTime>(new DateTime(2021, 4, 15, 21, 1, 0, DateTimeKind.Utc), helper.Json2Dyn(jsonString).ZuluTimeType);\n    }\n\n    [Fact]\n    public void ObjectWithNullProperty()\n    {\n        var dynJson = helper.Json2Dyn(@\"{ \n                \"\"NullType\"\": null, \n                \"\"UndefinedType\"\": null, // undefined would not be valid\n            }\");\n        Null(dynJson.NullType);\n        Null(dynJson.UndefinedType);\n        Null(dynJson.NonExistingProperty);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynStack/Startup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.DataTests.DynStack;\n\npublic class Startup: StartupSxcCoreOnly\n{\n    public override void ConfigureServices(IServiceCollection services) =>\n        base.ConfigureServices(services.AddTransient<DynAndTypedTestHelper>());\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynStack/TypedStackGet.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.DynamicJacket;\nusing ToSic.Sxc.Data.Sys.Wrappers;\nusing static ToSic.Sxc.DataTests.DynStack.TypedStackTestData;\n\nnamespace ToSic.Sxc.DataTests.DynStack;\n\n\npublic class TypedStackGet(DynAndTypedTestHelper helper)\n{\n    private ITypedStack StackFromAnon => GetStackForKeysUsingAnon(helper);\n\n#if NETCOREAPP\n    [field: System.Diagnostics.CodeAnalysis.AllowNull, System.Diagnostics.CodeAnalysis.MaybeNull]\n#endif\n    private ITypedStack StackFromJson => field ??= GetStackForKeysUsingJson(helper);\n\n\n    public static TheoryData<PropInfo> StackProps => [..StackOrder12PropInfo];\n    public static TheoryData<PropInfo> StackPropsWithValue => [..StackOrder12PropInfo.Where(sp => sp.HasData && sp.Value?.ToString() != ValueNotTestable)];\n\n\n    [Theory]\n    [MemberData(nameof(StackProps))]\n    public void IsNotEmpty_BasedOnAnon(PropInfo pti)\n        => Equal(pti.HasData, StackFromAnon.IsNotEmpty(pti.Name));//, pti.ToString());\n\n    [Theory]\n    [MemberData(nameof(StackProps))]\n    public void ExistsNotNull_FromAnon_ReqFalse(PropInfo pti) \n        => Equal(pti.Exists, StackFromAnon.Get(pti.Name, required: false) != null);\n\n    [Theory]\n    [MemberData(nameof(StackPropsWithValue))]\n    public void ExistsNotNull_FromJson_ReqFalse(PropInfo pti)\n        => Equal(pti.Exists, StackFromJson.Get(pti.Name, required: false) != null);\n\n    [Theory]\n    [MemberData(nameof(StackProps))]\n    public void IsNotEmpty_FromAnon_ReqFalse(PropInfo pti) \n        => Equal(pti.Exists, StackFromAnon.IsNotEmpty(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(StackPropsWithValue))]\n    public void IsNotEmpty_FromJson_ReqFalse(PropInfo pti)\n        => Equal(pti.Exists, StackFromJson.IsNotEmpty(pti.Name));\n\n    [Theory]\n    [MemberData(nameof(StackPropsWithValue))]\n    public void Get_FromJson_ReqFalse(PropInfo pti)\n        => Equal(pti.Value, StackFromJson.Get(pti.Name, required: false));\n\n\n    [Theory]\n    [MemberData(nameof(StackPropsWithValue))]\n    public void Get_FromAnon_ReqFalse(PropInfo pti) \n        => Equal(pti.Value, StackFromAnon.Get(pti.Name, required: false));\n\n\n    #region Verify that what's inside the object matches expectation\n\n    [Fact]\n    public void Verify_StackFromAnonWrapsObjectTyped()\n    {\n        var inspect = (IWrapper<IPropertyStack>)StackFromAnon;\n        IsType<PreWrapObject>(inspect.GetContents().Sources.FirstOrDefault().Value);\n    }\n\n\n    [Fact]\n    public void Verify_StackFromJsonWrapsJacket()\n    {\n        var inspect = (IWrapper<IPropertyStack>)StackFromJson;\n        IsType<PreWrapJsonObject>(inspect.GetContents().Sources.FirstOrDefault().Value);\n    }\n\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynStack/TypedStackKeys_NotImplemented.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynStack;\n\n\npublic class TypedStackKeys_NotImplemented(DynAndTypedTestHelper helper)\n{\n    public static TheoryData<PropInfo> StackProps => [..TypedStackTestData.StackOrder12PropInfo];//.ToTestEnum();\n\n    [Theory]\n    [MemberData(nameof(StackProps))]\n    //[ExpectedException(typeof(NotImplementedException))]\n    public void Keys_AnonObjects(PropInfo pti) =>\n        Throws<NotImplementedException>(() => Equal(pti.Exists, StackForKeysFromAnon.ContainsKey(pti.Name)));\n\n\n#if NETCOREAPP\n    [field: System.Diagnostics.CodeAnalysis.AllowNull, System.Diagnostics.CodeAnalysis.MaybeNull]\n#endif\n    private ITypedStack StackForKeysFromAnon => field ??= TypedStackTestData.GetStackForKeysUsingAnon(helper);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynStack/TypedStackTestData.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynStack;\n\ninternal class TypedStackTestData\n{\n    public static object Anon1 => new\n    {\n        Key1 = \"hello\",\n        Key2 = \"goodbye\",\n        Deep1 = new\n        {\n            Sub1 = \"hello deep1.sub\",\n        }\n    };\n    public static List<PropInfo> Anon1PropInfo =>\n    [\n        new(\"Key1\", true, true, \"hello\"),\n        new(\"Key2\", true, true, \"goodbye\"),\n        new(\"Deep1\", true, true),\n        new(\"Deep1.Sub1\", true, true, \"hello\")\n    ];\n\n    public static object Anon2 => new\n    {\n        Key1 = \"hello 2\",\n        Part1 = \"part1-text\",\n        Part2 = \"test\",\n        Deep = new\n        {\n            Deeper = new\n            {\n                Value = \"hello deep.deeper.value\",\n            },\n        },\n    };\n\n    public static string ValueNotTestable = \"value-not-testable\";\n\n\n    public static List<PropInfo> StackOrder12PropInfo =>\n    [\n        new(\"Key1\", true, true, \"hello\"),\n        new(\"dummy\", false),\n        new(\"Part1\", true, hasData: true, value: \"part1-text\"),\n        new(\"Deep1\", true, hasData: true, value: ValueNotTestable),\n        new(\"Deep1.Sub1\", true, true, \"hello deep1.sub\"),\n        new(\"Deep\", true, hasData: true, value: ValueNotTestable),\n        new(\"Deep.Deeper\", true, hasData: true, value: ValueNotTestable),\n        new(\"Deep.NotDeeper\", false),\n        new(\"Deep.NotDeeper.ReallyNot\", false),\n        new(\"Deep.Deeper.Value\", true, hasData: true, value: \"hello deep.deeper.value\"),\n        new(\"Deep.Deeper.NotValue\", false)\n    ];\n\n\n    public static ITypedStack GetStackForKeysUsingAnon(DynAndTypedTestHelper helper)\n    {\n        var part1 = helper.Obj2Typed(Anon1);\n        var part2 = helper.Obj2Typed(Anon2);\n        var stack = helper.Factory.AsStack([part1, part2]);\n        return stack;\n    }\n    public static ITypedStack GetStackForKeysUsingJson(DynAndTypedTestHelper helper)\n    {\n        var part1 = helper.Obj2Json2TypedStrict(Anon1);\n        var part2 = helper.Obj2Json2TypedStrict(Anon2);\n        var stack = helper.Factory.AsStack([part1, part2]);\n        return stack;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/Startup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\npublic class Startup: StartupSxcCoreOnly\n{\n    public override void ConfigureServices(IServiceCollection services) =>\n        base.ConfigureServices(services.AddTransient<DynAndTypedTestHelper>());\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/TestPerson.cs",
    "content": "﻿namespace ToSic.Sxc.DataTests.DynWrappers;\n\npublic class TestPerson\n{\n    public int Id { get; set; }\n    public string Title { get; set; }\n    public string FirstName { get; set; }\n    public string Type { get; set; } = \"Person\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapDicBasic.cs",
    "content": "﻿using ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class WrapDicBasic(ICodeDataPoCoWrapperService wrapper)\n{\n    private /*DynamicFromDictionary<TKey, TValue>*/ object ToDyn<TKey, TValue>(Dictionary<TKey, TValue> dic)\n        => wrapper.FromDictionary(dic ?? []);\n\n    [Fact]\n    public void BasicUseDictionary()\n    {\n        var dic = new Dictionary<string, object>\n        {\n            [\"Name\"] = \"2sxc\",\n            [\"Description\"] = \"\",\n            [\"Founded\"] = 2012,\n            [\"Birthday\"] = new DateTime(2012, 5, 4),\n            [\"Truthy\"] = true,\n        };\n\n        var typed = ToDyn(dic); // as ITyped;\n        dynamic dynAnon = typed;\n\n        Null(dynAnon.NotExisting);\n        Equal(dic[\"Name\"], dynAnon.Name);\n        Equal(dic[\"Name\"], dynAnon.naME);//, \"Should be the same irrelevant of case\");\n        Equal(dic[\"Birthday\"], dynAnon.Birthday);//, \"dates should be the same\");\n        Equal(dic[\"Truthy\"], dynAnon.truthy);\n\n        // 2023-08-07 2dm - DynamicFromDictionary does not implement ITyped as of now\n\n        //True(typed.Has(\"Name\"));\n        //True(typed.Has(\"NAME\"));\n        //True(typed.Has(\"Description\"));\n        //False(typed.Has(\"NonexistingField\"));\n    }\n    [Fact]\n    public void Keys()\n    {\n        var anon = new Dictionary<string, object>\n        {\n            [\"Key1\"] = \"hello\",\n            [\"Key2\"] = \"goodbye\"\n        };\n        var typed = ToDyn(anon) as IHasKeys;\n        True(typed.ContainsKey(\"Key1\"));\n        False(typed.ContainsKey(\"Nonexisting\"));\n        True(typed.Keys().Any());\n        Equal(2, typed.Keys().Count());\n        Equal(1, typed.Keys(only: [\"Key1\"]).Count());\n        Equal(0, typed.Keys(only: [\"Nonexisting\"]).Count());\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapObjBasic.cs",
    "content": "﻿using ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Wrappers;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\n\npublic class WrapObjBasic(DynAndTypedTestHelper helper)\n{\n    public class TestData\n    {\n        public string Name => \"2sic\";\n        public string Description => \"Some description\";\n        /// <summary> This one is not a real property but just a value! </summary>\n        public string DescriptionAsProperty = \"Some description\";\n        public int Founded => 2012;\n        public DateTime Birthday { get; } = new(2012, 5, 4);\n        public bool Truthy => true;\n    }\n    public static TestData Data = new();\n\n    [Fact]\n    public void SourceAnonymous()\n    {\n        var anon = new { Data.Name, Data.Description, Data.Founded, Data.Birthday, Data.Truthy };\n        var typed = helper.Obj2Typed(anon);\n        dynamic dynAnon = helper.Obj2WrapObj(anon, false, false);\n\n        Null(dynAnon.NotExisting);\n        Equal(anon.Name, dynAnon.Name);\n        Equal(anon.Name, dynAnon.naME);//, \"Should be the same irrelevant of case\");\n        Equal(anon.Birthday, dynAnon.Birthday);//, \"dates should be the same\");\n        Equal(anon.Truthy, dynAnon.truthy);\n\n        True(typed.TestContainsKey(\"Name\"));\n        True(typed.TestContainsKey(\"NAME\"));\n        True(typed.TestContainsKey(\"Description\"));\n        False(typed.TestContainsKey(\"NonexistingField\"));\n    }\n\n    [Fact]\n    public void SourceTyped()\n    {\n        var data = new TestData();\n        var typed = helper.Obj2Typed(data);\n        dynamic dynAnon = helper.Obj2WrapObj(data, false, false);\n\n        Null(dynAnon.NotExisting);\n        Equal(data.Name, (string) dynAnon.Name);\n        Equal(data.Name, (string) dynAnon.naME);//, \"Should be the same irrelevant of case\");\n\n        // This line is different from the anonymous test\n        NotEqual(data.DescriptionAsProperty, (object) dynAnon.DescriptionAsProperty);//, \"Should NOT work for values, only properties\");\n        Equal(null, (object) dynAnon.DescriptionAsProperty);//, \"Should NOT work for values, only properties\");\n        Equal(data.Birthday, (DateTime) dynAnon.Birthday);//, \"dates should be the same\");\n        Equal(data.Truthy, (bool) dynAnon.truthy);\n\n        True(typed.TestContainsKey(\"Name\"));\n        True(typed.TestContainsKey(\"NAME\"));\n        True(typed.TestContainsKey(\"Description\"));\n        False(typed.TestContainsKey(\"NonexistingField\"));\n    }\n\n    [Fact]\n    public void RequiredDynDefaultExisting() => True(helper.Obj2WrapObjAsDyn(Data).Truthy);\n\n    [Fact]\n    public void RequiredDynDefaultNonExisting() => Null(helper.Obj2WrapObjAsDyn(Data).TruthyXyz);\n\n    [Fact]\n    public void RequiredTypedDefaultExisting() => True(helper.Obj2Typed(Data).Bool(nameof(TestData.Truthy)));\n\n    [Fact]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void RequiredTypedDefaultNonExisting() =>\n        Throws<ArgumentException>(() => helper.Obj2Typed(Data).Bool(\"FakeName\"));\n\n    [Fact]\n    public void RequiredTypedDefaultNonExistingWithParam() =>\n        False(helper.Obj2Typed(Data).Bool(\"FakeName\", required: false));\n\n    [Fact]\n    public void RequiredTypedDefaultNonExistingWithParamFallback() =>\n        True(helper.Obj2Typed(Data).Bool(\"FakeName\", fallback: true, required: false));\n\n    [Fact]\n    public void RequiredTypedNonStrictNonExistingWithParam() =>\n        False(helper.Obj2Typed(Data, WrapperSettings.Typed(true, true, false)).Bool(\"FakeName\"));\n\n\n\n\n\n\n    [Fact]\n    public void Keys()\n    {\n        var anon = new\n        {\n            Key1 = \"hello\",\n            Key2 = \"goodbye\",\n            Deep = new \n            {\n                Sub1 = \"hello\",\n                Sub2 = \"hello\",\n                Deeper = new\n                {\n                    SubSub1 = \"hello\"\n                }\n            }\n        };\n        var typed = helper.Obj2Typed(anon);\n        True(typed.TestContainsKey(\"Key1\"));\n        False(typed.TestContainsKey(\"Nonexisting\"));\n        True(typed.TestKeys().Any());\n        Equal(3, typed.TestKeys().Count());\n        Equal(1, typed.TestKeys(only: [\"Key1\"]).Count());\n        Equal(0, typed.TestKeys(only: [\"Nonexisting\"]).Count());\n    }\n\n    [Fact] public void DeepParent() => True(DataForDeepKeys.TestContainsKey(\"Deep\"));\n\n    [Fact] public void DeepSub1() => True(DataForDeepKeys.TestContainsKey(\"Deep.Sub1\"));\n    [Fact] public void DeepDeeper() => True(DataForDeepKeys.TestContainsKey(\"Deep.Deeper\"));\n    [Fact] public void DeepDeeperSub() => True(DataForDeepKeys.TestContainsKey(\"Deep.Deeper.SubSub1\"));\n    [Fact] public void DeepHasArray() => True(DataForDeepKeys.TestContainsKey(\"List\"));\n\n    // Note: Arrays are not supported\n    //True(typed.TestContainsKey(\"List.L1\"));\n    //True(typed.TestContainsKey(\"List.L2\"));\n\n    private ITyped DataForDeepKeys\n    {\n        get\n        {\n            var anon = new\n            {\n                Key1 = \"hello\",\n                Key2 = \"goodbye\",\n                Deep = new\n                {\n                    Sub1 = \"hello\",\n                    Sub2 = \"hello\",\n                    Deeper = new\n                    {\n                        SubSub1 = \"hello\"\n                    }\n                },\n                List = new object[]\n                {\n                    new\n                    {\n                        L1 = \"hello\",\n                    },\n                    new\n                    {\n                        L2 = \"hello\",\n                    }\n                }\n            };\n            var typed = helper.Obj2Typed(anon);\n            return typed;\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapObjDeep.cs",
    "content": "﻿using Microsoft.CSharp.RuntimeBinder;\nusing ToSic.Sxc.Data.Sys.Dynamic;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\n\npublic class WrapObjDeep(DynAndTypedTestHelper helper)\n{\n\n    [Fact]\n    public void SubObjectNotWrapped()\n    {\n        var anon = new\n        {\n            Simple = \"simple\",\n            Sub = new\n            {\n                SubSub = \"Test\"\n            }\n        };\n\n        dynamic dynAnon = helper.Obj2WrapObj(anon, false, false);\n        Equal(anon.Sub, dynAnon.Sub);\n    }\n\n    [Fact] public void SubObjectAutoWrappedTrueFalse() \n        => Equal(\"TF-ok\", SubObjectAutoWrapped(true, false, \"TF\"));\n\n    [Fact] public void SubObjectAutoWrappedTrueTrue() \n        => Equal(\"TT-ok\", SubObjectAutoWrapped(true, true, \"TT\"));\n\n    [Fact] public void SubObjectAutoWrappedFalseFalse() \n        => Equal(\"FF-ok\", SubObjectAutoWrapped(false, false, \"FF\"));\n    [Fact] public void SubObjectAutoWrappedFalseTrue() \n        => Equal(\"FT-ok\", SubObjectAutoWrapped(false, true, \"FT\"));\n\n    #region Exeption-tests because wrappings shouldn't work\n\n        \n\n    //[ExpectedException(typeof(RuntimeBinderException))]\n    [Fact] public void SubObjectAutoWrappedErrSubFf() =>\n        Throws<RuntimeBinderException>(() => Equal(\"ErrSub-ok\", SubObjectAutoWrapped(false, false, \"ErrSub\")));\n\n    //[ExpectedException(typeof(RuntimeBinderException))]\n    [Fact] public void SubObjectAutoWrappedErrSubFt() =>\n        Throws<RuntimeBinderException>(() => Equal(\"ErrSub-ok\", SubObjectAutoWrapped(false, true, \"ErrSub\")));\n\n    //[ExpectedException(typeof(RuntimeBinderException))]\n    [Fact] public void SubObjectAutoWrappedErrSubSubFf() =>\n        Throws<RuntimeBinderException>(() => Equal(\"ErrSubSub-ok\", SubObjectAutoWrapped(false, false, \"ErrSubSub\")));\n\n    //[ExpectedException(typeof(RuntimeBinderException))]\n    [Fact] public void SubObjectAutoWrappedErrSubSubFt() =>\n        Throws<RuntimeBinderException>(() => Equal(\"ErrSubSub-ok\", SubObjectAutoWrapped(false, true, \"ErrSubSub\")));\n\n    //[ExpectedException(typeof(RuntimeBinderException))]\n    [Fact] public void SubObjectAutoWrappedErrSubSomethingFf() =>\n        Throws<RuntimeBinderException>(() => Equal(\"ErrSubSomething-ok\", SubObjectAutoWrapped(false, false, \"ErrSubSomething\")));\n\n    //[ExpectedException(typeof(RuntimeBinderException))]\n    [Fact] public void SubObjectAutoWrappedErrSubSomethingFt() =>\n        Throws<RuntimeBinderException>(() => Equal(\"ErrSubSomething-ok\", SubObjectAutoWrapped(false, true, \"ErrSubSomething\")));\n    #endregion\n\n    private string SubObjectAutoWrapped(bool wrapChildren, bool wrapRealChildren, string testSet)\n    {\n        var anon = new\n        {\n            Simple = \"simple\",\n            Sub = new\n            {\n                Something = \"Test\",\n                Sub = new {\n                    Sub = new { }\n                }\n            },\n            Guid = new Guid(),\n            SubNonDynamic = new List<string>(),\n            Arr = Array.Empty<string>(),\n        };\n\n        // Test wrapping anonymous sub-objects only\n        var msgPlus = $\" - DynRead(..., {wrapChildren}, {wrapRealChildren})\";\n        dynamic dynWrapAnon = helper.Obj2WrapObj(anon, wrapChildren, wrapRealChildren);\n\n        // These tests should run in all cases\n        NotEqual(anon, (object) dynWrapAnon);//, $\"wrapper should never be equal {msgPlus}\");\n        Equal(anon, dynWrapAnon.GetContents());//, $\"Wrapped content should be equal {msgPlus}\");\n        Equal<string[]>(anon.Arr, dynWrapAnon.Arr);//, $\"Arrays shouldn't be re-wrapped {msgPlus}\");\n        Equal(anon.Guid, dynWrapAnon.Guid);//, $\"Guids shouldn't be re-wrapped {msgPlus}\");\n\n        if (testSet is \"TF\" or \"TT\")\n        {\n            NotEqual<object>(anon.Sub, dynWrapAnon.Sub);//, $\"Should not be equal, as the Sub should be re-wrapped {msgPlus}\");\n            Equal(anon.Sub, dynWrapAnon.Sub.GetContents());//, $\"Sub should be = to unwrapped {msgPlus}\");\n            Equal(typeof(WrapObjectDynamic), dynWrapAnon.Sub.GetType());//, $\"type should be {nameof(WrapObjectDynamic)}\");\n            NotEqual<object>(anon.Sub.Sub, dynWrapAnon.Sub.Sub);//, $\"sub-sub shouldn't be equal either, as they are still wrapped {msgPlus}\");\n            Equal(anon.Sub.Sub, dynWrapAnon.Sub.Sub.GetContents());//, $\"sub-sub GetContents {msgPlus}\");\n            Equal(anon.Sub.Something, dynWrapAnon.sub.something);//, $\"simple value, but case-invariant {msgPlus}\");\n            // added, todo\n            Equal(anon.Sub.Something, dynWrapAnon.Sub.something);//, $\"simple value, but case-invariant {msgPlus}\");\n            Equal(anon.Sub.Something, dynWrapAnon.Sub.Something);//, $\"simple value, but case-invariant {msgPlus}\");\n            // </added>\n        }\n\n        if (testSet is \"TF\" or \"FF\" or \"FT\")\n        {\n            Equal(anon.SubNonDynamic, dynWrapAnon.SubNonDynamic);//, $\"real object, shouldn't be re-wrapped {msgPlus}\");\n        }\n\n        if (testSet == \"TT\")\n        {\n            NotEqual<object>(anon.SubNonDynamic, dynWrapAnon.SubNonDynamic);//, $\"real object, shouldn't be re-wrapped {msgPlus}\");\n            Equal(anon.SubNonDynamic, dynWrapAnon.SubNonDynamic.GetContents());//, $\"real object, shouldn't be re-wrapped {msgPlus}\");\n        }\n\n\n        if (testSet is \"FT\" or \"FF\")\n        {\n            Equal(anon.Sub, dynWrapAnon.Sub);//, $\"Should not be equal, as the Sub should be re-wrapped {msgPlus}\");\n            NotEqual<object>(typeof(WrapObjectDynamic), dynWrapAnon.Sub.GetType());//, $\"type should be {nameof(WrapObjectDynamic)}\");\n            Equal(anon.Sub.Sub, dynWrapAnon.Sub.Sub);//, $\"sub-sub shouldn't be equal either, as they are still wrapped {msgPlus}\");\n        }\n\n\n        // Test wrapping no sub-objects\n            \n        // All these should throw errors when in FF or FT mode\n        if (testSet == \"ErrSub\")\n            Equal(anon.Sub, dynWrapAnon.Sub.GetContents(), $\"Sub should be = to unwrapped {msgPlus}\");\n\n        if (testSet == \"ErrSubSub\")\n            Equal(anon.Sub.Sub, dynWrapAnon.Sub.Sub.GetContents(), $\"sub-sub GetContents {msgPlus}\");\n\n        if (testSet == \"ErrSubSomething\")\n            Equal(anon.Sub.Something, dynWrapAnon.sub.something, $\"simple value, but case-invariant {msgPlus}\");\n\n        return testSet + \"-ok\";\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapObjTypedItem.cs",
    "content": "﻿namespace ToSic.Sxc.DataTests.DynWrappers;\n\n\npublic class WrapObjTypedItem(DynAndTypedTestHelper helper)\n{\n\n    [Fact]\n    public void PropsWhichDefaultToNull()\n    {\n        var anon = new\n        {\n            Simple = \"simple\",\n            Sub = new\n            {\n                SubSub = \"Test\"\n            }\n        };\n\n        var typed = helper.Obj2Item(anon);\n        Null(typed.Entity);\n        Null(typed.Type);\n        Null(typed.Presentation);\n        Null(typed.Child(\"DoesntExist\"));\n    }\n\n    [Fact] public void IsDemoItemDefault() => False(helper.Obj2Item(new { }).IsDemoItem);\n    [Fact] public void IsDemoItemFalse() => False(helper.Obj2Item(new { IsDemoItem = false }).IsDemoItem);\n    [Fact] public void IsDemoItemTrue() => True(helper.Obj2Item(new { IsDemoItem = true }).IsDemoItem);\n\n    [Fact] public void IdDefault() => Equal(0, helper.Obj2Item(new { }).Id);\n    [Fact] public void Id27() => Equal(27, helper.Obj2Item(new { Id = 27 }).Id);\n    [Fact] public void Id27Case() => Equal(27, helper.Obj2Item(new { ID = 27 }).Id);\n\n    [Fact] public void GuidDefault() => Equal(Guid.Empty, helper.Obj2Item(new { }).Guid);\n    [Fact] public void GuidCustom() => Equal(_guid, helper.Obj2Item(new { Guid = _guid }).Guid);\n    private static readonly Guid _guid = Guid.NewGuid();\n    [Fact] public void TitleDefault() => Null(helper.Obj2Item(new { }).Title);\n    [Fact] public void TitleCustom() => Equal(\"title X\", helper.Obj2Item(new { Title = \"title X\" }).Title);\n    [Fact] public void TitleNumber() => Equal(\"222\", helper.Obj2Item(new { Title = 222 }).Title);\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapObjTypedItemAdvanced.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\n\npublic class WrapObjTypedItemAdvanced(DynAndTypedTestHelper helper)\n{\n    private class TestData\n    {\n        public string ForField { get; set; } = \"Hello\";\n\n        public string File => \"file:72\";\n\n    }\n    private static readonly TestData Data = new();\n\n    private ITypedItem Item => helper.Obj2Item(Data);\n    private IField Field => Item.Field(\"ForField\");\n\n    [Fact] public void FieldExists() => NotNull(Field);\n\n    [Fact] public void FieldHasName() => Equal(\"ForField\", Field.Name);\n\n    [Fact] public void FieldHasUrl() => Equal(\"Hello\", Field.Url);\n    [Fact] public void FieldHasRaw() => Equal(\"Hello\", Field.Raw);\n        \n    // File / Folder Tests are more complex, as they need an App context\n    // Disabled for now\n    //[Fact] public void FileExists() => NotNull(Item.File(\"File\"));\n    //[Fact] public void FileIs72() => Equal(72, Item.File(\"File\").Id);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapObjTypedItemChildren.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\n\npublic class WrapObjTypedItemChildren(DynAndTypedTestHelper helper)\n{\n\n    private class TestData\n    {\n        public TestPerson Author { get; } = new()\n        {\n            Id = 101,\n            Title = \"some author\",\n            FirstName = \"Some\"\n        };\n\n        public TestPerson[] Readers { get; } =\n        [\n            new()\n            {\n                Id = 201\n            },\n            new()\n            {\n                Id = 202\n            },\n            new()\n            {\n                Id = 301,\n                Type = \"Company\"\n            }\n        ];\n    }\n    private static readonly TestData Data = new();\n    private ITypedItem Item => helper.Obj2Item(Data);\n    private ITypedItem Author() => Item.Child(\"author\");\n    private ITypedItem Reader() => Item.Child(\"readers\");\n    private IEnumerable<ITypedItem> Readers() => Item.Children(\"readers\");\n\n    [Fact] public void ChildSingleExists() => NotNull(Author());\n    [Fact] public void ChildDummyNotExists() => Null(Item.Child(\"dummy\"));\n    [Fact] public void ChildSingleId() => Equal(Data.Author.Id, Author().Id);\n    [Fact] public void ChildSingleTitle() => Equal(Data.Author.Title, Author().Title);\n    [Fact] public void ChildSingleFirstName() => Equal(Data.Author.FirstName, Author().String(\"firstname\"));\n\n    [Fact] public void ReaderSingleExists() => NotNull(Reader());\n    [Fact] public void ReaderSingleId() => Equal(Data.Readers[0].Id, Reader().Id);\n\n    [Fact] public void ReadersListExists() => NotNull(Readers());\n\n    [Fact] public void ReadersListCount() => Equal(Data.Readers.Length, Readers().Count());\n    [Fact] public void ReadersPersonCount() => Equal(Data.Readers.Length - 1, Item.Children(\"readers\", type: \"Person\").Count());\n    [Fact] public void ReadersCompanyCount() => Equal(1, Item.Children(\"readers\", type: \"Company\").Count());\n    [Fact] public void FakeListNotExists() => NotNull(Item.Children(\"dummy\"));\n    [Fact] public void ReadersList1Exists() => NotNull(Readers().First());\n    [Fact] public void ReadersList1Id() => Equal(Data.Readers[0].Id, Readers().First().Id);\n    [Fact] public void ReadersList2Exists() => NotNull(Readers().Skip(1).First());\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapObjTypedItemEquality.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Typed;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\n\npublic class WrapObjTypedItemEquality(DynAndTypedTestHelper helper)\n{\n    private static object CreateAnon() => new\n    {\n        Simple = \"simple\",\n        Sub = new\n        {\n            SubSub = \"Test\"\n        }\n    };\n\n    [Fact]\n    public void DiffWrapTwiceShouldBeDiff_Typed()\n        => NotEqual(helper.Obj2Typed(CreateAnon()), helper.Obj2Typed(CreateAnon()));\n\n    [Fact]\n    public void DiffWrapTwiceShouldBeDiff_Item()\n        => NotEqual(helper.Obj2Item(CreateAnon()), helper.Obj2Item(CreateAnon()));\n\n    [Fact]\n    public void SameWrapTwiceShouldBeEqual_Typed()\n    {\n        var anon = CreateAnon();\n        Equal(helper.Obj2Typed(anon), helper.Obj2Typed(anon));\n    }\n\n    [Fact(Skip=\"This can't work, because we can't overload == on interfaces - pls preserve this test, so it's documented\")]\n    public void SameWrapTwiceShouldBeEqual_TypedUsingEqEq()\n    {\n        var anon = CreateAnon();\n        var a = helper.Obj2Typed(anon);\n        var b = helper.Obj2Typed(anon);\n        var c = helper.Obj2Typed(anon) as WrapObjectTyped;\n        // ReSharper disable EqualExpressionComparison\n        // ReSharper disable PossibleUnintendedReferenceComparison\n        var x = c == c;\n        True(a == a, \"Test basic comparison\");\n        True(a as WrapObjectTyped == b, \"a as ... == b should work\");\n        True(a == b, \"a == b should work\");\n        // ReSharper restore EqualExpressionComparison\n        // ReSharper restore PossibleUnintendedReferenceComparison\n    }\n\n    [Fact]\n    public void SameWrapTwiceShouldBeEqual_Item()\n    {\n        var anon = CreateAnon();\n        Equal(helper.Obj2Item(anon), helper.Obj2Item(anon));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapObjTypedItemMetadata.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\n\npublic class WrapObjTypedItemMetadata(DynAndTypedTestHelper helper)\n{\n    private class TestDataMd1\n    {\n        public dynamic Metadata => new\n        {\n            Id = 999,\n            Description = \"MD Description\"\n        };\n    }\n    private ITypedItem ItemMd1 => helper.Obj2Item(new TestDataMd1());\n\n    [Fact] public void MetadataHasValue() => NotNull(ItemMd1.TestMetadata());\n    [Fact] public void MetadataCount1() => Equal(1, ((ItemMd1.TestMetadata() as IHasMetadata).Metadata as IEnumerable<IEntity>).Count());\n    //[Fact] public void MetadataId() => Equal(999, Item.Metadata.Entity.EntityId);\n    [Fact] public void MetadataDescription() => Equal(\"MD Description\", ItemMd1.TestMetadata().Get<string>(\"Description\"));\n\n    private class TestDataMd3\n    {\n        public dynamic Metadata => new object[]\n        {\n            new\n            {\n                Id = 999,\n                Description = \"MD3 Description\"\n            },\n            new {\n                Id = 555,\n                Color = \"white\"\n            },\n            new {\n                Id = 555,\n                Color = \"black\"\n            },\n        };\n\n    }\n    private ITypedItem ItemMd3 => helper.Obj2Item(new TestDataMd3());\n    [Fact] public void Metadata3HasValue() => NotNull(ItemMd3.TestMetadata());\n    [Fact] public void Metadata3Count3() => Equal(3, ((ItemMd3.TestMetadata() as IHasMetadata).Metadata /*as IEnumerable<IDynamicEntity>*/).Count());\n    [Fact] public void Metadata3Description() => Equal(\"MD3 Description\", ItemMd3.TestMetadata().Get<string>(\"Description\"));\n    [Fact] public void Metadata3Color() => Equal(\"white\", ItemMd3.TestMetadata().Get<string>(\"Color\"));\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/DynWrappers/WrapObjTypedItemParents.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests.DynWrappers;\n\n\npublic class WrapObjTypedItemParents(DynAndTypedTestHelper helper)\n{\n    private class TestTag\n    {\n        public int Id { get; set; }\n        public string Title { get; set; }\n        public string Field { get; set; }\n        public virtual string Type => \"Tag\";\n    }\n\n    private class TestCategory : TestTag\n    {\n        public override string Type => \"Category\";\n    }\n    private static readonly TestTag[] TestTagList =\n    [\n        new()\n        {\n            Id = 1001,\n            Title = \"Web\",\n            Field = \"Tags\",\n        },\n        new()\n        {\n            Id = 1002,\n            Title = \"IT\",\n            Field = \"Advanced\"\n        },\n        new TestCategory\n        {\n            Id = 2001,\n            Title = \"Cat1\",\n            Field = \"Advanced\"\n        },\n        new TestCategory\n        {\n            Id = 2002,\n            Title = \"Cat2\",\n            Field = \"Advanced\"\n        }\n    ];\n\n\n    private class TestDataParents\n    {\n        public TestTag[] Parents => TestTagList;\n    }\n    private static readonly TestDataParents DataParent = new();\n    private ITypedItem Item => helper.Obj2Item(DataParent);\n\n    private IEnumerable<ITypedItem> TagsFlat => Item.Parents();\n    private IEnumerable<ITypedItem> TagsFlatInField(string field) => Item.Parents(field: field);\n\n    [Fact] public void ParentsFlatExists() => NotNull(TagsFlat);\n    [Fact] public void ParentsFlatCount() => Equal(4, TagsFlat.Count());\n    [Fact] public void ParentsFlat1Id() => Equal(DataParent.Parents[0].Id, TagsFlat.First().Id);\n    [Fact] public void ParentsFlat1Name() => Equal(DataParent.Parents[0].Title, TagsFlat.First().Title);\n    [Fact] public void ParentsFlat2Id() => Equal(DataParent.Parents[1].Id, TagsFlat.Skip(1).First().Id);\n    [Fact] public void ParentsFlatTagsCount() => Equal(1, TagsFlatInField(\"Tags\").Count());\n    [Fact] public void ParentsFlatCategoriesCount() => Equal(3, TagsFlatInField(\"Advanced\").Count());\n\n        \n    /// <summary> Only the ones of type \"Tag\" </summary>\n    private IEnumerable<ITypedItem> Tags => Item.Parents(type: \"Tag\");\n    private IEnumerable<ITypedItem> TypeFake => Item.Parents(type: \"Fake\");\n    [Fact] public void ParentTagsExists() => NotNull(Tags);\n    [Fact] public void ParentTagsExists2() => Equal(2, Tags.Count());\n    [Fact] public void ParentFakeEmptyList() => NotNull(TypeFake);\n    [Fact] public void ParentFakeEmptyList0() => Equal(0, TypeFake.Count());\n\n    [Fact] public void ParentTagsOfField() => Equal(1, Item.Parents(type: \"Tag\", field: \"Tags\").Count());\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/GetAndConvertHelperTestAccessors.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Dynamic;\n\nnamespace ToSic.Sxc.DataTests;\n\ninternal static class GetAndConvertHelperTestAccessors\n{\n    public static string?[] TacGetFinalLanguagesList(string language, List<string> possibleDims, string[] defaultDims)\n        => LanguagePreprocessor.GetFinalLanguagesList(language, possibleDims, defaultDims);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/GetAndConvertHelperTests.cs",
    "content": "﻿using static ToSic.Sxc.DataTests.GetAndConvertHelperTestAccessors;\n\nnamespace ToSic.Sxc.DataTests;\n\n\npublic class GetAndConvertHelperTests\n{\n    private static readonly List<string> MockSystemLanguages2 = [\"en\", \"de\"];\n    private static readonly List<string> MockSystemLanguages4 = [\"en-us\", \"de-ch\", \"fr-fr\"];\n\n    [Fact]\n    public void GetFinalLanguagesList_LangsNull()\n    {\n        var dims = new[] { \"en\", \"de\", null };\n        var languages = TacGetFinalLanguagesList(null, MockSystemLanguages2, dims);\n        //Assert.True(skipAddDef);\n        Equal(dims, languages);\n    }\n\n    [Fact]\n    public void GetFinalLanguagesList_LangsEmpty()\n    {\n        var dims = new[] { \"en\", \"de\", null };\n        var languages = TacGetFinalLanguagesList(\"\", MockSystemLanguages2, dims);\n        //Assert.True(skipAddDefault);\n        Equal(new string[] { null }, languages);\n    }\n\n    [Fact]\n    public void GetFinalLanguagesList_LangsFirst()\n    {\n        var dims = new[] { \"en\", \"de\", null };\n        var languages = TacGetFinalLanguagesList(\"en\", MockSystemLanguages2, dims);\n        //Assert.True(skipAddDefault);\n        Equal(new[] { \"en\" }, languages);\n    }\n\n    [Fact]\n    public void GetFinalLanguagesList_LangsBoth()\n    {\n        var dims = new[] { \"en\", \"de\", null };\n        var languages = TacGetFinalLanguagesList(\"en,de\", MockSystemLanguages2, dims);\n        //Assert.True(skipAddDefault);\n        Equal(new[] { \"en\", \"de\" }, languages);\n    }\n\n    [Fact]\n    public void GetFinalLanguagesList_LangsFirstAndEmpty()\n    {\n        var dims = new[] { \"en\", \"de\", null };\n        var languages = TacGetFinalLanguagesList(\"en,\", MockSystemLanguages2, dims);\n        //Assert.True(skipAddDefault);\n        Equal(new[] { \"en\", null }, languages);\n    }\n\n    [Fact]\n    public void GetFinalLanguagesList_LangsFirstShortened()\n    {\n        var dims = new[] { \"en-us\", \"de-CH\", null };\n        var languages = TacGetFinalLanguagesList(\"en\", MockSystemLanguages4, dims);\n        //Assert.True(skipAddDefault);\n        Equal(new[] { \"en-us\" }, languages);\n    }\n\n    [Fact]\n    public void GetFinalLanguagesList_LangsNotFound()\n    {\n        var dims = new[] { \"en-us\", \"de-CH\", null };\n        var languages = TacGetFinalLanguagesList(\"qr\", MockSystemLanguages4, dims);\n        //Assert.True(skipAddDefault);\n        Equal(Array.Empty<string>() , languages);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/HasKeysTests.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Typed;\n\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.DataTests;\n\n\npublic class HasKeysTests\n{\n    [Fact]\n    public void IsFilledNull() \n        => False(HasKeysHelper.IsNotEmpty(null, blankIsEmpty: null));\n\n    [Fact]\n    public void IsEmptyNull() \n        => True(HasKeysHelper.IsEmpty(null, blankIsEmpty: null));\n\n    public static IEnumerable<object[]> BlankStrings =>\n    [\n        [\"\"],\n        [\" \"],\n        [\"   \"],\n        [\"\\t\", \"tab\"],\n        [\"\\t \\t\", \"tabs\"],\n        [\"\\n \\r\", \"new lines\"],\n        [\"\\u00A0\", \"non-breaking space\"],\n        [\"&nbsp;\", \"non-breaking space HTML\"],\n        [\" &nbsp; \\n\", \"non-breaking space HTML\"]\n    ];\n\n    [Theory]\n    [MemberData(nameof(BlankStrings))]\n    public void IsFilled_StringsBlank_BlankIsDefault(string value, string? testName = default) \n        => False(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: null));//, testName ?? value + \" blankIs: null\");\n\n    [Theory]\n    [MemberData(nameof(BlankStrings))]\n    public void IsFilled_StringsBlank_BlankFalse(string value, string? testName = default) \n        => False(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: false));//, testName ?? value + \" blankIs: false\");\n\n    [Theory]\n    [MemberData(nameof(BlankStrings))]\n    public void IsFilled_StringsBlank_BlankTrue(string value, string? testName = default) \n        => True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: true));//, testName ?? value + \" blankIs: true\");\n        \n    [Theory]\n    [MemberData(nameof(BlankStrings))]\n    public void IsEmpty_StringsBlank_BlankIsDefault(string value, string? testName = default) \n        => True(HasKeysHelper.IsEmpty(value, blankIsEmpty: null));//, testName ?? value + \" blankIs: null\");\n\n    [Theory]\n    [MemberData(nameof(BlankStrings))]\n    public void IsEmpty_StringsBlank_BlankFalse(string value, string? testName = default) \n        => False(HasKeysHelper.IsEmpty(value, blankIsEmpty: false));//, testName ?? value + \" blankIs: null\");\n\n    [Theory]\n    [MemberData(nameof(BlankStrings))]\n    public void IsEmpty_StringsBlank_BlankTrue(string value, string? testName = default) \n        => True(HasKeysHelper.IsEmpty(value, blankIsEmpty: true));//, testName ?? value + \" blankIs: null\");\n\n\n    public static IEnumerable<object[]> SimpleData =>\n    [\n        [0],\n        [-1],\n        [27],\n        [true],\n        [false],\n        [\"hello\"],\n        ['x', \"Character\"]\n    ];\n\n    [Theory]\n    [MemberData(nameof(SimpleData))]\n    public void IsFilled_SimpleData_BlankIsDefault(object value, string? testName = default) \n        => True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: null));//, testName ?? value + \" blankIs: null\");\n\n    [Theory]\n    [MemberData(nameof(SimpleData))]\n    public void IsFilled_SimpleData_BlankFalse(object value, string? testName = default) \n        => True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: false));//, testName ?? value + \" blankIs: false\");\n\n    [Theory]\n    [MemberData(nameof(SimpleData))]\n    public void IsFilled_SimpleData_BlankTrue(object value, string? testName = default) \n        => True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: true));//, testName ?? value + \" blankIs: true\");\n        \n\n    [Fact]\n    public void ContainsDataObject()\n    {\n        var value = new object();\n        True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: null));//, testName ?? value + \" blankIs: null\");\n        True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: false));//, testName ?? value + \" blankIs: false\");\n        True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: true));//, testName ?? value + \" blankIs: true\");\n    }\n\n    [Fact]\n    public void ContainsDataListEmpty()\n    {\n        var value = new List<string>();\n        False(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: null));//, testName ?? value + \" blankIs: null\");\n        False(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: false));//, testName ?? value + \" blankIs: false\");\n        False(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: true));//, testName ?? value + \" blankIs: true\");\n    }\n\n    [Fact]\n    public void ContainsDataListNonEmpty()\n    {\n        var value = new List<string> { \"hello\" };\n        var testName = \"object\";\n        True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: null));//, testName ?? value + \" blankIs: null\");\n        True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: false));//, testName ?? value + \" blankIs: false\");\n        True(HasKeysHelper.IsNotEmpty(value, blankIsEmpty: true));//, testName ?? value + \" blankIs: true\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/PropInfo.cs",
    "content": "﻿using Xunit.Abstractions;\n\nnamespace ToSic.Sxc.DataTests;\n\n/// <summary>\n/// Helper structure to create data describing what a property is like\n/// for tests which then use this\n/// </summary>\npublic struct PropInfo(string name, bool exists, bool hasData = false, object? value = default, string? note = default): IXunitSerializable\n{\n    public string Name = name;\n    public bool Exists = exists;\n    public bool HasData = hasData;\n    public object Value = value;\n    public string Note = note;\n    public override string ToString() => $\"Name: '{Name}' Note: '{Note}'\";\n\n    //public static IEnumerable<object[]> ToTestEnum(IEnumerable<PropertyTestInfo> source)\n    //    => source.Select(bk => new object[] { bk }).ToList();\n    public void Deserialize(IXunitSerializationInfo info)\n    {\n        //throw new NotImplementedException();\n    }\n\n    public void Serialize(IXunitSerializationInfo info)\n    {\n        //throw new NotImplementedException();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/DataTests/TypedItemTestAccessors.cs",
    "content": "﻿using ToSic.Sxc.Data;\n\nnamespace ToSic.Sxc.DataTests;\n\ninternal static class TypedItemTestAccessors\n{\n    public static ITypedMetadata TestMetadata(this ITypedItem item) => item.Metadata;\n\n    public static bool TestContainsKey(this ITyped item, string key) => item.ContainsKey(key);\n\n    public static IEnumerable<string> TestKeys(this ITyped item, IEnumerable<string>? only = default) => item.Keys(only: only);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using ToSic.Eav.Data.Build.Sys;\nglobal using ToSic.Eav.Testing;\nglobal using ToSic.Eav.Testing.Scenarios;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sys.Wrappers;\nglobal using Xunit.DependencyInjection;\nglobal using static Xunit.Assert;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkHelperImagePartFullTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Link.Sys;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LinkHelperImagePartFullTests(ILinkService Link)\n{\n    private void ImagePartFullVerifyUrlEqual(string testUrl)\n    {\n        Equal(testUrl, Link.ImageTac(url: testUrl, type: \"full\"));\n    }\n\n    [Fact]\n    public void ImageNoUrlOrParamsTest()\n    {\n        // todo: this looks wrong - if the image is empty, it shouldn't link the page\n        // in that case it should at most add the url to empty\n        Equal(LinkServiceUnknown.DefRoot /*$\"{LinkHelperUnknown.MockHost}/folder/subfolder/page?param=a#fragment\"*/, Link.ImageTac(url: \"\", type: \"full\"));\n    }\n\n    [Fact]\n    public void ImageCommonUrlsTest()\n    {\n        Equal($\"{LinkServiceUnknown.DefRoot}/\", Link.ImageTac(url: \"/\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/?a=1&b=2#fragment\", Link.ImageTac(url: \"/?a=1&b=2#fragment\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/page\", Link.ImageTac(url: \"/page\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/page?a=1&b=2#fragment\", Link.ImageTac(url: \"/page?a=1&b=2#fragment\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/file.ext\", Link.ImageTac(url: \"/file.ext\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/file.ext?a=1&b=2#fragment\", Link.ImageTac(url: \"/file.ext?a=1&b=2#fragment\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/\", Link.ImageTac(url: \"/folder/\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/?a=1&b=2#fragment\", Link.ImageTac(url: \"/folder/?a=1&b=2#fragment\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/page\", Link.ImageTac(url: \"/folder/page\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/page?a=1&b=2#fragment\", Link.ImageTac(url: \"/folder/page?a=1&b=2#fragment\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/file.ext\", Link.ImageTac(url: \"/folder/file.ext\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/file.ext?a=1&b=2#fragment\", Link.ImageTac(url: \"/folder/file.ext?a=1&b=2#fragment\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/subfolder/\", Link.ImageTac(url: \"/folder/subfolder/\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/subfolder/?a=1&b=2#fragment\", Link.ImageTac(url: \"/folder/subfolder/?a=1&b=2#fragment\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/subfolder/page\", Link.ImageTac(url: \"/folder/subfolder/page\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/subfolder/page?a=1&b=2#fragment\", Link.ImageTac(url: \"/folder/subfolder/page?a=1&b=2#fragment\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/subfolder/file.ext\", Link.ImageTac(url: \"/folder/subfolder/file.ext\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/folder/subfolder/file.ext?a=1&b=2#fragment\", Link.ImageTac(url: \"/folder/subfolder/file.ext?a=1&b=2#fragment\", type: \"full\"));\n    }\n\n    [Fact]\n    public void ImageUrlPathIsMissingTest()\n    {\n        Equal($\"{LinkServiceUnknown.DefRoot}?c=3\", Link.ImageTac(url: \"?c=3\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}?param=c\", Link.ImageTac(url: \"?param=c\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}?param=b&b=3&c=3\", Link.ImageTac(url: \"?param=b&b=3&c=3\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}#fragmentB\", Link.ImageTac(url: \"#fragmentB\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}#fragmentB\", Link.ImageTac(url: \"?#fragmentB\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}?param=c#fragmentB\", Link.ImageTac(url: \"?param=c#fragmentB\", type: \"full\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}#fragmentC\", Link.ImageTac(url: \"#fragmentC\", type: \"full\"));\n    }\n\n    [Fact]\n    public void ImageWithoutProtocolTest()\n    {\n        Equal($\"//{LinkServiceUnknown.DefDomain}/test\", Link.ImageTac(url: \"//unknown.2sxc.org/test\", type: \"full\"));\n    }\n\n    [Fact]\n    public void ImageWithAbsoluteUrlTest()\n    {\n        ImagePartFullVerifyUrlEqual(\"https://unknown2.2sxc.org/\");\n        ImagePartFullVerifyUrlEqual(\"https://unknown2.2sxc.org/page\");\n        ImagePartFullVerifyUrlEqual(\"https://unknown2.2sxc.org/file.ext\");\n        ImagePartFullVerifyUrlEqual(\"https://unknown2.2sxc.org/folder/\");\n    }\n\n    [Fact(Skip = \"ATM these tests fail, but it's actually not quite clear what should happen\")]\n    public void ImageWithInvalidUrlTest()\n    {\n        // ImagePartFullVerifyUrlEqual(\"hello:there\");\n        ImagePartFullVerifyUrlEqual(\"file:593902\");\n        ImagePartFullVerifyUrlEqual(\"../file.ext\");\n        ImagePartFullVerifyUrlEqual(\"/sibling1/../sibling2/image.jpg\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkHelperImagePartUndefinedTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LinkHelperImagePartUndefinedTests(ILinkService Link)\n{\n    private void ImageVerifyUrlEqual(string testUrl)\n    {\n        Equal(testUrl, Link.ImageTac(url: testUrl));\n    }\n\n    [Fact]\n    public void ImageNoUrlOrParamsTest()\n    {\n        ImageVerifyUrlEqual(\"\");\n    }\n\n    [Fact]\n    public void ImageCommonUrlsTest()\n    {\n        ImageVerifyUrlEqual(\"/\");\n        ImageVerifyUrlEqual(\"/?a=1&b=2#fragment\");\n        ImageVerifyUrlEqual(\"/page\");\n        ImageVerifyUrlEqual(\"/page?a=1&b=2#fragment\");\n        ImageVerifyUrlEqual(\"/file.ext\");\n        ImageVerifyUrlEqual(\"/file.ext?a=1&b=2#fragment\");\n        ImageVerifyUrlEqual(\"/folder/\");\n        ImageVerifyUrlEqual(\"/folder/?a=1&b=2#fragment\");\n        ImageVerifyUrlEqual(\"/folder/page\");\n        ImageVerifyUrlEqual(\"/folder/page?a=1&b=2#fragment\");\n        ImageVerifyUrlEqual(\"/folder/file.ext\");\n        ImageVerifyUrlEqual(\"/folder/file.ext?a=1&b=2#fragment\");\n        ImageVerifyUrlEqual(\"/folder/subfolder/\");\n        ImageVerifyUrlEqual(\"/folder/subfolder/?a=1&b=2#fragment\");\n        ImageVerifyUrlEqual(\"/folder/subfolder/page\");\n        ImageVerifyUrlEqual(\"/folder/subfolder/page?a=1&b=2#fragment\");\n        ImageVerifyUrlEqual(\"/folder/subfolder/file.ext\");\n        ImageVerifyUrlEqual(\"/folder/subfolder/file.ext?a=1&b=2#fragment\");\n    }\n\n    [Fact]\n    public void ImageUrlPathIsMissingTest()\n    {\n        ImageVerifyUrlEqual(\"?c=3\");\n        ImageVerifyUrlEqual(\"?param=c\");\n        ImageVerifyUrlEqual(\"?param=b&b=3&c=3\");\n        ImageVerifyUrlEqual(\"?#fragmentB\");\n        ImageVerifyUrlEqual(\"?param=c#fragmentB\");\n        ImageVerifyUrlEqual(\"#fragmentC\");\n    }\n\n    [Fact]\n    public void ImageWithoutProtocolTest() // current behavior, potentially we can improve like in part \"full\"\n    {\n        Equal(\"//unknown.2sxc.org/test\", Link.ImageTac(url: \"//unknown.2sxc.org/test\"));\n    }\n\n    [Fact]\n    public void ImageUrlWithTildeTest() // current behavior, potentially we can improve like in part \"full\"\n    {\n        Equal(\"~\", Link.ImageTac(url: \"~\"));\n        Equal(\"~/\", Link.ImageTac(url: \"~/\"));\n        Equal(\"~/page\", Link.ImageTac(url: \"~/page\"));\n        Equal(\"~/file.ext\", Link.ImageTac(url: \"~/file.ext\"));\n        Equal(\"~/folder/\", Link.ImageTac(url: \"~/folder/\"));\n    }\n\n    [Fact]\n    public void ImageWithAbsoluteUrlTest()\n    {\n        ImageVerifyUrlEqual(\"https://unknown2.2sxc.org/\");\n        ImageVerifyUrlEqual(\"https://unknown2.2sxc.org/page\");\n        ImageVerifyUrlEqual(\"https://unknown2.2sxc.org/file.ext\");\n        ImageVerifyUrlEqual(\"https://unknown2.2sxc.org/folder/\");\n    }\n\n    [Fact]\n    public void ImageWithInvalidUrlTest()\n    {\n        ImageVerifyUrlEqual(\"hello:there\");\n        ImageVerifyUrlEqual(\"file:593902\");\n        ImageVerifyUrlEqual(\"../file.ext\");\n        ImageVerifyUrlEqual(\"/sibling1/../sibling2/image.jpg\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkHelperToApiPartUndefinedTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing static ToSic.Sxc.LinksAndImages.ParametersTestExtensions;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LinkHelperToApiPartUndefinedTests(ILinkService Link)\n{\n    private void ToApiPartUndefinedVerifyUrlEqual(string testUrl)\n    {\n        Equal(testUrl, Link.ToTac(api: testUrl));\n    }\n\n    [Fact]\n    public void ToNoApiOrParamsTest()\n    {\n        ToApiPartUndefinedVerifyUrlEqual(\"\");\n    }\n\n    [Fact]\n    public void ToApiCommonUrlsTest()\n    {\n        Equal($\"/\", Link.ToTac(api: \"/\"));\n        Equal($\"/?a=1&b=2#fragment\", Link.ToTac(api: \"/\", parameters: \"a=1&b=2#fragment\"));\n        Equal($\"/api\", Link.ToTac(api: \"/api\"));\n        Equal($\"/api?a=1&b=2#fragment\", Link.ToTac(api: \"/api\", parameters: \"a=1&b=2#fragment\"));\n        Equal($\"/app/\", Link.ToTac(api: \"/app/\"));\n        Equal($\"/app/?a=1&b=2#fragment\", Link.ToTac(api: \"/app/\", parameters: \"a=1&b=2#fragment\"));\n        Equal($\"/app/api\", Link.ToTac(api: \"/app/api\"));\n        Equal($\"/app/api?a=1&b=2#fragment\", Link.ToTac(api: \"/app/api\", parameters: \"a=1&b=2#fragment\"));\n    }\n\n    [Fact]\n    public void ToApiParametersTest()\n    {\n        Equal($\"/app/api\", Link.ToTac(api: \"/app/api\"));\n        Equal($\"/app/api\", Link.ToTac(api: \"/app/api\", parameters: null));\n        Equal($\"/app/api?a=1&b=2#fragment\", Link.ToTac(api: \"/app/api\", parameters: \"a=1&b=2#fragment\"));\n        Equal($\"/app/api?a=1&b=2&c=3\", Link.ToTac(api: \"/app/api\", parameters: NewParameters(new()\n        {\n            { \"a\", \"1\" },\n            { \"b\", \"2\" },\n            { \"c\", \"3\" }\n        })));\n    }\n\n    [Fact]\n    public void ToApiPathIsMissingTest()\n    {\n        Equal($\"?param=b&b=3&c=3\", Link.ToTac(api: \"\", parameters: \"param=b&b=3&c=3\"));\n    }\n\n    [Fact]\n    public void ToApiWithoutProtocolTest() // current behavior, potentially we can improve like in part \"full\"\n    {\n        Equal($\"//unknown.2sxc.org/api?param=b&b=3&c=3\", Link.ToTac(api: \"//unknown.2sxc.org/api\", parameters: \"param=b&b=3&c=3\"));\n    }\n\n    [Fact]\n    public void ToApiWithTildeTest() // current behavior, potentially we can improve like in part \"full\"\n    {\n        Equal($\"~/api?p=1&r=2\", Link.ToTac(api: \"~/api\", parameters: \"p=1&r=2\"));\n        Equal($\"~/app/\", Link.ToTac(api: \"~/app/\"));\n    }\n\n    [Fact]\n    public void ToApiWithAbsoluteUrlTest()\n    {\n        ToApiPartUndefinedVerifyUrlEqual(\"https://unknown2.2sxc.org/\");\n        ToApiPartUndefinedVerifyUrlEqual(\"https://unknown2.2sxc.org/api\");\n        Equal(\"https://unknown2.2sxc.org/app/api?a=1\", Link.ToTac(api: \"https://unknown2.2sxc.org/app/api\", parameters: \"a=1\"));\n    }\n\n    [Fact]\n    public void ToApiWithInvalidUrlTest()\n    {\n        ToApiPartUndefinedVerifyUrlEqual(\"hello2:there\");\n        ToApiPartUndefinedVerifyUrlEqual(\"file:123\");\n        ToApiPartUndefinedVerifyUrlEqual(\"../api\");\n        ToApiPartUndefinedVerifyUrlEqual(\"/sibling1/../sibling2/api\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkHelperToCommonTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LinkHelperToCommonTests(ILinkService Link)\n{\n    [Fact]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void ToConflictingValuesProvidedTest()\n    {\n        Throws<ArgumentException>(() => Link.ToTac(pageId: 27, api: \"api\"));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkHelperToPagePartUnknownTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Link.Sys;\nusing static ToSic.Sxc.LinksAndImages.ParametersTestExtensions;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LinkHelperToPagePartUnknownTests (ILinkService Link)\n{\n    [Fact]\n    public void ToNoPageIdOrParamsTest()\n    {\n        Equal(LinkServiceUnknown.NiceCurrentUrl, Link.ToTac());\n    }\n\n    [Fact]\n    public void ToPageCommonsTest()\n    {\n        //Equal($\"{LinkHelperUnknown.MockHost}/page\", Link.TestTo(pageId: null));\n        Equal($\"{LinkServiceUnknown.DefRoot}/page{27}\", Link.ToTac(pageId: 27));\n    }\n\n    [Fact]\n    public void ToPageParametersTest()\n    {\n        Equal($\"{LinkServiceUnknown.DefRoot}/page27\", Link.ToTac(pageId: 27));\n        Equal($\"{LinkServiceUnknown.DefRoot}/page27\", Link.ToTac(pageId: 27, parameters: null));\n        Equal($\"{LinkServiceUnknown.DefRoot}/page27?a=1&b=2#fragment\", Link.ToTac(pageId: 27, parameters: \"a=1&b=2#fragment\"));\n        Equal($\"{LinkServiceUnknown.DefRoot}/page27?a=1&b=2&c=3\", Link.ToTac(pageId: 27, parameters: NewParameters(new()\n        {\n            { \"a\", \"1\" },\n            { \"b\", \"2\" },\n            { \"c\", \"3\" }\n        })));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkHelperToPartTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing static ToSic.Sxc.Services.Link.Sys.LinkServiceUnknown;\nusing static ToSic.Sxc.LinksAndImages.ParametersTestExtensions;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LinkHelperToPartTests(ILinkService link) : LinkHelperToTestBase(link)\n{\n\n    [Fact]\n    public void NoPage()\n    {\n        TestToPageParts(null, null, NiceCurrentUrl, NiceCurrentUrl, NiceCurrentRelative);\n    }\n\n    [Fact]\n    public void NoPageStringParamWithQuestion()\n    {\n        var query = \"active=true\";\n        var exp = $\"{NiceCurrentUrlRoot}?{query}\";\n        var rel = $\"{NiceCurrentRelative}?{query}\";\n        TestToPageParts(null, $\"?{query}\", exp, exp, rel);\n    }\n\n    [Fact]\n    public void NoPageStringParamWithAmpersand()\n    {\n        var query = \"active=true\";\n        var exp = $\"{NiceCurrentUrlRoot}?{query}\";\n        var rel = $\"{NiceCurrentRelative}?{query}\";\n        TestToPageParts(null, $\"&{query}\", exp, exp, rel);\n    }\n\n    private void NoPageStringParam(string query)\n    {\n        var exp = NiceCurrentUrlRoot + \"?\" + query;\n        var rel = $\"{NiceCurrentRelative}?{query}\";\n        TestToPageParts(null, query, exp, exp, rel);\n    }\n\n    [Fact] public void NoPageStringParamNoValue() => NoPageStringParam(\"active\");\n    [Fact] public void NoPageStringParamNoValue2() => NoPageStringParam(\"active&passive\");\n    [Fact] public void NoPageStringParamValue1() => NoPageStringParam(\"this=active\");\n    [Fact] public void NoPageStringParamValue2() => NoPageStringParam(\"this=active&that=passive\");\n    [Fact] public void NoPageStringParamValueParamNoValue() => NoPageStringParam(\"this=active&passive\");\n    [Fact] public void NoPageStringParamNoValueParamValue() => NoPageStringParam(\"active&that=passive\");\n\n    private void NoPageObjectParam(object parameters, string expQuery)\n    {\n        var fullQuery = (string.IsNullOrEmpty(expQuery) ? \"\" : \"?\") + expQuery;\n        var exp = NiceCurrentUrlRoot + fullQuery;\n        var rel = $\"{NiceCurrentRelative}{fullQuery}\";\n        TestToPageParts(null, parameters, exp, exp, rel);\n    }\n\n    [Fact] public void NoPageObjectParamUnsupported() => NoPageObjectParam(new DateTime(), \"\");\n\n    [Fact]\n    public void NoPageObjectParamsEmpty() => NoPageObjectParam(NewParameters(null), \"\");\n\n    [Fact]\n    public void NoPageObjectParamsKeyOnly() =>\n        NoPageObjectParam(NewParameters(new() { { \"active\", null } }), \"active\");\n\n    [Fact]\n    public void NoPageObjectParamsKeyValueEmpty() =>\n        NoPageObjectParam(NewParameters(new() { { \"active\", \"\" } }), \"active\");\n\n    [Fact]\n    public void NoPageObjectParamsKeyEmpty() =>\n        NoPageObjectParam(NewParameters(new() { { \"\", \"\" } }), \"\");\n\n    [Fact]\n    public void NoPageObjectParamDicKeyValue() =>\n        NoPageObjectParam(NewParameters(new() { { \"active\", \"true\" } }), \"active=true\");\n\n    [Fact]\n    public void NoPageObjectParamDicObject() =>\n        NoPageObjectParam(NewParameters(new() { { \"active\", \"true\" }, {\"passive\", \"false\"} }), \"active=true&passive=false\");\n\n\n    /// <summary>\n    /// This will reconfigure the LinkHelperUnknown to deliver ugly dnn-url like ...?tabId=27\n    /// </summary>\n    /// <param name=\"action\"></param>\n    private void RunWithUglyUrl(Action action)\n    {\n        SwitchModeToUgly(true);\n        try\n        {\n            action.Invoke();\n        }\n        finally\n        {\n            SwitchModeToUgly(false);\n        }\n    }\n\n    //[Fact]\n    //[Ignore]\n    //public void NoPageUgly()\n    //{\n    //    RunWithUglyUrl(() => { }\n    //        //TestToPageParts(null, null, UglyCurrentUrl, UglyCurrentUrl, DefProtocol, DefDomain, null, null,\n    //        //    UglyCurrentQuery, \"\", \"?\" + UglyCurrentQuery)\n    //    );\n    //}\n\n\n    [Fact]\n    public void Page27Plain()\n    {\n        var exp = NiceAnyPageUrl.Replace(\"{0}\", \"27\");\n        var rel = NiceAnyRelative.Replace(\"{0}\", \"27\");\n        TestToPageParts(27, null, exp, exp, rel);\n    }\n\n    private void Page27StringParam(string query)\n    {\n        var exp = NiceCurrentUrlRoot + \"?\" + query;\n        var rel = NiceAnyRelative.Replace(\"{0}\", \"27\") + \"?\" + query;\n        TestToPageParts(27, query, exp, exp, rel);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkHelperToTestBase.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\n\npublic class LinkHelperToTestBase(ILinkService Link)\n{\n    private const string SkipTest = \"!skip-test!\";\n\n    public void TestToPageParts(int? pageId = null, object? p = null, string standard = SkipTest, string full = SkipTest, string relative = SkipTest)\n    {\n        void TestType(string expected, string type)\n        {\n            if (expected == SkipTest) return;\n            // note: we do this on 2 lines of code to make debugging easier if the value is not what's expected\n            var result = Link.ToTac(pageId: pageId, parameters: p, type: type);\n            Equal(expected, result);//, $\"Tested with type: {type}\");\n        }\n\n        TestType(standard, default);\n        TestType(full, \"full\");\n        TestType(full.Replace(\"https://\", \"//\"), \"//\");\n        TestType(relative, \"/\");\n\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkHelperToVerifyTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing Xunit.Sdk;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LinkHelperToVerifyTests(ILinkService link) : LinkHelperToTestBase(link)\n{\n\n    [Fact]\n    //[ExpectedException(typeof(AssertFailedException))]\n    public void TestTheTestStandard() => Throws<EqualException>(() => TestToPageParts(null, standard: \"somethingwrong\"));\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkHelperTests/LinkTestHelperExtensions.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\npublic static class LinkTestHelperExtensions\n{\n    extension(ILinkService link)\n    {\n        /// <summary>\n        /// Special helper to avoid accessing the real To so many times\n        /// </summary>\n        public string ToTac(NoParamOrder npo = default,\n            int? pageId = null,\n            object? parameters = null,\n            string? api = null,\n            string? type = null) =>\n            link.To(npo: npo, pageId: pageId, parameters: parameters, api: api, type: type);\n\n        public string? ImageTac(string? url = null,\n            object? settings = null,\n            object? factor = null,\n            NoParamOrder npo = default,\n            object? width = null,\n            object? height = null,\n            object? quality = null,\n            string? resizeMode = null,\n            string? scaleMode = null,\n            string? format = null,\n            object? aspectRatio = null,\n            string? type = null,\n            string? parameters = null) =>\n            link.Image(url, settings, factor, npo, width: width, height: height, quality: quality, resizeMode: resizeMode, scaleMode: scaleMode, format: format,\n                aspectRatio: aspectRatio, type: type, parameters: parameters);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/ImageBasic.cs",
    "content": "﻿using System.Globalization;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\n\npublic class ImageBasic(LinkImageTestHelper helper)// : LinkImageTestBase\n{\n    [Fact]\n    public void UrlOnly()\n    {\n        var urls = new[]\n        {\n            \"test.jpg\",\n            \"test.png\",\n            \"/test.jpg\",\n            \"//test.jpg\",\n            \"http://www.2sxc.org/test.jpg\",\n            \"weird-extension.abc\"\n        };\n\n        foreach (var url in urls) helper.TestOnLinkerAndHelper(url, url);\n    }\n\n    [Fact]\n    public void BadCharacters()\n    {\n        helper.TestOnLinkerAndHelper(\"test%20picture.jpg?w=200\", \"test picture.jpg\", width: 200);\n        helper.TestOnLinkerAndHelper(\"gr%C3%A4%C3%9Flich.jpg?h=200\", \"gräßlich.jpg\", height: 200);\n        helper.TestOnLinkerAndHelper(\"test%20picture.jpg?x=chuchich%C3%A4schtly&w=200\", \"test picture.jpg?x=chuchichäschtly\", width: 200);\n    }\n\n\n    [Fact]\n    public void BasicWidthAndHeight()\n    {\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200\", \"test.jpg\", width: 200);\n        helper.TestOnLinkerAndHelper(\"test.jpg?h=200\", \"test.jpg\", height: 200);\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=200\", \"test.jpg\", width: 200, height:200);\n    }\n\n    [Fact]\n    public void BasicWidthAndAspectRatio()\n    {\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200\", \"test.jpg\", width: 200, aspectRatio: 0);\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=200\", \"test.jpg\", width: 200, aspectRatio: 1);\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=400\", \"test.jpg\", width: 200, aspectRatio: 0.5);\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=100\", \"test.jpg\", width: 200, aspectRatio: 2);\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=80\", \"test.jpg\", width: 200, aspectRatio: 2.5);\n            \n        // Note: in this case it should be 112.5 and will be rounded down by default\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=112\", \"test.jpg\", width: 200, aspectRatio: 16f/9);\n    }\n\n    [Fact]\n    public void BasicWidthAndAspectRatioString()\n    {\n        // Simple Strings\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200\", \"test.jpg\", width: 200, aspectRatio: \"0\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=200\", \"test.jpg\", width: 200, aspectRatio: \"1\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=400\", \"test.jpg\", width: 200, aspectRatio: \"0.5\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=100\", \"test.jpg\", width: 200, aspectRatio: \"2\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=80\", \"test.jpg\", width: 200, aspectRatio: \"2.5\");\n    }\n\n    [Fact]\n    public void BasicWidthAndAspectRatioCommaBadCulture()\n    {\n        // test before setting culture\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=400\", \"test.jpg\", width: 200, aspectRatio: \"0,5\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=400\", \"test.jpg\", width: 200, aspectRatio: \"0.5\");\n\n        // Now set culture and run again\n        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(\"de-DE\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=400\", \"test.jpg\", width: 200, aspectRatio: \"0.5\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=400\", \"test.jpg\", width: 200, aspectRatio: \"0.5\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=100\", \"test.jpg\", width: 200, aspectRatio: \"2\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=80\", \"test.jpg\", width: 200, aspectRatio: \"2.5\");\n    }\n\n    [Fact]\n    public void BasicWidthAndAspectRatioStringWithSeparator()\n    {\n        // Simple Strings\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200\", \"test.jpg\", width: 200, aspectRatio: \"0\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=200\", \"test.jpg\", width: 200, aspectRatio: \"1:1\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=200\", \"test.jpg\", width: 200, aspectRatio: \"1/1\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=400\", \"test.jpg\", width: 200, aspectRatio: \"1:2\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=400\", \"test.jpg\", width: 200, aspectRatio: \"1/2\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=100\", \"test.jpg\", width: 200, aspectRatio: \"2:1\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=100\", \"test.jpg\", width: 200, aspectRatio: \"2/1\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=100\", \"test.jpg\", width: 200, aspectRatio: \"2\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=80\", \"test.jpg\", width: 200, aspectRatio: \"2.5\");\n            \n        // Note: in this case it should be 112.5 and will be rounded down by default\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=112\", \"test.jpg\", width: 200, aspectRatio: \"16/9\");\n    }\n\n    [Fact]\n    //[ExpectedException(typeof(ArgumentOutOfRangeException))]\n    public void ErrorHeightAndAspectRatio()\n    {\n        var linker = helper.GetLinker();\n        Throws<ArgumentOutOfRangeException>(() => linker.ImageUrl(\"test.jpg\", height: 200, aspectRatio: 1));\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/ImageWithSettings.cs",
    "content": "﻿namespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\n\npublic class ImageWithSettings(LinkImageTestHelper helper)//: LinkImageTestBase\n{\n    [Theory]\n    [InlineData(true)]\n    //[InlineData(false)]\n    public void BasicHWandAR(bool makeDyn)\n    {\n        var raw = new { Width = 200, Height = 300 };\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=300\", \"test.jpg\", makeDyn ? helper.ToDyn(raw) : raw);\n\n        var raw2 = new { Width = 200, Height = 300, AspectRatio = 1 };\n        helper.TestOnLinkerAndHelper(\"test.png?w=200&h=200\", \"test.png\", makeDyn ? helper.ToDyn(raw2) : raw2);\n\n        // if h & ar are given, ar should take precedence\n        var raw3 = new { Width = 200, Height = 300, AspectRatio = 1 };\n        helper.TestOnLinkerAndHelper(\"test.png?w=200&h=200\", \"test.png\", makeDyn ? helper.ToDyn(raw3) : raw3);\n    }\n\n    [Theory]\n    [InlineData(true)]\n    [InlineData(false)]\n    public void BasicFormat(bool makeDyn)\n    {\n        var raw = new { Format = \"webp\" };\n        // helper.TestOnLinkerAndHelper(\"test.jpg?format=webp\", \"test.jpg\", format: \"webp\");\n        helper.TestOnLinkerAndHelper(\"test.jpg?format=webp\", \"test.jpg\", makeDyn ? helper.ToDyn(raw) : raw);\n    }\n\n\n    [Fact]\n    public void SettingsWithOverride()\n    {\n        var settings = helper.ToDyn(new { Width = 200, Height = 300 });\n        helper.TestOnLinkerAndHelper(\"test.jpg?h=300\", \"test.jpg\", settings, width: 0);\n\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=700&h=300\", \"test.jpg\", settings, width: 700);\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=550\", \"test.jpg\", settings, height: 550);\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200&h=100\", \"test.jpg\", settings, aspectRatio: 2);\n        helper.TestOnLinkerAndHelper(\"test.jpg?h=300\", \"test.jpg\", settings, width: 0);\n        helper.TestOnLinkerAndHelper(\"test.jpg?w=200\", \"test.jpg\", settings, height: 0);\n\n        var settings2 = helper.ToDyn(new { Width = 200, AspectRatio = 1 });\n        helper.TestOnLinkerAndHelper(\"test.png?w=200&h=200\", \"test.png\", settings2);\n\n        // if h & ar are given, ar should take precedence\n        var settings3 = helper.ToDyn(new { Width = 200, Height = 300, AspectRatio = 1 });\n        helper.TestOnLinkerAndHelper(\"test.png?w=200&h=200\", \"test.png\", settings3);\n    }\n\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/ImgSrcSet.cs",
    "content": "﻿using ToSic.Sxc.Images;\nusing ToSic.Sxc.Images.Sys;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\n\npublic class ImgSrcSet(LinkImageTestHelper helper)// : LinkImageTestBase\n{\n    [Theory]\n    [InlineData(\"test.jpg\")]\n    [InlineData(\"test.png\")]\n    [InlineData(\"/test.jpg\")]\n    [InlineData(\"//test.jpg\")]\n    [InlineData(\"http://www.2sxc.org/test.jpg\")]\n    [InlineData(\"weird-extension.abc\")]\n    public void EmptySrcSet(string url) \n        => helper.TestOnLinkerSrcSet(url, url, variants: \"d\");\n\n    [Theory]\n    [InlineData(\"test.jpg?w=1000 1000w\", \"test.jpg\", \"1000\")]\n    [InlineData(\"test.jpg?w=1000 1000w\", \"test.jpg\", \"1000w\")]\n    [InlineData(\"test.jpg?w=1000 1000w,\\ntest.jpg?w=2000 2000w\", \"test.jpg\", \"1000,2000\")]\n    [InlineData(\"test.jpg?w=500 500w,\\ntest.jpg?w=1000 1000w,\\ntest.jpg?w=2000 2000w\", \"test.jpg\", \"500w,1000w,2000w\")]\n    public void SrcSetUrlOnlyW(string expected, string url, string variants) \n        => helper.TestOnLinkerSrcSet(expected, url, variants: variants);\n\n\n\n    [Theory]\n    [InlineData(\"test.jpg 1x\", \"test.jpg\", \"1\")]\n    [InlineData(\"test.jpg 1.5x\", \"test.jpg\", \"1.5x\")]\n    public void SrcSetUrlOnlyX(string expected, string url, string variants) \n        => helper.TestOnLinkerSrcSet(expected, url, variants: variants);\n\n    [Theory]\n    [InlineData(\"test.jpg?w=1800 1.5x\", \"test.jpg\", \"1.5x\")]\n    [InlineData(\"test.jpg?w=1200 1x\", \"test.jpg\", \"1\")]\n    [InlineData(\"test.jpg?w=1200 1x,\\ntest.jpg?w=1800 1.5x,\\ntest.jpg?w=2400 2x\", \"test.jpg\", \"1x,1.5x,2\")]\n    [InlineData(\"test.jpg?w=1200 1x,\\ntest.jpg?w=1800 1.5x,\\ntest.jpg?w=2000 2x\", \"test.jpg\", \"1x,1.5x,2x=2000\")]\n    [InlineData(\"test.jpg?w=1200 1x,\\ntest.jpg?w=1800 1.5x,\\ntest.jpg?w=2000&h=1000 2x\", \"test.jpg\", \"1x,1.5x,2x=2000:1000\")]\n    public void SrcSetUrlXAndWidth(string expected, string url, string variants)\n        => helper.TestOnLinkerSrcSet(expected, url, width: 1200, variants: variants);\n\n\n\n\n    [Theory]\n    [InlineData(\"test.jpg?w=1200 1200w\", \"test.jpg\", \"1*\")]\n    [InlineData(\"test.jpg?w=1800 1800w\", \"test.jpg\", \"1.5*\")]\n    [InlineData(\"test.jpg?w=600 600w\", \"test.jpg\", \"0.5*\")]\n    [InlineData(\"test.jpg?w=600 600w\", \"test.jpg\", \"1:2*\")]\n    [InlineData(\"test.jpg?w=600 600w\", \"test.jpg\", \"1/2*\")]\n    [InlineData(\"test.jpg?w=600 600w\", \"test.jpg\", \"1/2\")] // without '*' it auto-detects a proportion\n    [InlineData(\"test.jpg?w=600 600w\", \"test.jpg\", \"1:2\")] // without '*' it auto-detects a proportion\n    public void SrcSetUrlOnlyStar(string expected, string url, string variants) \n        => helper.TestOnLinkerSrcSet(expected, url, variants: variants);\n\n    [Theory]\n    [InlineData(\"test.jpg?w=120 120w\", \"test.jpg\", \"1*\")]\n    [InlineData(\"test.jpg?w=180 180w\", \"test.jpg\", \"1.5*\")]\n    [InlineData(\"test.jpg?w=120 120w,\\ntest.jpg?w=180 180w,\\ntest.jpg?w=240 240w\", \"test.jpg\", \"1*,1.5*,2*\")]\n    // Note: These two cases don't make sense but could be configured - as soon as you give an exact pixel, the 2* doesn't do much\n    [InlineData(\"test.jpg?w=120 120w,\\ntest.jpg?w=200 200w\", \"test.jpg\", \"1*,2*=200\")]\n    [InlineData(\"test.jpg?w=120 120w,\\ntest.jpg?w=200&h=180 200w\", \"test.jpg\", \"1*,2*=200:180\")]\n    public void SrcSetUrlStarAndWidth(string expected, string url, string variants)\n        => helper.TestOnLinkerSrcSet(expected, url, width: 120, variants: variants);\n\n\n    [Fact]\n    public void WipDoubleResize()\n    {\n        var linker = helper.GetLinker();\n        var settings = linker.ResizeParamMerger.BuildResizeSettings(width: 1000, factor: 0.5, advanced: AdvancedSettings.Parse(\"0.5\"));\n        var src = linker.SrcSet(\"test.jpg\", settings, SrcSetType.Img);\n        Equal(\"test.jpg?w=250 250w\", src);//, \"Src should be a quarter now\");\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/LinkImageParameters.cs",
    "content": "﻿using ToSic.Sxc.LinksAndImages.LinkHelperTests;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\n\npublic class LinkImageParameters(LinkImageTestHelper helper)//: LinkImageTestBase\n{\n    [Fact]\n    public void BasicParameters() =>\n        Equal(\"test.jpg?name=daniel\", helper.GetLinkHelper().ImageTac(\"test.jpg\", parameters: \"name=daniel\"));\n\n    [Fact]\n    public void KeyOnly() =>\n        Equal(\"test.jpg?active\", helper.GetLinkHelper().ImageTac(\"test.jpg\", parameters: \"active\"));\n\n    [Fact]\n    public void AddKeyToExisting() =>\n        Equal(\"test.jpg?wx=200&active\", helper.GetLinkHelper().ImageTac(\"test.jpg?wx=200\", parameters: \"active\"));\n\n    [Fact]\n    public void AddPairToExisting() =>\n        Equal(\"test.jpg?wx=200&active=true\", helper.GetLinkHelper().ImageTac(\"test.jpg?wx=200\", parameters: \"active=true\"));\n\n\n    [Fact]\n    public void AddPairToWh() =>\n        Equal(\"test.jpg?w=200&h=200&active=true\", helper.GetLinkHelper().ImageTac(\"test.jpg\", width: 200, height: 200, parameters: \"active=true\"));\n\n    [Fact]\n    public void AddPairToWhAndExisting() =>\n        Equal(\"test.jpg?wx=700&w=200&h=200&active=true\", helper.GetLinkHelper().ImageTac(\"test.jpg?wx=700\", width: 200, height: 200, parameters: \"active=true\"));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/LinkImageTestBase.cs",
    "content": "﻿//using ToSic.Eav.Internal.Loaders;\n//using ToSic.Sxc.Data.Internal.Dynamic;\n//using ToSic.Sxc.Data.Internal.Wrapper;\n//using ToSic.Sxc.Images;\n//using ToSic.Sxc.Images.Internal;\n//using ToSic.Sxc.LinksAndImages.LinkHelperTests;\n//using ToSic.Sxc.Services;\n\n//namespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\n//[Startup(typeof(StartupSxcCoreOnly))]\n//public class LinkImageTestBase\n//{\n//    private readonly CodeDataWrapper _cdf;\n//    private readonly ImgResizeLinker _linker;\n//    private readonly ILinkService _linkHelper;\n\n//    public LinkImageTestBase(CodeDataWrapper cdf, ImgResizeLinker linker, ILinkService linkHelper, EavSystemLoader systemLoader)\n//    {\n//        _cdf = cdf;\n//        _linker = linker;\n//        _linkHelper = linkHelper;\n//        systemLoader.LoadLicenseAndFeatures();\n//    }\n\n//    public ImgResizeLinker GetLinker() => _linker;\n//    public ILinkService GetLinkHelper() => _linkHelper;\n\n//    public WrapObjectDynamic ToDyn(object contents) => _cdf\n//        .FromObject(contents, WrapperSettings.Dyn(children: false, realObjectsToo: false));\n\n\n//    protected void TestOnLinkerAndHelper(string expected,\n//        string url = null,\n//        object settings = null,\n//        object factor = null,\n//        NoParamOrder npo = default,\n//        object width = null,\n//        object height = null,\n//        object quality = null,\n//        string resizeMode = null,\n//        string scaleMode = null,\n//        string format = null,\n//        object aspectRatio = null)\n//    {\n//        // Test with Linker\n//        var linker = GetLinker();\n//        var linkerResult = linker.Image(url: url, settings: settings, factor: factor, width: width, height: height,\n//            quality: quality, resizeMode: resizeMode, scaleMode: scaleMode, format: format,\n//            aspectRatio: aspectRatio);\n//        Equal(expected, linkerResult);//, \"Failed on ImgResizeLinker\");\n\n//        // Skip Helper-tests if using SrcSet as that's not supported in that case\n//        // Because it would lead to not-expected result\n//        //if (variants != null) return;\n\n//        var linkHelper = GetLinkHelper();\n//        var helperResult = linkHelper.TestImage(url: url, settings: settings, factor: factor, width: width,\n//            height: height,\n//            quality: quality, resizeMode: resizeMode, scaleMode: scaleMode, format: format,\n//            aspectRatio: aspectRatio);\n//        Equal(expected, helperResult);//, \"Failed on ILinkHelper\");\n//    }\n\n\n//    protected void TestOnLinkerSrcSet(string expected,\n//        string url = null,\n//        object settings = null,\n//        object factor = null,\n//        NoParamOrder npo = default,\n//        object width = null,\n//        object height = null,\n//        object quality = null,\n//        string resizeMode = null,\n//        string scaleMode = null,\n//        string format = null,\n//        object aspectRatio = null,\n//        string variants = null)\n//    {\n//        // Test with Linker\n//        var linker = GetLinker();\n//        var typedSettings = linker.ResizeParamMerger.BuildResizeSettings(settings: settings, factor: factor,\n//            width: width,\n//            height: height,\n//            quality: quality, resizeMode: resizeMode, scaleMode: scaleMode, format: format,\n//            aspectRatio: aspectRatio, advanced: AdvancedSettings.Parse(new Recipe(variants: variants)));\n//        var linkerResult = linker.SrcSet(url, typedSettings, SrcSetType.Img);\n//        Equal(expected, linkerResult);//, $\"Failed on ImgResizeLinker for srcSet '{variants}'\");\n//    }\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/LinkImageTestHelper.cs",
    "content": "﻿using ToSic.Sxc.Data.Sys.Wrappers;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.LinksAndImages.LinkHelperTests;\nusing ToSic.Sxc.Services;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.GetByName;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\npublic class LinkImageTestHelper\n{\n    private readonly ICodeDataPoCoWrapperService _wrapper;\n    private readonly ImgResizeLinker _linker;\n    private readonly ILinkService _linkHelper;\n\n    public LinkImageTestHelper(ICodeDataPoCoWrapperService wrapper, ImgResizeLinker linker, ILinkService linkHelper, EavFeaturesLoader featuresLoader)\n    {\n        _wrapper = wrapper;\n        _linker = linker;\n        _linkHelper = linkHelper;\n        featuresLoader.LoadLicenseAndFeatures();\n    }\n\n    public ImgResizeLinker GetLinker() => _linker;\n    public ILinkService GetLinkHelper() => _linkHelper;\n\n    public /*WrapObjectDynamic*/ICanGetByName ToDyn(object contents) => (ICanGetByName)_wrapper\n        .DynamicFromObject(contents, WrapperSettings.Dyn(children: false, realObjectsToo: false));\n\n\n    public void TestOnLinkerAndHelper(string expected,\n        string? url = null,\n        object? settings = null,\n        object? factor = null,\n        NoParamOrder npo = default,\n        object? width = null,\n        object? height = null,\n        object? quality = null,\n        string? resizeMode = null,\n        string? scaleMode = null,\n        string? format = null,\n        object? aspectRatio = null)\n    {\n        // Test with Linker\n        var linker = GetLinker();\n        var linkerResult = linker.ImageUrl(url: url, settings: settings, factor: factor, width: width, height: height,\n            quality: quality, resizeMode: resizeMode, scaleMode: scaleMode, format: format,\n            aspectRatio: aspectRatio);\n        Equal(expected, linkerResult);//, \"Failed on ImgResizeLinker\");\n\n        // Skip Helper-tests if using SrcSet as that's not supported in that case\n        // Because it would lead to not-expected result\n        //if (variants != null) return;\n\n        var linkHelper = GetLinkHelper();\n        var helperResult = linkHelper.ImageTac(url: url, settings: settings, factor: factor, width: width,\n            height: height,\n            quality: quality, resizeMode: resizeMode, scaleMode: scaleMode, format: format,\n            aspectRatio: aspectRatio);\n        Equal(expected, helperResult);//, \"Failed on ILinkHelper\");\n    }\n\n\n    public void TestOnLinkerSrcSet(string expected,\n        string? url = null,\n        object? settings = null,\n        object? factor = null,\n        NoParamOrder npo = default,\n        object? width = null,\n        object? height = null,\n        object? quality = null,\n        string? resizeMode = null,\n        string? scaleMode = null,\n        string? format = null,\n        object? aspectRatio = null,\n        string? variants = null)\n    {\n        // Test with Linker\n        var linker = GetLinker();\n        var typedSettings = linker.ResizeParamMerger.BuildResizeSettings(settings: settings, factor: factor,\n            width: width,\n            height: height,\n            quality: quality, resizeMode: resizeMode, scaleMode: scaleMode, format: format,\n            aspectRatio: aspectRatio, advanced: AdvancedSettings.Parse(new Recipe(variants: variants)));\n        var linkerResult = linker.SrcSet(url, typedSettings, SrcSetType.Img);\n        Equal(expected, linkerResult);//, $\"Failed on ImgResizeLinker for srcSet '{variants}'\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/MultiResizeTests.cs",
    "content": "﻿using ToSic.Sxc.Images;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Images.Sys.ResizeSettings;\nusing static ToSic.Sxc.DataForImageTests.ResizeRecipesData;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\n\npublic class MultiResizeTests(LinkImageTestHelper helper)//: LinkImageTestBase\n{\n    [Fact]\n    public void NoFactorMap()\n    {\n        var l = helper.GetLinker();\n        var settings = l.ResizeParamMerger.BuildResizeSettings(width: 1000);\n        var f1 = l.DimGen.ResizeDimensions(settings, settings.Find(SrcSetType.Img, true, null));\n        Equal(1000, f1.Width);\n\n        var f2 = new ResizeSettings(settings, factor: 0.5);\n        var dims = l.DimGen.ResizeDimensions(f2, f2.Find(SrcSetType.Img, true, null));\n        Equal(500, dims.Width);\n    }\n\n    [InlineData(W50, 0.5, CssNone, \"0.5 should be changed\")]\n    [InlineData(700, 0.70, CssNone, \"0.70 should not be changed\")]\n    [InlineData(W75ImgOnly777, 0.75, CssNone, \"0.75 should be changed\")]\n    [InlineData(W75CssUnknown, 0.75, CssUnknown, \"0.75 should be changed\")]\n    [InlineData(W100, 1, CssNone, \"1 should be changed too\")]\n    [InlineData((int)(1000 * .9), 0.9, CssNone, \"0.9 should just calculate, because it's not in the factor-list\")]\n    [Theory]\n\n    public void WithFactorMap(int expected, double factor, string cssFramework, string name) \n        => WithFactorMapInternal(expected, factor, cssFramework, TestRecipeSet(), name);\n\n\n\n    [InlineData(W50, 0.5, CssNone, \"0.5 should be changed\")]\n    [InlineData(700, 0.70, CssNone, \"0.70 should not be changed\")]\n    [InlineData(W75ImgOnly777, 0.75, CssNone, \"0.75 should be changed\")]\n    [InlineData(W75CssUnknown, 0.75, CssUnknown, \"0.75 should be changed\")]\n    [InlineData(W100, 1, CssNone, \"1 should be changed too\")]\n    [InlineData((int)(1000 * .9), 0.9, CssNone, \"0.9 should just calculate, because it's not in the factor-list\")]\n    [Theory]\n\n    public void WithFactorMapJson(int expected, double factor, string cssFramework, string name) \n        => WithFactorMapInternal(expected, factor, cssFramework, TestRecipeSetFromJson, name + \"-json\");\n\n\n    private void WithFactorMapInternal(int expected, double factor, string cssFramework, AdvancedSettings recipes, string name)\n    {\n        var l = helper.GetLinker();\n        var settings = l.ResizeParamMerger.BuildResizeSettings(width: 1000, advanced: recipes);\n\n        // Normally UseFactorMap is false because we set the width explicitly\n        // But to run the test, we must set it to true\n        settings.UseFactorMap = true;\n\n        settings = new(settings, factor: factor);\n        var srcSetSettings = settings.Find(SrcSetType.Img, true, cssFramework);\n        var f1 = l.DimGen.ResizeDimensions(settings, srcSetSettings);\n        Equal(expected, f1.Width);//, name);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/ResizeParamMergeTests.cs",
    "content": "﻿using ToSic.Sxc.Images.Sys.ResizeSettings;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\n\npublic class ResizeParamMergeTests\n{\n    [Fact]\n    public void TestMethod1()\n    {\n        var merger = new ResizeParamMerger(null);\n\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/ResizeParamsBestWh.cs",
    "content": "﻿using ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Images.Sys.ResizeSettings;\nusing ToSic.Sys.GetByName;\n\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\n\npublic class ResizeParamsBestWh(LinkImageTestHelper helper)//: LinkImageTestBase\n{\n\n\n    const int s = 1440; // standard value, divisible by 1/2/3/4/6/12\n\n    [Fact]\n    public void FigureOutBestWidthAndHeight()\n    {\n        // All Zero and Nulls\n        True(TestBestWH(0, 0), \"Null everything\");\n        True(TestBestWH(0, 0, 0), \"Null everything\");\n        True(TestBestWH(0, 0, 0, 0), \"Null everything\");\n        True(TestBestWH(0, 0, 0, 0, 0), \"Null everything\");\n        True(TestBestWH(0, 0, 0, 0, 0, 0), \"Null everything\");\n\n        // Single Aspect is set\n        True(TestBestWH(s, 0, width: s), \"W only\");\n        True(TestBestWH(0, s, height: s), \"H only\");\n        True(TestBestWH(0, 0, factor: 7), \"factor only\");\n        True(TestBestWH(0, 0, ar: 7), \"ar only\");\n\n        // H / W\n        True(TestBestWH(s, s, width: s, height: s), \"W & H only\");\n    }\n\n\n    // W / Factor - factor should apply now 13.03\n    [InlineData(s, 0, s, 1, \"W/F only\")]\n    [InlineData(s * .5, 0, s, .5, \"W/F only\")]\n    [InlineData(s * 2, 0, s, 2, \"W/F only\")]\n    [InlineData(s * 1.5, 0, s, 1.5, \"W/F only\")]\n    [Theory]\n    public void FigureOutBestWidthAndHeight_Width(double expW, int expH, int w, double f, string name) \n        => True(TestBestWH((int)expW, expH, width: w, factor: f), name);\n\n    // H / W / Factor - factor should  apply now 13.03\n    [InlineData(s, s, 1, \"W/H/F\")]\n    [InlineData(s * 0.5, s, .5, \"W/H/F\")]\n    [InlineData(s * 2, s, 2, \"W/H/F\")]\n    [InlineData(s * 1.5, s, 1.5, \"W/H/F\")]\n    [Theory]\n    public void FigureOutBestWidthAndHeight_Square(double exp, int x, double f, string name) \n        => True(TestBestWH((int)exp, (int)exp, width: x, height: x, factor: f), name);\n\n\n    // W / Factor - factor should apply now 13.03\n    [InlineData(s, 0, s, 1, \"W/F only\")]\n    [InlineData(s * .5, 0, s, .5, \"W/F only\")]\n    [InlineData(s * 2, 0, s, 2, \"W/F only\")]\n    [InlineData(s * 1.5, 0, s, 1.5, \"W/F only\")]\n    [Theory]\n    public void FigureOutBestWidthAndHeight_Height(double expH, int expW, int h, double f, string name) \n        => True(TestBestWH(expW, (int)expH, height: h, factor: f), \"H/F only\");\n\n    [Fact]\n    public void FigureOutBestWidthAndHeight_SettingsWH()\n    {\n        True(TestBestWH(s, 0, settings: helper.ToDyn(new { Width = s })), \"W only\");\n        True(TestBestWH(0, s, settings: helper.ToDyn(new { Height = s })), \"H only\");\n        True(TestBestWH(0, 0, settings: helper.ToDyn(new { })), \"No params\");\n        True(TestBestWH(s, s, settings: helper.ToDyn(new { Width = s, Height = s })), \"W/H params\");\n    }\n\n\n    [Fact]\n    public void FigureOutBestWH_SettingsWithNeutralizer()\n    {\n        True(TestBestWH(0, 0, 0, null, null, null, helper.ToDyn(new { Width = 700 })));\n    }\n\n    [InlineData(0, 1, \"Factor 0, result 1\")]\n    [InlineData(1, 1, \"Factor 1, result 1\")]\n    [InlineData(2, 2, \"Factor 2, result 2\")]\n    [InlineData(0.5, 0.5, \"Factor / result 0.5\")]\n    [Theory]\n    public void FigureOutBestWidthAndHeight_SettingsWHF(double factor, double fResult, string name)\n    {\n        Console.WriteLine(\"Run with Factor: \" + factor + $\"; start-value is {s}\");\n        // Factor 1\n        True(TestBestWH((int)(fResult * s), 0, factor: factor, settings: helper.ToDyn(new { Width = s })), $\"Calc W with f:{factor}\");\n        True(TestBestWH(0, (int)(fResult * s), factor: factor, settings: helper.ToDyn(new { Height = s })), $\"Calc H with f:{factor}\");\n        True(TestBestWH(0, 0, factor: factor, settings: helper.ToDyn(new { })), $\"No params - f shouldn't have an effect f:{factor}\");\n        True(TestBestWH((int)(fResult * s), (int)(fResult * s), factor: factor, settings: helper.ToDyn(new { Width = s, Height = s })), $\"Calc W and H in settings with f:{factor}\");\n    }\n\n\n    internal static bool TestBestWH(int expW, int expH, object? width = null, object? height = null, object? factor = null, object? ar = null, ICanGetByName? settings = null)\n    {\n        // Get a new linker for each test run\n        var paramMerger = new ResizeParamMerger(null);\n        var dimGen = new ResizeDimensionGenerator();\n\n        var resizeSettings = paramMerger.BuildCoreSettings(new(null), width, height, factor, ar, null, settings);\n        var t1 = dimGen.ResizeDimensions(resizeSettings, resizeSettings.Find(SrcSetType.Img, true, null));\n        var okW = expW.Equals(t1.Width);\n        var okH = expH.Equals(t1.Height);\n        var ok = okW && okH;\n        Console.WriteLine((ok ? \"ok\" : \"error\") + \"; W:\" + t1.Width + (okW ? \"==\": \"!=\") + expW + \"; H:\" + t1.Width + (okH ? \"==\" : \"!=\") + expH);\n        return ok;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkImageTests/Startup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.LinksAndImages.LinkImageTests;\n\npublic class Startup: StartupSxcCoreOnly\n{\n    public override void ConfigureServices(IServiceCollection services) =>\n        base.ConfigureServices(services.AddTransient<LinkImageTestHelper>());\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/LinkToBasicTests.cs",
    "content": "﻿using ToSic.Sxc.LinksAndImages.LinkHelperTests;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Link.Sys;\n\nnamespace ToSic.Sxc.LinksAndImages;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LinkToBasicTests(ILinkService Link)\n{\n    [Fact]\n    public void NormalPage()\n    {\n        Equal($\"{LinkServiceUnknown.DefRoot}/page0\", Link.ToTac(pageId: 0));\n        Equal($\"{LinkServiceUnknown.DefRoot}/page27\", Link.ToTac(pageId: 27));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/LinksAndImages/ParametersTestExtensions.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Web.Sys.Url;\nusing Parameters = ToSic.Sxc.Context.Sys.Parameters;\n\nnamespace ToSic.Sxc.LinksAndImages;\n\ninternal static class ParametersTestExtensions\n{\n    public static IParameters NewParameters(NameValueCollection originals) => new Parameters { Nvc = originals };\n\n    public static IParameters AsParameters(this NameValueCollection originals) => new Parameters { Nvc = originals };\n\n    public static IParameters AsParameters(this string originals) => UrlHelpers.ParseQueryString(originals).AsParameters();\n\n    public static IParameters TestAdd(this IParameters p, string key) => p.Add(key);\n\n    public static IParameters TestAdd(this IParameters p, string key, string value) => p.Add(key, value);\n\n    public static IParameters TestAdd(this IParameters p, string key, object value) => p.Add(key, value);\n\n    public static IParameters TestRemove(this IParameters p, string name) => p.Remove(name);\n\n    public static IParameters TestRemove(this IParameters p, string name, object value) => p.Remove(name, value);\n\n    public static IParameters TestSet(this IParameters p, string name) => p.Set(name);\n    public static IParameters TestSet(this IParameters p, string name, string value) => p.Set(name, value);\n\n    public static IParameters TestSet(this IParameters p, string name, object value) => p.Set(name, value);\n\n    public static IParameters TestToggle(this IParameters p, string name, object value) => p.Toggle(name, value);\n    public static IParameters TestFilter(this IParameters p, string names) => p.Filter(names);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/Mocks/ExecutionContextMock.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Apps;\nusing ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;\n\nnamespace ToSic.Sxc.Mocks;\npublic class ExecutionContextMock : ExecutionContext\n{\n    public ExecutionContextMock(App app, Dependencies services) : base(services, \"Mck\")\n    {\n        app.Init(null, KnownAppsConstants.PresetIdentity.PureIdentity(), null);\n        AttachApp(app);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CacheTests/CacheKeyForElevationTests.cs",
    "content": "﻿using ToSic.Sxc.Services.Cache.Sys.CacheKey;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.ServicesTests.CacheTests;\npublic class CacheKeyForElevationTests\n{\n    #region Setup / Helpers\n\n    private const int OneMinute = 60;\n    private const int TwoMinutes = 120;\n\n    private static List<UserElevation> UserElevations =>\n        Enum.GetValues(typeof(UserElevation)).Cast<UserElevation>().ToList();\n\n    private static Dictionary<UserElevation, int> GetElevationsForOne(UserElevation elevation, int time) =>\n        new() { { elevation, time } };\n\n    private void AllMatchIsEnabledFor(Dictionary<UserElevation, int> dic, IEnumerable<UserElevation> elevations, bool expected)\n    {\n        foreach (var elevation in elevations)\n            Equal(expected, dic.IsEnabledFor(elevation));\n    }\n\n    private void AllMatchIsEnabledForExact(Dictionary<UserElevation, int> dic, IEnumerable<UserElevation> elevations, bool? expected)\n    {\n        foreach (var elevation in elevations)\n            Equal(expected, dic.IsEnabledForExact(elevation));\n    }\n\n    #endregion\n\n    [Fact]\n    public void EmptyEnabledForExactAlwaysNull() =>\n        AllMatchIsEnabledForExact(new(), UserElevations, null);\n\n    [Fact]\n    public void EmptyEnabledForAlwaysFalse() =>\n        AllMatchIsEnabledFor(new(), UserElevations, false);\n\n    [Fact]\n    public void ForSystemAdminTrueForSystemAdmin()\n    {\n        var dic = GetElevationsForOne(UserElevation.SystemAdmin, OneMinute);\n        True(dic.IsEnabledFor(UserElevation.SystemAdmin));\n    }\n\n    [Fact]\n    public void ForSystemAdminFalseForAllOthers() =>\n        AllMatchIsEnabledFor(\n            GetElevationsForOne(UserElevation.SystemAdmin, OneMinute),\n            UserElevations.Where(e => e != UserElevation.SystemAdmin),\n            false\n        );\n\n    [Fact]\n    public void SetExactSystemAdminEqualsForSystemAdmin()\n    {\n        var dic = GetElevationsForOne(UserElevation.SystemAdmin, OneMinute);\n        var empty = new Dictionary<UserElevation, int>()\n            .SetOne(UserElevation.SystemAdmin, OneMinute);\n        Equal(empty, dic);\n    }\n\n    [Fact]\n    public void SetExact2X()\n    {\n        var dic = GetElevationsForOne(UserElevation.SystemAdmin, OneMinute);\n        dic.Add(UserElevation.ContentEdit, TwoMinutes);\n        var empty = new Dictionary<UserElevation, int>()\n            .SetOne(UserElevation.SystemAdmin, OneMinute)\n            .SetOne(UserElevation.ContentEdit, TwoMinutes);\n        Equal(empty, dic);\n    }\n\n    [Theory]\n    [InlineData(CacheKeyConfig.Disabled, false)]\n    [InlineData(CacheKeyConfig.EnabledWithoutTime, true)]\n    [InlineData(OneMinute, true)]\n    public void ResetAll(int duration, bool expected) =>\n        AllMatchIsEnabledFor(ForElevationExtensions.ResetAll(duration), UserElevations, expected);\n\n    [Fact]\n    public void EnabledForAllExceptSystemAdmins()\n    {\n        var dic = ForElevationExtensions.ResetAll(OneMinute)\n            .SetOne(UserElevation.SystemAdmin, CacheKeyConfig.Disabled);\n\n        AllMatchIsEnabledFor(dic, UserElevations.Where(e => e != UserElevation.SystemAdmin), true);\n        False(dic.IsEnabledFor(UserElevation.SystemAdmin));\n    }\n\n    [Theory]\n    [InlineData(UserElevation.SystemAdmin,  false, true)]\n    [InlineData(UserElevation.ContentEdit,  false, true)]\n    [InlineData(UserElevation.Anonymous,   false,  true)]\n    [InlineData(UserElevation.All,  false, false)]\n    [InlineData(UserElevation.Unknown,  false, false)]\n    public void SetOneOrAll(UserElevation elevation, bool forOne, bool forRest)\n    {\n        var dic = ForElevationExtensions.ResetAll(OneMinute)\n            .SetForOneOrAll(elevation, CacheKeyConfig.Disabled);\n\n        AllMatchIsEnabledFor(dic, [elevation], forOne);\n        AllMatchIsEnabledFor(dic, UserElevations.Where(e => e != elevation), forRest);\n    }\n\n    [Fact]\n    public void DisableRangeEditToSysAdmin()\n    {\n        var dic = ForElevationExtensions.ResetAll(OneMinute)\n            .SetRange(UserElevation.ContentEdit, UserElevation.SystemAdmin, CacheKeyConfig.Disabled);\n        AllMatchIsEnabledFor(dic, UserElevations.Where(e => e < UserElevation.ContentEdit), true);\n        AllMatchIsEnabledFor(dic, UserElevations.Where(e => e >= UserElevation.ContentEdit), false);\n    }\n\n    [Fact]\n    public void DisableRangeInvalid() =>\n        Throws<ArgumentOutOfRangeException>(() =>\n            ForElevationExtensions.ResetAll(OneMinute)\n                .SetRange(UserElevation.ContentEdit, UserElevation.Anonymous, CacheKeyConfig.Disabled)\n        );\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CacheTests/CacheKeyTests.cs",
    "content": "﻿using ToSic.Sxc.Services.Cache.Sys.CacheKey;\nusing static ToSic.Sxc.Services.Cache.Sys.CacheServiceConstants;\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.ServicesTests.CacheTests;\n\npublic class CacheKeyTests\n{\n    internal const string FullDefaultPrefix = $\"{DefaultPrefix}{Sep}App:0{Sep}{SegmentPrefix}{DefaultSegment}{Sep}\";\n\n    [Theory]\n    [InlineData(null)]\n    [InlineData(\"\")]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void MainKeyBad(string main)\n        => Throws<ArgumentException>(() => Equal(FullDefaultPrefix + main, new CacheKeyParts { AppId = 0, Main = main }.GetKey()));\n\n    [Theory]\n    [InlineData(Sep + \"App:0\", 0, \"zero\")]\n    [InlineData(Sep + \"App:27\", 27, \"27\")]\n    [InlineData(Sep + \"App:42\", 42, \"42\")]\n    [InlineData(\"\", CacheKeyParts.NoApp, \"no app\")]\n    public void MainKeyAppIds(string expectedReplace, int appId, string message)\n        => Equal(FullDefaultPrefix.Replace(Sep + \"App:0\", expectedReplace) + \"Test\", new CacheKeyParts { AppId = appId, Main = \"Test\" }.GetKey());\n\n\n\n    [InlineData(\"TestKey\")]\n    [InlineData(\"A\")]\n    [InlineData(\"A\\nB\")]\n    [Theory]\n    public void MainKeyOnly(string main)\n        => Equal( FullDefaultPrefix + main, new CacheKeyParts{ AppId = 0, Main = main }.GetKey());\n\n    private const string FullSegmentPrefix = $\"{DefaultPrefix}{Sep}App:0{Sep}{SegmentPrefix}\";\n\n    [InlineData($\"{DefaultSegment}{Sep}Main\", \"Main\", null)]\n    [InlineData($\"{DefaultSegment}{Sep}Main\", \"Main\", \"\")]\n    [InlineData($\"MySegment{Sep}Main\", \"Main\", \"MySegment\")]\n    [Theory]\n    public void MainAndSegment(string expected, string main, string segment)\n        => Equal( FullSegmentPrefix + expected, new CacheKeyParts { AppId = 0, Main = main, RegionName = segment }.GetKey());\n\n\n    [Fact]\n    public void EnsureDicIsSorted()\n    {\n        var expected = $\"{Sep}A=AVal{Sep}B=BVal{Sep}C=CVal\";\n        var dic = new Dictionary<string, string>\n        {\n            { \"B\", \"BVal\" },\n            { \"A\", \"AVal\" },\n            { \"C\", \"CVal\" }\n        };\n        var resultDic1 = CacheKeyPartsExtensions.GetVaryByOfDic(dic);\n        Equal(expected, resultDic1);\n\n        var dic2 = new Dictionary<string, string>\n        {\n            { \"C\", \"CVal\" },\n            { \"A\", \"AVal\" },\n            { \"B\", \"BVal\" }\n        };\n        var resultDic2 = CacheKeyPartsExtensions.GetVaryByOfDic(dic2);\n        Equal(expected, resultDic2);\n        Equal(resultDic1, resultDic2);\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CacheTests/CacheSpecsTestAccessors.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Cache;\nusing ToSic.Sxc.Services.Cache.Sys;\nusing ToSic.Sxc.Services.Cache.Sys.CacheKey;\n\nnamespace ToSic.Sxc.ServicesTests.CacheTests;\n\ninternal static class CacheSpecsTestAccessors\n{\n    public static ICacheSpecs CreateSpecsTac(this ICacheService cacheSpecs, string key, NoParamOrder npo = default,\n        string? regionName = default, bool? shared = default)\n    {\n        var almost = (CacheSpecs)cacheSpecs.CreateSpecs(\n            key,\n            npo,\n            regionName,\n            shared: true /* pretend that shared is true, so it doesn't try to access the AppId */\n        );\n\n        // Simulate situation as if shared was specified originally, so it doesn't try to access the AppId\n        if (shared == null)\n            almost = almost with\n            {\n                CacheSpecsContextAndTools = almost.CacheSpecsContextAndTools with\n                {\n                    BaseKeyParts = almost.CacheSpecsContextAndTools.BaseKeyParts with\n                    {\n                        AppId = shared == null ? -1 : CacheKeyParts.NoApp,\n                    }\n                }\n            };\n        return almost;\n    }\n\n    public static ICacheSpecs VaryByParametersTac(this ICacheSpecs cacheSpecs, IParameters parameters, NoParamOrder npo = default, string? names = default, bool caseSensitive = false)\n        => cacheSpecs.VaryByParameters(parameters, npo, names, caseSensitive);\n\n    public static ICacheSpecs VaryByTac(this ICacheSpecs cacheSpecs, string name, string value, NoParamOrder npo = default, bool caseSensitive = false)\n        => cacheSpecs.VaryBy(name, value, npo, caseSensitive);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CacheTests/CacheSpecsTests.cs",
    "content": "﻿using ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Cache;\nusing ToSic.Sxc.Services.Cache.Sys.CacheKey;\nusing static ToSic.Sxc.Services.Cache.Sys.CacheServiceConstants;\nusing ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;\n\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.ServicesTests.CacheTests;\n\n[Startup(typeof(/*StartupSxcCoreOnly*/StartupSxcWithDb))]\npublic class CacheSpecsTests(ExecutionContext exCtx)\n{\n    private static readonly string MainPrefix = $\"{CacheKeyTests.FullDefaultPrefix.Replace(\"App:0\", \"App:-1\")}Main{Sep}\";\n\n    private ICacheService CacheSvc => exCtx.GetService<ICacheService>(reuse: true);\n\n    private string CurrentCultureCode => exCtx.GetService<Context.ICmsContext>(reuse: true).Culture.CurrentCode;\n\n    private ICacheSpecs GetForMain(string name = \"Main\") =>\n        CacheSvc.CreateSpecsTac(name);\n\n    [Fact]\n    public void ShareKeyAcrossApps()\n    {\n        var expected = $\"{CacheKeyTests.FullDefaultPrefix.Replace(Sep + \"App:0\", \"\")}Main\";\n        var specs = CacheSvc.CreateSpecsTac(\"Main\", shared: true);\n        Equal(expected, specs.Key);\n    }\n\n    [Fact]\n    public void VaryByCustom1CaseSensitive()\n    {\n        var expected = MainPrefix + \"VaryByKey1=Value1\";\n        var specs = CacheSvc.CreateSpecsTac(\"Main\")\n            .VaryByTac(\"Key1\", \"Value1\", caseSensitive: true);\n        Equal(expected, specs.Key);\n    }\n\n    [Fact]\n    public void VaryByCustom1()\n    {\n        var expected = MainPrefix + \"VaryByKey1=Value1\".ToLowerInvariant();\n        var specs = GetForMain()\n            .VaryByTac(\"Key1\", \"Value1\");\n        Equal(expected, specs.Key);\n    }\n\n    [Fact]\n    public void VaryByCustom2SameKey()\n    {\n        var expected = MainPrefix + \"VaryByKey1=Value1\".ToLowerInvariant();\n        var specs = GetForMain()\n            .VaryByTac(\"Key1\", \"valueWhichWillGoAway\")\n            .VaryByTac(\"Key1\", \"Value1\");\n        Equal(expected, specs.Key);\n    }\n\n    [Fact]\n    public void VaryByCustom2DiffKey()\n    {\n        var expected = MainPrefix + $\"VaryByKey1=Val1{Sep}VaryByKey2=Value2\".ToLowerInvariant();\n        var specs = GetForMain()\n            .VaryByTac(\"Key1\", \"Val1\")\n            .VaryByTac(\"Key2\", \"Value2\");\n        Equal(expected, specs.Key);\n    }\n\n    // Disabled for now, not sure if this single-value case is needed\n    //[Fact]\n    //public void VaryByCustom1ValueOnly()\n    //{\n    //    var expected = MainPrefix + \"VaryByThisIsTheValue=\".ToLowerInvariant();\n    //    var specs = GetForMain()\n    //        .VaryBy(\"ThisIsTheValue\");\n    //    Equal(expected, specs.Key);\n    //}\n\n    [Fact]\n    public void VaryByParameters()\n    {\n        var expected = MainPrefix + \"VaryByParameters=\".ToLowerInvariant();\n        var pars = new Parameters();\n        var specs = GetForMain().VaryByParametersTac(pars);\n        Equal(expected, specs.Key);\n    }\n\n    [Theory]\n    [InlineData(null, \"no names specified, use all\")]\n    [InlineData(\"\", \"empty names specified, use none\", \"\")]\n    [InlineData(\"A,B,C\", \"too many names\")]\n    [InlineData(\"A\", \"names with exact casing\")]\n    [InlineData(\"a\", \"names with different casing\")]\n    public void VaryByParametersOneNamed(string names, string testName, string? specialExpected = default)\n    {\n        var expected = MainPrefix + (\"VaryByParameters=\" + (specialExpected ?? \"A=AVal\")).ToLowerInvariant();\n        var pars = new Parameters\n        {\n            Nvc = new()\n            {\n                { \"A\", \"AVal\" }\n            }\n        };\n        var specs = GetForMain().VaryByParametersTac(pars, names: names);\n        Equal(expected, specs.Key);//, testName);\n    }\n\n\n    [Fact]\n    public void VaryByParametersWithNamesAll()\n    {\n        var expected = MainPrefix + \"VaryByParameters=A=AVal&B=BVal&C=CVal\".ToLowerInvariant();\n        var pars = new Parameters\n        {\n            Nvc = new()\n            {\n                { \"A\", \"AVal\" },\n                { \"B\", \"BVal\" },\n                { \"C\", \"CVal\" }\n            }\n        };\n        var specs = GetForMain().VaryByParametersTac(pars, names: \"A,B,c\");\n        Equal(expected, specs.Key);\n    }\n\n    [Fact]\n    public void VaryByParametersWithNamesSome()\n    {\n        var expected = MainPrefix + \"VaryByParameters=A=AVal&C=CVal\".ToLowerInvariant();\n        var pars = new Parameters\n        {\n            Nvc = new()\n            {\n                { \"A\", \"AVal\" },\n                { \"B\", \"BVal\" },\n                { \"C\", \"CVal\" }\n            }\n        };\n        var specs = GetForMain().VaryByParametersTac(pars, names: \"A,c\");\n        Equal(expected, specs.Key);\n    }\n\n    [Theory]\n    [InlineData(null, true)]\n    [InlineData(\"\", false)]\n    [InlineData(\"*\", true)]\n    public void VaryByParametersBlankSameAsNone(string? namesAll, bool shouldMatch)\n    {\n        var expected = MainPrefix + \"VaryByParameters=A=AVal&C=CVal\".ToLowerInvariant();\n        var pars = new Parameters\n        {\n            Nvc = new()\n            {\n                { \"A\", \"AVal\" },\n                { \"B\", \"\" },\n                { \"C\", \"CVal\" }\n            }\n        };\n        var specsFiltered = GetForMain().VaryByParametersTac(pars, names: \"A,c\");\n        var specsAll = GetForMain().VaryByParametersTac(pars, names: namesAll);\n        Equal(expected, specsFiltered.Key);\n        if (shouldMatch)\n            Equal(expected, specsAll.Key);\n        else\n            NotEqual(expected, specsAll.Key);\n    }\n\n    [Fact]\n    public void VaryByLanguage()\n    {\n        var expected = MainPrefix + $\"VaryByLanguage={CurrentCultureCode}\".ToLowerInvariant();\n        var specs = GetForMain().VaryByLanguage();\n        Equal(expected, specs.Key);\n    }\n\n    [Fact]\n    public void VaryByLanguageFromConfig()\n    {\n        var expected = MainPrefix + $\"VaryByLanguage={CurrentCultureCode}\".ToLowerInvariant();\n        var specs = GetForMain().RestoreAll(new(varyBy: \"language\"), new());\n        Equal(expected, specs.Key);\n    }\n\n    [Fact]\n    public void TestCacheKeys()\n    {\n        var key = \"TestKey\";\n        var previousKey = new CacheKeyParts { AppId = -1, Main = key }.GetKey();\n\n        var spec = GetForMain(key);\n        Equal(previousKey, spec.Key);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/CmsServiceTests.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.Data.Build;\nusing ToSic.Razor.Blade;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Services.Sys.Cms;\nusing ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService;\n\npublic class CmsServiceTests(ICodeDataFactory cdf, ExecutionContext exCtx, /*ICmsService cmsService,*/ DataForCmsServiceTests dataForCmsTests, CodeContentTypesManager ctDefFactory)\n    : IClassFixture<DoFixtureStartup<ScenarioFullPatronsWithDb>>\n{\n#if NETCOREAPP\n    [field: System.Diagnostics.CodeAnalysis.AllowNull, System.Diagnostics.CodeAnalysis.MaybeNull]\n#endif\n    public IContentType TstDataContentType => field ??= ctDefFactory.CreateTac<MockHtmlContentType>();\n\n    [Theory]\n    [InlineData(null, \"\", \"\")]\n    [InlineData(null, null, \"<div></div>\")]\n    [InlineData(\"\", \"\", \"\")]\n    [InlineData(\"\", null, \"<div></div>\")]\n    [InlineData(\"<p>some html</p>\", \"\", \"<p>some html</p>\")]\n    [InlineData(\"<p>some html</p>\", null, \"<div><p>some html</p></div>\")]\n    public void BasicCmsService(string html, string container, string expectedHtml)\n        => Equal(expectedHtml, CmsServiceShow(html, container).ToString());\n\n\n    public IHtmlTag CmsServiceShow(string someHtmlValue, string? container = default, IContentType? contentType = default)\n    {\n        const string someTextValue = \"Just Basic Text\";\n        var entity = dataForCmsTests.TstDataEntity(someTextValue, someHtmlValue, contentType);\n        var dynamicEntity = DynEntStrict(entity);\n        var dynamicField = dynamicEntity.Field(DataForCmsServiceTests.SomeHtmlField);\n        var cmsService = exCtx.GetService<ICmsService>();\n        return cmsService.Html(dynamicField, container: container);\n    }\n\n    public IDynamicEntity DynEntStrict(IEntity? entity = null) => cdf.AsDynamic(entity, new() { ItemIsStrict = true });\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/DataForCmsServiceTests.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.Data.Build;\nusing ToSic.Sxc.Adam;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService;\n\npublic class DataForCmsServiceTests(DataAssembler dataAssembler)\n{\n    public const int AppId = -1;\n    public const string SomeTextField = \"SomeText\";\n    public const string SomeHtmlField = \"SomeHtml\";\n\n    internal const string ImgExtension = \"png\";\n    internal const string ImageName = \"test.png\";\n    internal const string AltText = \"testing\";\n    internal const string ImageTag = $\"<img src='{ImageName}' data-cmsid='file:{ImageName}' class='wysiwyg-width1of5' alt='{AltText}'>\";\n\n    internal const string FolderName = \"TestFolder\";\n    internal const string FolderBase = \"/Portals/0/Adam/9876\";\n    internal const string FolderUrl = FolderBase + \"/TestFolder\";\n\n    internal static MockSxcFolder GenerateFolderWithTestPng()\n    {\n        var mockFile = new MockSxcFile\n        {\n            Extension = ImgExtension,\n            FullName = ImageName,\n            Url = $\"{FolderUrl}/{ImageName}\"\n        };\n        var folder = new MockSxcFolder\n        {\n            Name = FolderName,\n            Files = [mockFile],\n            Url = $\"{FolderUrl}/\",\n        };\n        return folder;\n    }\n\n    public IEntity TstDataEntity(string text = \"\", string html = \"\", IContentType? contentType = null)\n    {\n        var values = new Dictionary<string, object>\n        {\n            { SomeTextField, text },\n            { SomeHtmlField, html }\n        };\n        return dataAssembler.CreateEntityTac(appId: AppId, entityId: 1, contentType: contentType, values: values, titleField: SomeTextField);\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/DataForImgConversionTest.cs",
    "content": "﻿using static ToSic.Sxc.ServicesTests.CmsService.DataForCmsServiceTests;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService;\n\npublic class DataForImgConversionTest\n{\n    public static TheoryData<ImgConversionTest> ImageConversions =>\n    [\n        new()\n        {\n            AName = \"Basic test.png - found in folders\",\n            ImgName = ImageName,\n        },\n        new()\n        {\n            AName = \"Basic 123.png (no path) - NOT found in folders\",\n            ImgName = \"123.png\",\n        },\n        new()\n        {\n            AName = \"Basic 123.png (with path) - NOT found in folders\",\n            ImgName = \"123.png\",\n            Expected = $\"<picture class='wysiwyg-width1of5'><source type='image/png' srcset='{FolderUrl}/123.png'><img src='{FolderUrl}/123.png' class='wysiwyg-width1of5'></picture>\",\n        },\n        new()\n        {\n            AName = \"Basic with path\",\n            ImgName = \"img.png\",\n            ImgNameAndFolder = $\"{FolderUrl}/img.png\"\n        },\n        new()\n        {\n            AName = \"jpg with path\",\n            ImgName = \"img.jpg\",\n            ImgNameAndFolder = $\"{FolderUrl}/img.jpg\",\n            MimeType = \"image/jpeg\"\n        },\n        new()\n        {\n            AName = \"Extensive with tst.jpg\",\n            Original = $\"<img src='{FolderUrl}/tst.jpg' data-cmsid='file:tst.jpg' class='img-fluid' loading='lazy' alt='description' width='1230' height='760' style='width:auto;'>\",\n            Expected = $\"<picture class='img-fluid'><source type='image/jpeg' srcset='{FolderUrl}/tst.jpg?w=1230'><img src='{FolderUrl}/tst.jpg?w=1230' loading='lazy' height='760' alt='description' class='img-fluid' style='width:auto;'></picture>\",\n        }\n    ];\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/HtmlImgToPictureHelperTests.cs",
    "content": "﻿using ToSic.Sxc.Mocks;\nusing ToSic.Sxc.Services.Cms.Sys;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService;\n\npublic class HtmlImgToPictureHelperTests(ExecutionContextMock exCtxMock, ITestOutputHelper output)\n    // Needs fixture to load the Primary App\n    : IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n    /// <summary>\n    /// Must get service through executionContext, because the class is internal & it needs to have a parent CodeApiService for sub-dependencies\n    /// </summary>\n    private HtmlImgToPictureHelper GetHtmlImgToPictureHelper()\n        => exCtxMock.GetService<HtmlImgToPictureHelper>();\n\n    // needs a lot more tests, such as with / without paths, etc.\n    [Theory, MemberData(nameof(DataForImgConversionTest.ImageConversions), MemberType = typeof(DataForImgConversionTest))]\n    public void Test(ImgConversionTest conversion)\n    {\n        var parser = GetHtmlImgToPictureHelper();\n\n        var folder = DataForCmsServiceTests.GenerateFolderWithTestPng();\n\n        // These are necessary, as otherwise the test will automatically look up the \"Content\" settings for image resizing\n        // which would result in a different result.\n        // TODO: ALSO create a test which uses null, and expects the proper resized with default settings\n        var fakeEmptySettings = new object();\n\n        var result = parser\n            .ConvertImgToPicture(conversion.Original, folder, fakeEmptySettings)\n            .ToString();\n\n        NotNull(result);\n\n        output.WriteLine($\"Original: {conversion.Original}\");\n        output.WriteLine($\"Expected: {conversion.Expected}\");\n        output.WriteLine($\"Result: {result}\");\n\n        Equal(conversion.Expected, result);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/ImageExtractor/CmsServiceImageExtractorTestAccessors.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Services.Cms.Sys;\nusing static ToSic.Sxc.Services.Cms.Sys.CmsServiceImageExtractor;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService.ImageExtractor;\n\ninternal static class CmsServiceImageExtractorTestAccessors\n{\n    public static string GetImgServiceResizeFactorTac(string classAttribute)\n        => GetImgServiceResizeFactor(classAttribute);\n\n    public static string GetPictureClassesTac(string classAttribute)\n    => GetPictureClasses(classAttribute);\n\n    public static bool UseLightboxTac(string classAttribute)\n        => UseLightbox(classAttribute);\n\n    public static ImagePropertiesExtracted ExtractImagePropertiesTac( this CmsServiceImageExtractor extractor, string imgTag, IFolder folder)\n        => extractor.ExtractImageProperties(imgTag, folder);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/ImageExtractor/CmsServiceImageExtractorTests.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Services.Cms.Sys;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService.ImageExtractor;\n\npublic class CmsServiceImageExtractorTests(IServiceProvider sp)\n{\n    /// <summary>\n    /// Must get it like this, because the extractor is internal.\n    /// </summary>\n    private CmsServiceImageExtractor GetExtractor() => sp.Build<CmsServiceImageExtractor>();\n\n    private (IFolder Folder, CmsServiceImageExtractor.ImagePropertiesExtracted Properties) GetFolderAndProperties(string imgTag)\n    {\n        var folder = DataForCmsServiceTests.GenerateFolderWithTestPng();\n        var properties = GetExtractor().ExtractImagePropertiesTac(imgTag, folder);\n        return (folder, properties);\n    }\n\n    [Fact]\n    public void ExtractorGetsData()\n    {\n        var (_, props) = GetFolderAndProperties(DataForCmsServiceTests.ImageTag);\n        NotNull(props);\n        Equal(DataForCmsServiceTests.AltText, props.ImgAlt);\n    }\n\n    [Fact]\n    public void FindFileInFolder()\n    {\n        var (folder, props) = GetFolderAndProperties(DataForCmsServiceTests.ImageTag);\n        NotNull(props.File);\n        Equal(folder.Files.First(), props.File);\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/ImageExtractor/ExtractorPartsTests.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.HtmlParsing;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService.ImageExtractor;\n\npublic class ExtractorPartsTests\n{\n    [Theory]\n    [InlineData(\"css\", null)]\n    [InlineData(\"wysiwyg-75\", \"3/4\")]\n    [InlineData(\"wysiwyg-width of5\", null)]\n    [InlineData(\"class1   WYSIWYG-66 class3 wysiwyg-width1of5\", \"2/3\")]\n    [InlineData(\"wysiwyg-7\", \"7\")]//, DisplayName = \"odd unprepared number\")]\n    public void GetFactor(string classAttribute, string expectedFactor)\n        => Equal(expectedFactor, CmsServiceImageExtractorTestAccessors.GetImgServiceResizeFactorTac(classAttribute));\n\n    [Theory]\n    [InlineData(\"<p>some html</p>\", 0)]\n    [InlineData(\"<p><img bbb='cccccc'><img/><IMG aaa data-cmsid='xxx'/><iMG     data-cmsid='yyy'  QQQ=\\\"abc\\\"  ></p>\", 2)]\n    public void ImagesWithDataCmsid(string html, int matches)\n        => Equal(matches, RegexUtil.ImagesDetection.Value.Matches(html).Count);\n\n    [Theory]\n    [InlineData(\"wysiwyg-lightbox\", true)]\n    [InlineData(\"wysiwyg-lightbox other-class\", true)]\n    [InlineData(\"other-class wysiwyg-lightbox\", true)]\n    [InlineData(\"other-class\", false)]\n    [InlineData(null, false)]\n    public void UseLightbox(string classAttribute, bool expected)\n        => Equal(expected, CmsServiceImageExtractorTestAccessors.UseLightboxTac(classAttribute));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/ImgConversionTest.cs",
    "content": "﻿namespace ToSic.Sxc.ServicesTests.CmsService;\n\npublic class ImgConversionTest\n{\n    public string AName { get; init; } = \"todo\";\n\n    public string ImgName { get; init; } = DataForCmsServiceTests.ImageName;\n\n#if NETCOREAPP\n    [field: System.Diagnostics.CodeAnalysis.AllowNull, System.Diagnostics.CodeAnalysis.MaybeNull]\n#endif\n    public string ImgNameAndFolder\n    {\n        get => field ??= $\"{DataForCmsServiceTests.FolderUrl}/{ImgName}\";\n        init;\n    }\n\n    public string ImgClass { get; init; } = \"wysiwyg-width1of5\";\n\n    public string MimeType { get; init; } = \"image/png\";\n\n#if NETCOREAPP\n    [field: System.Diagnostics.CodeAnalysis.AllowNull, System.Diagnostics.CodeAnalysis.MaybeNull]\n#endif\n    public string Original\n    {\n        get => field ??= $\"<img src='{ImgNameAndFolder}' data-cmsid='file:{ImgName}' class='{ImgClass}'>\";\n        init;\n    }\n\n#if NETCOREAPP\n    [field: System.Diagnostics.CodeAnalysis.AllowNull, System.Diagnostics.CodeAnalysis.MaybeNull]\n#endif\n    public string Expected\n    {\n        get => field ??=\n            $\"<picture class='{ImgClass}'><source type='{MimeType}' srcset='{ImgNameAndFolder}'><img src='{ImgNameAndFolder}' class='{ImgClass}'></picture>\";\n        init;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/MockHtmlContentType.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Sxc.Data.Sys;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService;\n\npublic class MockHtmlContentType\n{\n    public string? SomeText { get; set; }\n\n    [ContentTypeAttributeSpecs(InputTypeWIP = InputTypes.InputTypeWysiwyg)]\n    public string? SomeHtml { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/Startup.cs",
    "content": "﻿namespace ToSic.Sxc.ServicesTests.CmsService;\n\npublic class Startup : StartupMockExecutionContext;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/CmsService/StringWysiwygTests.cs",
    "content": "﻿using ToSic.Eav.Data.Build;\nusing ToSic.Sxc.Data.Sys.Factory;\nusing ToSic.Sxc.Mocks;\nusing ToSic.Sxc.Services.Cms.Sys;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.ServicesTests.CmsService;\n\npublic class StringWysiwygTests(\n    ExecutionContextMock executionContext,\n    CodeContentTypesManager ctDefFactory,\n    DataForCmsServiceTests dataForCmsTests,\n    ICodeDataFactory cdf,\n    ITestOutputHelper output\n    )\n    // Needs fixture to load the Primary App\n    : IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n\n    // TODO: needs a lot more tests, such as with / without paths, etc.\n\n    /// <summary>\n    /// This test is almost identical to the <see cref=\"HtmlImgToPictureHelperTests\"/> but going through one more layer of objects.\n    /// The primary test should be there, this should just confirm that these simple setups create the same result.\n    /// </summary>\n    /// <param name=\"conversion\"></param>\n    [Theory, MemberData(nameof(DataForImgConversionTest.ImageConversions), MemberType = typeof(DataForImgConversionTest))]\n    public void ImageTagOnlyHasSameResultAsHtmlImgToPictureHelper(ImgConversionTest conversion)\n    {\n        // Must get service through codeApiSvc, because the class is internal & it needs to have a parent CodeApiService for sub-dependencies\n        var parser = executionContext.GetService<CmsServiceStringWysiwyg>();\n\n        var ctWithHtmlField = ctDefFactory.CreateTac<MockHtmlContentType>();\n\n        var attribute = ctWithHtmlField.Attributes\n            .First(a => a.Name == nameof(MockHtmlContentType.SomeHtml));\n\n        var data = dataForCmsTests.TstDataEntity(\"hello\", conversion.Original, ctWithHtmlField);\n        var typed = cdf.AsItem(data, new() { ItemIsStrict = true });\n        var field = typed.Field(nameof(MockHtmlContentType.SomeHtml))!;\n\n        var folder = DataForCmsServiceTests.GenerateFolderWithTestPng();\n\n        // These are necessary, as otherwise the test will automatically look up the \"Content\" settings for image resizing\n        // which would result in a different result.\n        // TODO: ALSO create a test which uses null, and expects the proper resized with default settings\n        var fakeEmptySettings = new object();\n\n        parser.Init(field, ctWithHtmlField, attribute, folder, false, fakeEmptySettings);\n\n        var result = parser.HtmlForStringAndWysiwyg(conversion.Original);\n\n        NotNull(result);\n\n        output.WriteLine($\"Expected: {conversion.Expected}\");\n        output.WriteLine($\"Result: {result.Contents}\");\n\n        Equal(conversion.Expected, result.Contents);\n    }\n\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ConvertService/ConvertServiceTest.cs",
    "content": "﻿using System.Globalization;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.ConvertService;\n\n/// <summary>\n/// Note: there are not many tests here, because the true engine is in the EAV conversion system which is tested very thoroughly already\n/// </summary>\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class ConvertServiceTest(IConvertService convertSvc)\n{\n    private const string StrGuid = \"424e56ce-570a-4747-aee2-44c04caf7f12\";\n    private static readonly Guid ExpGuid = new(StrGuid);\n    [Fact] public void ToGuidNull() => Equal(Guid.Empty, convertSvc.ToGuid(null));\n    [Fact] public void ToGuidEmpty() => Equal(Guid.Empty, convertSvc.ToGuid(\"\"));\n    [Fact] public void ToGuidBasic() => Equal(ExpGuid, convertSvc.ToGuid(StrGuid));\n    [Fact] public void ToGuidFallback() => Equal(ExpGuid, convertSvc.ToGuid(\"\", ExpGuid));\n\n    [Fact]\n    public void ForCodeDate() \n        => Equal(\"2021-09-29T08:45:59.000z\", convertSvc.ForCode(new DateTime(2021, 09, 29, 08, 45, 59)));\n\n    [Fact]\n    public void ForCodeBool()\n    {\n        Equal(\"true\", convertSvc.ForCode(true));\n        NotEqual(true.ToString(), convertSvc.ForCode(true));\n        Equal(\"false\", convertSvc.ForCode(false));\n    }\n\n    [Fact]\n    public void ForCodeNumberBadCulture()\n    {\n        // Now change threading culture to a comma-culture and verify that change happened\n        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(\"de-DE\");\n        Equal(\"1,11\", 1.11.ToString());\n\n        // Now run tests expecting things to \"just-work\"\n        var conv = convertSvc;\n        Equal(\"0\", conv.ForCode(\"0\"));\n        Equal(\"1.11\", conv.ForCode(1.11f));\n        Equal(\"27.42\", conv.ForCode(27.42));\n        Equal(\"-27.42\", conv.ForCode(-27.42));\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/FactorMapTests.cs",
    "content": "﻿namespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n// 2022-03-15 2dm disabled - factor maps don't work like this, will probably stick to json format\n//[TestClass]\n//public class FactorMapTests\n//{\n//    [InlineData(null, \"null\")]\n//    [InlineData(\"\", \"empty string\")]\n//    [InlineData(\"   \", \"spaces\")]\n//    [InlineData(\"   \\n  \", \"spaces and new lines\")]\n//    [InlineData(\"   \\r\\n  \", \"spaces and new lines\")]\n//    [InlineData(\"0.5\", \"factor, no value\")]\n//    [InlineData(\"=500\", \"value, no factor\")]\n//    [InlineData(\"0.5:500\", \"bad separator\")]\n//    [InlineData(\"x=500\", \"invalid factor\")]\n//    [InlineData(\"1=2=600\", \"multi :\")]\n//    [Theory]\n\n//    public void EmptyAndInvalidMaps(string original, string name)\n//    {\n//        var fm = FactorMapHelper.CreateFromString(original);\n//        Assert.NotNull(fm);\n//        Assert.Equal(0, fm.Length, name);\n//    }\n\n\n//    [InlineData(\"0.5=600\", \"double\")]\n//    [InlineData(\"1/2=600\", \"/\")]\n//    [InlineData(\"1:2=600\", \":\")]\n//    [InlineData(\" 1 / 2=600\", \"/ with spaces\")]\n//    [Theory]\n//    public void Simple(string original, string name)\n//    {\n//        var fm = FactorMapHelper.CreateFromString(original);\n//        Assert.Equal(1, fm.Length, name);\n//        AssertFandW(0.5, 600, fm[0], name);\n//    }\n\n//    [InlineData(\"x\\n0.5=600\", \"double\")]\n//    [InlineData(\"0.5=600\\nx=500\", \"double\")]\n//    [InlineData(\"1/2=600\\n=500\", \"/\")]\n//    [InlineData(\" 1 / 2=600\\n0.5\", \"/ with spaces\")]\n//    [InlineData(\"x\\n0.5\\n1\\n:500\\n0.5=600\\n22\", \"double\")]\n//    [Theory]\n//    public void OneGoodRestBad(string original, string name)\n//    {\n//        var fm = FactorMapHelper.CreateFromString(original);\n//        Assert.Equal(1, fm.Length, name);\n//        AssertFandW(0.5, 600, fm[0], name);\n//    }\n\n//    private static void AssertFandW(double expectedF, int expectedW, FactorRule fm, string name)\n//    {\n//        Assert.Equal(expectedF, fm.Factor, name);\n//        Assert.Equal(expectedW, fm.Width, name);\n//    }\n\n\n//    [InlineData(\"0.5=600;1x,2x\", \"1x,2x\", \"double\")]\n//    [InlineData(\"1/2=600\", \"\", \"/\")]\n//    [InlineData(\"1:2=600\", \"\", \":\")]\n//    [InlineData(\" 1 / 2=600\", \"\", \"/ with spaces\")]\n//    [Theory]\n//    public void WithSrcMap(string original, string srcSet, string name)\n//    {\n//        var fm = FactorMapHelper.CreateFromString(original);\n//        Assert.Equal(1, fm.Length, name);\n//        AssertFandW(0.5, 600, fm[0], name);\n//        Assert.Equal(srcSet, fm[0].SrcSet, name + \" srcSet\");\n//    }\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceAttributes.cs",
    "content": "﻿using ToSic.Sxc.Mocks;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n[Startup(typeof(StartupMockExecutionContext))]\npublic class ImageServiceAttributes(ExecutionContextMock executionContext)\n    // Needs fixture to load the Primary App\n    : IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n    //[field: AllowNull, MaybeNull]\n    private IImageService ImgSvc => field ??= executionContext.GetService<IImageService>(reuse: true);\n\n    /// <summary>\n    /// \n    /// </summary>\n    /// <param name=\"Name\">Test name</param>\n    /// <param name=\"Expected\">Expected result</param>\n    /// <param name=\"OnCall\">Parameter to use when calling .Picture() or .Img() </param>\n    /// <param name=\"OnRecipe\">Parameter to use when calling with recipe...</param>\n    /// <param name=\"useRecipe\"></param>\n    public record TestCase(string Name, string Expected, string OnCall, string? OnRecipe = default, bool useRecipe = false)\n    {\n        public readonly bool UseRecipe = useRecipe || OnRecipe != null;\n\n        public override string ToString() => $\"Test: '{Name}\";\n    }\n\n    private static readonly List<TestCase> TestCasesClass =\n    [\n        new(\"Call Only\", \"class='img-class'\", \"img-class\"),\n        new(\"Call Only multiple\", \"class='img-class img-class2'\", \"img-class img-class2\"),\n        new(\"Call only, recipe null\", \"class='img-class'\", \"img-class\", useRecipe: true),\n        new(\"Call only, recipe empty\", \"class='img-class'\", \"img-class\", useRecipe: true, OnRecipe: \"\"),\n        new(\"recipe only\", \"class='rec-class'\", null, OnRecipe: \"rec-class\"),\n        new(\"Call and recipe\", \"class='img-class rec-class'\", \"img-class\", useRecipe: true,\n            OnRecipe: \"rec-class\")\n    ];\n\n    public static TheoryData<TestCase> TestDataImgClass { get; } = [..TestCasesClass];\n\n    [Theory]\n    [MemberData(nameof(TestDataImgClass))]\n    public void TestClassImg(TestCase test)\n    {\n        var recDic = new Dictionary<string, object> { { \"class\", test.OnRecipe } };\n        var recipe = test.UseRecipe\n            ? ImgSvc.Recipe(null, attributes: recDic)\n            : null;\n        // Classic API\n        var pic = ImgSvc.Picture(\"dummy.jpg\", imgClass: test.OnCall, recipe: recipe);\n        True(pic.Img.ToString().Contains(test.Expected), $\"{test}: {pic.Img}\");\n\n        // New Tweak API\n        var picTweak = ImgSvc.Picture(\"dummy.jpg\", tweak: t => t.ImgClass(test.OnCall), recipe: recipe);\n        Equal(pic.Img.ToString(), picTweak.Img.ToString());//, $\"Should be identical for tweak {test}\");\n    }\n\n    public static TheoryData<TestCase> TestDataPicClass { get; } = [..TestCasesClass.Where(t => !t.UseRecipe)];\n    [Theory]\n    [MemberData(nameof(TestDataPicClass))]\n    public void TestClassPic(TestCase test)\n    {\n        var pic = ImgSvc.Picture(\"dummy.jpg\", pictureClass: test.OnCall);\n        True(pic.ToString().Contains(test.Expected), $\"{test}: {pic.Picture}\");\n        False(pic.Img.ToString().Contains(test.Expected), $\"{test}: {pic.Img}\");\n\n        // New Tweak API\n        var picTweak = ImgSvc.Picture(\"dummy.jpg\", tweak: t => t.PictureClass(test.OnCall));\n        Equal(pic.ToString(), picTweak.ToString());//, $\"Should be identical for tweak {test}\");\n    }\n\n\n    private static readonly List<TestCase> TestCasesStyles =\n    [\n        new(\"Call Only\", \"style='img-style: 50px'\", \"img-style: 50px\"),\n        new(\"Call Only multiple\", \"style='img-style: 50px; width: 10px'\", \"img-style: 50px; width: 10px\"),\n        new(\"Call only, recipe null\", \"style='img-style: 50px'\", \"img-style: 50px\", useRecipe: true),\n        new(\"Call only, recipe empty\", \"style='img-style: 50px'\", \"img-style: 50px\", useRecipe: true, OnRecipe: \"\"),\n        new(\"recipe only\", \"style='rec-style: 20px'\", null, OnRecipe: \"rec-style: 20px\"),\n        new(\"Call and recipe\", \"style='img-style: 50px;rec-style: 20px'\", \"img-style: 50px\",\n            useRecipe: true,\n            OnRecipe: \"rec-style: 20px\")\n\n    ];\n\n    public static TheoryData<TestCase> TestDataImgStyle { get; } = [..TestCasesStyles];\n\n    [Theory]\n    [MemberData(nameof(TestDataImgStyle))]\n    public void TestImgStyleOnAttributes(TestCase test)\n    {\n        var callDic = new Dictionary<string, object> { { \"style\", test.OnCall} };\n        var recipeDic = new Dictionary<string, object> { { \"style\", test.OnRecipe } };\n        var recipe = test.UseRecipe ? ImgSvc.Recipe(null, attributes: recipeDic) : null;\n        var pic = ImgSvc.Picture(\"dummy.jpg\", imgAttributes: callDic, recipe: recipe);\n        // True(pic.ToString().Contains(expected), name + \": \" + pic);\n        True(pic.Img.ToString().Contains(test.Expected), $\"{test} (expected: {test.Expected}): {pic.Img}\");\n\n        // New Tweak API\n        var picTweak = ImgSvc.Picture(\"dummy.jpg\", tweak: t => t.ImgAttributes(callDic), recipe: recipe);\n        Equal(pic.ToString(), picTweak.ToString());//, $\"Should be identical for tweak {test}\");\n    }\n\n    public static TheoryData<TestCase> TestDataPicStyle { get; } = [..TestCasesStyles.Where(t => !t.UseRecipe)];\n    [Theory]\n    [MemberData(nameof(TestDataPicStyle))]\n    public void TestStylePic(TestCase test)\n    {\n        var callDic = new Dictionary<string, object> { { \"style\", test.OnCall } };\n        //var recipeDic = new Dictionary<string, object> { { \"style\", test.OnRecipe } };\n        //var recipe = test.UseRecipe ? imgSvc.Recipe(null, attributes: recipeDic) : null;\n        var pic = ImgSvc.Picture(\"dummy.jpg\", pictureAttributes: callDic);\n        True(pic.ToString().Contains(test.Expected), $\"{test} (expected '{test.Expected}'): {pic.Picture}\");\n        False(pic.Img.ToString().Contains(test.Expected), $\"{test} (expected '{test.Expected}'): {pic.Img}\");\n\n        // New Tweak API\n        var picTweak = ImgSvc.Picture(\"dummy.jpg\", tweak: t => t.PictureAttributes(callDic));\n        Equal(pic.ToString(), picTweak.ToString());//, $\"Should be identical for tweak {test}\");\n    }\n\n\n    private const string ImageAttributesStyleValue = \"some: 50px\";\n    private void ImageAttributes(object callDic)\n    {\n        const string expected = \"style='some: 50px\";\n        var pic = ImgSvc.Picture(\"dummy.jpg\", imgAttributes: callDic);\n        True(pic.Img.ToString().Contains(expected), $\"expected: {expected}: {pic.Img}\");\n\n        // New Tweak API\n        var picTweak = ImgSvc.Picture(\"dummy.jpg\", tweak: t => t.ImgAttributes(callDic));\n        Equal(pic.ToString(), picTweak.ToString());//, $\"Should be identical for tweak {callDic}\");\n    }\n\n    [Fact]\n    public void ImageAttributesDicStringObj() => \n        ImageAttributes(new Dictionary<string, object> { { \"style\", ImageAttributesStyleValue } });\n    [Fact]\n    public void ImageAttributesDicStringObjCasing() => \n        ImageAttributes(new Dictionary<string, object> { { \"Style\", ImageAttributesStyleValue } });\n\n\n    [Fact]\n    public void ImageAttributesDicStringString() => \n        ImageAttributes(new Dictionary<string, string> { { \"style\", ImageAttributesStyleValue } });\n    [Fact]\n    public void ImageAttributesDicStringStringCasing() => \n        ImageAttributes(new Dictionary<string, string> { { \"Style\", ImageAttributesStyleValue } });\n\n    [Fact]\n    public void ImageAttributesAnonymous() => \n        ImageAttributes(new { style = ImageAttributesStyleValue } );\n    [Fact]\n    public void ImageAttributesAnonymousCamelCase() => \n        ImageAttributes(new { Style = ImageAttributesStyleValue } );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceFormatsBase.cs",
    "content": "﻿using ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic abstract partial  class ImageServiceFormatsBase(IImageService imgSvc)\n{\n    [Theory]\n    [InlineData(\"test.png\")]\n    [InlineData(\".png\")]\n    [InlineData(\"png\")]\n    [InlineData(\"PNG\")]\n    [InlineData(\"test.png?w=2000\")]\n    [InlineData(\"/abc/test.png\")]\n    [InlineData(\"/abc/test.png?w=2000\")]\n    [InlineData(\"//domain.com/abc/test.png\")]\n    [InlineData(\"https://domain.com/abc/test.png\")]\n    public void TestPng(string path)\n    {\n        var fileInfo = imgSvc.GetFormatTac(path);\n        AssertOneFileInfo(ImageConstants.Png, fileInfo);\n    }\n\n\n    [Theory]\n    [InlineData(\"//domain.com/abc/test.jpg\")]\n    [InlineData(\"//domain.com/abc/test.jpeg\")]\n    public void TestJpg(string path)\n    {\n        var fileInfo = imgSvc.GetFormatTac(path);\n        AssertOneFileInfo(ImageConstants.Jpg, fileInfo);\n    }\n\n    [Theory]\n    [InlineData(\"docx\", \"docx\")]\n    [InlineData(\".docx\", \"docx\")]\n    [InlineData(\".x\", \"x\")]\n    public void TestUnknown(string path, string expected)\n    {\n        var typeInfo = imgSvc.GetFormatTac(path);\n        AssertUnknownFileInfo(expected, typeInfo);\n    }\n\n    private static void AssertUnknownFileInfo(string expected, IImageFormat format)\n    {\n        NotNull(format);\n        Equal(expected, format.Format);\n        Equal(\"\", format.MimeType);\n    }\n\n    private static void AssertOneFileInfo(string expectedType, IImageFormat imageInfo)\n    {\n        NotNull(imageInfo);\n        Equal(expectedType, imageInfo.Format);\n        Equal(ImageConstants.FileTypes[expectedType].MimeType, imageInfo.MimeType);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceFormatsBase_Best.cs",
    "content": "﻿using ToSic.Sxc.Images.Sys;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\npublic abstract partial class ImageServiceFormatsBase\n{\n    protected abstract int ExpectedPngFormats { get; }\n\n    [InlineData(\"test.png\")]\n    [InlineData(\".png\")]\n    [InlineData(\"png\")]\n    [InlineData(\"PNG\")]\n    [InlineData(\"test.png?w=2000\")]\n    [InlineData(\"/abc/test.png\")]\n    [InlineData(\"/abc/test.png?w=2000\")]\n    [InlineData(\"//domain.com/abc/test.png\")]\n    [InlineData(\"https://domain.com/abc/test.png\")]\n    [Theory]\n    public void TestBestPng(string path)\n    {\n        var formats = imgSvc.GetResizeFormatTac(path);\n        NotNull(formats);\n        Equal(ExpectedPngFormats, formats.Count);\n        // If we have many, we expect that the original will be listed as the second alternative\n        if (formats.Count > 0)\n            AssertOneFileInfo(ImageConstants.Png, formats.Skip(1).First());\n    }\n\n    [InlineData(null)]\n    [InlineData(\"\")]\n    [InlineData(\" \")]\n    [Theory]\n    public void TestBestEmpty(string path)\n    {\n        var formats = imgSvc.GetResizeFormatTac(path);\n        NotNull(formats);\n        Equal(0, formats.Count);\n    }\n\n    [InlineData(\"https://domain.com/abc/test.avif\")]\n    [Theory]\n    public void TestBestUnknownAvif(string path)\n    {\n        var formats = imgSvc.GetResizeFormatTac(path);\n        NotNull(formats);\n        Equal(0, formats.Count);\n    }\n\n    [InlineData(\"https://domain.com/abc/test.svg?w=2000\")]\n    [Theory]\n    public void TestBestSvg(string path)\n    {\n        var formats = imgSvc.GetResizeFormatTac(path);\n        NotNull(formats);\n        Equal(0, formats.Count);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceFormatsNoPatron.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n[Startup(typeof(StartupSxcWithDbBasic))]\npublic class ImageServiceFormatsNoPatron(IImageService imgSvc)\n    : ImageServiceFormatsBase(imgSvc), IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n    protected override int ExpectedPngFormats => 0;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceFormatsPatronPerfectionist.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n[Startup(typeof(StartupSxcWithDbPatronPerfectionist))]\npublic class ImageServiceFormatsPatronPerfectionist(IImageService imgSvc)\n    : ImageServiceFormatsBase(imgSvc), IClassFixture<DoFixtureStartup<ScenarioFullPatronsWithDb>>\n{\n    protected override int ExpectedPngFormats => 2;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceResizeSettings.cs",
    "content": "﻿using ToSic.Sxc.Images;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Web.Sys.Url;\nusing Xunit.Sdk;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class ImageServiceResizeSettings(IImageService imgSvc) \n{\n    /// <summary>\n    /// Main internal test to see if the value is expected, and the rest of the values are not set.\n    /// </summary>\n    /// <typeparam name=\"T\"></typeparam>\n    /// <param name=\"settings\"></param>\n    /// <param name=\"name\"></param>\n    /// <param name=\"getValue\"></param>\n    /// <param name=\"expected\"></param>\n    private void EqualsAndRestEmpty<T>(IResizeSettings settings, string name, Func<IResizeSettings, T> getValue, T expected)\n    {\n        Equal(expected, getValue(settings));\n        AssertAllEmptyExceptSpecified(settings, name);\n    }\n\n    /// <summary>\n    /// Make sure the test setup would throw an error if the value doesn't match\n    /// </summary>\n    [Fact]\n    //[ExpectedException(typeof(AssertFailedException))]\n    public void VerifyTestValue() =>\n        Throws<EqualException>(() => EqualsAndRestEmpty(imgSvc.SettingsTac(width: 50), nameof(IResizeSettings.Width), s => s.Width, 100));\n\n    /// <summary>\n    /// Make sure the test setup would throw an error if the wrong ones are empty\n    /// </summary>\n    [Fact]\n    //[ExpectedException(typeof(AssertFailedException))]\n    public void VerifyTestRestEmpty() =>\n        Throws<EqualException>(() => EqualsAndRestEmpty(imgSvc.SettingsTac(width: 50), nameof(IResizeSettings.Height), s => s.Width, 100));\n\n    [Fact]\n    public void EmptyOnlyWidth_Param() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(width: 100), nameof(IResizeSettings.Width), s => s.Width, 100);\n\n    [Fact]\n    public void EmptyOnlyWidth_Tweak() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(tweak: t => t.Width(100)), nameof(IResizeSettings.Width), s => s.Width, 100);\n\n    [Fact]\n    public void EmptyOnlyWidth_Mix() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(width: 42, tweak: t => t.Width(100)), nameof(IResizeSettings.Width), s => s.Width, 100);\n\n    [Fact]\n    public void EmptyOnlyHeight_Params() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(height: 100), nameof(IResizeSettings.Height), s => s.Height, 100);\n\n    [Fact]\n    public void EmptyOnlyHeight_Tweak() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(tweak: t => t.Height(100)), nameof(IResizeSettings.Height), s => s.Height, 100);\n\n    [Fact]\n    public void EmptyOnlyFormat_Params() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(format: \"jpg\"), nameof(IResizeSettings.Format), s => s.Format, \"jpg\");\n\n    [Fact]\n    public void EmptyOnlyFormat_Tweak() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(tweak: t => t.Format(\"jpg\")), nameof(IResizeSettings.Format), s => s.Format, \"jpg\");\n\n    [Fact]\n    public void EmptyOnlyResizeMode_Params() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(resizeMode: ImageConstants.ModeCrop), nameof(IResizeSettings.ResizeMode), s => s.ResizeMode, ImageConstants.ModeCrop);\n\n    [Fact]\n    public void EmptyOnlyResizeMode_Tweak() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(tweak: t => t.ResizeMode(ImageConstants.ModeCrop)), nameof(IResizeSettings.ResizeMode), s => s.ResizeMode, ImageConstants.ModeCrop);\n\n    [Fact]\n    public void EmptyOnlyScaleMode_Params()\n    {\n        // todo: use constants for the final result\n        EqualsAndRestEmpty(imgSvc.SettingsTac(scaleMode: \"up\"), nameof(IResizeSettings.ScaleMode), s => s.ScaleMode, \"upscaleonly\");\n    }\n\n    [Fact]\n    public void EmptyOnlyScaleMode_Tweak()\n    {\n        // todo: use constants for the final result\n        EqualsAndRestEmpty(imgSvc.SettingsTac(tweak: t => t.ScaleMode(\"up\")), nameof(IResizeSettings.ScaleMode), s => s.ScaleMode, \"upscaleonly\");\n    }\n\n    [Fact]\n    public void EmptyOnlyParameters_Params() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(parameters: \"count=17\"), nameof(IResizeSettings.Parameters), s => s.Parameters.NvcToString(), \"count=17\");\n\n    [Fact]\n    public void EmptyOnlyParameters_Tweak() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(tweak: t => t.Parameters(\"count=17\")), nameof(IResizeSettings.Parameters), s => s.Parameters.NvcToString(), \"count=17\");\n\n    [Fact]\n    public void EmptyOnlyQuality75_Params() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(quality: 75), nameof(IResizeSettings.Quality), s => s.Quality, 75);\n\n    [Fact]\n    public void EmptyOnlyQuality75_Tweak() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(tweak: t => t.Quality(75)), nameof(IResizeSettings.Quality), s => s.Quality, 75);\n\n    [Fact]\n    public void EmptyOnlyQualityDot75_Params() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(quality: .75f), nameof(IResizeSettings.Quality), s => s.Quality, 75);\n\n    [Fact]\n    public void EmptyOnlyQualityDot75_Tweak() =>\n        EqualsAndRestEmpty(imgSvc.SettingsTac(tweak: t => t.Quality(75f)), nameof(IResizeSettings.Quality), s => s.Quality, 75);\n\n    // 2022-03-17 not valid any more, this property will be removed\n    //[Fact]\n    //public void EmptyOnlySrcSet()\n    //{\n    //    var settings = Build<IImageService>().ResizeSettings(rules: new MultiResizeRule {SrcSet = \"100,200,300\" });\n    //    Assert.Equal(\"100,200,300\", settings.SrcSet);\n    //    AssertAllEmptyExceptSpecified(settings, nameof(settings.SrcSet));\n    //}\n\n\n\n    [Fact]\n    public void EmptyWidthAndHeight()\n    {\n        var settings = imgSvc.SettingsTac(width: 100, height: 49);\n        Equal(100, settings.Width);\n        Equal(49, settings.Height);\n        AssertAllEmptyExceptSpecified(settings, [nameof(settings.Width), nameof(settings.Height)]);\n    }\n\n\n\n    private void AssertAllEmptyExceptSpecified(IResizeSettings settings, string nameToSkip)\n        => AssertAllEmptyExceptSpecified(settings, [nameToSkip]);\n\n    private void AssertAllEmptyExceptSpecified(IResizeSettings settings, string[] namesToSkip)\n    {\n        var count = 0;\n        count += MaybeTestOneProperty(settings.Height, 0, namesToSkip, nameof(settings.Height));\n        count += MaybeTestOneProperty(settings.Width, 0, namesToSkip, nameof(settings.Width));\n        count += MaybeTestOneProperty(settings.Format, null, namesToSkip, nameof(settings.Format));\n        count += MaybeTestOneProperty(settings.ResizeMode, null, namesToSkip, nameof(settings.ResizeMode));\n        count += MaybeTestOneProperty(settings.Parameters, null, namesToSkip, nameof(settings.Parameters));\n        count += MaybeTestOneProperty(settings.Quality, 0, namesToSkip, nameof(settings.Quality));\n        count += MaybeTestOneProperty(settings.ScaleMode, null, namesToSkip, nameof(settings.ScaleMode));\n        // 2022-03-17 2dm removing this property\n        //count += MaybeTestOneProperty(settings.SrcSet, null, namesToSkip, nameof(settings.SrcSet));\n\n        // Verify the total count matches expected\n        const int expectedCount = 7;\n        Equal(expectedCount - namesToSkip.Length, count);//, \"count should be total fields minus untested\");\n    }\n\n    private static int MaybeTestOneProperty<T>(T actual, T expected, string[] namesToSkip, string notToTest)\n    {\n        if (namesToSkip.Any(n => n == notToTest)) return 0;\n        Equal(expected, actual);//, notToTest);\n        return 1;\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceTagsBase.cs",
    "content": "﻿using ToSic.Sxc.Images;\nusing ToSic.Sxc.Services;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\npublic abstract class ImageServiceTagsBase(IImageService imgSvc, ITestOutputHelper output, TestScenario? testScenario = default)\n{\n    protected IImageService ImgSvc => imgSvc;\n\n    protected const string ImgUrl = \"/abc/def/test.jpg\";\n    protected const string Img120x24 = ImgUrl + \"?w=120&amp;h=24\";\n    protected const string Img120x24x = Img120x24 + \" 1x\";\n    protected const string Img240x48 = ImgUrl + \"?w=240&amp;h=48\";\n    protected const string Img240x48x = Img240x48 + \" 2x\";\n    protected const string SrcSet12 = \"1,2\";\n    protected const string SrcSet12ResultWebP = \"srcset='\" + Img120x24 + \"&amp;format=webp 1x,\" + ImgUrl + \"?w=240&amp;h=48&amp;format=webp 2x'\";\n    protected const string SrcSet12ResultJpg = \"srcset='\" + Img120x24x + \",\" + Img240x48x + \"'\";\n    protected const string SrcWebP12 = \"<source type='image/webp' \" + SrcSet12ResultWebP + \">\";\n    protected const string SrcJpg12 = \"<source type='image/jpeg' \" + SrcSet12ResultJpg + \">\";\n    protected const string ImgTagJpg12 = \"<img src='\" + Img120x24 + \"' \" + SrcSet12ResultJpg + \">\";\n\n    protected const string SrcSetNone = null;\n    protected const string SrcWebPNone = \"<source type='image/webp' srcset='\" + Img120x24 + \"&amp;format=webp'>\";\n    protected const string SrcJpgNone = \"<source type='image/jpeg' srcset='\" + Img120x24 + \"'>\";\n    protected const string ImgTagJpgNone = \"<img src='\" + Img120x24 + \"'>\";\n    protected const string ImgTagJpgNoneF05 = \"<img src='\" + ImgUrl + \"?w=60&amp;h=12'>\";\n\n    // These are necessary, as otherwise the test will automatically look up the \"Content\" settings for image resizing\n    // which would result in a different result.\n    // TODO: ALSO create a test which uses null, and expects the proper resized with default settings\n    object fakeEmptySettings = new object();\n\n    #region Tests which both Img and Picture should do\n\n    protected virtual bool TestModeImg => true;\n\n    [Fact]\n    public void UrlResized()\n    {\n        \n        var url = TestModeImg\n            ? ImgSvc.Img(ImgUrl, settings: fakeEmptySettings).Src\n            : ImgSvc.Picture(ImgUrl, settings: fakeEmptySettings).Src;\n        Equal(ImgUrl, url);\n    }\n\n    [Fact]\n    public void ImgAlt()\n    {\n        const string imgAlt = \"test-alt\";\n        \n        var result = TestModeImg \n            ? ImgSvc.Img(ImgUrl, imgAlt: imgAlt, settings: fakeEmptySettings).ToString()\n            : ImgSvc.Picture(ImgUrl, imgAlt: imgAlt, settings: fakeEmptySettings).Img.ToString();\n        Equal($\"<img src='{ImgUrl}' alt='{imgAlt}'>\", result);\n    }\n\n    [Fact]\n    public void ImgClass()\n    {\n        \n        var cls = \"class-dummy\";\n        var result = TestModeImg\n            ? ImgSvc.Img(ImgUrl, imgClass: cls, settings: fakeEmptySettings).ToString()\n            : ImgSvc.Picture(ImgUrl, imgClass: cls, settings: fakeEmptySettings).Img.ToString();\n        Equal($\"<img src='{ImgUrl}' class='{cls}'>\", result);\n    }\n\n    #endregion\n\n\n    protected void PictureTagInner(string expectedParts, string variants, bool inPicTag, string testName)\n    {\n        \n        var rule = new Recipe(variants: variants);\n        var settings = ImgSvc.SettingsTac(\n            settings: fakeEmptySettings,\n            width: 120,\n            height: 24,\n            recipe: inPicTag ? null : rule\n        );\n        var pic = ImgSvc.Picture(link: ImgUrl, settings: settings, recipe: inPicTag ? rule : null);\n\n        var expected = $\"<picture>{expectedParts}<img src='{Img120x24}'></picture>\";\n        output.WriteLine($\"Expected: '{expected}'\");\n        output.WriteLine($\"Actual  : '{pic}'\");\n        Equal(expected, pic.ToString());//, $\"Test failed: {testName}\");\n    }\n\n\n    /// <summary>\n    /// Run a batch of tests on the source tags, with permutations of where the settings are given\n    /// </summary>\n    protected void BatchTestManySrcSets(string expected, string variants, string testName)\n    {\n        var testSet = ImageTagsTestPermutations.GenerateTestParams(testName, variants);\n        TestManyButThrowOnceOnly(testSet.Select(ts => (ts.Name, ts)), test =>\n        {\n            output.WriteLine($\"Test: {test}\");\n\n            var settings = ImgSvc.SettingsTac(\n                settings: fakeEmptySettings,\n                width: test.Set.Width,\n                height: test.Set.Height,\n                recipe: test.Set.SrcSetRule);\n            var pic = ImgSvc.Picture(link: ImgUrl, settings: settings, recipe: test.Pic.SrcSetRule).Sources;\n\n            output.WriteLine($\"Expected: '{expected}'\");\n            output.WriteLine($\"Actual  : '{pic}'\");\n            Equal(expected, pic.ToString());//, $\"Failed: {test.Name}\");\n\n        });\n    }\n\n\n\n    public void TestManyButThrowOnceOnly<T>(IEnumerable<(string Name, T Data)> tests, Action<T> innerCall)\n    {\n        Exception lastException = null;\n        foreach (var (name, data) in tests)\n        {\n            output.WriteLine(name);\n            try\n            {\n                innerCall(data);\n                output.WriteLine(\" ok\");\n            }\n            catch (Exception ex)\n            {\n                output.WriteLine(\" error\");\n                Console.WriteLine(ex);\n                lastException = ex;\n            }\n\n        }\n        if (lastException != null) throw lastException;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceTagsImgBase.cs",
    "content": "﻿using ToSic.Sxc.Images;\nusing ToSic.Sxc.Services;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\npublic abstract class ImageServiceTagsImgBase(IImageService svc, ITestOutputHelper output, TestScenario? testScenario = default) : ImageServiceTagsBase(svc, output, testScenario)\n{\n    // These are necessary, as otherwise the test will automatically look up the \"Content\" settings for image resizing\n    // which would result in a different result.\n    // TODO: ALSO create a test which uses null, and expects the proper resized with default settings\n    object fakeEmptySettings = new object();\n\n    public virtual void ImageTagMultiTest(string expected, string variants, object? factor, string testName)\n    {\n        var testSet = ImageTagsTestPermutations.GenerateTestParams(testName, variants);\n        TestManyButThrowOnceOnly(testSet.Select(ts => (ts.Name, ts)), test =>\n        {\n            // Factor set on the Img call\n            var settingsWithoutFactor = ImgSvc.SettingsTac(\n                settings: fakeEmptySettings,\n                width: test.Set.Width,\n                height: test.Set.Height,\n                recipe: new Recipe(variants: test.Set.Variants)\n            );\n            var imgSetNoFactor = ImgSvc.Img(link: ImgUrl, settings: settingsWithoutFactor, factor: factor,\n                recipe: test.Pic.Variants);\n            Equal(expected, imgSetNoFactor.ToString());//, $\"Failed (factor on Img): {test.Name}\");\n\n            // Factor specified on settings\n            var settingsWithFactor = ImgSvc.SettingsTac(\n                settings: fakeEmptySettings,\n                factor: factor,\n                width: test.Set.Width,\n                height: test.Set.Height,\n                recipe: new Recipe(variants: test.Set.Variants)\n            );\n            var imgSetFactor = ImgSvc.Img( link: ImgUrl, settings: settingsWithFactor, recipe: test.Pic.Variants);\n            Equal(expected, imgSetFactor.ToString());//, $\"Failed (factor on settings): {test.Name}\");\n\n            // Factor on both - should not equal, because the factor is only applied 1x\n            if (factor == null)\n                return; // Skip if the factor has no effect\n            var imgBothFactors = ImgSvc.Img(link: ImgUrl, settings: settingsWithFactor, factor: factor,\n                recipe: test.Pic.Variants);\n            Equal(expected, imgBothFactors.ToString());//, $\"Failed (factor on both): {test.Name}\");\n        });\n    }\n\n    public virtual void ImageSrcSetMultiTest(string expected, string variants, string testName)\n    {\n        var testSet = ImageTagsTestPermutations.GenerateTestParams(testName, variants);\n        TestManyButThrowOnceOnly(testSet.Select(ts => (ts.Name, ts)), test =>\n        {\n            var settings = ImgSvc.SettingsTac(\n                settings: fakeEmptySettings,\n                width: test.Set.Width,\n                height: test.Set.Height,\n                recipe: test.Set.SrcSetRule\n            );\n            var img = ImgSvc.Img(link: ImgUrl, settings: settings, recipe: test.Pic.SrcSetRule);\n            Equal(expected?.Replace(\"&amp;\", \"&\"), img.SrcSet);//, $\"Failed: {test.Name}\");\n        });\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceTagsImgNoPatron.cs",
    "content": "﻿using ToSic.Sxc.Mocks;\nusing ToSic.Sxc.Services;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n// Start the test with a platform-info that has no patron\n[Startup(typeof(StartupMockExecutionContext))]\npublic class ImageServiceTagsImgNoPatron(ExecutionContextMock executionContext, ITestOutputHelper output)\n    : ImageServiceTagsImgBase(executionContext.GetService<IImageService>(reuse: true), output, new ScenarioBasic()),\n        IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n    protected override bool TestModeImg => true;\n\n    [Theory]\n    [InlineData(ImgTagJpgNone, SrcSetNone, null, \"No Src Set\")]\n    [InlineData(ImgTagJpgNone, SrcSet12, null, \"With Src Set 1,2 - non patrons just like no srcset\")]\n    [InlineData(ImgTagJpgNoneF05, SrcSetNone, 0.5, \"No Src Set, factor 0.5\")]\n    public override void ImageTagMultiTest(string expected, string variants, object factor, string testName) \n        => base.ImageTagMultiTest(expected, variants, factor, testName);\n\n    [Theory]\n    [InlineData(null, SrcSet12, \"With Src Set 1,2, no patron\")]\n    [InlineData(null, SrcSetNone, \"No Src Set, no patron\")]\n    public override void ImageSrcSetMultiTest(string expected, string variants, string testName) \n        => base.ImageSrcSetMultiTest(expected, variants, testName);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceTagsImgPatronPerfectionist.cs",
    "content": "﻿using ToSic.Sxc.Mocks;\nusing ToSic.Sxc.Services;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n//// Start the test with a platform-info that has WebP support\n[Startup(typeof(StartupSxcWithDbPatronPerfectionist))]\npublic class ImageServiceTagsImgPatronPerfectionist(ExecutionContextMock executionContext, ITestOutputHelper output)\n    : ImageServiceTagsImgBase(executionContext.GetService<IImageService>(), output),\n        IClassFixture<DoFixtureStartup<ScenarioFullPatronsWithDb>>\n{\n    protected override bool TestModeImg => true;\n\n    [Theory]\n    [InlineData(ImgTagJpgNone, SrcSetNone, null, \"No Src Set\")]\n    [InlineData(ImgTagJpg12, SrcSet12, null, \"With Src Set 1,2\")]\n    [InlineData(ImgTagJpgNoneF05, SrcSetNone, 0.5, \"No Src Set, factor 0.5\")]\n    public override void ImageTagMultiTest(string expected, string variants, object factor, string testName) \n        => base.ImageTagMultiTest(expected, variants, factor, testName);\n\n    [Theory]\n    [InlineData(Img120x24x + \",\\n\" + Img240x48x, SrcSet12, \"With Src Set 1,2\")]\n    [InlineData(null, SrcSetNone, \"No Src Set\")]\n    public override void ImageSrcSetMultiTest(string expected, string variants, string testName) \n        => base.ImageSrcSetMultiTest(expected, variants, testName);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceTagsNoPatron.cs",
    "content": "﻿using ToSic.Sxc.Mocks;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sys.Capabilities.Licenses;\nusing ToSic.Sys.Capabilities.Platform;\nusing ToSic.Testing.Shared.Platforms;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n// TODO: SOME OF THESE tests should probably go to the configuration folder...\n\n/// <summary>\n/// Run tests with Patrons not enabled.\n/// </summary>\n[Startup(typeof(StartupMockExecutionContextNoPatron))]\npublic class ImageServiceTagsNoPatron(ExecutionContextMock exCtxMock, ITestOutputHelper output, IPlatformInfo platform, ILicenseService licenseSvc, IFeaturesService features)\n    : ImageServiceTagsBase(exCtxMock.GetService<IImageService>(), output, new ScenarioBasic()),\n        IClassFixture<DoFixtureStartup<ScenarioBasic>>\n{\n    [Fact]\n    public void VerifyNotPatron() => Equal(platform.Name, new TestPlatformNotPatron().Name);\n\n    [Fact]\n    public void VerifyFeatureSetDisabled()\n    {\n        var enabled = licenseSvc.IsEnabled(BuiltInLicenses.PatronPerfectionist);\n        False(enabled);\n    }\n\n    [Fact]\n    public void VerifyNotMultiSrcSet()\n    {\n        var enabled = features.IsEnabled(SxcFeatures.ImageServiceMultipleSizes.NameId);\n        False(enabled);\n    }\n\n    protected override bool TestModeImg => false;\n\n\n    [Theory]\n    [InlineData(SrcJpgNone, SrcSetNone, \"No Src Set, no patron\")]\n    [InlineData(SrcJpgNone, SrcSet12, \"With Src Set 1,2; no patron\")]\n    public void SourceTagsMultiTests(string expected, string variants, string name) \n        => BatchTestManySrcSets(expected, variants, name);\n\n\n    [Theory]\n    [InlineData(SrcJpgNone, SrcSetNone, true, \"No Src Set, in-pic\")]\n    [InlineData(SrcJpgNone, SrcSetNone, false, \"No Src Set, in-settings\")]\n    [InlineData(SrcJpgNone, SrcSet12, true, \"With Src Set 1,2, in-pic\")]\n    [InlineData(SrcJpgNone, SrcSet12, false, \"With Src Set 1,2, in-settings\")]\n    public void PictureTags(string expected, string variants, bool inPicTag, string name) \n        => PictureTagInner(expected, variants, inPicTag, name);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceTagsPatronPerfectionist.cs",
    "content": "﻿using ToSic.Sxc.DataForImageTests;\nusing ToSic.Sxc.Images;\nusing ToSic.Sxc.Mocks;\nusing ToSic.Sxc.Services;\nusing Xunit.Abstractions;\n\n// Disable warning that the test-name parameter is not used.\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n/// <summary>\n/// Start the test with a platform-info that has WebP support\n/// </summary>\n[Startup(typeof(StartupSxcWithDbPatronPerfectionist))]\npublic class ImageServiceTagsPatronPerfectionist(ExecutionContextMock exCtxMock, ITestOutputHelper output)\n    : ImageServiceTagsBase(exCtxMock.GetService<IImageService>(), output), IClassFixture<DoFixtureStartup<ScenarioFullPatronsWithDb>>\n{\n    protected override bool TestModeImg => false;\n\n    // These are necessary, as otherwise the test will automatically look up the \"Content\" settings for image resizing\n    // which would result in a different result.\n    // TODO: ALSO create a test which uses null, and expects the proper resized with default settings\n    object fakeEmptySettings = new object();\n\n    [InlineData(SrcWebPNone + SrcJpgNone, SrcSetNone, \"No Src Set\")]\n    [InlineData(SrcWebP12 + SrcJpg12, SrcSet12, \"With Src Set 1,2\")]\n    [Theory]\n    public void SourceTagsMultiTests(string expected, string variants, string name) \n        => BatchTestManySrcSets(expected, variants, name);\n\n    [InlineData(SrcWebPNone + SrcJpgNone, SrcSetNone, true, \"No Src Set, in-pic\")]\n    [InlineData(SrcWebPNone + SrcJpgNone, SrcSetNone, false, \"No Src Set, in-setting\")]\n    [InlineData(SrcWebP12 + SrcJpg12, SrcSet12, true, \"With Src Set 1,2, in-pic\")]\n    [InlineData(SrcWebP12 + SrcJpg12, SrcSet12, false, \"With Src Set 1,2, in-settings\")]\n    [Theory]\n    public void PictureTags(string expected, string variants, bool inPicTag, string name)\n        => PictureTagInner(expected, variants, inPicTag, name);\n\n\n    [Theory]\n    [InlineData(\"<img src='test.jpg?w=678' loading='lazy' test='value' class='img-fluid'>\", 0.75, false, \"0.75 with attributes, settings-object\")]\n    [InlineData(\"<img src='test.jpg?w=678' loading='lazy' test='value' class='img-fluid'>\", 0.75, true, \"0.75 with attributes, json-object\")]\n    public void ImgWhichShouldAutoGetAttributes(string expected, double factor, bool json, string name)\n    {\n        var set = json ? ResizeRecipesData.TestRecipeSetFromJson : ResizeRecipesData.TestRecipeSet();\n        var img = ImgSvc.Img(\"test.jpg\", factor: factor, recipe: set, settings: fakeEmptySettings);\n        Equal(expected, img.ToString());//, name);\n    }\n\n    [Theory]\n    [InlineData(\"<img src='test.jpg?w=1000&amp;h=500' class='manual img-fluid' srcset='test.jpg?w=1000&amp;h=500 1x' sizes='100vw'>\", false, false, \"neither\")]\n    [InlineData(\"<img src='test.jpg?w=1000&amp;h=500' class='manual img-fluid' width='1000' srcset='test.jpg?w=1000&amp;h=500 1x' sizes='100vw'>\", true, false, \"Width only\")]\n    [InlineData(\"<img src='test.jpg?w=1000&amp;h=500' class='manual img-fluid' height='500' srcset='test.jpg?w=1000&amp;h=500 1x' sizes='100vw'>\", false, true, \"Height only\")]\n    [InlineData(\"<img src='test.jpg?w=1000&amp;h=500' class='manual img-fluid' width='1000' height='500' srcset='test.jpg?w=1000&amp;h=500 1x' sizes='100vw'>\", true, true, \"both\")]\n    public void ImgWhichShouldSetWidth(string expected, bool setWidth, bool setHeight, string name)\n    {\n        var recipe = new Recipe(\n            width: 1000,\n            variants: \"1\",\n            setWidth: setWidth,\n            setHeight: setHeight,\n            attributes: new Dictionary<string, object?>\n            {\n                { \"class\", \"img-fluid\" },\n                { \"sizes\", \"100vw\" }\n            });\n        var settings = ImgSvc.SettingsTac(settings: fakeEmptySettings, aspectRatio: 2 / 1);\n        var img = ImgSvc.Img(\"test.jpg\", settings: settings, factor: 0.5, imgClass: \"manual\", recipe: recipe);\n        Equal(expected, img.ToString());//, name);\n\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageServiceTestAccessors.cs",
    "content": "﻿using ToSic.Sxc.Images;\nusing ToSic.Sxc.Images.Sys;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\ninternal static class ImageServiceTestAccessors\n{\n\n    public static IResizeSettings SettingsTac(this IImageService parent,\n        object? settings = null,\n        NoParamOrder npo = default,\n        Func<ITweakResize, ITweakResize>? tweak = null,\n        object? factor = null,\n        object? width = null,\n        object? height = null,\n        object? quality = null,\n        string? resizeMode = null,\n        string? scaleMode = null,\n        string? format = null,\n        object? aspectRatio = null,\n        string? parameters = null,\n        object? recipe = null\n    ) => parent.Settings(settings: settings, npo: npo, tweak: tweak,\n        factor: factor, width: width, height: height,\n        quality: quality, resizeMode: resizeMode, scaleMode: scaleMode, format: format, aspectRatio: aspectRatio,\n        parameters: parameters, recipe: recipe);\n\n    public static IImageFormat GetFormatTac(this IImageService imageSvc, string path) =>\n        imageSvc.GetFormat(path);\n\n    public static IList<IImageFormat> GetResizeFormatTac(this IImageService imageSvc, string path) =>\n        imageSvc.GetFormatTac(path).ResizeFormats;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/ImageTagsTestPermutations.cs",
    "content": "﻿using ToSic.Sxc.Images;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\npublic class ImageTagsTestPermutations\n{\n    public static List<TestParamSet> GenerateTestParams(string name, string variants)\n    {\n        var i = 1;\n        return\n        [\n            new($\"Test #{i++} {name}-both\", true, true, true, variants),\n            new($\"Test #{i++} {name}-both\", true, true, false, variants),\n            new($\"Test #{i++} {name}-on set\", true, false, true, variants),\n            new($\"Test #{i++} {name}-on set\", true, false, false, variants)\n            // The On-Pic variations don't exist, as the pic doesn't have params for width/height\n            //new TestParamSet($\"{i++}{name}-on pic\", false, true, true, srcset),\n            //new TestParamSet($\"{i++}{name}-on pic\", false, true, false, srcset),\n        ];\n    }\n\n    public class TestParams\n    {\n        public TestParams(bool width = false, bool height = false, string? variants = null)\n        {\n            if (width) Width = 120;\n            if (height) Height = 24;\n            Variants = variants;\n        }\n        public int? Width;\n        public int? Height;\n        public string? Variants;\n\n        public Recipe? SrcSetRule => Variants == null ? null : new Recipe(variants: Variants);\n\n        public override string ToString() => $\"Width: {Width}, Height: {Height}, Variants: {Variants}, SrcSetRule: {SrcSetRule}\";\n    }\n\n    public class TestParamSet(string name, bool useSet, bool usePic, bool putSrcOnSet, string variants)\n    {\n        public TestParams Set = new(useSet, useSet, putSrcOnSet ? variants : null);\n        public TestParams Pic = new(usePic, usePic, putSrcOnSet ? null : variants);\n        public string Name = name + $\" (Settings on Pic: {usePic}, On Set: {useSet}, srcset: '{variants}' - on \"\n                                  + (putSrcOnSet ? \"set\" : \"pic\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/ImageServiceTests/TweakMediaTests.cs",
    "content": "﻿using ToSic.Sxc.Images;\nusing ToSic.Sxc.Images.Sys;\n\nnamespace ToSic.Sxc.ServicesTests.ImageServiceTests;\n\n/// <summary>\n/// Tests to check that the TweakMedia API works as expected.\n/// </summary>\n//[TestClass]\npublic class TweakMediaTests\n{\n    #region Resize Settings - not implemented, as we should probably have an entire Resize(name, t => ...) API for this instead\n\n    /// <summary>\n    /// Create a TweakMedia with Resize settings for testing changes on the resize.\n    /// </summary>\n    private static ITweakMedia ResizeOnly() => new TweakMedia(\n        null,\n        null,\n        new(null, null, 100, 100, 2.5, 0.5, null, \"not-based-on-anything\"),\n        null,\n        null,\n        null,\n        null\n    );\n\n    [Fact]\n    public void ChangeWidth() => Equal(42, ((TweakMedia)ResizeOnly().Resize(null as string, tweak: t => t.Width(42))).ResizeSettings.Width);\n\n    [Fact]\n    public void ResizeChangeMakesCopyOfTweakMedia()\n    {\n        var original = ResizeOnly();\n        var changeWidth = original.Resize(null as string, tweak: t => t.Width(42));\n        var changeFactor = original.Resize(null as string, tweak: t => t.Factor(0.75));\n        // Verify that the objects are different\n        NotEqual(original, changeWidth);\n        NotEqual(original, changeFactor);\n        NotEqual(changeWidth, changeFactor);\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Mail/AddMailAddressesInputTypeTests.cs",
    "content": "﻿using System.Net.Mail;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Mail.Sys;\n\nnamespace ToSic.Sxc.ServicesTests.Mail;\n\npublic class AddMailAddressesInputTypeTests(IMailService mailSvc, MailServiceTestsHelper helper)\n{\n    [Fact]\n    public void MailAddressCollectionType()\n    {\n        var expected = new MailAddressCollection { MailServiceTestsHelper.Addresses };\n        var actual = new MailAddressCollection();\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, expected);\n        Equivalent(expected, actual);\n    }\n\n    [Fact]\n    public void MailAddressArrayType()\n    {\n        var mailAddressCollection = new MailAddressCollection { MailServiceTestsHelper.Addresses };\n        var expected = mailAddressCollection.ToArray();\n        var actual = new MailAddressCollection();\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, expected);\n        Equivalent(mailAddressCollection, actual);\n    }\n\n    [Fact]\n    public void StringArrayType()\n    {\n        var expected = MailServiceTestsHelper.Emails.Split(',');\n        var actual = new MailAddressCollection();\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, expected);\n        Equal(expected.Length, actual.Count);\n    }\n\n    [Fact]\n    public void StringArrayTypeWithTwoEmptyItems()\n    {\n        const string addresses = @\"a@a.com,,,c@c.com,d@d.com\";\n        var expected = addresses.Split(',');\n        var actual = new MailAddressCollection();\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, expected);\n        Equal(expected.Length, actual.Count+2);\n    }\n\n    [Fact]\n    public void StringType()\n    {\n        const int expected = 4; // number of emails in Emails string\n        var actual = new MailAddressCollection();\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, MailServiceTestsHelper.Emails);\n        Equal(expected, actual.Count);\n    }\n\n    [Fact]\n    public void StringTypeWithNonStandardSeparator()\n    {\n        const string emailsWithNonStandardSeparator = @\"a@a.com;b@b.com;c@c.com;d@d.com\";\n        const int expected = 4; // number of emails\n        var actual = new MailAddressCollection();\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, emailsWithNonStandardSeparator);\n        Equal(expected, actual.Count);\n    }\n\n    [Fact]\n    //[ExpectedException(typeof(FormatException))]\n    public void InvalidString()\n    {\n        // An invalid character was found in the mail header.\n        Throws<FormatException>(() => ((MailServiceBase)mailSvc).MailAddress(\"test\", @\";;;ffff@@@@@@gggggg\"));\n    }\n\n    [Fact]\n    public void EmptyString()\n    {\n        // The parameter 'mailAddresses' can be empty string.\n        const int expected = 0; // number of emails\n        var actual = new MailAddressCollection();\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, string.Empty);\n        Equal(expected, actual.Count);\n    }\n\n    [Fact]\n    public void Null()\n    {\n        // The parameter 'mailAddresses' can be null.\n        const int expected = 0; // number of emails\n        var actual = new MailAddressCollection();\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, null);\n        Equal(expected, actual.Count);\n    }\n\n    [Fact]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void UnknownType() =>\n        Throws<ArgumentException>(() =>\n        {\n            var mailAddresses = new { a = \"test\" }; // unknown type\n            // Trying to parse e-mails for test but got unknown type for mailAddresses.\n            ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", new(), mailAddresses);\n        });\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Mail/MailAddressCollectionTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.Mail;\n\n\npublic class MailAddressCollectionTests(IMailService mailSvc, MailServiceTestsHelper helper)\n{\n    [Theory]\n\n    [InlineData(@\"a@a.com,b@b.com,c@c.com\", \"a@a.com\", \"\", \"b@b.com\", \"\")]\n    [InlineData(@\"a@a.com, b@b.com, c@c.com\", \"a@a.com\", \"\", \"b@b.com\", \"\")]\n    [InlineData(@\"  a@a.com  ,  b@b.com  ,  c@c.com  \", \"a@a.com\", \"\", \"b@b.com\", \"\")]\n\n    // use ; as address separator\n    [InlineData(@\"a@a.com;b@b.com;c@c.com\", \"a@a.com\", \"\", \"b@b.com\", \"\")]\n    [InlineData(@\"<a@a.com>,<b@b.com>,<c@c.com>\", \"a@a.com\", \"\", \"b@b.com\", \"\")]\n\n    // sometimes use ; as address separator\n    [InlineData(@\"<a@a.com>,b@b.com;<c@c.com>\", \"a@a.com\", \"\", \"b@b.com\", \"\")]\n    [InlineData(@\"John Doe user@host, Bob Smith user2@host\", \"user@host\", \"John Doe\", \"user2@host\", \"Bob Smith\")]\n\n    // have , as part of displayName when displayName is quoted\n    [InlineData(@\"\"\"John, Doe\"\" <user@host>, \"\"Bob, Smith\"\" <user2@host>\", \"user@host\", \"John, Doe\", \"user2@host\", \"Bob, Smith\")]\n    [InlineData(@\"\"\"John, Doe\"\" <user@host>, Bob Smith user2@host\", \"user@host\", \"John, Doe\", \"user2@host\", \"Bob Smith\")]\n\n    // use ; as address separator\n    [InlineData(@\"\"\"John, Doe\"\" <user@host>; \"\"Bob, Smith\"\" <user2@host>\", \"user@host\", \"John, Doe\", \"user2@host\", \"Bob, Smith\")]\n    public void ParseInputStringTheory(string input, string expMail1, string expName1, string expMail2, string expName2) =>\n        helper.MailAddressEqual(input, expMail1, expName1, expMail2, expName2);\n\n\n\n    [Theory(Skip = \"unclear why disabled, but they fail, must ask @STV\")]\n    // failed. Expected:<a@a.com>. Actual:<c@c.com>.\n    [InlineData(@\"a@a.com b@b.com c@c.com\", \"a@a.com\", \"\", \"b@b.com\", \"\")]\n\n    // !!! have ; as part of displayName\n    // failed. Expected:<John; Doe>. Actual:<John, Doe>.\n    [InlineData(@\"\"\"John; Doe\"\" <user@host>, \"\"Bob; Smith\"\" <user2@host>\", \"user@host\", \"John; Doe\", \"user2@host\", \"Bob; Smith\")]\n\n    public void ParseInputStringThatFails(string input, string expMail1, string expName1, string expMail2, string expName2) =>\n        helper.MailAddressEqual(input, expMail1, expName1, expMail2, expName2);\n\n    [Theory]\n    // FormatException: An invalid character was found in the mail header: ','.\n    [InlineData(@\"a@a.com,,c@c.com\", \"a@a.com\", \"\", \"c@c.com\", \"\")]\n    // have , as part of displayName when displayName is not quoted\n    // FormatException: The specified string is not in the form required for an e-mail address.\n    [InlineData(@\"John, Doe user@host, Bob, Smith user2@host\", \"user@host\", \"John, Doe\", \"user2@host\", \"Bob, Smith\")]\n    public void ParseInputStringExpectFormatExceptions(string input, string expMail1, string expName1, string expMail2, string expName2) =>\n        Throws<FormatException>(() => helper.MailAddressEqual(input, expMail1, expName1, expMail2, expName2));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Mail/MailAddressInputTypeTests.cs",
    "content": "﻿using System.Net.Mail;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Mail.Sys;\n\nnamespace ToSic.Sxc.ServicesTests.Mail;\n\npublic class MailAddressInputTypeTests(IMailService mailSvc, MailServiceTestsHelper helper)\n{\n    [Fact]\n    public void MailAddressType()\n    {\n        var expected = new MailAddress(MailServiceTestsHelper.Address, MailServiceTestsHelper.DisplayName);\n        var actual = ((MailServiceBase)mailSvc).MailAddress(\"test\", expected);\n        Equal(expected, actual);\n    }\n\n    [Fact]\n    public void StringType()\n    {\n        Equal(MailServiceTestsHelper.Address, ((MailServiceBase)mailSvc).MailAddress(\"test\", MailServiceTestsHelper.Address).Address);\n    }\n\n    // An invalid character was found in the mail header.\n    [Fact]\n    //[ExpectedException(typeof(FormatException))]\n    public void InvalidString() =>\n        Throws<FormatException>(() =>\n            ((MailServiceBase)mailSvc).MailAddress(\"test\", @\";;;ffff@@@@@@gggggg\"));\n\n    // The parameter 'address' cannot be an empty string.\n    [Fact]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void EmptyString() =>\n        Throws<ArgumentException>(() => ((MailServiceBase)mailSvc).MailAddress(\"test\", string.Empty));\n\n        // Unknown type for MailAddress\n    [Fact]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void Null() => Throws<ArgumentException>(() => ((MailServiceBase)mailSvc).MailAddress(\"test\", null));\n\n    [Fact]\n    //[ExpectedException(typeof(ArgumentException))]\n    public void UnknownType()\n    {\n        var mailAddress = new { a = \"test\" }; // unknown type\n        // Trying to parse e-mails for test but got unknown type for mailAddress\n        Throws<ArgumentException>(() => ((MailServiceBase)mailSvc).MailAddress(\"test\", mailAddress));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Mail/MailAddressTests.cs",
    "content": "﻿using static ToSic.Sxc.ServicesTests.Mail.MailServiceTestsHelper;\n\nnamespace ToSic.Sxc.ServicesTests.Mail;\n\npublic class MailAddressTests(MailServiceTestsHelper helper)\n{\n    // Actually tests System.Net.Mail.MailAddress\n    // that is responsible for parsing input to email Address and display name\n    [Theory]\n    [InlineData(Address, Address, \"\")]\n    [InlineData($\"<{Address}>\", Address, \"\")]\n    [InlineData($\"{DisplayName} {Address}\", Address, DisplayName)]\n    [InlineData($\"{DisplayName}  {Address}\", Address, DisplayName)]\n    [InlineData($\"   {DisplayName}    {Address}   \", Address, DisplayName)]\n    [InlineData($\"{DisplayName} <{Address}>\", Address, DisplayName)]\n    [InlineData($\" {DisplayName}   <{Address}>  \", Address, DisplayName)]\n    [InlineData($@\"\"\"{DisplayName}\"\" {Address}\", Address, DisplayName)]\n    [InlineData($@\"  \"\"{DisplayName}\"\"  {Address}    \", Address, DisplayName)]\n    [InlineData($@\"\"\"{DisplayName}\"\" <{Address}>\", Address, DisplayName)]\n    [InlineData($\"first@last {Address}\", Address, \"first@last\")]\n    [InlineData($\"   <first@last>    <{Address}>   \", Address, \"<first@last>\")]\n    [InlineData($\"{DisplayName}<{Address}>\", Address, DisplayName)]\n    [InlineData($@\"\"\"{DisplayName}\"\"{Address}\", Address, DisplayName)]\n\n    public void ParseInputString(string input, string expMail, string expName) =>\n        helper.MailAddressEqual(input, expMail, expName);\n\n    [Theory]\n    // FormatException: An invalid character was found in the mail header: 't'.\n    [InlineData($@\"\"\"first\"\" last\"\" <{Address}>\", Address, @\"first\"\" last\")]\n\n    // FormatException: The specified string is not in the form required for an e-mail address.\n    [InlineData(@\"{DisplayName} {Address}>\", Address, DisplayName)]\n\n    // FormatException: The specified string is not in the form required for an e-mail address.\n    [InlineData(@\"{DisplayName} <{Address}\", Address, DisplayName)]\n\n    // FormatException: The specified string is not in the form required for an e-mail address.\n    [InlineData(@\"\"\"{DisplayName} {Address}\", Address, DisplayName)]\n\n    // FormatException: The specified string is not in the form required for an e-mail address.\n    [InlineData(@\"{DisplayName}\"\" {Address}\", Address, DisplayName)]\n\n    // FormatException: The specified string is not in the form required for an e-mail address.\n    [InlineData(@\" \"\" \"\" {DisplayName} \"\" \"\" {Address}\", Address, DisplayName)]\n\n    // FormatException: The specified string is not in the form required for an e-mail address.\n    [InlineData(@\"first\"\" last {Address}\", Address, @\"first\"\" last\")]\n\n    // FormatException: The specified string is not in the form required for an e-mail address.\n    [InlineData(@\"<first@last> {Address}\", Address, @\"<first@last>\")]\n    public void ParseInputStringThatFails(string input, string expMail, string expName) =>\n        Throws<FormatException>(() => helper.MailAddressEqual(input, expMail, expName));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Mail/MailServiceBaseTests.cs",
    "content": "﻿using ToSic.Sxc.Services.Mail.Sys;\n\nnamespace ToSic.Sxc.ServicesTests.Mail;\n\npublic class MailServiceBaseTests\n{\n    [Fact]\n    public void AutoDetectHtmlTest()\n    {\n        False(MailServiceBase.AutoDetectHtml(null));\n        False(MailServiceBase.AutoDetectHtml(string.Empty));\n        False(MailServiceBase.AutoDetectHtml(\"text\"));\n        True(MailServiceBase.AutoDetectHtml(\"<b>html</b>\"));\n    }\n\n    [Fact]\n    public void NormalizeEmailSeparatorsTest()\n    {\n        Null(MailServiceBase.NormalizeEmailSeparators(null));\n        Null(MailServiceBase.NormalizeEmailSeparators(string.Empty));\n        // all standard separators\n        Equal(\",,,,\", MailServiceBase.NormalizeEmailSeparators(\",,,,\"));\n        // all non standard separators\n        Equal(\",,,,\", MailServiceBase.NormalizeEmailSeparators(\";;;;\"));\n        // some non standard separators\n        Equal(\",,,,\", MailServiceBase.NormalizeEmailSeparators(\",,;;\"));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Mail/MailServiceTestsHelper.cs",
    "content": "﻿using System.Net.Mail;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.Mail.Sys;\n\nnamespace ToSic.Sxc.ServicesTests.Mail;\n\npublic class MailServiceTestsHelper(IMailService mailSvc) \n{\n    #region Helpers\n\n    public const string Address = @\"user@host\";\n    public const string DisplayName = @\"Display Name\";\n    public const string Addresses = @\"\"\"John, Doe\"\" <user@host>, \"\"Bob, Smith\"\" <user2@host>\";\n    public const string Emails = @\"a@a.com,b@b.com,c@c.com,d@d.com\";\n\n    public void MailAddressEqual(string input, string expMail, string expName)\n    {\n        // Actually tests System.Net.Mail.MailAddress\n        // that is responsible for parsing input to email Address and display name\n        var actual = ((MailServiceBase)mailSvc).MailAddress(\"test\", input);\n        Equal(expMail, actual.Address);\n        Equal(expName, actual.DisplayName);\n    }\n\n    public void MailAddressEqual(string input, string expMail1, string expName1, string expMail2, string expName2)\n    {\n        // Actually tests System.Net.Mail.MailAddressCollection\n        // that is responsible for parsing string input to list of MailAddresses\n        var actual = new MailAddressCollection();\n\n        ((MailServiceBase)mailSvc).AddMailAddresses(\"test\", actual, input);\n        Equal(expMail1, actual[0].Address);\n        Equal(expName1, actual[0].DisplayName);\n        Equal(expMail2, actual[1].Address);\n        Equal(expName2, actual[1].DisplayName);\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Mail/Startup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.ServicesTests.Mail;\n\npublic class Startup: StartupSxcCoreOnly\n{\n    public override void ConfigureServices(IServiceCollection services)\n    {\n        base.ConfigureServices(services\n            .AddTransient<MailServiceTestsHelper>());\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/SecureData/SecureDataHashTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing ToSic.Sys.Security.Encryption;\n\nnamespace ToSic.Sxc.ServicesTests.SecureData;\n\n/// <summary>\n/// Test Hash functions on SecureData Service.\n/// </summary>\n/// <remarks>\n/// Test data created using https://emn178.github.io/online-tools/sha256.html\n/// </remarks>\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class SecureDataHashTests(ISecureDataService sds)\n{\n    private ISecureDataService GetSecureDataService()\n    {\n        sds.Debug = true;\n        return sds;\n    }\n\n    [Fact]\n    public void TestSha256RootWithNull()\n        => Throws<ArgumentNullException>(() => Sha256.Hash((string)null!));\n\n    /// <remarks>\n    /// test data created using https://emn178.github.io/online-tools/sha256.html\n    /// </remarks>\n    [Theory]\n    [InlineData(\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\", \"\")]\n    [InlineData(\"aef87954c3c56f1d53eaca2e1ae5f863bf1c0331e418bdf71e9e4c07085eebdd\", \"\", \"asc4y9is2!y\")]\n    [InlineData(\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\", (string?)null)]\n    [InlineData(\"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\", \"test\")]\n    [InlineData(\"532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25\", \"Test\")]\n    [InlineData(\"94ee059335e587e501cc4bf90613e0814f00a7b08bc7c648fd865a2af6a22cc2\", \"TEST\")]\n    [InlineData(\"2c9cc266a15dc85945c040defd12387b3fca49a2a6ef2cd49102b010e9bbc307\", \"TEST\", \"asc4y9is2!y\")]\n    public void TestSha256(string expected, string value, string? salt = default)\n    {\n        var sds = GetSecureDataService();\n        var result = sds.HashSha256(value + salt);\n        Equal(expected, result);//, $\"failed on '{value}'; salt: '{salt}'\");\n    }\n\n    /// <summary>\n    /// Verify that incorrect values do not match the expected hash.\n    /// </summary>\n    /// <param name=\"expected\"></param>\n    /// <param name=\"value\"></param>\n    /// <param name=\"salt\"></param>\n    [Theory]\n    [InlineData(\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\", \".\")]\n    [InlineData(\"aef87954c3c56f1d53eaca2e1ae5f863bf1c0331e418bdf71e9e4c07085eebdd\", \".\", \"asc4y9is2!y\")]\n    public void TestSha256Invalid(string expected, string value, string? salt = default)\n    {\n        var sds = GetSecureDataService();\n        var result = sds.HashSha256(value + salt);\n        NotEqual(expected, result);//, $\"failed on '{value}'; salt: '{salt}'\");\n    }\n\n\n    /// <remarks>\n    /// test data created using https://emn178.github.io/online-tools/sha512.html\n    /// </remarks>\n    [Theory]\n    [InlineData(\"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e\", \"\")]\n    [InlineData(\"3578b7e749b86c2a7d2e38ad9bd29573edb96edee4b1a4367ab917321d8adac0965d16b9a440cc99cf50014be3d9cc904043ca5d531131e0b7ae34cae25b3788\", \"\", \"asc4y9is2!y\")]\n    [InlineData(\"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e\", (string?)null)]\n    [InlineData(\"ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff\", \"test\")]\n    [InlineData(\"c6ee9e33cf5c6715a1d148fd73f7318884b41adcb916021e2bc0e800a5c5dd97f5142178f6ae88c8fdd98e1afb0ce4c8d2c54b5f37b30b7da1997bb33b0b8a31\", \"Test\")]\n    [InlineData(\"7bfa95a688924c47c7d22381f20cc926f524beacb13f84e203d4bd8cb6ba2fce81c57a5f059bf3d509926487bde925b3bcee0635e4f7baeba054e5dba696b2bf\", \"TEST\")]\n    [InlineData(\"b74814c96b1f0c76c4f1cc10aed08a0c56f25a2611aaf32f4560a8abcffe30ff2c7828a953d1c18e1f03a4fa1c335c84807bbedf7fb6b7da5b4b1e56d46a30d9\", \"TEST\", \"asc4y9is2!y\")]\n    public void TestSha512(string expected, string value, string? salt = default)\n    {\n        var sds = GetSecureDataService();\n        var result = sds.HashSha512(value + salt);\n        Equal(expected, result);//, $\"failed on '{value}'; salt: '{salt}'\");\n    }\n\n    /// <summary>\n    /// Verify that incorrect values do not match the expected hash.\n    /// </summary>\n    /// <param name=\"expected\"></param>\n    /// <param name=\"value\"></param>\n    /// <param name=\"salt\"></param>\n    [Theory]\n    [InlineData(\"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e\", \" \")]\n    [InlineData(\"3578b7e749b86c2a7d2e38ad9bd29573edb96edee4b1a4367ab917321d8adac0965d16b9a440cc99cf50014be3d9cc904043ca5d531131e0b7ae34cae25b3788\", \" \", \"asc4y9is2!y\")]\n    public void TestSha512Invalid(string expected, string value, string? salt = default)\n    {\n        var sds = GetSecureDataService();\n        var result = sds.HashSha512(value + salt);\n        NotEqual(expected, result);//, $\"failed on '{value}'; salt: '{salt}'\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/SecureData/SecureDataTest.cs",
    "content": "﻿using System.Diagnostics;\nusing ToSic.Sxc.Services;\nusing Xunit.Abstractions;\nusing static ToSic.Sxc.Services.SecureDataService;\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.ServicesTests.SecureData;\n\npublic class SecureDataTest(ISecureDataService sds, ITestOutputHelper output)\n{\n    private ISecureDataService GetSecureDataService()\n    {\n        sds.Debug = true;\n        return sds;\n    }\n\n    //[Fact]\n    //public void TestEncryptGoogleApiKey()\n    //{\n    //    var svc = GetSecureDataService() as SecureDataService;\n\n    //    var newSecure = svc.Create(NewApiKeyV20);\n    //    output.WriteLine($\"New: '{newSecure}'\");\n\n    //    var secured = svc.Parse(SecuredApiKeyV19);\n    //    Equal(OriginalApiKeyV19, secured.Value);\n    //    Equal(SecuredApiKeyV19, svc.Create(OriginalApiKeyV19));\n    //}\n\n    private const string OriginalApiKeyV19 = \"todo\";\n    private const string SecuredApiKeyV19 = \"secure:pycbhspVSBHE662IjdEfFG8rwwCdxN9jCQaMJK6/QfLl/JxaDhAk+6q1WU4BSXw4;iv:HUyYDwdMhsuiaxZo3TG4Zg==\";\n    private const string NewApiKeyV20 = \"todo\";\n\n    private const string TestGoogleApiKey = \"Made-Up-Google-Maps-Key3423\";\n    private const string EncryptedApiKey = /*\"secure:\" +*/ \"vOo8fn0SVDlt7GCtUrIpm120zrdufrR94WA3QsUUWiU=;iv:CQ7Rq+9p9CvWEtTeh8uhlA==\";\n\n    [Theory]\n    [InlineData(\"No secret\", \"Test\", \"Test\", false)]\n    [InlineData(\"No secret with Prefix\", PrefixSecure + \"Test\", PrefixSecure + \"Test\", false)]\n    [InlineData(\"No secret with different cased prefix\", \"SECure:Test\", \"SECure:Test\", false)]\n    [InlineData(\"Google Api - no prefix, treat as not encrypted\", TestGoogleApiKey, TestGoogleApiKey, false)]\n    [InlineData(\"Google Api - with Prefix\", TestGoogleApiKey, PrefixSecure + EncryptedApiKey)]\n    [InlineData(\"Google Api - prefix lower case\", TestGoogleApiKey, \"secure:\" + EncryptedApiKey)]\n    public void TestDecryptPrefixes(string testName, string? expected, string original, bool mustBeSecure = true)\n    {\n        expected ??= original;\n        var sds = GetSecureDataService() as SecureDataService;\n        var result = sds.Parse(original);\n        Trace.WriteLine($\"Test: '{testName}'; Result: '{result.Value}'\");\n        Equal(expected, result.Value);\n        Equal(mustBeSecure, result.IsSecured);//, \"Must be Secure\");\n    }\n\n    //[InlineData(\"test translate\", \"Secure:OaB/h/7jUZomSeEvhfFUhCvmrsH6XfmDykIpgXH9JBf6SxoTPY3FjW6O3PebeZ8X\")]\n    //[InlineData(\"test maps\", \"Secure:YPIieaLHdWhoeI1q0ULQv4WjGQMce2dKZ2apW7IVumwTzAap9LLJ4dmBQfDABC1g\")]\n    //[InlineData(\"test recaptcha Private\", \"Secure:OXtlYBVC2ijMLQqrev2XQCO9vwL12YmACxBh9JsWm6UE1H59Iehl93AmDRqZ3xId\")]\n    //[InlineData(\"test recaptcha Site Key public\", \"Secure:RVJvPMj+l9MJPTZhER0w/1P3kYD0+QYcoBZ4BZOAkpNYBxRBzfqcvl/SvfM5517T\")]\n    //[Fact]\n    //public void TestDecrypt(string testName, string original)\n    //{\n    //    var sds = GetSecureDataService();\n    //    ((SecureDataService)sds).Aes.TempUseNewMode = false;\n    //    var normal = sds.Parse(original);\n    //    Assert.Equal(-1, normal.Value.IndexOf(\"secure:\", InvariantCultureIgnoreCase));\n    //    var expected = normal.Value;\n    //    Trace.WriteLine($\"Test: '{testName}'; Result: '{normal.Value}'\");\n\n    //    Trace.WriteLine(\"Will re-encrypt new with OLD 2 iterations\");\n    //    var encrypted = sds.Create(normal.Value);\n    //    Trace.WriteLine($\"Re-encrypted {testName} '{encrypted}'\");\n    //    var reDecrypted = sds.Parse(encrypted);\n    //    Assert.Equal(expected, reDecrypted.Value);\n\n    //    Trace.WriteLine(\"Now with new key and 1000 iterations\");\n    //    sds = GetSecureDataService(); //.Aes.TempUseNewMode = true;\n    //    encrypted = sds.Create(normal.Value);\n    //    Trace.WriteLine($\"Re-encrypted {testName} '{encrypted}'\");\n    //    reDecrypted = sds.Parse(encrypted);\n    //    Assert.Equal(expected, reDecrypted.Value);\n    //}\n\n    [Theory]\n    [InlineData(\"Google Maps v15.01\", \"secure:8Y3oOFHkGH0iMbZOsWfuqWnim7z1OgoNPrLsMZ/llCIhRJG+kUtDGC1m99v4GAlT;iv:jvZcqtq64R7eYzEFIphnzw==\")]\n    [InlineData(\"Google Translate v15.01\", \"secure:1mVLM8QnaXWvW/HgUXMk5wdNeXRXF6i59+5/wf19+yFU4AqZYRNPfcvufV3ObTf2;iv:Rb50nlPbqsz87QThp7BTWA==\")]\n    [InlineData(\"Google Recaptcha Private v15.01\", \"secure:WrrPM8F712DXIRuBe/eFW87L1AcrMKxPLFEJOJjqdFRZWNEPPRA2eHyz5yWIuF7N;iv:fIMctbzYuZFPQw0X151CLA==\")]\n    [InlineData(\"Google Recaptcha Site Key v15.01\", \"secure:fcU5EQMMf8tgoJG7VuR0nXvVKJNBsjSsnZPtctu1u45qb0j7Fsjuopvp6SImfWBw;iv:sNhfaORhKo4BT89qXGrlKw==\")]\n    public void TestBuiltInSecrets(string testName, string original)\n    {\n        var sds = GetSecureDataService() as SecureDataService;\n        var normal = sds.Parse(original);\n        Trace.WriteLine($\"Test: '{testName}'; Result: '{normal.Value}'\");\n        Trace.WriteLine(\"Will re-encrypt new\");\n        var encrypted = sds.Create(normal.Value);\n        Trace.WriteLine($\"Re-encrypted {testName} '{encrypted}'\");\n        var reDecrypted = sds.Parse(encrypted);\n        Equal(normal.Value, reDecrypted.Value);\n\n        Trace.WriteLine(\"Now with new key\");\n        encrypted = sds.Create(normal.Value);\n        Trace.WriteLine($\"Re-encrypted {testName} '{encrypted}'\");\n        reDecrypted = sds.Parse(encrypted);\n        Equal(normal.Value, reDecrypted.Value);\n    }\n\n\n    /// <summary>\n    /// This doesn't actually test anything, but we can use it to get encrypted values for further testing\n    /// and to encrypt stuff we need for our basic encrypted settings\n    /// </summary>\n    [Theory]\n    [InlineData(\"Test Message 1\", \"Test Message - Original\")]\n    [InlineData(\"Test Message 2\", \"1234567890\")]\n    [InlineData(\"Test Made-Up Maps Key\", \"Made-Up-Google-Maps-Key3423\")]\n    public void TestRoundTrip(string testName, string value)\n    {\n        var secDataService = GetSecureDataService();\n        var encrypted = ((SecureDataService)secDataService).Create(value);\n        Trace.WriteLine(\"Encrypted: \" + encrypted);\n\n        var decrypted = secDataService.Parse(encrypted);\n        Equal(value, decrypted.Value);\n        Trace.WriteLine($\"Parsed/Restored: '{decrypted.Value}'\");\n        Trace.WriteLine(\"Log Dump\");\n        Trace.WriteLine(secDataService.Log.Dump());\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/SecureData/Startup.cs",
    "content": "﻿namespace ToSic.Sxc.ServicesTests.SecureData;\n\npublic class Startup: StartupSxcCoreOnly;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Templates/Startup.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\n\nnamespace ToSic.Sxc.ServicesTests.Templates;\n\npublic class Startup: StartupSxcCoreOnly\n{\n    public override void ConfigureServices(IServiceCollection services)\n    {\n        base.ConfigureServices(services\n            .AddTransient<TemplatesTestsBaseHelper>());\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Templates/TemplatesBasicTests.cs",
    "content": "﻿using System.Globalization;\nusing ToSic.Sxc.Services;\nusing Xunit.Abstractions;\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.ServicesTests.Templates;\n\npublic class TemplatesBasicTests(ITemplateService templateSvc, TemplatesTestsBaseHelper helper, ITestOutputHelper output)// : TemplatesTestsBase\n{\n    [InlineData(\"Hello World\", \"Hello World\")]\n    [InlineData(\"Hello Val1\", \"Hello [Dic:Key1]\")]\n    [InlineData(\"Hello Val2\", \"Hello [Dic:Key2]\")]\n    [InlineData(\"Hello \", \"Hello [Dic:unknown]\")]\n    [InlineData(\"Hello There\", \"Hello [Dic:unknown||There]\")]\n    [InlineData(\"Hello Val2\", \"Hello [Dic:unknown||[Dic:Key2]]\")]\n    [InlineData(\"Hello \", \"Hello [Unknown:Key1]\")]\n    [Theory]\n    public void EmptyDictionary(string expected, string value, string? notes = default)\n    {\n        var result = templateSvc.Empty(sources: [helper.GetDicSource()]).Parse(value);\n        Equal(expected, result);//, $\"Value: '{value}', notes: {notes}\");\n    }\n\n    [InlineData(\"Hello World\", \"Hello World\")]\n    [InlineData(\"Hello Val1\", \"Hello [Fn:Key1]\")]\n    [InlineData(\"Hello Val2\", \"Hello [Fn:Key2]\")]\n    [InlineData(\"Hello WrappedVal1Done\", \"Hello [Fn:Key1|Wrapped{0}Done]\")]\n    [Theory]\n    public void EmptyFunction(string expected, string value, string? notes = default)\n    {\n        var result = templateSvc.Empty(sources: [helper.GetFnSource()]).Parse(value);\n        Equal(expected, result);//, $\"Value: '{value}', notes: {notes}\");\n    }\n\n    [InlineData(\"Hello World\", \"Hello World\")]\n    [InlineData(\"Hello 42\", \"Hello [Fn:Key1]\")]\n    [InlineData(\"Hello 27\", \"Hello [Fn:Key2]\")]\n    [InlineData(\"Hello 42\", \"Hello [Fn:Key1|G]\")]\n    [InlineData(\"Hello 27\", \"Hello [Fn:Key2|G]\")]\n    [InlineData(\"Hello 42.00\", \"Hello [Fn:Key1|F]\")]\n    [InlineData(\"Hello 27.00\", \"Hello [Fn:Key2|F]\")]\n    [InlineData(\"Hello (42)\", \"Hello [Fn:Key1|(##)]\")]\n    [InlineData(\"Hello 42.00\", \"Hello [Fn:Key1|00.00]\")]\n    [Theory]\n    public void EmptyFunctionFormatter(string expected, string value, string? notes = default)\n    {\n        var culture = new CultureInfo(\"en-US\")\n        {\n            // Workaround for .net 9 - in 472 this is the default, but in .net 9 it's 3 digits.\n            // Not sure if we should also change the internals of 2sxc for other conversions,\n            // here it only affects the unit test\n            NumberFormat =\n            {\n                NumberDecimalDigits = 2\n            }\n        };\n\n        output.WriteLine($\"Culture: {culture.Name}; {culture.NumberFormat.CurrencyDecimalDigits}\");\n        Thread.CurrentThread.CurrentCulture = culture;\n        var templateEngine = templateSvc.Empty(sources: [helper.GetFnNumberSourcesWithFormat()]);\n        var result = templateEngine.Parse(value);\n        Equal(expected, result);//, $\"Value: '{value}', notes: {notes}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Templates/TemplatesDefaultSourcesTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.Templates;\n\n// TODO: should change to have more standard DI based sources\n// ATM it has 0\n// but if the lookups were in DI it would have more, so we could test more\n\n\npublic class TemplatesDefaultSourcesTests(ITemplateService templateSvc, TemplatesTestsBaseHelper helper) //: TemplatesTestsBase\n{\n    // This is as of v19.03 2025-03\n    // Both frameworks have\n    // - QueryStringLookUp\n    // - LookUpInLookUps\n    // NetCore also has\n    // - Ticks (DNN provides that so it's not included in .net 472)\n    // - DateTime (DNN provides that so it's not included in .net 472)\n#if NETCOREAPP\n    private const int SourcesAddedByDefault = 4;\n#else\n    private const int SourcesAddedByDefault = 2;\n#endif\n\n    [Fact]\n    public void SourcesDefault0()\n    {\n        var sources = templateSvc.Default().GetSources();\n        Equal(SourcesAddedByDefault, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesDefaultDeep()\n    {\n        var sources = templateSvc.Default().GetSources(depth: 10);\n        Equal(SourcesAddedByDefault, sources.Count());\n    }\n\n\n    [Fact]\n    public void SourcesOnEmptyAdd1()\n    {\n        var sources = templateSvc.Default(sources: [helper.GetDicSource()]).GetSources();\n        Equal(1, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesOnEmptyAdd1GetDeep()\n    {\n        var sources = templateSvc.Default(sources: [helper.GetDicSource()]).GetSources(depth: 10);\n        Equal(SourcesAddedByDefault + 1, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesOnEmptyAdd2()\n    {\n        var sources = templateSvc.Default(sources: [helper.GetDicSource(), helper.GetFnSource()]).GetSources();\n        Equal(2, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesOnEmptyGet2Identical1()\n    {\n        var sources = templateSvc.Default(sources: [helper.GetDicSource(), helper.GetDicSource()]).GetSources();\n        Equal(1, sources.Count());\n    }\n\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Templates/TemplatesDefaultTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.Templates;\n\n/// <summary>\n/// Run tests on the Default() templates - ATM can't work, because the App doesn't exist, which is used to get the Default() template.\n/// </summary>\npublic class TemplatesDefaultTests(ITemplateService templateSvc, TemplatesTestsBaseHelper helper) //: TemplatesTestsBase\n{\n    [Fact]\n    public void DefaultServiceIsReused()\n    {\n        var instance1 = templateSvc.Default();\n        var instance2 = templateSvc.Default();\n        Equal(instance1, instance2);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Templates/TemplatesEmptySourcesTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.Templates;\n\npublic class TemplatesEmptySourcesTests(ITemplateService templateSvc, TemplatesTestsBaseHelper helper)// : TemplatesTestsBase\n{\n\n    [Fact]\n    public void SourcesDefault0()\n    {\n        var sources = templateSvc.Empty().GetSources();\n        Equal(0, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesDefaultDeep()\n    {\n        var sources = templateSvc.Empty().GetSources(depth: 10);\n        Equal(0, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesOnEmptyGet1()\n    {\n        var sources = templateSvc.Empty(sources: [helper.GetDicSource()]).GetSources();\n        Equal(1, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesOnEmptyGet1Deep()\n    {\n        var sources = templateSvc.Empty(sources: [helper.GetDicSource()]).GetSources(depth: 10);\n        Equal(1, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesOnEmptyGet2()\n    {\n        var sources = templateSvc.Empty(sources: [helper.GetDicSource(), helper.GetFnSource()]).GetSources();\n        Equal(2, sources.Count());\n    }\n\n    [Fact]\n    public void SourcesOnEmptyGet2Identical1()\n    {\n        var sources = templateSvc.Empty(sources: [helper.GetDicSource(), helper.GetDicSource()]).GetSources();\n        Equal(1, sources.Count());\n    }\n\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Templates/TemplatesEmptyTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.Templates;\n\npublic class TemplatesEmptyTests(ITemplateService templateSvc, TemplatesTestsBaseHelper helper)  //: TemplatesTestsBase\n{\n\n    [Fact]\n    public void EmptyServiceIsReused()\n    {\n        var instance1 = templateSvc.Empty();\n        var instance2 = templateSvc.Empty();\n        Equal(instance1, instance2);\n    }\n\n\n    [Theory]\n    [InlineData(\"Hello World\")]\n    public void EmptyNoData(string expectedAndValue)\n    {\n        var svc = templateSvc;\n        var result = svc.Empty().Parse(expectedAndValue);\n        Equal(expectedAndValue, result);\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Templates/TemplatesHtmlTests.cs",
    "content": "﻿using ToSic.Eav.LookUp;\nusing ToSic.Sxc.Services;\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.ServicesTests.Templates;\n\npublic class TemplatesHtmlTests(ITemplateService templateSvc, TemplatesTestsBaseHelper helper) // : TemplatesTestsBase\n{\n    private const string HtmlValue = \"<div>message</div>\";\n    private ILookUp GetHtml() => templateSvc.CreateSource(\"html\", new Dictionary<string, string>\n    {\n        { \"Key1\", \"Val1\" },\n        { \"Key2\", \"Val2\" },\n        { \"Html\", HtmlValue }\n    });\n\n\n    [Theory]\n    [InlineData(\"<div>Val1</div>\", \"<div>[Html:Key1]</div>\")]\n    [InlineData(\"<strong>Val2</strong>\", \"<strong>[Html:Key2]</strong>\")]\n    [InlineData(\"<strong>\" + HtmlValue + \"</strong>\", \"<strong>[Html:HTml]</strong>\")]\n    public void HtmlAllowed(string expected, string value, string? notes = default)\n    {\n        var svc = templateSvc;\n        var result = svc.Empty(sources: [GetHtml()]).Parse(value, allowHtml: true);\n        Equal(expected, result);//, $\"Value: '{value}', notes: {notes}\");\n    }\n\n    [Theory]\n    [InlineData(\"<div>Val1</div>\", \"<div>[Html:Key1]</div>\")]\n    [InlineData(\"<strong>Val2</strong>\", \"<strong>[Html:Key2]</strong>\")]\n    [InlineData(\"<strong>&lt;div&gt;message&lt;/div&gt;</strong>\", \"<strong>[Html:Html]</strong>\")]\n    public void HtmlForbidden(string expected, string value, string? notes = default)\n    {\n        var svc = templateSvc;\n        var result = svc.Empty(sources: [GetHtml()]).Parse(value);\n        Equal(expected, result);//, $\"Value: '{value}', notes: {notes}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ServicesTests/Templates/TemplatesTestsBaseHelper.cs",
    "content": "﻿using ToSic.Eav.LookUp;\nusing ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.ServicesTests.Templates;\n\npublic class TemplatesTestsBaseHelper(ITemplateService templateSvc) \n{\n    internal ILookUp GetDicSource(string name = \"dic\") =>\n        templateSvc.CreateSource(name, new Dictionary<string, string>\n        {\n            { \"Key1\", \"Val1\" },\n            { \"Key2\", \"Val2\" }\n        });\n\n    internal ILookUp GetFnSource(string name = \"fn\") =>\n        templateSvc.CreateSource(name, s => s?.ToLowerInvariant() switch\n        {\n            \"key1\" => \"Val1\",\n            \"key2\" => \"Val2\",\n            _ => \"\"\n        });\n\n    internal ILookUp GetFnNumberSourcesWithFormat(string name = \"fn\") =>\n        templateSvc.CreateSource(name, (s, f) =>\n        {\n            var result = s?.ToLowerInvariant() switch\n            {\n                \"key1\" => 42,\n                \"key2\" => 27,\n                _ => 0\n            };\n            return string.IsNullOrWhiteSpace(f)\n                ? result.ToString()\n                : result.ToString(f);\n        });\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/StartupMockExecutionContext.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.Apps.Mocks;\nusing ToSic.Eav.Context;\nusing ToSic.Sxc.Mocks;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Services.PageService;\nusing ToSic.Sxc.ServicesTests.CmsService;\nusing ToSic.Sys.Capabilities.Platform;\nusing ToSic.Testing.Shared.Platforms;\n\nnamespace ToSic.Sxc;\n\npublic class StartupMockExecutionContext : StartupSxcWithDb\n{\n    public override void ConfigureServices(IServiceCollection services)\n    {\n        //services.TryAddTransient<IValueConverter, MockValueConverter>();\n        base.ConfigureServices(\n            services\n                // Add the MockPageService to the services - needed as a sub-dependency of the CmsService / StringWysiwyg\n                .AddTransient<IPageService, MockPageService>()\n                .AddTransient<DataForCmsServiceTests>()\n\n                // This is a dependency of the IApp\n                .AddTransient<ISite, MockSite>()\n                .AddTransient<ExecutionContextMock>()\n                .AddTransient<IAppsCatalog, AppsCatalogMock>()\n        );\n    }\n\n}\n\npublic class StartupMockExecutionContextNoPatron : StartupMockExecutionContext\n{\n    public override void ConfigureServices(IServiceCollection services)\n    {\n        // Don't add the patron, as this is not needed for the tests\n        base.ConfigureServices(services\n            .AddTransient<IPlatformInfo, TestPlatformNotPatron>());\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/StartupSxcCoreOnly.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Run.Startup;\nusing ToSic.Sxc.Run.Startup;\n\n#pragma warning disable CA1822\n\nnamespace ToSic.Sxc;\n\n// NOTE: QUITE A FEW DUPLICATES OF THIS - may want to consolidate\n\n/// <summary>\n/// A Startup helper for tests which need Dependency-Injection setup for EAV Core.\n/// </summary>\n/// <remarks>\n/// Use by adding this kind of attribute to your test class:\n/// `[Startup(typeof(TestStartupEavCore))]`\n/// </remarks>\npublic class StartupSxcCoreOnly\n{\n    /// <summary>\n    /// Startup helper\n    /// </summary>\n    public virtual void ConfigureServices(IServiceCollection services) =>\n        services\n            .AddFixtureHelpers()\n            .AddDataSourceTestHelpers()\n            // First add the \"Fallbacks\" since these don't have Dnn/Oqtane specific implementations\n            // Without this, some of the link tests will fail\n            .AddSxcCoreFallbacks()\n\n            // 2sxc core\n            .AddSxcApps()\n            .AddSxcEdit()\n            .AddSxcData()\n            .AddSxcAdam()\n            .AddSxcAdamWork<int, int>()\n            .AddSxcBlocks()\n            .AddSxcRender()\n            .AddSxcCore()\n            .AddSxcCms()\n            .AddSxcImages()\n            .AddSxcServices()\n            .AddSxcWeb()\n            .AddSxcCode()\n            .AddSxcLightSpeed()\n\n            .AddEavPersistence()\n            .AddEavDataBuild()\n            .AddEavDataStack()\n            .AddEavModels()\n            .AddEavData()\n            // EAV Core and Downstream\n            .AddAllLibAndSys()\n\n            .AddSxcAppsFallbacks()\n            .AddEavDataBuildFallbacks()\n            .AddEavDataFallbacks()\n            .AddAllLibAndSysFallbacks();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/StartupSxcWithDb.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Run.Startup;\nusing ToSic.Sxc.Run.Startup;\n\n#pragma warning disable CA1822\n\nnamespace ToSic.Sxc;\n\n// NOTE: QUITE A FEW DUPLICATES OF THIS - may want to consolidate\n\n/// <summary>\n/// A Startup helper for tests which need Dependency-Injection setup for EAV Core.\n/// </summary>\n/// <remarks>\n/// Use by adding this kind of attribute to your test class:\n/// `[Startup(typeof(TestStartupEavCore))]`\n/// </remarks>\npublic class StartupSxcWithDb\n{\n    /// <summary>\n    /// Startup helper\n    /// </summary>\n    public virtual void ConfigureServices(IServiceCollection services) =>\n        services\n            .AddFixtureHelpers()\n            .AddDataSourceTestHelpers()\n            // 2sxc core\n            .AddSxcCore()\n            .AddSxcApps()\n            .AddSxcEdit()\n            .AddSxcData()\n            .AddSxcAdam()\n            .AddSxcAdamWork<int, int>()\n            .AddSxcBlocks()\n            .AddSxcRender()\n            .AddSxcCms()\n            .AddSxcServices()\n            .AddSxcCode()\n            .AddSxcEngines()\n            .AddSxcImages()\n            .AddSxcWeb()\n            .AddSxcLightSpeed()\n            .AddSxcAppsFallbacks()\n\n            .AddEavAll()\n            .AddEavAllFallbacks();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/StartupSxcWithDbBasic.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Sys.Capabilities.Platform;\nusing ToSic.Testing.Shared.Platforms;\n\nnamespace ToSic.Sxc;\n\npublic class StartupSxcWithDbBasic : StartupSxcWithDb\n{\n    public override void ConfigureServices(IServiceCollection services) =>\n        base.ConfigureServices(\n            services\n                .AddTransient<IPlatformInfo, TestPlatformNotPatron>()\n        );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/StartupSxcWithDbPatronPerfectionist.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing ToSic.Sys.Capabilities.Platform;\nusing ToSic.Testing.Shared.Platforms;\n\nnamespace ToSic.Sxc;\n\npublic class StartupSxcWithDbPatronPerfectionist : StartupMockExecutionContext\n{\n    public override void ConfigureServices(IServiceCollection services) =>\n        base.ConfigureServices(\n            services\n                .AddTransient<IPlatformInfo, TestPlatformPatronPerfectionist>()\n        );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/ToSic.Sxc.Various.SystemTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForTestCode.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <PropertyGroup>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.DataSource.TestHelpers\\ToSic.Eav.DataSource.TestHelpers.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Testing.FullDbFixtures\\ToSic.Eav.Testing.FullDbFixtures.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Features.TestHelpers\\ToSic.Sys.Features.TestHelpers.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Cms\\ToSic.Sxc.Cms.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Edit\\ToSic.Sxc.Edit.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.LightSpeed\\ToSic.Sxc.LightSpeed.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n    <ProjectReference Include=\"..\\..\\Sxc\\ToSic.Sxc.Web\\ToSic.Sxc.Web.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core.TestHelpers\\ToSic.Sxc.Core.TestHelpers.csproj\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/Web.PageFeatures/SimpleFeatureManagement.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.PageFeatures;\n\nnamespace ToSic.Sxc.Web.PageFeatures;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class SimpleFeatureManagement(IPageFeaturesManager fm, PageFeaturesCatalog cat)\n{\n    [Fact]\n    public void PageFeaturesCaseInsensitive()\n    {\n        NotNull(fm.Features[\"turnOn\"]);\n        NotNull(fm.Features[\"Turnon\"]);\n    }\n    [Fact]\n    public void AdditionalFeatures()\n    {\n        False(fm.Features.TryGetValue(\"dummy\", out _));\n\n        cat.Register(new PageFeature { NameId = \"dummy\", Name = \"dummy-feature\" });\n\n        NotNull(fm.Features[\"dummy\"]);\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/WebLightSpeed/LightSpeedDecoratorTests.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\n\nnamespace ToSic.Sxc.WebLightSpeed;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LightSpeedDecoratorTests(DataAssembler dataAssembler, ContentTypeAssembler typeAssembler)//: TestBaseEavCore\n{\n    //public LightSpeedDecoratorTests() => _testData = new(dataBuilder);\n\n    private readonly LightSpeedTestData _testData = new(dataAssembler, typeAssembler);\n\n\n    [Fact]\n    public void DecoratorWithNullEntity()\n    {\n        var lsDecorator = (null as IEntity).ToModel<LightSpeedDecorator>(nullHandling: ModelNullHandling.PreferModel);\n        TestEmptyDecorator(lsDecorator);\n        True(lsDecorator.UrlParametersOthersDisableCache);\n    }\n\n    [Fact]\n    public void DecoratorWithEntity()\n    {\n        var lsDecorator = _testData.Decorator();\n        Equal(LightSpeedTestData.DefTitle, lsDecorator.Title);\n        TestEmptyDecorator(lsDecorator);\n    }\n\n    private static void TestEmptyDecorator(LightSpeedDecorator lsDecorator)\n    {\n        False(lsDecorator.IsEnabled);\n        Equal(\"\", lsDecorator.UrlParameterNames);\n        False(lsDecorator.ByUrlParameters);\n        False(lsDecorator.UrlParametersCaseSensitive);\n        True(lsDecorator.UrlParametersOthersDisableCache);\n    }\n\n    [Fact]\n    public void DecoratorWithByUrlParameter()\n        => True(_testData.Decorator(byUrlParameters: true).ByUrlParameters);\n\n    [Fact]\n    public void DecoratorWithCaseSensitive()\n        => True(_testData.Decorator(caseSensitive: true).UrlParametersCaseSensitive);\n\n    [Fact]\n    public void DecoratorWithNames()\n        => Equal(\"a\\nb\\nc\", _testData.Decorator(names: \"a\\nb\\nc\").UrlParameterNames);\n\n    [Fact]\n    public void DecoratorWithDisableCache()\n        => False(_testData.Decorator(othersDisableCache: false).UrlParametersOthersDisableCache);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/WebLightSpeed/LightSpeedOutputCacheCompressionTestData.cs",
    "content": "using System.IO.Compression;\nusing System.Text;\n\nnamespace ToSic.Sxc.WebLightSpeed;\n\npublic enum TestCompressionProfile\n{\n    GZipFastest,\n    GZipOptimal,\n}\n\npublic record HtmlCompressionCase(string Name, int ApproxChars)\n{\n    public override string ToString() => Name;\n}\n\npublic static class LightSpeedOutputCacheCompressionTestData\n{\n    public static TheoryData<HtmlCompressionCase> HtmlSizes { get; } =\n    [\n        new(\"Approx 100 B\", 100),\n        new(\"Approx 1 KB\", 1_000),\n        new(\"Approx 5 KB\", 5_000),\n        new(\"Approx 10 KB\", 10_000),\n    ];\n\n    public static TheoryData<HtmlCompressionCase, TestCompressionProfile> HtmlSizesAndProfiles { get; } = BuildSizesAndProfiles();\n\n    private static TheoryData<HtmlCompressionCase, TestCompressionProfile> BuildSizesAndProfiles()\n    {\n        TheoryData<HtmlCompressionCase, TestCompressionProfile> data = [];\n        foreach (var htmlSize in HtmlSizes)\n        {\n            data.Add(htmlSize, TestCompressionProfile.GZipFastest);\n            data.Add(htmlSize, TestCompressionProfile.GZipOptimal);\n        }\n\n        return data;\n    }\n\n    public static string CreateRealisticHtml(int approxChars)\n    {\n        var html = new StringBuilder(approxChars + 1024);\n        var random = new Random(approxChars);\n        html.AppendLine(\"<main class=\\\"page page--cache-test\\\" data-cache=\\\"lightspeed\\\">\");\n\n        var index = 1;\n        while (html.Length < approxChars)\n        {\n            html.AppendLine(BuildFragment(index, random));\n            index++;\n        }\n\n        html.AppendLine(\"</main>\");\n        return html.ToString();\n    }\n\n    private static string BuildFragment(int index, Random random)\n    {\n        var title = $\"{Pick(Titles, random)} {Pick(Topics, random)}\";\n        var author = Pick(Authors, random);\n        var city = Pick(Cities, random);\n        var category = Pick(Categories, random);\n        var blockKind = Pick(BlockKinds, random);\n        var stateClass = index % 3 == 0 ? \"is-featured\" : \"is-standard\";\n        var slug = ToSlug(title, index, random.Next(1000, 9999));\n        var isoDate = new DateTime(2025, 1, 1).AddDays((index * 17) % 320).ToString(\"yyyy-MM-dd\");\n        var uniqueKey = BuildUniqueKey(index, random);\n        var tags = BuildTags(index, random);\n        var metrics = $\"{{&quot;views&quot;:{random.Next(20, 9000)},&quot;score&quot;:{random.Next(10, 99)},&quot;v&quot;:&quot;{uniqueKey}&quot;}}\";\n        var imageWidth = 320 + index % 5 * 40;\n        var imageHeight = 180 + index % 4 * 20;\n        var imageQuality = 60 + index % 30;\n\n        return (index % 4) switch\n        {\n            0 => $@\"<article class=\"\"card card--{blockKind} {stateClass}\"\" data-id=\"\"{index}\"\" data-category=\"\"{category}\"\" data-state=\"\"{metrics}\"\">\n  <header class=\"\"card__header\"\">\n    <h2 class=\"\"card__title\"\">{title}</h2>\n    <p class=\"\"card__meta\"\">\n      <span class=\"\"author\"\">{author}</span>\n      <span class=\"\"city\"\">{city}</span>\n      <time datetime=\"\"{isoDate}\"\">{isoDate}</time>\n    </p>\n  </header>\n  <div class=\"\"card__body\"\">\n    <p>{Pick(Sentences, random)} {Pick(Sentences, random)}</p>\n    <ul class=\"\"tag-list\"\">{tags}</ul>\n    <a class=\"\"btn btn--primary\"\" href=\"\"/news/{slug}?cat={category}&amp;ref={random.Next(100, 999)}\"\">Read more</a>\n  </div>\n</article>\",\n            1 => $@\"<section class=\"\"teaser teaser--split teaser--{blockKind}\"\" data-ref=\"\"{uniqueKey}\"\">\n  <div class=\"\"teaser__content\"\">\n    <h3>{title}</h3>\n    <p>{Pick(Sentences, random)}</p>\n    <p>{Pick(Sentences, random)}</p>\n  </div>\n  <aside class=\"\"teaser__aside\"\">\n    <img src=\"\"/img/{slug}.jpg?width={imageWidth}&amp;quality={imageQuality}\"\" width=\"\"{imageWidth}\"\" height=\"\"{imageHeight}\"\" alt=\"\"{title}\"\">\n  </aside>\n</section>\",\n            2 => $@\"<li class=\"\"search-result search-result--{category}\"\" data-score=\"\"{random.NextDouble():F3}\"\" data-key=\"\"{uniqueKey}\"\">\n  <a href=\"\"/docs/{slug}\"\">\n    <strong>{title}</strong>\n    <span class=\"\"breadcrumb\"\">/{category}/{city}/{index}</span>\n    <span class=\"\"excerpt\"\">{Pick(Sentences, random)} {Pick(Sentences, random)}</span>\n  </a>\n</li>\",\n            _ => $@\"<div class=\"\"content-block content-block--{blockKind}\"\" id=\"\"block-{index}\"\" data-json=\"\"{metrics}\"\">\n  <h4>{title}</h4>\n  <blockquote>{Pick(Quotes, random)}</blockquote>\n  <pre class=\"\"snippet\"\">var cfg = {{ \"\"id\"\": {index}, \"\"key\"\": \"\"{uniqueKey}\"\", \"\"slug\"\": \"\"{slug}\"\", \"\"city\"\": \"\"{city}\"\" }};</pre>\n</div>\",\n        };\n    }\n\n    private static string BuildTags(int index, Random random)\n    {\n        var tagCount = 2 + index % 4;\n        var tags = new StringBuilder(tagCount * 32);\n        for (var tagIndex = 0; tagIndex < tagCount; tagIndex++)\n            tags.Append($\"<li class=\\\"tag tag--{tagIndex}\\\">{Pick(Tags, random)}</li>\");\n\n        return tags.ToString();\n    }\n\n    private static string Pick(IReadOnlyList<string> values, Random random)\n        => values[random.Next(values.Count)];\n\n    private static string BuildUniqueKey(int index, Random random)\n      => $\"{index:x4}{random.Next(0, 1 << 16):x4}{random.Next(0, 1 << 16):x4}\";\n\n    private static string ToSlug(string value, int index, int suffix)\n      => string.Join(\"-\", value.ToLowerInvariant().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)) + $\"-{index}-{suffix}\";\n\n    public static byte[] Compress(string html, TestCompressionProfile profile)\n    {\n        var input = Encoding.UTF8.GetBytes(html);\n\n        using var output = new MemoryStream(input.Length);\n        using (var compressionStream = new GZipStream(output, ToCompressionLevel(profile), leaveOpen: true))\n            compressionStream.Write(input, 0, input.Length);\n\n        return output.ToArray();\n    }\n\n    public static string Decompress(byte[] compressed)\n    {\n        using var input = new MemoryStream(compressed);\n        using var decompressionStream = new GZipStream(input, CompressionMode.Decompress, leaveOpen: true);\n        using var reader = new StreamReader(decompressionStream, Encoding.UTF8, detectEncodingFromByteOrderMarks: false);\n        return reader.ReadToEnd();\n    }\n\n    public static int GetUtf8ByteCount(string html)\n        => Encoding.UTF8.GetByteCount(html);\n\n    private static CompressionLevel ToCompressionLevel(TestCompressionProfile profile)\n        => profile switch\n        {\n            TestCompressionProfile.GZipFastest => CompressionLevel.Fastest,\n            TestCompressionProfile.GZipOptimal => CompressionLevel.Optimal,\n            _ => throw new ArgumentOutOfRangeException(nameof(profile), profile, null),\n        };\n\n    private static readonly string[] Titles =\n    [\n      \"Latest\",\n      \"Breaking\",\n      \"Weekly\",\n      \"Community\",\n      \"Editorial\",\n      \"Release\",\n      \"Migration\",\n      \"Preview\",\n    ];\n\n    private static readonly string[] Topics =\n    [\n      \"Caching\",\n      \"Search\",\n      \"Content\",\n      \"Images\",\n      \"Templates\",\n      \"Security\",\n      \"Routing\",\n      \"Insights\",\n    ];\n\n    private static readonly string[] Authors =\n    [\n      \"2sxc Team\",\n      \"Daniel Mettler\",\n      \"Benjamin Freitag\",\n      \"Roman Opalko\",\n      \"Dominik Graf\",\n      \"Raoul Bossi\",\n    ];\n\n    private static readonly string[] Cities =\n    [\n      \"Buchs\",\n      \"Zurich\",\n      \"Vienna\",\n      \"Berlin\",\n      \"Ljubljana\",\n      \"Oslo\",\n      \"Milan\",\n    ];\n\n    private static readonly string[] Categories =\n    [\n      \"guides\",\n      \"blog\",\n      \"docs\",\n      \"news\",\n      \"release-notes\",\n      \"announcements\",\n    ];\n\n    private static readonly string[] BlockKinds =\n    [\n      \"teaser\",\n      \"feature\",\n      \"summary\",\n      \"compact\",\n      \"quote\",\n      \"code\",\n    ];\n\n    private static readonly string[] Tags =\n    [\n      \"cache\",\n      \"lightspeed\",\n      \"html\",\n      \"compression\",\n      \"razor\",\n      \"rendering\",\n      \"cms\",\n      \"performance\",\n    ];\n\n    private static readonly string[] Sentences =\n    [\n      \"This fragment simulates CMS output with varying metadata and nested markup.\",\n      \"The benchmark should include repeated patterns, but not to the point of synthetic compression ratios.\",\n      \"Rendered pages often contain unique slugs, ids, dates, image urls and query strings.\",\n      \"Some blocks include short text while others contain denser paragraphs and attribute-heavy markup.\",\n      \"Mixed page output usually combines cards, lists, snippets, images and editorial text.\",\n    ];\n\n    private static readonly string[] Quotes =\n    [\n      \"Cache correctness matters more than micro-bench optimism.\",\n      \"Compression only helps if the memory trade is real.\",\n      \"Synthetic markup should be representative, not flattering.\",\n    ];\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/WebLightSpeed/LightSpeedOutputCacheCompressionTests.cs",
    "content": "using System.Diagnostics;\nusing System.Text;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sys.Memory;\nusing Xunit.Abstractions;\n\nnamespace ToSic.Sxc.WebLightSpeed;\n\npublic class LightSpeedOutputCacheCompressionTests(ITestOutputHelper output)\n{\n    [Theory(Skip = \"Disabled benchmark/report test.\")]\n    [MemberData(nameof(LightSpeedOutputCacheCompressionTestData.HtmlSizesAndProfiles), MemberType = typeof(LightSpeedOutputCacheCompressionTestData))]\n    public void GZipProfiles_RoundTrip_And_Report(HtmlCompressionCase testCase, TestCompressionProfile profile)\n    {\n        var html = LightSpeedOutputCacheCompressionTestData.CreateRealisticHtml(testCase.ApproxChars);\n        var compressed = LightSpeedOutputCacheCompressionTestData.Compress(html, profile);\n        var decompressed = LightSpeedOutputCacheCompressionTestData.Decompress(compressed);\n\n        Equal(html, decompressed);\n\n        var utf8Bytes = LightSpeedOutputCacheCompressionTestData.GetUtf8ByteCount(html);\n        var estimatedStringPayloadBytes = html.Length * sizeof(char);\n        var compressDuration = Measure(() => LightSpeedOutputCacheCompressionTestData.Compress(html, profile), iterations: 100);\n        var decompressDuration = Measure(() => LightSpeedOutputCacheCompressionTestData.Decompress(compressed), iterations: 100);\n\n        output.WriteLine($\"{testCase.Name} | {profile} | chars: {html.Length} | utf8: {utf8Bytes} B | string payload: {estimatedStringPayloadBytes} B | compressed: {compressed.Length} B | compress x100: {compressDuration.TotalMilliseconds:F2} ms | decompress x100: {decompressDuration.TotalMilliseconds:F2} ms\");\n    }\n\n    [Theory(Skip = \"Disabled benchmark/report test.\")]\n    [MemberData(nameof(LightSpeedOutputCacheCompressionTestData.HtmlSizes), MemberType = typeof(LightSpeedOutputCacheCompressionTestData))]\n    public void Lifecycle_Report_For_CacheLike_Reads(HtmlCompressionCase testCase)\n    {\n        var html = LightSpeedOutputCacheCompressionTestData.CreateRealisticHtml(testCase.ApproxChars);\n\n        foreach (var reads in new[] { 1, 10, 50 })\n        {\n            var compressedDuration = Measure(() =>\n            {\n                var compressed = LightSpeedOutputCacheCompressionTestData.Compress(html, TestCompressionProfile.GZipFastest);\n                var lastLength = 0;\n                for (var index = 0; index < reads; index++)\n                    lastLength = LightSpeedOutputCacheCompressionTestData.Decompress(compressed).Length;\n                return lastLength;\n            }, iterations: 50);\n\n            var rawDuration = Measure(() =>\n            {\n                var lastLength = 0;\n                for (var index = 0; index < reads; index++)\n                    lastLength = html.Length;\n                return lastLength;\n            }, iterations: 50);\n\n            output.WriteLine($\"{testCase.Name} | 1 write + {reads} reads | compressed x50: {compressedDuration.TotalMilliseconds:F2} ms | raw x50: {rawDuration.TotalMilliseconds:F2} ms\");\n        }\n    }\n\n    [Fact]\n    public void OutputCacheItem_DoesNotCompress_WhenDisabled()\n    {\n        var html = LightSpeedOutputCacheCompressionTestData.CreateRealisticHtml(10_000);\n        var result = CreateRenderResult(html);\n\n        var cacheItem = new OutputCacheItem(LightSpeedDataCompression.OptimizeForCache(result, useCompression: false, minBytes: 5_000));\n\n        False(IsCompressed(cacheItem.Data));\n        Same(result, cacheItem.Data);\n    }\n\n    [Fact]\n    public void OutputCacheItem_DoesNotCompress_WhenBelowThreshold()\n    {\n        var html = LightSpeedOutputCacheCompressionTestData.CreateRealisticHtml(1_000);\n        var result = CreateRenderResult(html);\n\n        var cacheItem = new OutputCacheItem(LightSpeedDataCompression.OptimizeForCache(result, useCompression: true, minBytes: 5_000));\n\n        False(IsCompressed(cacheItem.Data));\n        Same(result, cacheItem.Data);\n    }\n\n    [Fact]\n    public void OutputCacheItem_DoesNotCompress_WhenCompressionDoesNotSaveSpace()\n    {\n        const string html = \"<p class=\\\"teaser\\\">Hi</p>\";\n        var result = CreateRenderResult(html);\n\n        var cacheItem = new OutputCacheItem(LightSpeedDataCompression.OptimizeForCache(result, useCompression: true, minBytes: 1));\n\n        False(IsCompressed(cacheItem.Data));\n        Same(result, cacheItem.Data);\n    }\n\n    [Fact]\n    public void OutputCacheItem_Compresses_And_RoundTrips_WhenEnabled_AndUseful()\n    {\n        var html = LightSpeedOutputCacheCompressionTestData.CreateRealisticHtml(10_000);\n        var result = CreateRenderResult(html) with\n        {\n            AppId = 27,\n            ModuleId = 99,\n            IsPartial = false,\n            Errors = [\"sample-error\"],\n        };\n        result.DependentApps.Add(new TestDependentApp(7));\n\n        var cacheItem = new OutputCacheItem(LightSpeedDataCompression.OptimizeForCache(result, useCompression: true, minBytes: 5_000));\n        var compressedResult = (RenderResult)cacheItem.Data;\n\n        True(IsCompressed(cacheItem.Data));\n        var compressedBytes = result.CompressedHtml?.Length;\n        NotNull(compressedBytes);\n        NotNull(compressedResult.CompressedTrueSize);\n        True(compressedBytes < compressedResult.CompressedTrueSize);\n\n        var cachedResult = cacheItem.Data;\n        Equal(html, cachedResult.Html);\n        Equal(result.AppId, cachedResult.AppId);\n        Equal(result.ModuleId, cachedResult.ModuleId);\n        Equal(result.CanCache, cachedResult.CanCache);\n        Equal(result.IsPartial, cachedResult.IsPartial);\n        Equal(result.Errors, cachedResult.Errors);\n        Single(cachedResult.DependentApps!);\n        NotSame(result, cachedResult);\n    }\n\n    [Fact]\n    public void RenderResult_ReDecompressesHtml_OnEachRead_WhenCompressed()\n    {\n        var html = LightSpeedOutputCacheCompressionTestData.CreateRealisticHtml(10_000);\n        var result = CreateRenderResult(html);\n\n        var cacheItem = new OutputCacheItem(LightSpeedDataCompression.OptimizeForCache(result, useCompression: true, minBytes: 5_000));\n\n        True(IsCompressed(cacheItem.Data));\n\n        var firstRead = cacheItem.Data;\n        var secondRead = cacheItem.Data;\n\n        Equal(html, firstRead.Html);\n        Equal(html, secondRead.Html);\n        Same(firstRead, secondRead);\n        False(ReferenceEquals(firstRead.Html, secondRead.Html));\n    }\n\n    private static RenderResult CreateRenderResult(string html) => new()\n    {\n        Html = html,\n        CanCache = true,\n        AppId = 3,\n        ModuleId = 4,\n        IsPartial = false,\n    };\n\n    private static bool IsCompressed(IRenderResult result)\n        => (result as IOptimizeMemory)?.UseCompression == true;\n\n    private static TimeSpan Measure<T>(Func<T> action, int iterations)\n    {\n        action();\n\n        var stopwatch = Stopwatch.StartNew();\n        for (var index = 0; index < iterations; index++)\n            _ = action();\n        stopwatch.Stop();\n\n        return stopwatch.Elapsed;\n    }\n\n    private class TestDependentApp(int appId) : IDependentApp\n    {\n        public int AppId { get; } = appId;\n        public bool IsSitePrimaryApp { get; } = false;\n        public bool IsEnabled { get; } = true;\n        public List<string> CacheKeys { get; } = [$\"app-{appId}\"];\n        public ICollection<string> PathsToMonitor { get; } = [];\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/WebLightSpeed/LightSpeedTestData.cs",
    "content": "﻿using ToSic.Eav.Data;\nusing ToSic.Eav.Data.Build;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\n\nnamespace ToSic.Sxc.WebLightSpeed;\n\npublic class LightSpeedTestData(DataAssembler dataAssembler, ContentTypeAssembler typeAssembler)\n{\n    public const int AppId = -1;\n    internal const string DefTitle = \"LightSpeed Configuration\";\n\n    internal LightSpeedDecorator Decorator(bool? isEnabled = default, bool? byUrlParameters = null, bool? caseSensitive = null, string? names = default, bool? othersDisableCache = default)\n        => LightSpeedTestEntity(isEnabled: isEnabled, byUrlParameters: byUrlParameters, caseSensitive: caseSensitive, names: names, othersDisableCache: othersDisableCache)\n            .ToModel<LightSpeedDecorator>(skipTypeCheck: true)!;\n\n    /// <summary>\n    /// Basic LightSpeed Content Type with Url Fields only for testing\n    /// </summary>\n    private IContentType LsCtUrlFields => typeAssembler.Type.CreateContentTypeTac(appId: AppId, name: LightSpeedDecorator.ContentTypeName, attributes:\n        [\n            typeAssembler.ContentTypeAttributeTac(AppId, nameof(LightSpeedDecorator.Title), DataTypes.Boolean, true),\n            typeAssembler.ContentTypeAttributeTac(AppId, nameof(LightSpeedDecorator.IsEnabled), DataTypes.Boolean),\n            typeAssembler.ContentTypeAttributeTac(AppId, nameof(LightSpeedDecorator.ByUrlParameters), DataTypes.Boolean),\n            typeAssembler.ContentTypeAttributeTac(AppId, nameof(LightSpeedDecorator.UrlParametersCaseSensitive), DataTypes.Boolean),\n            typeAssembler.ContentTypeAttributeTac(AppId, nameof(LightSpeedDecorator.UrlParameterNames), DataTypes.String),\n            typeAssembler.ContentTypeAttributeTac(AppId, nameof(LightSpeedDecorator.UrlParametersOthersDisableCache), DataTypes.Boolean),\n        ]\n    );\n\n    private IEntity LightSpeedTestEntity(bool? isEnabled = default, bool? byUrlParameters = default, bool? caseSensitive = default, string? names = default, bool? othersDisableCache = default)\n    {\n        var values = new Dictionary<string, object>\n        {\n            {nameof(LightSpeedDecorator.Title), DefTitle},\n            {nameof(LightSpeedDecorator.IsEnabled), isEnabled},\n            {nameof(LightSpeedDecorator.ByUrlParameters), byUrlParameters},\n            {nameof(LightSpeedDecorator.UrlParametersCaseSensitive), caseSensitive},\n            {nameof(LightSpeedDecorator.UrlParameterNames), names},\n            {nameof(LightSpeedDecorator.UrlParametersOthersDisableCache), othersDisableCache }\n        };\n        var ent = dataAssembler.CreateEntityTac(appId: AppId, entityId: 1, contentType: LsCtUrlFields, values: values, titleField: nameof(LightSpeedDecorator.Title));\n        return ent;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/WebLightSpeed/LightSpeedUrlParamsTest.cs",
    "content": "﻿using System.Collections.Specialized;\nusing System.Diagnostics;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Context.Sys;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sxc.Web.Sys.Url;\n\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.WebLightSpeed;\n\n[Startup(typeof(StartupSxcCoreOnly))]\npublic class LightSpeedUrlParamsTest(DataAssembler dataAssembler, ContentTypeAssembler typeAssembler)//: TestBaseEavCore\n{\n    //public LightSpeedUrlParamsTest() => _testData = new(dataBuilder);\n\n    private readonly LightSpeedTestData _testData = new(dataAssembler, typeAssembler);\n\n    private static NameValueCollection Parse(string query) => UrlHelpers.ParseQueryString(query);\n\n    internal static (bool CachingAllowed, string Extension) GetUrlParamsTac(LightSpeedDecorator lsConfig,\n        string pageParameters, ILog? log = null, bool usePiggyBack = true)\n        => GetUrlParamsTac(lsConfig, new Parameters { Nvc = Parse(pageParameters) }, log, usePiggyBack);\n\n    internal static (bool CachingAllowed, string Extension) GetUrlParamsTac(LightSpeedDecorator lsConfig,\n        IParameters? pageParameters = null, ILog? log = null, bool usePiggyBack = true)\n        => LightSpeedUrlParams.GetUrlParams(lsConfig, pageParameters ?? new Parameters(), log, usePiggyBack);\n\n    [Theory]\n    [InlineData(true, null, \"no setting\")]\n    [InlineData(true, true, \"true\")]\n    [InlineData(false, false, \"false\")]\n    public void IsEnabled(bool expected, bool? isEnabled, string message)\n    {\n        var lsDecorator = _testData.Decorator(isEnabled: isEnabled);\n        var result = GetUrlParamsTac(lsDecorator);\n        Equal(expected, result.CachingAllowed);//, message);\n        Equal(\"\", result.Extension);\n    }\n\n    [Theory]\n    [InlineData(true, \"\", null, null, \"\", \"blank, enabled/byUrl not defined\")]\n    [InlineData(true, \"\", true, true, \"\", \"blank, enabled/byUrl true\")]\n    [InlineData(true, \"\", true, false, \"\", \"blank, enabled, but not byUrl\")]\n    [InlineData(true, \"\", true, false, \"a=b\")]\n    [InlineData(true, \"a=b\", true, true, \"a=b\")]\n    [InlineData(true, \"a=b&test=y\", true, true, \"test=y&a=b\")]//, DisplayName = \"Ensure parameters are sorted\")]\n    [InlineData(true, \"a=b&test=y&zeta=beta\", true, true, \"zeta=beta&test=y&a=b\")]//, DisplayName = \"Ensure parameters are sorted\")]\n    [InlineData(true, \"a=alpha&a=beta\", true, true, \"a=beta&a=alpha\")]//, DisplayName = \"Ensure parameter values are sorted\")]\n    [InlineData(false, \"\", false, null, \"\")]\n    public void ByUrlParameters(bool expected, string expValue, bool? isEnabled, bool? byUrlParameters, string urlParameters, string? message = default)\n    {\n        var lsDecorator = _testData.Decorator(isEnabled: isEnabled, byUrlParameters: byUrlParameters, othersDisableCache: false);\n        var result = GetUrlParamsTac(lsDecorator, urlParameters);\n        Equal(expected, result.CachingAllowed);//, message);//, \"caching allowed\");\n        Equal(expValue, result.Extension);//, \"strings match\");\n    }\n\n    [Theory]\n    [InlineData(\"\", \"\", \"\")]\n    [InlineData(\"\", \"a\", \"\")]\n    [InlineData(\"a=b\", \"a\", \"a=b\")]\n    [InlineData(\"a=b&b=c\", \"a,b\", \"a=b&b=c\")]\n    [InlineData(\"a=b\", \"a,b\", \"a=b\")]//, DisplayName = \"more possible, but only some given\")]\n    [InlineData(\"a=b\", \"*\", \"a=b\")]\n    [InlineData(\"a=b&c=d\", \"*\", \"a=b&c=d\")]\n    public void NamesShouldFilterResults(string expValue, string names, string urlParameters, string? message = default)\n    {\n        var lsDecorator = _testData.Decorator(isEnabled: true, byUrlParameters: true, names: names, othersDisableCache: true);\n        var result = GetUrlParamsTac(lsDecorator, urlParameters);\n        True(result.CachingAllowed);//, message);\n        Equal(expValue, result.Extension);\n    }\n\n    [Theory]\n    [InlineData(true, \"\", \"\")]//, DisplayName = \"no names, params\")]\n    [InlineData(false, \"\", \"a=b\")]//, DisplayName = \"has params but none expected\")]\n    [InlineData(true, \"a\", \"a=b\")]//, DisplayName = \"Has params, expected\")]\n    [InlineData(false, \"b\", \"a=b\")]//, DisplayName = \"Has params, others expected\")]\n    [InlineData(true, \"a,b\", \"a=b&b=c\")]//, DisplayName = \"Has params, expected\")]\n    [InlineData(false, \"a\", \"a=b&b=c\")]//, DisplayName = \"Has params, not all expected\")]\n    [InlineData(true, \"*\", \"a=b\")]//, DisplayName = \"has params, all expected\")]\n    [InlineData(true, \"*\", \"a=b&b=c\")]//, DisplayName = \"has params, all expected\")]\n    [InlineData(true, \"a,b\", \"a=b\")]//, DisplayName = \"Has params, more can be expected\")]\n    [InlineData(true, \"a,b\", \"\")]//, DisplayName = \"No params, various expected\")]\n    public void NamesShouldDisable(bool expected, string names, string urlParameters)\n    {\n        var lsDecorator = _testData.Decorator(isEnabled: true, byUrlParameters: true, names: names, othersDisableCache: true);\n        var result = GetUrlParamsTac(lsDecorator, urlParameters);\n        Equal(expected, result.CachingAllowed);\n    }\n\n    [Theory]\n    [InlineData(\"\", \"\", \"\")]\n    [InlineData(\"\", \"a\", \"\")]\n    [InlineData(\"a=b\", \"a // this is because xyz\", \"a=b\")]\n    [InlineData(\"a=b&b=c\", \"a // ok\\nb // also ok\", \"a=b&b=c\")]\n    [InlineData(\"a=b&c=d\", \"* // whatever\", \"a=b&c=d\")]\n    public void NamesCanBeMultilineAndCommented(string expValue, string names, string urlParameters, string? message = default)\n    {\n        var lsDecorator = _testData.Decorator(isEnabled: true, byUrlParameters: true, names: names, othersDisableCache: true);\n        var result = GetUrlParamsTac(lsDecorator, urlParameters);\n        True(result.CachingAllowed);//, message);\n        Equal(expValue, result.Extension);\n    }\n\n\n    [Fact]\n    public void LoadTestWithoutCaching()\n    {\n        const int repeat = 10000;\n        var lsDecorator = _testData.Decorator(isEnabled: true, byUrlParameters: true, names: \"a // nice idea\\nb // ok too, but a bit nasty\\n\\ntest // another one to parse\", othersDisableCache: true);\n        var parameters = \"ZETA=last&d=27&a=b&b=c\";\n\n        var stopwatch = Stopwatch.StartNew();\n        for (var i = 0; i < repeat; i++) \n            GetUrlParamsTac(lsDecorator, parameters, usePiggyBack: false);\n        stopwatch.Stop();\n\n        Trace.WriteLine($\"Ran {repeat} iterations without cache, duration was {stopwatch.ElapsedMilliseconds}ms\");\n\n        stopwatch = Stopwatch.StartNew();\n        for (var i = 0; i < repeat; i++) \n            GetUrlParamsTac(lsDecorator, parameters);\n        stopwatch.Stop();\n\n        Trace.WriteLine($\"Ran {repeat} iterations with cache, duration was {stopwatch.ElapsedMilliseconds}ms\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/WebLightSpeed/NamedCacheDependencyServiceTests.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Apps;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.Metadata;\nusing ToSic.Sxc.Apps;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.ModuleHtml;\nusing ToSic.Sxc.Services.Cache;\nusing ToSic.Sxc.Services.OutputCache;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sys.Caching;\nusing ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;\n\nnamespace ToSic.Sxc.WebLightSpeed;\n\n[Startup(typeof(StartupSxcWithDb))]\npublic class NamedCacheDependencyServiceTests(ExecutionContext exCtx)\n{\n    private const string DataCacheScope = \"data-cache\";\n\n    private INamedCacheDependencyService Dependencies => exCtx.GetService<INamedCacheDependencyService>(reuse: true);\n\n    private ModuleOutputCacheService OutputCache => exCtx.GetService<ModuleOutputCacheService>(reuse: true);\n\n    private ModuleHtmlService ModuleHtml => (ModuleHtmlService)exCtx.GetService<IModuleHtmlService>(reuse: true);\n\n    private MemoryCacheService Cache => exCtx.GetService<MemoryCacheService>(reuse: true);\n\n    [Fact]\n    public void KeysAreScopedByAppAndScope()\n    {\n        var outputApp7Keys = Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 7, [\" Products \", \"pricing\", \"PRODUCTS\"]);\n        var outputApp8Keys = Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 8, [\"products\"]);\n        var dataApp7Keys = Dependencies.GetOrEnsureKeys(DataCacheScope, 7, [\"products\"]);\n\n        Equal([\"pricing\", \"products\"], Dependencies.NormalizeNames([\" Products \", \"pricing\", \"PRODUCTS\"]));\n        Equal(3, outputApp7Keys.Count);\n        Equal(2, outputApp8Keys.Count);\n        Equal(2, dataApp7Keys.Count);\n        NotEqual(outputApp7Keys[0], outputApp8Keys[0]);\n        NotEqual(outputApp7Keys[0], dataApp7Keys[0]);\n        NotEqual(outputApp7Keys[1], dataApp7Keys[1]);\n    }\n\n    [Fact]\n    public void GetOrEnsureKeysWithoutDependenciesReturnsAppKeyOnly()\n    {\n        var keys = Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 7, null);\n\n        Single(keys);\n    }\n\n    [Fact]\n    public void DependOnMergesKeysOncePerModuleRender()\n    {\n        OutputCache.ModuleId = 42;\n\n        OutputCache.DependOn(\"Products\");\n        OutputCache.DependOn(\" products \");\n\n        var settings = ModuleHtml.GetOutputCache(42);\n\n        NotNull(settings);\n        var dependencies = settings!.ExternalDependencyKeys;\n        NotNull(dependencies);\n        var dependency = Single(dependencies!);\n        Equal(\"Products\", dependency);\n    }\n\n    [Fact]\n    public void TouchInvalidatesOnlyMatchingCacheEntries()\n    {\n        var entryKeyA = nameof(TouchInvalidatesOnlyMatchingCacheEntries) + \"-a\";\n        var entryKeyB = nameof(TouchInvalidatesOnlyMatchingCacheEntries) + \"-b\";\n        var dependencyKeysA = Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 7, [\"products\"]);\n        var dependencyKeysB = Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 7, [\"pricing\"]);\n\n        Cache.Set(entryKeyA, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(dependencyKeysA));\n        Cache.Set(entryKeyB, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(dependencyKeysB));\n\n        NotNull(Cache.Get<OutputCacheItem>(entryKeyA));\n        NotNull(Cache.Get<OutputCacheItem>(entryKeyB));\n\n        Dependencies.Touch(CacheDependencyScopes.OutputCache, 7, [\"products\"]);\n\n        Null(Cache.Get<OutputCacheItem>(entryKeyA));\n        NotNull(Cache.Get<OutputCacheItem>(entryKeyB));\n    }\n\n    [Fact]\n    public void TouchAppInvalidatesAllMatchingAppCacheEntriesOnly()\n    {\n        var entryKeyA = nameof(TouchAppInvalidatesAllMatchingAppCacheEntriesOnly) + \"-a\";\n        var entryKeyB = nameof(TouchAppInvalidatesAllMatchingAppCacheEntriesOnly) + \"-b\";\n        var entryKeyC = nameof(TouchAppInvalidatesAllMatchingAppCacheEntriesOnly) + \"-c\";\n\n        Cache.Set(entryKeyA, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 7, [\"products\"])));\n        Cache.Set(entryKeyB, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 7, [\"pricing\"])));\n        Cache.Set(entryKeyC, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 8, [\"products\"])));\n\n        Dependencies.TouchApp(CacheDependencyScopes.OutputCache, 7);\n\n        Null(Cache.Get<OutputCacheItem>(entryKeyA));\n        Null(Cache.Get<OutputCacheItem>(entryKeyB));\n        NotNull(Cache.Get<OutputCacheItem>(entryKeyC));\n    }\n\n    [Fact]\n    public void TouchUnknownKeyDoesNotInvalidateExistingEntries()\n    {\n        var entryKey = nameof(TouchUnknownKeyDoesNotInvalidateExistingEntries);\n        var dependencyKeys = Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, 7, [\"products\"]);\n\n        Cache.Set(entryKey, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(dependencyKeys));\n        NotNull(Cache.Get<OutputCacheItem>(entryKey));\n\n        Dependencies.Touch(CacheDependencyScopes.OutputCache, 7, [\"unknown\"]);\n\n        NotNull(Cache.Get<OutputCacheItem>(entryKey));\n    }\n}\n\npublic class StartupSxcWithDbWithoutLightSpeed : StartupSxcWithDb\n{\n    public override void ConfigureServices(IServiceCollection services)\n    {\n        base.ConfigureServices(services);\n        services.RemoveAll<IOutputCache>();\n    }\n}\n\ninternal class TestApp(int appId) : IApp\n{\n    public int AppId => appId;\n    public int ZoneId => 0;\n    public string Name => \"Test App\";\n    public string Folder => \"TestApp\";\n    public string NameId => \"test-app\";\n    public string AppGuid => NameId;\n    public IAppData Data => null!;\n    public IAppConfiguration Configuration => null!;\n    public dynamic? Settings => null;\n    public dynamic? Resources => null;\n    public IDictionary<string, IQuery> Query { get; } = new Dictionary<string, IQuery>();\n    public IQuery GetQuery(string name) => throw new NotSupportedException();\n    public string Path => \"/test-app\";\n    public string PhysicalPath => @\"c:\\test-app\";\n    public string PathShared => \"/test-app-shared\";\n    public string PhysicalPathShared => @\"c:\\test-app-shared\";\n    public string RelativePath => \"test-app\";\n    public string RelativePathShared => \"test-app-shared\";\n    public string? Thumbnail => null;\n    public IMetadata Metadata => null!;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.SystemTests/WebLightSpeed/OutputCacheServiceWithoutLightSpeedTests.cs",
    "content": "using ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Services.Cache;\nusing ToSic.Sxc.Services.OutputCache;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sys.Caching;\nusing ExecutionContext = ToSic.Sxc.Sys.ExecutionContext.ExecutionContext;\n\nnamespace ToSic.Sxc.WebLightSpeed;\n\n[Startup(typeof(StartupSxcWithDbWithoutLightSpeed))]\npublic class OutputCacheManagementServiceWithoutLightSpeedTests(ExecutionContext exCtx)\n{\n    public class LightSpeedTestCase(ExecutionContext exCtx, string key)\n    {\n        public int CurrentAppId = 7;\n\n        private INamedCacheDependencyService Dependencies =>\n            exCtx.GetService<INamedCacheDependencyService>(reuse: true);\n\n        private MemoryCacheService Cache =>\n            exCtx.GetService<MemoryCacheService>(reuse: true);\n\n        public int OtherAppId =>\n            CurrentAppId + 1;\n\n        public string EntryKeyA => key + \"-a\";\n        public string EntryKeyB => key + \"-b\";\n        public string EntryKeyC => key + \"-c\";\n\n        public LightSpeedTestCase Setup()\n        {\n            Cache.Set(EntryKeyA, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(GetDependencies(CurrentAppId, [\"products\"])));\n            Cache.Set(EntryKeyB, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(GetDependencies(CurrentAppId, [\"pricing\"])));\n            Cache.Set(EntryKeyC, new OutputCacheItem(new RenderResult()), policy => policy.WatchCacheKeys(GetDependencies(OtherAppId, [\"products\"])));\n\n            // Verify everything is as it should be\n            NotNull(Cache.Get<OutputCacheItem>(EntryKeyA));\n            NotNull(Cache.Get<OutputCacheItem>(EntryKeyB));\n            NotNull(Cache.Get<OutputCacheItem>(EntryKeyC));\n            return this;\n        }\n\n        private IEnumerable<string> GetDependencies(int appId, IEnumerable<string> keys) =>\n            Dependencies.GetOrEnsureKeys(CacheDependencyScopes.OutputCache, appId, keys);\n    }\n\n    private IOutputCacheManagementService OutputCacheManagement =>\n        exCtx.GetService<IOutputCacheManagementService>(reuse: true);\n\n    private MemoryCacheService Cache =>\n        exCtx.GetService<MemoryCacheService>(reuse: true);\n\n\n    [Fact]\n    public void OutputCacheManagementServiceResolvesWithoutLightSpeed()\n        => NotNull(OutputCacheManagement);\n\n\n\n    [Theory]\n    [InlineData(1, \"basic case, run 1x\")]\n    [InlineData(2, \"repeat case, verify second flush works\")]\n    public void FlushSelectiveDependenciesWithoutLightSpeed(int runCount, string comment)\n    {\n        var testCase = new LightSpeedTestCase(exCtx, nameof(FlushSelectiveDependenciesWithoutLightSpeed));\n\n        var touched = 0;\n        for (var i = 0; i < runCount; i++)\n        {\n            testCase.Setup();\n            touched = OutputCacheManagement.Flush(testCase.CurrentAppId, dependencies: [\" products \", \"PRODUCTS\"]);\n        }\n\n        Equal(1, touched);\n        Null(Cache.Get<OutputCacheItem>(testCase.EntryKeyA));\n        NotNull(Cache.Get<OutputCacheItem>(testCase.EntryKeyB));\n        NotNull(Cache.Get<OutputCacheItem>(testCase.EntryKeyC));\n    }\n\n    [Theory]\n    [InlineData(1, true, \"basic case, run 1x\")]\n    [InlineData(1, false, \"basic case, run 1x\")]\n    [InlineData(2, true, \"repeat case, verify second flush works\")]\n    public void FlushNullTouchesAppWideMarkerForCurrentApp(int runCount, bool nullDependencies, string comment)\n    {\n        var testCase = new LightSpeedTestCase(exCtx, nameof(FlushNullTouchesAppWideMarkerForCurrentApp) + nullDependencies);\n\n        var touched = 0;\n        for (var i = 0; i < runCount; i++)\n        {\n            testCase.Setup();\n            touched = nullDependencies\n                ? OutputCacheManagement.Flush(testCase.CurrentAppId)\n                : OutputCacheManagement.Flush(testCase.CurrentAppId, dependencies: []);\n        }\n\n        Equal(0, touched);\n        Null(Cache.Get<OutputCacheItem>(testCase.EntryKeyA));\n        Null(Cache.Get<OutputCacheItem>(testCase.EntryKeyB));\n        NotNull(Cache.Get<OutputCacheItem>(testCase.EntryKeyC));\n    }\n\n    //[Fact]\n    //public void FlushEmptyTouchesAppWideMarkerForCurrentApp()\n    //{\n    //    var testCase = new LightSpeedTestCase(exCtx, nameof(FlushEmptyTouchesAppWideMarkerForCurrentApp))\n    //        .Setup();\n\n    //    var touched = OutputCacheManagement.Flush(testCase.CurrentAppId, dependencies: []);\n\n    //    Equal(0, touched);\n    //    Null(Cache.Get<OutputCacheItem>(testCase.EntryKeyA));\n    //    Null(Cache.Get<OutputCacheItem>(testCase.EntryKeyB));\n    //    NotNull(Cache.Get<OutputCacheItem>(testCase.EntryKeyC));\n    //}\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Adam/AdamPathsBaseTests.cs",
    "content": "using ToSic.Sxc.Adam.Sys.Paths;\n\nnamespace ToSic.Sxc.Tests.Adam;\n\n\npublic class AdamPathsBaseTests\n{\n    private static void ThrowIfPathContainsDotDot(string path) => AdamPathsBase.ThrowIfPathContainsDotDot(path);\n\n    [Theory]\n    [InlineData(\"../test\")]\n    [InlineData(\"test/../subfolder\")]\n    public void PathContainsDotDot_ThrowWhenPathIsInValid(string path) =>\n        // Act & Assert\n        Throws<System.ArgumentException>(() => ThrowIfPathContainsDotDot(path));\n\n\n    [Theory]\n    [InlineData(\"test/path\")]\n    [InlineData(\"test/..path\")]\n    //[InlineData(\"test/path..\")]\n    [InlineData(\"test/pa..th\")]\n    [InlineData(\"test/..path/subfolder\")]\n    [InlineData(\"test/path../subfolder\")]\n    [InlineData(\"test/pa..th/subfolder\")]\n    [InlineData(\"test/path/file.txt\")]\n    [InlineData(\"test/path/file..txt\")]\n    [InlineData(\"test/path/.gitignore\")]\n    //[InlineData(\"test/path/.config.\")]\n    [InlineData(\".file\")]\n    [InlineData(\"..other_file\")]\n    public void PathContainsDotDot_PathIsValid(string path) => ThrowIfPathContainsDotDot(path);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Adam/AdamSecurity.cs",
    "content": "﻿using ToSic.Eav.Security.Files;\n\nnamespace ToSic.Sxc.Tests.Adam;\n\n\npublic class AdamSecurity\n{\n    private readonly string[] _badFiles =\n    [\n        \"hello.exe\",\n        \"unhappy.exe \",\n        \"unhappy 2. exe\",\n        \"bad.cshtml\",\n        \"_notgood.cshtml\",\n        \"trying to be smart.jpg.js\"\n    ];\n        \n    private readonly string[] _goodFiles =\n    [\n        \"hello.doc\",\n        \"good.jpg\",\n        \"_notbad.png\",\n        \"this is a dot. and we love it.txt\",\n        \"list of flowers.csv\"\n    ];\n\n    [Fact]\n    public void BadExtensionsCaught()\n    {\n        var exts = _badFiles.Select(System.IO.Path.GetExtension).ToList();\n\n        exts.ForEach(e =>\n            True( FileNames.IsKnownRiskyExtension(e), $\"expected {e} to be marked as bad\")\n        );\n    }\n\n\n    [Fact]\n    public void GoodExtensionsNotCaught()\n    {\n        var exts = _goodFiles.Select(System.IO.Path.GetExtension).ToList();\n\n        exts.ForEach(e =>\n            False(FileNames.IsKnownRiskyExtension(e), $\"expected {e} to be marked as good\")\n        );\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Blocks/Output/BlockResourceExtractorGetHtmlAttributesTests.cs",
    "content": "﻿using ToSic.Sxc.Render.Sys.ResourceExtractor;\n\nnamespace ToSic.Sxc.Tests.Blocks.Output;\n\n\npublic class BlockResourceExtractorGetHtmlAttributesTests\n{\n \n    private Dictionary<string, string> GetHtmlAttributes(string htmlTag) => BlockResourceExtractor.GetHtmlAttributes(htmlTag).Attributes as Dictionary<string, string>;\n\n\n    [Theory]\n    [InlineData(null)]\n    [InlineData(\"\")]\n    [InlineData(\"   \")]\n    [InlineData(\"<tag/>\")]\n    [InlineData(\"    <tag \\n  \\n     />    \")]\n    //[InlineData(\"    <   tag      />    \")]\n    public void TagWithoutAttributesTest(string htmlTag)\n    {\n        Null(GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<tag key/>\")]\n    [InlineData(\"<tag     key/>\")]\n    [InlineData(\"<tag    key    />\")]\n    [InlineData(\"<tag \\n \\t   key    />\")]\n    public void OneAttributeWithoutValueTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"key\", \"\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<tag key1 key2 \\n key3    Key4  \\t  KEY5/>\")]\n    public void ManyAttributesWithoutValueTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"key1\", \"\" },\n            { \"key2\", \"\" }, \n            { \"key3\", \"\" },\n            { \"key4\", \"\" },\n            { \"key5\", \"\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<tag key1  key1 \\n key1    Key1   KEY1/>\")]\n    public void ManyDuplicateAttributesWithoutValueTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"key1\", \"\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<tag key=\\\"value\\\"/>\")]\n    [InlineData(\"<tag key='value'   />\")]\n    //[InlineData(\"<tag key=value/>\")]\n    public void OneAttributeWithValueTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            {\"key\", \"value\"}\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<tag key1 key2=\\\"value\\\"   \\n  key3=\\\"value\\\"     />\")]\n    public void ManyAttributesTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"key1\", \"\" } , \n            { \"key2\", \"value\" },\n            { \"key3\", \"value\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script type='module' async crossorigin='anonymous' defer integrity='filehash' nomodule='false' referrerpolicy='strict-origin-when-cross-origin'></script>\")]\n    public void ScriptOnlyAdditionalAttributesTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"type\", \"module\" } ,\n            { \"async\", \"\" },\n            { \"crossorigin\", \"anonymous\" },\n            { \"defer\", \"\" },\n            { \"integrity\", \"filehash\" },\n            { \"nomodule\", \"false\" },\n            { \"referrerpolicy\", \"strict-origin-when-cross-origin\" },\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script async defer></script>\")]\n    public void ScriptOnlyAdditionalAttributesNoValueTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"async\", \"\" },\n            { \"defer\", \"\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script async='async' defer='defer'></script>\")]\n    public void ScriptOnlyAdditionalAttributesWithValueTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"async\", \"async\" },\n            { \"defer\", \"defer\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script id='id' src='src' data-enableoptimizations='true'></script>\")]\n    public void ScriptOnlyBlacklistAttributesTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>() { };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script id='id' async src='src' defer data-enableoptimizations='true'></script>\")]\n    public void ScriptMixAttributesTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"async\", \"\" },\n            { \"defer\", \"\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script src='src' onload=\\\"loaded=1\\\" onerror=\\\"return false;\\\"></script>\")]\n    public void ScriptEventsTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"onload\", \"loaded=1\" },\n            { \"onerror\", \"return false;\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script src='src' onerror=\\\"alert('error!')\\\"></script>\")]\n    public void ScriptEventsWithQuotesTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"onerror\", \"alert('error!')\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script src='src' multiline=\\\"line1\\nli'ne2\\nli''ne3\\\"></script>\")]\n    public void ScriptMultilineAttributeTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"multiline\", \"line1\\nli'ne2\\nli''ne3\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory]\n    [InlineData(\"<script json=\\\"{&quot;Environment&quot;:{&quot;WebsiteId&quot;:74}}\\\"></script>\")]\n    public void ScriptAttributeWithDoubleQuoteSimpleJsonTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"json\", \"{&quot;Environment&quot;:{&quot;WebsiteId&quot;:74}}\" }\n        };\n        var actual = GetHtmlAttributes(htmlTag);\n        /* wip */ Equivalent(expected, actual);\n    }\n\n    [Theory]\n    [InlineData(\"<script json='{\\\"Environment\\\":{\\\"WebsiteId\\\":74}}'></script>\")]\n    public void ScriptAttributeWithQuoteSimpleJsonTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"json\", \"{\\\"Environment\\\":{\\\"WebsiteId\\\":74}}\" }\n        };\n        var actual = GetHtmlAttributes(htmlTag);\n        /* wip */ Equivalent(expected, actual);\n    }\n\n    [Theory]\n    [InlineData(\"<script json=\\\"{'Environment':{'WebsiteId':74}}\\\"></script>\")] // 2DM this would never be valid json because json can never use '...' as string holders.\n    public void ScriptAttributeWithSingleQuoteSimpleJsonTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"json\", \"{'Environment':{'WebsiteId':74}}\" }\n        };\n        var actual = GetHtmlAttributes(htmlTag);\n        /* wip */ Equivalent(expected, actual);\n    }\n\n    [Theory]\n    [InlineData(\"<script json=\\\"{'Environment':{'WebsiteId':74,'WebsiteUrl':'//2sxc-dnn742.dnndev.me/script-extractor/','PageId':2376,'PageUrl':'http://2sxc-dnn742.dnndev.me/script-extractor','parameters':[],'InstanceId':4139,'SxcVersion':'13.3.0.1646939878','SxcRootUrl':'/','IsEditable':true},'User':{'CanDevelop':true,'CanAdmin':true},'Language':{'Current':'en-us','Primary':'en-us','All':[]},'contentBlockReference':{'publishingMode':'DraftOptional','id':4139,'parentIndex':0,'partOfPage':true},'contentBlock':{'IsCreated':false,'IsList':false,'TemplateId':80568,'QueryId':null,'ContentTypeName':'','AppUrl':'/Portals/script-extractor/2sxc/ScriptExtractorTest','AppSettingsId':null,'AppResourcesId':null,'IsContent':false,'HasContent':false,'SupportsAjax':false,'TemplatePath':'/_v1.cshtml','TemplateIsShared':false,'ZoneId':77,'AppId':852,'Guid':'00000000-0000-0000-0000-000000000000','Id':0},'error':{'type':null},'Ui':{'AutoToolbar':true}}\\\"></script>\")]\n    public void ScriptAttributeWithSingleQuoteSxcJsonTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"json\", \"{'Environment':{'WebsiteId':74,'WebsiteUrl':'//2sxc-dnn742.dnndev.me/script-extractor/','PageId':2376,'PageUrl':'http://2sxc-dnn742.dnndev.me/script-extractor','parameters':[],'InstanceId':4139,'SxcVersion':'13.3.0.1646939878','SxcRootUrl':'/','IsEditable':true},'User':{'CanDevelop':true,'CanAdmin':true},'Language':{'Current':'en-us','Primary':'en-us','All':[]},'contentBlockReference':{'publishingMode':'DraftOptional','id':4139,'parentIndex':0,'partOfPage':true},'contentBlock':{'IsCreated':false,'IsList':false,'TemplateId':80568,'QueryId':null,'ContentTypeName':'','AppUrl':'/Portals/script-extractor/2sxc/ScriptExtractorTest','AppSettingsId':null,'AppResourcesId':null,'IsContent':false,'HasContent':false,'SupportsAjax':false,'TemplatePath':'/_v1.cshtml','TemplateIsShared':false,'ZoneId':77,'AppId':852,'Guid':'00000000-0000-0000-0000-000000000000','Id':0},'error':{'type':null},'Ui':{'AutoToolbar':true}}\" }\n        };\n        /* wip */ Equivalent(expected, GetHtmlAttributes(htmlTag));\n    }\n\n    [Theory(Skip = \"ATM not ready, Sxc JSON value extraction is not working\")]\n    [InlineData(\"<script json=\\\"{&quot;Environment&quot;:{&quot;WebsiteI&quot;:74,&quot;WebsiteUrl&quot;:&quot;//2sxc-dnn742.dnndev.me/script-extractor/&quot;,&quot;PageId&quot;:2376,&quot;PageUrl&quot;:&quot;http://2sxc-dnn742.dnndev.me/script-extractor&quot;,&quot;parameters&quot;:[],&quot;InstanceId&quot;:4139,&quot;SxcVersion&quot;:&quot;13.3.0.1646939878&quot;,&quot;SxcRootUrl&quot;:&quot;/&quot;,&quot;IsEditable&quot;:true},&quot;User&quot;:{&quot;CanDevelop&quot;:true,&quot;CanAdmin&quot;:true},&quot;Language&quot;:{&quot;Current&quot;:&quot;en-us&quot;,&quot;Primary&quot;:&quot;en-us&quot;,&quot;All&quot;:[]},&quot;contentBlockReference&quot;:{&quot;publishingMode&quot;:&quot;DraftOptional&quot;,&quot;id&quot;:4139,&quot;parentIndex&quot;:0,&quot;partOfPage&quot;:true},&quot;contentBlock&quot;:{&quot;IsCreated&quot;:false,&quot;IsList&quot;:false,&quot;TemplateId&quot;:80568,&quot;QueryId&quot;:null,&quot;ContentTypeName&quot;:&quot;&quot;,&quot;AppUrl&quot;:&quot;/Portals/script-extractor/2sxc/ScriptExtractorTest&quot;,&quot;AppSettingsId&quot;:null,&quot;AppResourcesId&quot;:null,&quot;IsContent&quot;:false,&quot;HasContent&quot;:false,&quot;SupportsAjax&quot;:false,&quot;TemplatePath&quot;:&quot;/_v1.cshtml&quot;,&quot;TemplateIsShared&quot;:false,&quot;ZoneId&quot;:77,&quot;AppId&quot;:852,&quot;Guid&quot;:&quot;00000000-0000-0000-0000-000000000000&quot;,&quot;Id&quot;:0},&quot;error&quot;:{&quot;type&quot;:null},&quot;Ui&quot;:{&quot;AutoToolbar&quot;:true}}\\\"></script>\")]\n    //[Ignore(\"ATM not ready, Sxc JSON value extraction is not working\")]\n    public void ScriptAttributeWithDoubleQuoteSxcJsonTests(string htmlTag)\n    {\n        var expected = new Dictionary<string, string>()\n        {\n            { \"json\", \"{&quot;Environment&quot;:{&quot;WebsiteId&quot;:74,&quot;WebsiteUrl&quot;:&quot;//2sxc-dnn742.dnndev.me/script-extractor/&quot;,&quot;PageId&quot;:2376,&quot;PageUrl&quot;:&quot;http://2sxc-dnn742.dnndev.me/script-extractor&quot;,&quot;parameters&quot;:[],&quot;InstanceId&quot;:4139,&quot;SxcVersion&quot;:&quot;13.3.0.1646939878&quot;,&quot;SxcRootUrl&quot;:&quot;/&quot;,&quot;IsEditable&quot;:true},&quot;User&quot;:{&quot;CanDevelop&quot;:true,&quot;CanAdmin&quot;:true},&quot;Language&quot;:{&quot;Current&quot;:&quot;en-us&quot;,&quot;Primary&quot;:&quot;en-us&quot;,&quot;All&quot;:[]},&quot;contentBlockReference&quot;:{&quot;publishingMode&quot;:&quot;DraftOptional&quot;,&quot;id&quot;:4139,&quot;parentIndex&quot;:0,&quot;partOfPage&quot;:true},&quot;contentBlock&quot;:{&quot;IsCreated&quot;:false,&quot;IsList&quot;:false,&quot;TemplateId&quot;:80568,&quot;QueryId&quot;:null,&quot;ContentTypeName&quot;:&quot;&quot;,&quot;AppUrl&quot;:&quot;/Portals/script-extractor/2sxc/ScriptExtractorTest&quot;,&quot;AppSettingsId&quot;:null,&quot;AppResourcesId&quot;:null,&quot;IsContent&quot;:false,&quot;HasContent&quot;:false,&quot;SupportsAjax&quot;:false,&quot;TemplatePath&quot;:&quot;/_v1.cshtml&quot;,&quot;TemplateIsShared&quot;:false,&quot;ZoneId&quot;:77,&quot;AppId&quot;:852,&quot;Guid&quot;:&quot;00000000-0000-0000-0000-000000000000&quot;,&quot;Id&quot;:0},&quot;error&quot;:{&quot;type&quot;:null},&quot;Ui&quot;:{&quot;AutoToolbar&quot;:true}}\" }\n        };\n        var actual = GetHtmlAttributes(htmlTag);\n        /* wip */ Equivalent(expected, actual);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Code/Help/SourceAnalyzerTests.cs",
    "content": "﻿using ToSic.Sxc.Code.Sys.SourceCode;\n\nnamespace ToSic.Sxc.Tests.Code.Help;\n\n\npublic class SourceAnalyzerTests\n{\n    private static string ExtractBaseClass(string sourceCode, string className) \n        => SourceAnalyzer.ExtractBaseClass(sourceCode, className);\n\n    [Fact]\n    public void ExtractBaseClass_ValidClass_ShouldReturnBaseClass()\n    {\n        var sourceCode = \"public class MyClass : MyBaseClass { }\";\n        var className = \"MyClass\";\n        Equal(\"MyBaseClass\", ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact]\n    public void ExtractBaseClass_ValidClassCaseInsensitive_ShouldReturnBaseClass()\n    {\n        var sourceCode = \"public class MyClass : MyBaseClass { }\";\n        var className = \"myclass\";\n        Equal(\"MyBaseClass\", ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact]\n    public void ExtractBaseClass_ClassWithoutBase_ShouldReturnNull()\n    {\n        var sourceCode = \"public class MyClass { }\";\n        var className = \"MyClass\";\n        Null(ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact]\n    public void ExtractBaseClass_InvalidClassName_ShouldReturnNull()\n    {\n        var sourceCode = \"public class MyClass : MyBaseClass { }\";\n        var className = \"UnknownClass\";\n        Null(ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact]\n    public void ExtractBaseClass_ClassWithGenericBase_ShouldHandleCorrectly()\n    {\n        var sourceCode = \"public class MyClass : List<string> { }\";\n        var className = \"MyClass\";\n        Equal(\"List<string>\", ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact]\n    public void ExtractBaseClass_ClassWithInterfaces_ShouldReturnFirstInterface()\n    {\n        var sourceCode = \"public class MyClass : IInterface, MyBaseClass { }\";\n        var className = \"MyClass\";\n        Equal(\"IInterface\", ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact(Skip = \"unsure\")]\n    //[Ignore]\n    public void ExtractBaseClass_NestedClass_ShouldReturnNull() // or correct behavior if intended\n    {\n        var sourceCode = \"public class OuterClass { public class MyClass : MyBaseClass { } }\";\n        var className = \"MyClass\";\n        Null(ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact(Skip = \"unsure\")]\n    //[Ignore]\n    public void ExtractBaseClass_ClassInComments_ShouldReturnNull()\n    {\n        var sourceCode = \"// public class MyClass : MyBaseClass { }\";\n        var className = \"MyClass\";\n        Null(ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact(Skip = \"unsure\")]\n    //[Ignore]\n    public void ExtractBaseClass_ClassInStringLiteral_ShouldReturnNull()\n    {\n        var sourceCode = \"string code = \\\"public class MyClass : MyBaseClass { }\\\";\";\n        var className = \"MyClass\";\n        Null(ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact]\n    public void ExtractBaseClass_UnusualFormatting_ShouldHandleCorrectly()\n    {\n        var sourceCode = \"public    class     MyClass\\n:\\nMyBaseClass { }\";\n        var className = \"MyClass\";\n        Equal(\"MyBaseClass\", ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact]\n    public void ExtractBaseClass_NullSourceCode_ShouldReturnNull()\n    {\n        string sourceCode = null;\n        var className = \"MyClass\";\n        Null(ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact]\n    public void ExtractBaseClass_EmptySourceCode_ShouldReturnNull()\n    {\n        var sourceCode = \"\";\n        var className = \"MyClass\";\n        Null(ExtractBaseClass(sourceCode, className));\n    }\n\n    [Fact(Skip = \"unsure\")]\n    //[Ignore]\n    public void ExtractBaseClass_NullClassName_ShouldThrowArgumentNullException()\n    {\n        Throws<ArgumentNullException>(() =>\n        {\n            var sourceCode = \"public class MyClass : MyBaseClass { }\";\n            string className = null;\n            ExtractBaseClass(sourceCode, className);\n        });\n    }\n\n    [Fact]\n    public void ExtractBaseClass_EmptyClassName_ShouldReturnNull()\n    {\n        var sourceCode = \"public class MyClass : MyBaseClass { }\";\n        var className = \"\";\n        Null(ExtractBaseClass(sourceCode, className));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/CodeTests/LoggingTests/LogAdapterTests.cs",
    "content": "﻿//using Microsoft.VisualStudio.TestTools.UnitTesting;\n//using System.Linq;\n//using ToSic.Lib.Logging;\n\n\n//namespace ToSic.Eav.Core.Tests.LogTests\n//{\n//    \n//    public class LogAdapterTests : LogTestBase\n//    {\n\n        \n//        [Fact]\n//        public void NoReturnBasic()\n//        {\n//            var log = LA(\"Test\");\n\n//            var call = log.Fn();\n//            Assert.Equal(1, log.L.Entries.Count);\n\n//            call.Done(\"ok\");\n//            Assert.Equal(2, log.L.Entries.Count); // Another for results\n\n//            var resultEntry = log.L.Entries.First();\n//            Assert.Equal(\"ok\", resultEntry.Result);\n//        }\n\n//        [Fact]\n//        public void NoReturnAll()\n//        {\n//            var log = LA(\"Test\");\n\n//            var call = log.Fn($\"something: {7}\", \"start msg\", true);\n//            Assert.IsTrue(call.Stopwatch.ElapsedMilliseconds < 1);\n//            Assert.Equal(1, log.L.Entries.Count);\n//            System.Threading.Thread.Sleep(10); // wait 10 ms\n\n//            call.Done(\"ok\");\n//            Assert.IsTrue(call.Stopwatch.ElapsedMilliseconds > 9);\n//            Assert.Equal(2, log.L.Entries.Count); // Another for results\n\n//            var resultEntry = log.L.Entries.First();\n//            Assert.Equal(\"ok\", resultEntry.Result);\n//        }\n\n//        [Fact]\n//        public void GenericBasic()\n//        {\n//            var log = LA(\"Test\");\n\n//            var call = log.Fn<string>();\n//            Assert.Equal(1, log.L.Entries.Count);  // Should have one when starting\n            \n//            var result = call.Return(\"result\", \"ok\");\n//            Assert.Equal(\"result\", result);\n//            Assert.Equal(2, log.L.Entries.Count);  // Another for results\n\n//            var resultEntry = log.L.Entries.First();\n//            Assert.Equal(\"ok\", resultEntry.Result);\n//        }\n//    }\n//}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/CodeTests/LoggingTests/LogFnOldTests.cs",
    "content": "﻿//using Microsoft.VisualStudio.TestTools.UnitTesting;\n//using System.Linq;\n\n//namespace ToSic.Eav.Core.Tests.LogTests\n//{\n//    \n//    public class LogFnOldTests : LogTestBase\n//    {\n//        [Fact]\n//        public void NoReturnBasic()\n//        {\n//            var log = SL(\"Test\");\n//            var call = log.Fn();\n//            Assert.Equal(1, log.Entries.Count);\n//            call.Done(\"ok\");\n            \n//            Assert.Equal(2, log.Entries.Count); // Another for results\n//            var resultEntry = log.Entries.First();\n//            Assert.Equal(\"ok\", resultEntry.Result);\n//        }\n\n//        [Fact]\n//        public void NoReturnAll()\n//        {\n//            var log = SL(\"Test\");\n//            var call = log.Fn($\"something: {7}\", \"start msg\", true);\n//            Assert.IsTrue(call.Stopwatch.ElapsedMilliseconds < 1);\n//            Assert.Equal(1, log.Entries.Count);\n//            System.Threading.Thread.Sleep(10); // wait 10 ms\n//            call.Done(\"ok\");\n\n//            Assert.IsTrue(call.Stopwatch.ElapsedMilliseconds > 9);\n            \n//            Assert.Equal(2, log.Entries.Count); // Another for results\n//            var resultEntry = log.Entries.First();\n//            Assert.Equal(\"ok\", resultEntry.Result);\n//        }\n\n//        [Fact]\n//        public void GenericBasic()\n//        {\n//            var log = SL(\"Test\");\n//            var call = log.Fn<string>();\n            \n//            Assert.Equal(1, log.Entries.Count);  // Should have one when starting\n//            var result = call.Return(\"result\", \"ok\");\n//            Assert.Equal(\"result\", result);\n\n//            Assert.Equal(2, log.Entries.Count);  // Another for results\n//            var resultEntry = log.Entries.First();\n//            Assert.Equal(\"ok\", resultEntry.Result);\n//        }\n//    }\n//}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/CodeTests/LoggingTests/LogFnTests.cs",
    "content": "﻿namespace ToSic.Eav.Core.Tests.LogTests;\n\n\npublic class LogFnTests : LogTestBase\n{\n    [Fact]\n    public void NoReturnBasic()\n    {\n        var log = L(\"Test\");\n        var call = log.Fn();\n        Equal(1, log.Entries.Count);\n        call.Done(\"ok\");\n            \n        Equal(2, log.Entries.Count); // Another for results\n        var resultEntry = log.Entries.First();\n        Equal(\"ok\", resultEntry.Result);\n    }\n\n    [Fact]\n    public void NoReturnAll()\n    {\n        var log = L(\"Test\");\n        var call = log.Fn($\"something: {7}\", \"start msg\", true);\n        True(call.Timer.ElapsedMilliseconds < 1);\n        Equal(1, log.Entries.Count);\n        System.Threading.Thread.Sleep(10); // wait 10 ms\n        call.Done(\"ok\");\n\n        True(call.Timer.ElapsedMilliseconds > 9);\n            \n        Equal(2, log.Entries.Count); // Another for results\n        var resultEntry = log.Entries.First();\n        Equal(\"ok\", resultEntry.Result);\n    }\n\n    [Fact]\n    public void GenericBasic()\n    {\n        var log = L(\"Test\");\n        var call = log.Fn<string>();\n            \n        Equal(1, log.Entries.Count);  // Should have one when starting\n        var result = call.Return(\"result\", \"ok\");\n        Equal(\"result\", result);\n\n        Equal(2, log.Entries.Count);  // Another for results\n        var resultEntry = log.Entries.First();\n        Equal(\"ok\", resultEntry.Result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/CodeTests/LoggingTests/LogTestBase.cs",
    "content": "﻿using ToSic.Sxc.Code;\n\nnamespace ToSic.Eav.Core.Tests.LogTests;\n\npublic class LogTestBase\n{\n    //public Logging.Simple.Log SL(string l) => new Logging.Simple.Log(l);\n    public Log L(string l) => new(l);\n    internal CodeLog LA(string l) => new(L(l));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ContentSecurityPolicyTests/CspParameterFinalizerTests.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\nnamespace ToSic.Sxc.Tests.ContentSecurityPolicyTests;\n\n\npublic class CspParameterFinalizerTests\n{\n    private readonly CspParameterFinalizer _finalizer = new();//null);\n\n    [Fact]\n    public void NothingHasNoDefault()\n    {\n        var cspp = new CspParameters();\n        cspp = _finalizer.MergedWithAll(cspp);\n        Equal(\"\", cspp.ToString());\n    }\n\n    [Fact]\n    public void AllEmptyDoesNotInitializeDefault()\n    {\n        var cspp = new CspParameters\n        {\n            { CspConstants.AllSrcName, \"\" }\n        };\n        cspp = _finalizer.MergedWithAll(cspp);\n        Equal(\"\", cspp.ToString());\n    }\n\n    [Fact]\n    public void AllInitializesDefault()\n    {\n        var cspp = new CspParameters\n        {\n            { CspConstants.AllSrcName, \"'self'\" }\n        };\n        cspp = _finalizer.MergedWithAll(cspp);\n        Equal(\"default-src 'self';\", cspp.ToString());\n    }\n\n    [Fact]\n    public void AllExtendsDefault()\n    {\n        var cspp = new CspParameters\n        {\n            { CspConstants.DefaultSrcName, \"'none'\"},\n            { CspConstants.AllSrcName, \"'self'\" }\n        };\n        cspp = _finalizer.MergedWithAll(cspp);\n        Equal(\"default-src 'none' 'self';\", cspp.ToString());\n    }\n\n    [Fact]\n    public void FinalizeWithoutDuplicates()\n    {\n        var cspp = new CspParameters\n        {\n            { CspConstants.DefaultSrcName, \"'none'\"},\n            { CspConstants.DefaultSrcName, \"'self'\"},\n            { CspConstants.AllSrcName, \"'self'\" }\n        };\n        cspp = _finalizer.Finalize(cspp);\n        Equal(\"default-src 'none' 'self';\", cspp.ToString());\n    }\n\n    [Fact]\n    public void DeduplicateEmpty()\n    {\n        var cspp = new CspParameters();\n        cspp = _finalizer.DeduplicateValues(cspp);\n        Equal(\"\", cspp.ToString());\n    }\n\n    [Fact]\n    public void DeduplicateNoDuplicates()\n    {\n        var cspp = new CspParameters\n        {\n            { CspConstants.AllSrcName, \"test\" },\n            { CspConstants.AllSrcName, \"test2\" },\n        };\n        cspp = _finalizer.DeduplicateValues(cspp);\n        Equal(\"all-src test test2;\", cspp.ToString());\n    }\n\n    [Fact]\n    public void DeduplicateDuplicates()\n    {\n        var cspp = new CspParameters\n        {\n            { CspConstants.AllSrcName, \"test\" },\n            { CspConstants.AllSrcName, \"test\" },\n        };\n        cspp = _finalizer.DeduplicateValues(cspp);\n        Equal(\"all-src test;\", cspp.ToString());\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ContentSecurityPolicyTests/CspParametersTests.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\nnamespace ToSic.Sxc.Tests.ContentSecurityPolicyTests;\n\n\npublic class CspParametersTests\n{\n    [Fact]\n    public void Empty()\n    {\n        var cspp = new CspParameters();\n        Equal(\"\", cspp.ToString());\n    }\n\n\n    [Fact]\n    public void OnePair()\n    {\n        var cspp = new CspParameters();\n        cspp.Add(\"test\", \"value\");\n        Equal(\"test value;\", cspp.ToString());\n    }\n    [Fact]\n    public void OnePairTwoValues()\n    {\n        var cspp = new CspParameters();\n        cspp.Add(\"test\", \"value\");\n        cspp.Add(\"test\", \"value2\");\n        Equal(\"test value value2;\", cspp.ToString());\n    }\n\n    [Fact]\n    public void TwoPairs()\n    {\n        var cspp = new CspParameters();\n        cspp.Add(\"test\", \"value\");\n        cspp.Add(\"test2\", \"value2\");\n        Equal(\"test value; test2 value2;\", cspp.ToString());\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ContentSecurityPolicyTests/CspPolicyTextProcessorTests.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.ContentSecurityPolicy;\n\nnamespace ToSic.Sxc.Tests.ContentSecurityPolicyTests;\n\n\npublic class CspPolicyTextProcessorTests\n{\n    private readonly CspPolicyTextProcessor _processor = new(null);\n\n    [Fact]\n    public void EmptyWhenNull() => Equal(0, _processor.Parse(null).Count);\n\n    [Fact]\n    public void EmptyWhenEmpty() => Equal(0, _processor.Parse(\"\").Count);\n\n    [Fact]\n    public void EmptyWhenSpaces() => Equal(0, _processor.Parse(\"   \").Count);\n\n    [Fact]\n    public void EmptyWhenEmptyLines() => Equal(0, _processor.Parse(\" \\n   \\n  \").Count);\n\n    [Fact]\n    public void EmptyWhenCommentOnly() => Equal(0, _processor.Parse(\"// Comment\").Count);\n\n    [Fact]\n    public void EmptyWhenMultipleCommentOnly() => Equal(0, _processor.Parse(\"  // Comment \\n// comment2\").Count);\n\n\n    [Theory]\n    [InlineData(\"default-src 'self'\")]\n    [InlineData(\"default-src:'self'\")]\n    [InlineData(\"default-src: 'self'\")]\n    [InlineData(\"default-src:   'self'\")]\n    [InlineData(\"default-src: 'self'  \")]\n    public void SimplePair(string singleString)\n    {\n        var result = _processor.Parse(singleString);\n        Equal(1, result.Count);\n        var first = result.First();\n        Equal(CspConstants.DefaultSrcName, first.Key);\n        Equal(\"'self'\", first.Value);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ContextTests/ParametersAccessedTests.cs",
    "content": "﻿using ToSic.Sxc.Context.Sys;\nusing static ToSic.Sxc.Tests.ContextTests.ParametersTestData;\n\nnamespace ToSic.Sxc.Tests.ContextTests;\n\n\npublic class ParametersAccessedTests\n{\n\n    #region Get - with access tracking new v17.09+\n\n    [Fact]\n    public void AccessedKeysCountNone()\n        => Equal(0, ((Parameters)ParametersId27SortDescending()).UsedKeys.Count);\n\n    [Theory]\n    [InlineData(0, \"\")]\n    [InlineData(0, \",\")]\n    [InlineData(0, \"unknown\")]\n    [InlineData(1, \"id\")]\n    [InlineData(1, \"id,ID\")]\n    [InlineData(1, \"id,unknown\")]\n    [InlineData(2, \"id,sort\")]\n    public void AccessedKeysCount(int count, string keysCsv)\n    {\n        var p = ParametersId27SortDescending();\n        var keys = keysCsv?.Split(',') ?? [];\n        foreach (var key in keys) p.Get(key);\n        Equal(count, ((Parameters)p).UsedKeys.Count);\n    }\n\n    [Theory]\n    [InlineData(null, \"\")]\n    [InlineData(null, \",\")]\n    [InlineData(null, \"unknown\")]\n    [InlineData(\"id\", \"id\")]\n    [InlineData(\"id\", \"ID\")]\n    [InlineData(\"id\", \"id,ID\")]\n    [InlineData(\"id\", \"ID,id\")]\n    [InlineData(\"id\", \"id,unknown\")]\n    [InlineData(\"id,sort\", \"id,sort\")]\n    [InlineData(\"id,sort\", \"id,sort,ID,unknown\")]\n    public void AccessedKeysList(string accessedCsv, string keysCsv)\n    {\n        var p = ParametersId27SortDescending();\n        var keys = keysCsv?.Split(',') ?? [];\n        var accessed = accessedCsv?.Split(',') ?? [];\n        foreach (var key in keys) p.Get(key);\n        Equal(accessed.Length, ((Parameters)p).UsedKeys.Count);\n        Equal(accessed, ((Parameters)p).UsedKeys.ToArray());\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ContextTests/ParametersTestData.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing static ToSic.Sxc.Tests.LinksAndImages.ParametersTestExtensions;\n\nnamespace ToSic.Sxc.Tests.ContextTests;\n\ninternal class ParametersTestData\n{\n    /// <summary>\n    /// Get TestParameters with id=27 and sort=descending\n    /// </summary>\n    internal static IParameters ParametersId27SortDescending() => NewParameters(new()\n    {\n        { \"id\", \"27\" },\n        { \"sort\", \"descending\" }\n    });\n\n    internal const string Id27SortDescending = \"id=27&sort=descending\";\n\n    /// <summary>\n    /// Get TestParameters with sort=descending and id=27 (so added in Z-A order)\n    /// </summary>\n    internal static IParameters ParametersSortDescendingId27() => NewParameters(new()\n    {\n        { \"sort\", \"descending\" },\n        { \"id\", \"27\" },\n    });\n\n    internal const string SortDescendingId27 = \"sort=descending&id=27\";\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ContextTests/ParametersTests.cs",
    "content": "﻿using ToSic.Sxc.Context;\nusing static ToSic.Sxc.Tests.ContextTests.ParametersTestData;\nusing static ToSic.Sxc.Tests.LinksAndImages.ParametersTestExtensions;\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.Tests.ContextTests;\n\n\npublic class ParametersTests\n{\n    #region Initial Data and Helper Methods\n\n    /// <summary>\n    /// Take the default params, modify them in some way, and verify that the count / result matches expectations\n    /// </summary>\n    /// <param name=\"count\"></param>\n    /// <param name=\"exp\"></param>\n    /// <param name=\"pFunc\"></param>\n    private void ModifyDefAndVerify(int count, string exp, Func<IParameters, IParameters> pFunc)\n    {\n        var p = pFunc(ParametersId27SortDescending());\n        Equal(count, p.Count);\n        Equal(exp, p.ToString());\n    }\n\n    #endregion\n\n    #region Get Tests\n\n    [Theory]\n    [InlineData(\"27\", \"id\")]\n    [InlineData(\"descending\", \"sort\")]\n    [InlineData(null, \"unknown\")]\n    public void Get(string expected, string key)\n        => Equal(expected, ParametersId27SortDescending().Get(key));\n\n    [Theory]\n    [InlineData(\"27\", \"id\")]\n    [InlineData(\"descending\", \"sort\")]\n    [InlineData(null, \"unknown\")]\n    public void GetString(string expected, string key)\n        => Equal(expected, ParametersId27SortDescending().String(key));\n\n    [Theory]\n    [InlineData(\"27\", \"id\")]\n    [InlineData(\"descending\", \"sort\")]\n    [InlineData(null, \"unknown\")]\n    public void GetStringT(string expected, string key)\n        => Equal(expected, ParametersId27SortDescending().Get<string>(key));\n\n    [Theory]\n    [InlineData(27, \"id\")]\n    [InlineData(0, \"sort\")]\n    [InlineData(0, \"unknown\")]\n    public void GetInt(int expected, string key)\n        => Equal(expected, ParametersId27SortDescending().Int(key));\n\n    [Theory]\n    [InlineData(27, \"id\")]\n    [InlineData(0, \"sort\")]\n    [InlineData(0, \"unknown\")]\n    public void GetBool(int expected, string key)\n        => Equal(expected, ParametersId27SortDescending().Int(key));\n\n    #endregion\n\n\n    [Fact]\n    public void BasicParameters()\n    {\n        var p = ParametersId27SortDescending();\n        Equal(2, p.Count);\n        True(p.ContainsKey(\"id\"));\n        True(p.ContainsKey(\"ID\"));\n    }\n\n    [Fact]\n    public void BasicCaseSensitivity()\n    {\n        var p = ParametersId27SortDescending();\n        True(p.ContainsKey(\"id\"));\n        True(p.ContainsKey(\"ID\"));\n        False(p.ContainsKey(\"fake\"));\n    }\n\n\n\n\n    #region Add String / Null\n\n        \n\n    [Theory]\n    [InlineData(3, Id27SortDescending + \"&test=wonderful\", \"test\", \"wonderful\")]\n    [InlineData(3, Id27SortDescending + \"&test\", \"test\", null, \"null\")]\n    [InlineData(3, Id27SortDescending + \"&test\", \"test\", \"\", \"empty\")]\n    public void AddStringNew(int count, string expected, string key = \"id\", string value = default, string testName = default)\n        => ModifyDefAndVerify(count, expected, p => p.TestAdd(key, value));\n\n    [Fact]\n    public void AddStringNewNoValue()\n        => ModifyDefAndVerify(3, Id27SortDescending + \"&test\", p => p.TestAdd(\"test\"));\n\n    [Fact]\n    public void AddStringNewMultipleSameKey()\n        => ModifyDefAndVerify(3, Id27SortDescending + \"&test=awesome&test=wonderful\",\n            p => p.TestAdd(\"test\", \"wonderful\").TestAdd(\"Test\", \"awesome\"));\n\n\n\n    #endregion\n\n    #region Add / Set boolean\n\n    [Theory]\n    [InlineData(3, Id27SortDescending + \"&test=true\", \"test\", true)]\n    [InlineData(3, Id27SortDescending + \"&test=false\", \"test\", false)]\n    public void AddBool(int count, string expected, string key, bool value, string testName = default)\n        => ModifyDefAndVerify(count, expected, p => p.TestAdd(key, value));\n\n\n    [Theory]\n    [InlineData(3, Id27SortDescending + \"&test=true\", \"test\", true)]\n    [InlineData(3, Id27SortDescending + \"&test=false\", \"test\", false)]\n    [InlineData(2, \"id=true&sort=descending\", \"id\", true, \"replace int-id with bool id\")]\n    [InlineData(2, \"id=false&sort=descending\", \"id\", false, \"replace int-id with bool id\")]\n    public void SetBool(int count, string expected, string key, bool value, string testName = default)\n        => ModifyDefAndVerify(count, expected, p => p.TestSet(key, value));\n\n    #endregion\n\n    #region Add Numbers\n\n    [Theory]\n    [InlineData(3, Id27SortDescending + \"&test=7\", \"test\", 7)]\n    [InlineData(3, Id27SortDescending + \"&test=-7\", \"test\", -7)]\n    [InlineData(3, Id27SortDescending + \"&test=7\", \"test\", 7L)]\n    [InlineData(3, Id27SortDescending + \"&test=7.7\", \"test\", 7.7)]\n    [InlineData(3, Id27SortDescending + \"&test=-7.7\", \"test\", -7.7)]\n    [InlineData(3, Id27SortDescending + \"&test=7.7\", \"test\", 7.7F)]\n    [InlineData(3, Id27SortDescending + \"&test=-7.7\", \"test\", -7.7F)]\n    public void AddNumberObjects(int count, string expected, string key, object value, string testName = default)\n        => ModifyDefAndVerify(count, expected, p => p.TestAdd(key, value));\n\n    #endregion\n\n    #region Add Dates\n\n    private static readonly DateTime TestDate = new(2042, 4, 2);\n    private static readonly DateTime TestDateTime = new(2042, 4, 2, 3, 4, 56);\n\n    [Fact]\n    public void AddNewDate()\n        => ModifyDefAndVerify(3, Id27SortDescending + \"&test=2042-04-02\", p => p.TestAdd(\"test\", TestDate));\n        \n    [Fact]\n    public void AddNewDateTime()\n        => ModifyDefAndVerify(3, Id27SortDescending + \"&test=2042-04-02T03:04:56\", p => p.TestAdd(\"test\", TestDateTime));\n\n    #endregion\n\n    [Theory]\n    [InlineData(3, Id27SortDescending + \"&test=wonderful\", \"test\", \"wonderful\")]\n    [InlineData(3, Id27SortDescending + \"&test\", \"test\", null, \"null\")]\n    [InlineData(3, Id27SortDescending + \"&test\", \"test\", \"\", \"empty\")]\n    public void SetNew(int count, string expected, string key = \"id\", string value = default, string testName = default)\n        => ModifyDefAndVerify(count, expected, p => p.TestSet(key, value));\n\n    [Fact]\n    public void SetNewNoValue()\n        => ModifyDefAndVerify(3, Id27SortDescending + \"&test\", p=>p.TestSet(\"test\"));\n\n\n    [Fact]\n    public void SetNewMultipleSameKey()\n        => ModifyDefAndVerify(3, Id27SortDescending + \"&test=awesome\", p => p.TestSet(\"test\", \"wonderful\").TestSet(\"test\", \"awesome\"));\n\n    [Theory]\n    [InlineData(2, \"id=27&id=42&sort=descending\", \"id\", \"42\")]\n    [InlineData(2, Id27SortDescending, \"id\", \"\", \"empty string\")]\n    [InlineData(2, Id27SortDescending, \"id\", null, \"null string\")]\n    public void AddExisting(int count, string expected, string key = \"id\", string value = default, string testName = default)\n        => ModifyDefAndVerify(count, expected, p => p.TestAdd(key, value));\n\n\n    [Theory]\n    [InlineData(2, \"id=42&sort=descending\", \"id\", \"42\")]\n    [InlineData(2, \"id&sort=descending\", \"id\", \"\", \"reset to empty string\")]\n    [InlineData(2, \"id&sort=descending\", \"id\", null, \"reset to null\")]\n    public void SetExisting(int count, string expected, string key = \"id\", string value = default, string testName = default)\n        => ModifyDefAndVerify(count, expected, p => p.TestSet(key, value));\n\n    [Theory]\n    [InlineData(1, \"sort=descending\", \"id\", \"remove existing\")]\n    [InlineData(2, Id27SortDescending, \"something\", \"remove non-existing\")]\n    public void Remove(int count, string expected, string key, string testName = default)\n        => ModifyDefAndVerify(count, expected, p => p.TestRemove(key));\n\n    [Fact]\n    public void RemoveOfMultiple()\n    {\n        var p = ParametersId27SortDescending().TestAdd(\"id\", 42).TestAdd(\"id\", \"hello\")\n            .TestRemove(\"id\", \"42\");\n        Equal(\"id=27&id=hello&sort=descending\", p.ToString());\n    }\n\n    [Theory]\n    [InlineData(\"id=27&id=hello\", \"id=27&id=42&id=hello\", \"id\", \"42\")]\n    [InlineData(\"id=27&id=42&id=hello\", \"id=27&id=42&id=hello\", \"id\", \"999\")]\n    [InlineData(\"id=27&id=42&id=hello\", \"id=27&id=42&id=hello\", \"notdefined\", \"999\")]\n    [InlineData(\"id=27&id=42\", \"id=27&id=42&id=hello\", \"id\", \"HELLO\")]\n    [InlineData(\"ID=27&ID=42\", \"id=27&id=42&id=hello\", \"ID\", \"HELLO\", \"removing a specific key will reset key casing\")]\n    public void RemoveOfMultipleFromBlank(string expected, string initial, string key, string rmvValue, string note = default)\n    {\n        var p = initial.AsParameters().TestRemove(key, rmvValue);\n        Equal(expected, p.ToString());\n    }\n\n    [Theory]\n    [InlineData(true, \"id\")]\n    [InlineData(true, \"sort\")]\n    [InlineData(false, \"dummy\")]\n    [InlineData(false, \"id.xyz\")]\n    [InlineData(false, \"id.xyz.abc\")]\n    public void ContainsKey(bool exists, string key, string testName = default)\n        => Equal(exists, ParametersId27SortDescending().ContainsKey(key));\n\n    #region Count Tests\n\n    public class ParameterCountTest\n    {\n        public int Count;\n        public Func<IParameters, IParameters> Prepare = p => p;\n    }\n\n    public static TheoryData<ParameterCountTest> CountTests =>\n    [\n        new() { Count = 2 },\n        new() { Count = 2, Prepare = p => p.TestSet(\"id\") },\n        new() { Count = 3, Prepare = p => p.TestSet(\"new\") },\n        new() { Count = 1, Prepare = p => p.TestRemove(\"id\") },\n    ];\n\n    [Theory]\n    [MemberData(nameof(CountTests))]\n    public void CountKeys(ParameterCountTest pct)\n        => Equal(pct.Count, pct.Prepare(ParametersId27SortDescending()).Keys().Count());\n\n    #endregion\n\n\n    [Theory]\n    [InlineData(true, \"id\")]\n    [InlineData(true, \"sort\")]\n    [InlineData(false, \"dummy\")]\n    public void IsNotEmpty(bool expected, string key, string testName = default)\n        => Equal(expected, ParametersId27SortDescending().IsNotEmpty(key));//, testName);\n\n    [Theory]\n    [InlineData(\"id=42&sort=descending\", \"id\", \"42\", \"should replace\")]\n    [InlineData(\"id=27&new=hello&sort=descending\", \"new\", \"hello\", \"should append\")]\n    [InlineData(\"sort=descending\", \"id\", \"27\", \"should remove\")]\n    [InlineData(\"id&sort=descending\", \"id\", \"\", \"empty value should remove\")]\n    [InlineData(\"id&sort=descending\", \"id\", null, \"null should ???\")]\n    public void ToggleFrom27Descending(string expected, string key, string value, string note)\n        => Equal(expected, ParametersId27SortDescending().TestToggle(key, value).ToString());//, note);\n\n    [Theory]\n    [InlineData(\"id=42\", \"id\", \"42\", \"should add\")]\n    [InlineData(\"new=hello\", \"new\", \"hello\", \"should add\")]\n    public void ToggleFromEmpty(string expected, string key, string value, string note)\n    {\n        var p = \"\".AsParameters().TestToggle(key, value);\n        Equal(expected, p.ToString());//, note);\n    }\n\n    [Theory]\n    [InlineData(\"id=42\", \"id\", \"42\", \"should replace\")]\n    [InlineData(\"id=hello\", \"id\", \"hello\", \"should replace\")]\n    public void ToggleFromExisting(string expected, string key, string value, string note)\n    {\n        var pOriginal = NewParameters(new() { { \"id\", \"999\" } });\n        var p = pOriginal.TestToggle(key, value);\n        Equal(expected, p.ToString());\n    }\n\n    [Theory]\n    [InlineData(\"id=42\", \"id=42\", \"id\", \"should preserve\")]\n    [InlineData(\"id=42\", \"id=42&sort=descending\", \"id\", \"should preserve id only\")]\n    [InlineData(\"id=27&id=42\", \"id=42&id=27&sort=descending\", \"id\", \"should preserve id only\")]\n    [InlineData(\"sort=descending\", \"id=42&sort=descending\", \"sort\", \"should preserve id only\")]\n    public void Filter(string expected, string initial, string names, string testNotes = default)\n    {\n        var p = initial.AsParameters().Filter(names);\n        Equal(expected, p.ToString());\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ContextTests/ParametersToStringTests.cs",
    "content": "﻿using ToSic.Sxc.Context.Sys;\nusing static ToSic.Sxc.Tests.ContextTests.ParametersTestData;\n\nnamespace ToSic.Sxc.Tests.ContextTests;\n\n\npublic class ParametersToStringTests\n{\n    [Fact]\n    public void TestMethod1()\n    {\n    }\n\n    #region Very Basic Tests - ToString etc.\n\n    [Fact]\n    public void ParamsToStringIdSort()\n        => Equal(Id27SortDescending, ParametersId27SortDescending().ToString());\n\n    [Fact]\n    public void ParamsToStringSortId()\n        => Equal(SortDescendingId27, ParametersSortDescendingId27().Prioritize(\"sort\").ToString());\n\n    [Fact]\n    public void ParamsToStringSortIdDifferentCasing()\n        => Equal(SortDescendingId27, ParametersSortDescendingId27().Prioritize(\"SORT\").ToString());\n\n    #endregion\n\n    #region Enforce Parameter Sort!\n\n    \n    /// <summary>\n    /// enforce sorting of the parameters for lightspeed use\n    /// </summary>\n    [Fact]\n    public void ParamsToStringSortIdForceSorted()\n        => Equal(Id27SortDescending, ((Parameters)ParametersSortDescendingId27()).ToString(sort: true));\n\n    [Fact]\n    public void ParamsToStringSortIdForceNotSorted()\n        => Equal(SortDescendingId27, ((Parameters)ParametersSortDescendingId27()).ToString(sort: false));\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ContextTests/UniqueKeyTests.cs",
    "content": "﻿using ToSic.Sxc.Services;\nusing static ToSic.Sxc.Services.UniqueKeysServices;\n#pragma warning disable xUnit1026\n\nnamespace ToSic.Sxc.Tests.ContextTests;\n\n\npublic class UniqueKeyTests\n{\n    private UniqueKeysServices GetNew() => new();\n\n    [Fact]\n    public void UniqueKeyLength() => Equal(UniqueKeysServices.UniqueKeyLength, GetNew().UniqueKey.Length);\n\n    public string TestKeyOf(object data) => UniqueKeyOf(data);\n    public string TestKeysOf(params object[] data) => UniqueKeysOf(data);\n\n    [Fact]\n    public void Generate100AllDistinct()\n    {\n        var list = Enumerable.Range(0, 100).Select(i => GetNew()).ToList();\n        Equal(100, list.Count);\n        var distinct = list.Distinct().ToList();\n        Equal(100, distinct.Count);\n    }\n\n    [Theory]\n    [InlineData(NullValue, null, \"null check\")]\n    [InlineData(PfxBool + \"true\", true)]\n    [InlineData(PfxBool + \"false\", false)]\n    [InlineData(PfxNum + \"0\", 0)]\n    [InlineData(PfxNum + \"1\", 1)]\n    [InlineData(PfxNum + \"-1\", -1)]\n    [InlineData(PfxNum + \"17_5\", 17.5)]\n    // TODO: strings, chars\n    public void UniqueKeyOfValues(string expected, object data, string testName = default) => \n        Equal(expected, TestKeyOf(data));\n\n#if NETFRAMEWORK\n    [Theory]\n    [InlineData(PfxString + \"-327419862\", \"hello\")]\n    [InlineData(PfxString + \"221721854\", \"abcdefg\")]\n    [InlineData(PfxString + \"222795742\", \"Abcdefg\")]\n    public void UniqueKeyOfString(string expected, object data, string testName = default) => \n        Equal(expected, TestKeyOf(data));\n#else\n    // Note that .net 9.0 uses a more random hash-code which is not deterministic for strings!\n    // https://learn.microsoft.com/en-us/dotnet/api/system.string.gethashcode?view=net-9.0\n    // https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/userandomizedstringhashalgorithm-element\n    [Theory]\n    [InlineData(\"hello\")]\n    [InlineData(\"abcdefg\")]\n    [InlineData(\"Abcdefg\")]\n    public void UniqueKeyOfString(object data, string testName = default) => \n        Equal(PfxString + data.GetHashCode(), TestKeyOf(data));\n#endif\n\n    [Theory]\n    [InlineData(\"20230824\", \"2023-08-24\")]\n    [InlineData(\"20230824063\", \"2023-08-24 06:30\")]\n    [InlineData(\"202308240645\", \"2023-08-24 06:45\")]\n    [InlineData(\"20230824000017\", \"2023-08-24 00:00:17\")]\n    [InlineData(\"202308240000001234\", \"2023-08-24 00:00:00.1234\")]\n    public void UniqueKeyOfDate(string expected, string date, string testName = default) => \n        Equal($\"{PfxDate}{expected}\", TestKeyOf(DateTime.Parse(date)));//, $\"{date} ({testName})\");\n\n    [Theory]\n    [InlineData(\"hFAeLybz\", \"2f1e5084-f326-4661-8176-305678db2230\")]\n    [InlineData(\"KgTK0W8g\", \"d1ca042a-206f-4a92-b74c-eabab90f0a80\")]\n    [InlineData(\"jt2C0tFj\", \"d282dd8e-63d1-4024-8f30-d9db23366478\")]\n    [InlineData(\"7N8R9ncf\", \"f611dfec-1f77-42f1-b789-d5038396a4c7\")]\n    [InlineData(\"2MlSvPdC\", \"bc52c9d8-42f7-4976-af37-650433eb9a7c\")]\n    [InlineData(\"AAAAAAAA\", \"00000000-0000-0000-0000-000000000000\")]\n    public void UniqueKeyOfGuid(string expected, string guid) => \n        Equal($\"{PfxGuid}{expected}\", TestKeyOf(Guid.Parse(guid)));\n\n\n    [Fact]\n    public void UniqueKeyOfNullableNumber() =>\n        Equal($\"{PfxNum}7\", TestKeyOf((int?)7));\n\n    [Fact]\n    public void UniqueKeyOfNullableGuid() =>\n        Equal($\"{PfxGuid}hFAeLybz\", TestKeyOf((Guid?)Guid.Parse(\"2f1e5084-f326-4661-8176-305678db2230\")));\n\n    #region UniqueKeys - Many\n\n    [Theory]\n    // Note: we always nee\n    [InlineData(\"n1-n2-n3\", 1, 2, 3)]\n    [InlineData(\"btrue-n2-n3\", true, 2, 3)]\n    public void ManyKeys(string expected, params object[] data) => \n        Equal(expected, TestKeysOf(data));\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/ItemToolbarPickerTests/ItemToolbarPikerWithRulesTests.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Edit.Toolbar.Sys;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing ToSic.Sxc.Tests.EditTests.ToolbarRuleTests;\n\nnamespace ToSic.Sxc.Tests.EditTests.ItemToolbarPickerTests;\n\n\npublic class ItemToolbarPikerWithRulesTests\n{\n    [Theory]\n    [InlineData(new[] { \"edit\" }, \"edit\")]\n    [InlineData(new[] { \"edit\", \"add\" }, \"edit,add\")]\n    public void BasicConvert(string[] expected, string namesCsv)\n    {\n        var list = namesCsv\n            .Split(',')\n            .Select(s => new ToolbarRuleForTest(s))\n            .Cast<ToolbarRule>()\n            .ToList();\n\n        var converted = ItemToolbarPicker.ToolbarV10OrNull(list);\n        Assert.Equal(expected, converted);\n    }\n\n    [Theory]\n    [InlineData(new[] { \"edit\" }, \" edit\")]\n    [InlineData(new[] { \"edit\", \"add\" }, \" edit, add\")]\n    [InlineData(new[] { \"+edit\", \"%add\" }, \"+edit,%add\")]\n    [InlineData(new[] { \"+edit\" }, \"+edit,^add\", /* note*/ \"skip add\")]\n    [InlineData(new[] { \"+edit\", \"new\" }, \"+edit,^add, new\", /* note */ \"skip add\")]\n    public void BasicConvertWithOp(string[] expected, string namesCsv, string? note = null)\n    {\n        var list = namesCsv\n            .Split(',')\n            .Select(s =>\n            {\n                var op = s[0];\n                s = s.Substring(1);\n                return new ToolbarRuleForTest(s, operation: op);\n            })\n            .Cast<ToolbarRule>()\n            .ToList();\n\n        var converted = ItemToolbarPicker.ToolbarV10OrNull(list);\n        Assert.Equal(expected, converted);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/ToolbarConfigurationTests/ToolbarConfigurationShowByRole.cs",
    "content": "﻿\nusing ToSic.Sxc.Cms.Users;\nusing ToSic.Sxc.Cms.Users.Sys;\nusing ToSic.Sxc.Edit.Toolbar.Sys.ToolbarBuilder;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Edit.ToolbarConfigurationTests;\n\npublic class ToolbarConfigurationShowByRole\n{\n    [Theory]\n    [InlineData(\"\", \"\", null, null)]\n    [InlineData(\"\", null, null, null)]\n    [InlineData(\"\", \"CarEditors\", null, null)]\n    [InlineData(\"\", null, \"CarEditors\", null)]\n\n    [InlineData(\"NotInList\", null, null, null)]\n    [InlineData(\"NotInList\", \"\", null, null)]\n    [InlineData(\"NotInList\", \"CarEditors\", null, null)]\n\n    [InlineData(\"NotInList\", null, \"\", null)]\n    [InlineData(\"NotInList\", null, \"CarEditors\", null)]\n\n    [InlineData(\"CarEditors\", \"CarEditors\", null, true)]\n    [InlineData(\"CarEditors\", \"carEditors\", null, true)]\n    [InlineData(\"CarEditors,Other\", \"CarEditors\", null, true)]\n    [InlineData(\"Other,CarEditors\", \"CarEditors\", null, true)]\n    [InlineData(\"CarEditors\", \"Abc,CarEditors\", null, true)]\n    [InlineData(\"CarEditors,Other\", \"Abc,CarEditors\", null, true)]\n    [InlineData(\"CarEditors\", \"Abc,CarEditors,More\", null, true)]\n\n    [InlineData(\"CarEditors\", null, \"CarEditors\", false)]\n    [InlineData(\"CarEditors\", null, \"carEditors\", false)]\n    [InlineData(\"CarEditors,Other\", null, \"CarEditors\", false)]\n    [InlineData(\"Other,CarEditors\", null, \"CarEditors\", false)]\n    [InlineData(\"CarEditors\", null, \"Abc,CarEditors\", false)]\n    [InlineData(\"CarEditors,Other\", null, \"Abc,CarEditors\", false)]\n    [InlineData(\"CarEditors\", null, \"Abc,CarEditors,More\", false)]\n    public void TestRoles(string userRoles, string? showFor, string? denyFor, bool? expected)\n    {\n        var config = new ToolbarBuilderConfiguration\n        {\n            ShowForRoles = showFor?.CsvToArrayWithoutEmpty().ToList(),\n            ShowDenyRoles = denyFor?.CsvToArrayWithoutEmpty().ToList(),\n        };\n\n        var user = new UserModel\n        {\n            Roles = userRoles.CsvToArrayWithoutEmpty()\n                .Select(IUserRoleModel (ur) => new UserRoleModel { Name = ur })\n        };\n\n        var show = new ToolbarConfigurationShowHelper().OverrideShowBecauseOfRoles(config, user);\n\n        Equal(expected, show);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/ToolbarRuleTests/ToolbarRuleBasicTests.cs",
    "content": "﻿using static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleOperation;\n\nnamespace ToSic.Sxc.Tests.EditTests.ToolbarRuleTests;\n\n\npublic class ToolbarRuleBasicTests\n{\n    [Fact]\n    public void VerbIsInCommandAndToString()\n        => Equal(\"edit\", new ToolbarRuleForTest(\"edit\").ToString());\n\n    [Fact]\n    public void VerbWithoutOperationToString()\n        => Equal(\"edit\", new ToolbarRuleForTest(\"edit\").ToString());\n\n    [Fact]\n    public void VerbWithOpPlusToString()\n        => Equal(\"+edit\", new ToolbarRuleForTest(\"edit\", operation: AddOperation).ToString());\n\n    [Fact]\n    public void VerbWithOpMinusToString()\n        => Equal(\"-edit\", new ToolbarRuleForTest(\"edit\", operation: RemoveOperation).ToString());\n\n    [Fact]\n    public void VerbWithOpModToString()\n        => Equal(\"%edit\", new ToolbarRuleForTest(\"edit\", operation: ModifyOperation).ToString());\n\n    [Fact]\n    public void VerbWithOpSkipToString()\n        => Equal(\"\", new ToolbarRuleForTest(\"edit\", operation: SkipInclude).ToString());\n\n    [Fact]\n    public void UiShouldBeAdded()\n        => Equal(\"edit&test=abc\", new ToolbarRuleForTest(\"edit\", ui: \"test=abc\").ToString());\n\n    [Fact]\n    public void ParamsShouldBeAdded()\n        => Equal(\"edit?test=param\", new ToolbarRuleForTest(\"edit\", parameters: \"test=param\").ToString());\n\n    [Fact]\n    public void ParamsAndUiShouldBeAdded()\n        => Equal(\"edit&ui=abc?test=param\", new ToolbarRuleForTest(\"edit\", ui: \"ui=abc\", parameters: \"test=param\").ToString());\n\n    [Fact]\n    public void OpMinusWithMoreToStringShouldNotKeepParams()\n        => Equal(\"-edit\", new ToolbarRuleForTest(\"edit\", ui: \"test=test\", operation: RemoveOperation).ToString());\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/ToolbarRuleTests/ToolbarRuleForTest.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\nnamespace ToSic.Sxc.Tests.EditTests.ToolbarRuleTests;\n\n/// <summary>\n/// Just a wrapper around toolbar rules, so we can test it, as the constructor is protected.\n/// </summary>\n/// <param name=\"command\"></param>\n/// <param name=\"ui\"></param>\n/// <param name=\"parameters\"></param>\n/// <param name=\"operation\"></param>\n/// <param name=\"operationCode\"></param>\n/// <param name=\"context\"></param>\ninternal class ToolbarRuleForTest(\n    string command,\n    string ui = null,\n    string parameters = null,\n    char? operation = null,\n    string operationCode = null,\n    ToolbarContext context = null)\n    : ToolbarRule(command, ui, parameters, operation, operationCode, context);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/ToolbarRuleTests/ToolbarRuleOpPickTests.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\n\nnamespace ToSic.Sxc.Tests.EditTests.ToolbarRuleTests;\n\n\npublic class ToolbarRuleOpPickTests\n{\n    private static char TacPick(string op, ToolbarRuleOps defOp, bool? condition = default)\n        => ToolbarRuleOperation.Pick(op, defOp, condition);\n\n    [Fact]\n    public void UnknownReturnsDefOp1()\n        => Equal((char)ToolbarRuleOps.OprNone, TacPick(\"\", ToolbarRuleOps.OprNone));\n\n    [Fact]\n    public void UnknownReturnsDefOp2()\n        => Equal(ToolbarRuleOperation.AddOperation, TacPick(\"\", ToolbarRuleOps.OprAdd));\n\n    [Theory]\n    [InlineData(ToolbarRuleOperation.AddOperation, \"+\")]\n    [InlineData(ToolbarRuleOperation.AddOperation, \"add\")]\n    [InlineData(ToolbarRuleOperation.RemoveOperation, \"-\")]\n    public void KnownReturnsValue(char expected, string operation)\n        => Equal(expected, TacPick(operation, ToolbarRuleOps.OprNone));\n\n    [Theory]\n    [InlineData(\"huh\")]\n    [InlineData(\"what\")]\n    [InlineData(\"/\")]\n    [InlineData(\"&\")]\n    public void KnownReturnsFallback(string operation)\n        => Equal((char)ToolbarRuleOps.OprNone, TacPick(operation, ToolbarRuleOps.OprNone));\n\n    [Theory]\n    [InlineData(ToolbarRuleOperation.AddOperation, \"+\")]\n    [InlineData(ToolbarRuleOperation.AddOperation, \"add\")]\n    [InlineData(ToolbarRuleOperation.RemoveOperation, \"-\")]\n    [InlineData(ToolbarRuleOperation.ModifyOperation, \"modify\")]\n    public void ConditionNullKeepsBehavior(char expected, string operation)\n        => Equal(expected, TacPick(operation, ToolbarRuleOps.OprUnknown, condition: null));\n\n    [Theory]\n    [InlineData(ToolbarRuleOperation.AddOperation, \"+\")]\n    [InlineData(ToolbarRuleOperation.AddOperation, \"add\")]\n    [InlineData(ToolbarRuleOperation.RemoveOperation, \"-\")]\n    [InlineData(ToolbarRuleOperation.ModifyOperation, \"modify\")]\n    public void ConditionTrueKeepsBehavior(char expected, string operation)\n        => Equal(expected, TacPick(operation, ToolbarRuleOps.OprUnknown, condition: true));\n\n    /// <summary>\n    /// Any kind of operation - if condition false - should not be added at all.\n    /// </summary>\n    /// <param name=\"expected\"></param>\n    /// <param name=\"operation\"></param>\n    [Theory]\n    [InlineData(\"\")]\n    [InlineData( \" \")]\n    [InlineData( \"+\")]\n    [InlineData( \"add\")]\n    [InlineData(\"-\")]\n    [InlineData(\"modify\")]\n    public void ConditionFalseReturnsMinus(string operation)\n        => Equal(ToolbarRuleOperation.SkipInclude, TacPick(operation, ToolbarRuleOps.OprNone, condition: false));\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/ToolbarRuleTests/ToolbarRuleToolbarTests.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Edit.Toolbar.Sys.Rules;\nusing static ToSic.Sxc.Edit.Toolbar.Sys.Rules.ToolbarRuleToolbar;\n\nnamespace ToSic.Sxc.Tests.EditTests.ToolbarRuleTests;\n\n\npublic class ToolbarRuleToolbarTests\n{\n    [Fact]\n    public void CommandIsCorrect()\n        => Equal(RuleToolbar, new ToolbarRuleToolbar().Command);\n\n    [Fact]\n    public void NameNone()\n        => Equal(RuleToolbar, new ToolbarRuleToolbar().ToString());\n\n    [Fact]\n    public void NameEmpty()\n        => Equal($\"{RuleToolbar}={ToolbarRuleToolbar.Empty}\", new ToolbarRuleToolbar(ToolbarRuleToolbar.Empty).ToString());\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/TweakButtonTests/TweakButtonColor.cs",
    "content": "﻿using static ToSic.Sxc.Edit.Toolbar.Sys.ToolbarConstants;\n\nnamespace ToSic.Sxc.Tests.ServicesTests.ToolbarService;\n\n\npublic class TweakButtonColor: TweakButtonTestsBase\n{\n    public static IEnumerable<object[]> ColorTestData =>\n    [\n        [\"red\", \"red\"],\n        [\"pink\", \"pink\"],\n        [\"000000\", \"000000\"],\n        [\"000000\", \"#000000\"],\n        [\"aabbcc\", \"aabbcc\"],\n        [\"aabbcc\", \"#aabbcc\"],\n    ];\n\n    [Theory]\n    [MemberData(nameof(ColorTestData))]\n    public void ColorPrimary(string expected, string color)\n        => AssertUi([$\"{RuleColor}={expected}\"], NewTb().TacColor(color));\n\n    [MemberData(nameof(ColorTestData))]\n    [Theory]\n    public void ColorPrimaryBoth(string expected, string color)\n        => AssertUi([$\"{RuleColor}={expected},{expected}\"], NewTb().TacColor(color + \",\" + color));\n\n    [MemberData(nameof(ColorTestData))]\n    [Theory]\n    public void ColorBackgroundNamed(string expected, string color)\n        => AssertUi([$\"{RuleColor}={expected}\"], NewTb().TacColor(background: color));\n\n    [MemberData(nameof(ColorTestData))]\n    [Theory]\n    public void ColorForeground(string expected, string color)\n        => AssertUi([$\"{RuleColor}=,{expected}\"], NewTb().TacColor(foreground: color));\n\n    /// <summary>\n    /// If the primary color is set, foreground will be ignored\n    /// </summary>\n    [MemberData(nameof(ColorTestData))]\n    [Theory]\n    public void ColorPrimaryAndForeground(string expected, string color)\n        => AssertUi([$\"{RuleColor}={expected}\"], NewTb().TacColor(color, foreground: color));\n\n    /// <summary>\n    /// If the primary color is set, foreground will be ignored\n    /// </summary>\n    [MemberData(nameof(ColorTestData))]\n    [Theory]\n    public void ColorPrimaryAndBackground(string expected, string color)\n        => AssertUi([$\"{RuleColor}={expected}\"], NewTb().TacColor(color, background: color));\n\n    /// <summary>\n    /// If the primary color is set, background will be ignored\n    /// </summary>\n    [MemberData(nameof(ColorTestData))]\n    [Theory]\n    public void ColorBackgroundAndForeground(string expected, string color)\n        => AssertUi([$\"{RuleColor}={expected},{expected}\"], NewTb().TacColor(background: color, foreground: color));\n\n    /// <summary>\n    /// This test ensures that fg/bg are placed in the correct locations,\n    /// as all other tests use the same value for both fg and bg\n    /// </summary>\n    [Fact]\n    public void ColorBackgroundAndForegroundPositions()\n        => AssertUi([$\"{RuleColor}=red,blue\"], NewTb().TacColor(background: \"red\", foreground: \"blue\"));\n\n\n    [Fact]\n    public void Tooltip()\n        => AssertUi([$\"{RuleTooltip}=Hello\"], NewTb().TacTooltip(\"Hello\"));\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/TweakButtonTests/TweakButtonOther.cs",
    "content": "﻿using static ToSic.Sxc.Edit.Toolbar.Sys.ToolbarConstants;\n\nnamespace ToSic.Sxc.Tests.ServicesTests.ToolbarService;\n\n\npublic class TweakButtonOther: TweakButtonTestsBase\n{\n    [Fact]\n    public void Tooltip()\n        => AssertUi([$\"{RuleTooltip}=Hello\"], NewTb().TacTooltip(\"Hello\"));\n\n    [Fact]\n    public void Group()\n        => AssertUi([$\"{RuleGroup}=Hello\"], NewTb().TacGroup(\"Hello\"));\n\n    [Fact]\n    public void Icon()\n        => AssertUiJson([new { icon = \"bomb\" }], NewTb().TacIcon(\"bomb\"));\n\n    [Fact]\n    public void Classes()\n        => AssertUi([$\"{RuleClass}=enhanced\"], NewTb().TacClasses(\"enhanced\"));\n\n    [Fact]\n    public void Position()\n        => AssertUi([$\"{RulePosition}=4\"], NewTb().TacPosition(4));\n\n    [Fact]\n    public void Ui1String()\n        => AssertUi([\"Hello\"], NewTb().TacUi(\"Hello\"));\n\n    [Fact]\n    public void Ui2Strings()\n        => AssertUi([\"Hello=World\"], NewTb().TacUi(\"Hello\", \"World\"));\n\n    [Fact]\n    public void Ui1ObjectA()\n        => AssertUi([new { hello = \"world\" }], NewTb().TacUi(new { hello = \"world\"}));\n\n    [Fact]\n    public void Ui1ObjectB()\n        => AssertUi([new { hello = \"world\", name = \"iJungleboy\" }], NewTb().TacUi(new { hello = \"world\", name = \"iJungleboy\"}));\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/TweakButtonTests/TweakButtonParameters.cs",
    "content": "﻿using static ToSic.Sxc.Edit.Toolbar.Sys.ToolbarConstants;\n\nnamespace ToSic.Sxc.Tests.ServicesTests.ToolbarService;\n\n\npublic class TweakButtonParameters: TweakButtonTestsBase\n{\n\n    [Fact]\n    public void FormParameters1String()\n        => AssertParams([$\"{RuleParamPrefixForm}Hello\"], NewTb().TacFormParameters(\"Hello\"));\n\n    [Fact]\n    public void FormParameters2Strings()\n        => AssertParams([$\"{RuleParamPrefixForm}Hello=World\"], NewTb().TacFormParameters(\"Hello\", \"World\"));\n\n    [Fact]\n    public void FormParameters1ObjectA()\n        => AssertParams([$\"{RuleParamPrefixForm}hello=world\"], NewTb().TacFormParameters(new { hello = \"world\"}));\n\n    [Fact]\n    public void FormParameters1ObjectB()\n        => AssertParams([$\"{RuleParamPrefixForm}hello=world&{RuleParamPrefixForm}name=iJungleboy\"], NewTb().TacFormParameters(new { hello = \"world\", name = \"iJungleboy\"}));\n\n    [Fact]\n    public void Parameters1String()\n        => AssertParams([\"Hello\"], NewTb().TacParameters(\"Hello\"));\n\n    [Fact]\n    public void Parameters2Strings()\n        => AssertParams([\"Hello=World\"], NewTb().TacParameters(\"Hello\", \"World\"));\n\n    [Fact]\n    public void Parameters2Int()\n        => AssertParams([\"Hello=42\"], NewTb().TacParameters(\"Hello\", 42));\n    [Fact]\n    public void Parameters2Bool()\n        => AssertParams([\"Hello=true\"], NewTb().TacParameters(\"Hello\", true));\n\n    [Fact]\n    public void Parameters1ObjectA()\n        => AssertParams([new { hello = \"world\" }], NewTb().TacParameters(new { hello = \"world\"}));\n\n    [Fact]\n    public void Parameters1ObjectB()\n        => AssertParams([new { hello = \"world\", name = \"iJungleboy\" }], NewTb().TacParameters(new { hello = \"world\", name = \"iJungleboy\"}));\n\n    [Fact]\n    public void Prefill1String()\n        => AssertParams([$\"{RuleParamPrefixPrefill}Hello\"], NewTb().TacPrefill(\"Hello\"));\n\n    [Fact]\n    public void Prefill2Strings()\n        => AssertParams([$\"{RuleParamPrefixPrefill}Hello=World\"], NewTb().TacPrefill(\"Hello\", \"World\"));\n\n    private static readonly Guid Guid1 = new(\"640df5cf-ec2b-4943-9962-5a98bb1e8d01\");\n    private static readonly Guid Guid2 = new(\"7b42eae8-2ead-479e-af67-8e1349939ed6\");\n    private static readonly Guid[] Guids = [Guid1, Guid2];\n    private static readonly string GuidsExpected = $\"[\\\"{Guid1}\\\",\\\"{Guid2}\\\"]\";\n\n    [Fact]\n    public void PrefillGuidArray()\n        => AssertParams([$\"{RuleParamPrefixPrefill}Children={GuidsExpected}\"], NewTb().TacPrefill(\"Children\", Guids));\n\n    // todo: also prefill w/second param being an object\n\n    [Fact]\n    public void Prefill1ObjectA()\n        => AssertParams([$\"{RuleParamPrefixPrefill}hello=world\"], NewTb().TacPrefill(new { hello = \"world\"}));\n\n    [Fact]\n    public void Prefill1ObjectB()\n        => AssertParams([$\"{RuleParamPrefixPrefill}hello=world&{RuleParamPrefixPrefill}name=iJungleboy\"], NewTb().TacPrefill(new { hello = \"world\", name = \"iJungleboy\"}));\n\n    // TODO: filters must test for arrays of string, int, guid\n    [Fact]\n    public void Filter1Object()\n    => AssertParams([$\"{RuleParamPrefixFilter}hello=world\"], NewTb().TacFilter(new { hello = \"world\"}));\n\n    [Fact]\n    public void Filter2Objects()\n        => AssertParams([$\"{RuleParamPrefixFilter}hello=world&{RuleParamPrefixFilter}name=iJungleboy\"], NewTb().TacFilter(new { hello = \"world\", name = \"iJungleboy\"}));\n\n    [Fact]\n    public void Filter1String()\n        => AssertParams([$\"{RuleParamPrefixFilter}Hello\"], NewTb().TacFilter(\"Hello\"));\n\n    [Fact]\n    public void Filter2Strings()\n        => AssertParams([$\"{RuleParamPrefixFilter}Hello=World\"], NewTb().TacFilter(\"Hello\", \"World\"));\n\n    [Fact]\n    public void FilterGuidArray()\n        => AssertParams([$\"{RuleParamPrefixFilter}Children={GuidsExpected}\"], NewTb().TacFilter(\"Children\", Guids));\n\n    [Fact]\n    public void FilterIntArray()\n        => AssertParams([$\"{RuleParamPrefixFilter}Children=[2,7,42]\"],\n            NewTb().TacFilter(\"Children\", new[] { 2, 7, 42 }));\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/TweakButtonTests/TweakButtonShow.cs",
    "content": "﻿using static ToSic.Sxc.Edit.Toolbar.Sys.ToolbarConstants;\n\nnamespace ToSic.Sxc.Tests.ServicesTests.ToolbarService;\n\n\npublic class TweakButtonShow: TweakButtonTestsBase\n{\n    [Fact]\n    public void ShowTrue() => AssertUi([$\"{RuleShow}=true\"], NewTb().TacShow(true));\n\n    [Fact]\n    public void ShowFalse() => AssertUi([$\"{RuleShow}=false\"], NewTb().TacShow(false));\n\n    [Fact]\n    public void ShowNoParam() => AssertUi([$\"{RuleShow}=true\"], NewTb().TacShow());\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/TweakButtonTests/TweakButtonTestAccessors.cs",
    "content": "﻿using ToSic.Sxc.Edit.Toolbar;\n\nnamespace ToSic.Sxc.Tests.ServicesTests.ToolbarService;\n\ninternal static class TweakButtonTestAccessors\n{\n    public static ITweakButton TacShow(this ITweakButton button, bool show = true)\n        => button.Show(show);\n\n    public static ITweakButton TacColor(this ITweakButton button, string color = default,\n        NoParamOrder npo = default, string background = default,\n        string foreground = default)\n        => button.Color(color, npo, background, foreground);\n\n    public static ITweakButton TacTooltip(this ITweakButton button, string value)\n        => button.Tooltip(value);\n\n    public static ITweakButton TacGroup(this ITweakButton button, string value)\n    => button.Group(value);\n\n    public static ITweakButton TacIcon(this ITweakButton button, string value)\n        => button.Icon(value);\n\n    public static ITweakButton TacClasses(this ITweakButton button, string value)\n        => button.Classes(value);\n\n    public static ITweakButton TacPosition(this ITweakButton button, int value)\n        => button.Position(value);\n\n    public static ITweakButton TacUi(this ITweakButton button, object value)\n        => button.Ui(value);\n\n    public static ITweakButton TacUi(this ITweakButton button, string name, object value)\n        => button.Ui(name, value);\n\n    public static ITweakButton TacFormParameters(this ITweakButton button, object value)\n        => button.FormParameters(value);\n\n    public static ITweakButton TacFormParameters(this ITweakButton button, string name, object value)\n        => button.FormParameters(name, value);\n\n    public static ITweakButton TacParameters(this ITweakButton button, object value)\n        => button.Parameters(value);\n\n    public static ITweakButton TacParameters(this ITweakButton button, string name, object value)\n        => button.Parameters(name, value);\n\n    public static ITweakButton TacPrefill(this ITweakButton button, object value)\n        => button.Prefill(value);\n\n    public static ITweakButton TacPrefill(this ITweakButton button, string name, object value)\n        => button.Prefill(name, value);\n\n    public static ITweakButton TacFilter(this ITweakButton button, string name, object value)\n        => button.Filter(name, value);\n\n    public static ITweakButton TacFilter(this ITweakButton button, object value)\n        => button.Filter(value);\n\n    public static ITweakButton TacCondition(this ITweakButton button, bool value)\n        => button.Condition(value);\n\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Edit/TweakButtonTests/TweakButtonTestsBase.cs",
    "content": "﻿using System.Diagnostics;\nusing System.Text.Json;\nusing ToSic.Sxc.Edit.Toolbar;\nusing ToSic.Sxc.Edit.Toolbar.Sys.TweakButton;\n\nnamespace ToSic.Sxc.Tests.ServicesTests.ToolbarService;\n\npublic class TweakButtonTestsBase\n{\n    protected ITweakButton NewTb() => new TweakButton();\n\n    /// <summary>\n    /// Compare the UiMerge of the tweak with the expected values\n    /// </summary>\n    /// <param name=\"expected\"></param>\n    /// <param name=\"tweak\"></param>\n    protected static void AssertUi(IEnumerable<string> expected, ITweakButton tweak)\n        => Equal(expected.ToList(), tweak.UiMerge.ToList());\n    \n    protected static void AssertUi(IEnumerable<object> expected, ITweakButton tweak)\n        => Equal(expected.ToList(), tweak.UiMerge.ToList());\n\n    protected static void AssertUiJson(IEnumerable<object> expected, ITweakButton tweak)\n        => Equal(ToJson(expected), ToJson(tweak.UiMerge));\n\n    private static List<string> ToJson(IEnumerable<object> values)\n        => values\n            .Select(v => JsonSerializer.Serialize(v))\n            .ToList();\n\n    protected static void AssertParams(IEnumerable<string> expected, ITweakButton tweak)\n    {\n        var parameters = tweak.ParamsMerge;\n        // Add trace of json objects for debugging\n        Trace.WriteLine(\"expected:\" + JsonSerializer.Serialize(expected));\n        Trace.WriteLine(\"actual  :\" + JsonSerializer.Serialize(parameters));\n        Equal(expected.ToList(), tweak.ParamsMerge.ToList());\n    }\n\n    protected static void AssertParams(IEnumerable<object> expected, ITweakButton tweak)\n    {\n        var parameters = tweak.ParamsMerge;\n        // Add trace of json objects for debugging\n        Trace.WriteLine(\"expected:\" + JsonSerializer.Serialize(expected));\n        Trace.WriteLine(\"actual  :\" + JsonSerializer.Serialize(parameters));\n        Equal(expected.ToList(), parameters.ToList());\n    }\n\n    protected static void AssertParamsJson(IEnumerable<object> expected, ITweakButton tweak)\n        => Equal(ToJson(expected), ToJson(tweak.ParamsMerge));\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.Logging;\nglobal using static Xunit.Assert;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Images/ImageflowRewriteTests.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Images;\n\nnamespace ToSic.Sxc.Tests.Images;\n\n\npublic class ImageflowRewriteTests\n{\n    #region shared\n\n    public static readonly string Quality = ImageflowRewrite.Quality;\n    public static readonly string PngQuality = ImageflowRewrite.PngQuality;\n    public static readonly string WebpQuality = ImageflowRewrite.WebpQuality;\n\n    private static NameValueCollection AddKeyWhenMissing(NameValueCollection queryString, string key, string value) =>\n        ImageflowRewrite.AddKeyWhenMissing(queryString, key, value);\n\n    private NameValueCollection QueryStringRewrite(NameValueCollection queryString) => \n        ImageflowRewrite.QueryStringRewrite(queryString);\n\n    private static void AreEquivalentAlsoByValues(NameValueCollection expected, NameValueCollection actual) =>\n        Equivalent(\n            expected.AllKeys.ToDictionary(k => k, k => expected[k]),\n            actual.AllKeys.ToDictionary(k => k, k => actual[k]));\n\n    #endregion\n\n\n    #region QueryStringRewrite MAIN TESTING\n\n    [Fact]\n    public void QueryStringRewriteWhenQueryStringNull()\n    {\n        Null(QueryStringRewrite(null));\n    }\n\n\n    [Fact]\n    public void QueryStringRewriteWhenQueryStringEmpty()\n    {\n        var actual = QueryStringRewrite(new());\n        var expected = new NameValueCollection ();\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n\n    [Fact]\n    public void QueryStringRewriteWhenQueryStringWithOneItem()\n    {\n        var actual = QueryStringRewrite(new() { { \"1\", \"1\" } });\n        var expected = new NameValueCollection\n        {\n            { \"1\", \"1\" }\n        };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n\n    [Fact]\n    public void QueryStringRewriteWhenQueryStringWithManyItems()\n    {\n        var actual = QueryStringRewrite(\n            new()\n            {\n                { \"1\", \"1\" },\n                { \"2\", \"2\" }\n            });\n        var expected = new NameValueCollection\n        {\n            { \"1\", \"1\" },\n            { \"2\", \"2\" },\n        };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n\n    [Fact]\n    public void QualityQueryStringRewrite()\n    {\n        var actual = QueryStringRewrite(new() { { Quality, \"value\" } });\n        var expected = new NameValueCollection\n        {\n            { Quality, \"value\" },\n            { PngQuality, \"value\" },\n            { WebpQuality, \"value\" },\n\n        };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n\n    [Fact]\n    public void QualityQueryStringRewriteWhenManyItems()\n    {\n        var actual = QueryStringRewrite(\n            new()\n            {\n                { \"1\", \"1\" },\n                { \"2\", \"2\" },\n                { Quality, \"value\" }\n            });\n        var expected = new NameValueCollection\n        {\n            { \"1\", \"1\" },\n            { \"2\", \"2\" },\n            { Quality, \"value\" },\n            { PngQuality, \"value\" },\n            { WebpQuality, \"value\" },\n        };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n\n    [Fact]\n    public void QualityQueryStringRewriteWhenQueryStringWithManyQualityItems()\n    {\n        var actual = QueryStringRewrite(new()\n        {\n            { Quality, \"value\" },\n            { PngQuality, \"69\" },\n            { WebpQuality, \"59\" }\n        });\n        var expected = new NameValueCollection\n        {\n            { Quality, \"value\" },\n            { PngQuality, \"69\" },\n            { WebpQuality, \"59\" },\n        };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n\n    #endregion\n\n\n    #region AddKeyWhenMissing function testing\n\n    [Fact]\n    public void AddKeyWhenMissingInQueryStringEmpty()\n    {\n        var actual = AddKeyWhenMissing(new(), \"key\", \"value\");\n        var expected = new NameValueCollection { { \"key\", \"value\" } };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n    [Fact]\n    public void AddKeyWhenNotMissingInQueryStringOneElement()\n    {\n        var actual = AddKeyWhenMissing(\n            new() { { \"key\", \"value\" } },\n            \"key\", \"value\");\n        var expected = new NameValueCollection { { \"key\", \"value\" } };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n    [Fact]\n    public void AddKeyWhenMissingInQueryStringOneElement()\n    {\n        var actual = AddKeyWhenMissing(\n            new() { { \"1\", \"1\" } },\n            \"key\", \"value\");\n        var expected = new NameValueCollection { { \"1\", \"1\" }, { \"key\", \"value\" } };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n    [Fact]\n    public void AddKeyWhenNotMissingInQueryStringManyElement()\n    {\n        var actual = AddKeyWhenMissing(\n            new() { { \"1\", \"1\" }, { \"key\", \"value\" } },\n            \"key\", \"value\");\n        var expected = new NameValueCollection { { \"1\", \"1\" }, { \"key\", \"value\" } };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n    [Fact]\n    public void AddKeyWhenMissingInQueryStringManyElement()\n    {\n        var actual = AddKeyWhenMissing(\n            new() { { \"1\", \"1\" }, { \"2\", \"2\" } },\n            \"key\", \"value\");\n        var expected = new NameValueCollection { { \"1\", \"1\" }, { \"2\", \"2\" } , { \"key\", \"value\" } };\n        AreEquivalentAlsoByValues(expected, actual);\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/ParametersTestExtensions.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Web.Sys.Url;\nusing Parameters = ToSic.Sxc.Context.Sys.Parameters;\n\nnamespace ToSic.Sxc.Tests.LinksAndImages;\n\ninternal static class ParametersTestExtensions\n{\n    public static IParameters NewParameters(NameValueCollection originals)\n        => new Parameters { Nvc = originals };\n\n    public static IParameters AsParameters(this NameValueCollection originals)\n        => new Parameters { Nvc = originals };\n\n    public static IParameters AsParameters(this string originals)\n        => UrlHelpers.ParseQueryString(originals).AsParameters();\n\n    public static IParameters TestAdd(this IParameters p, string key) => p.Add(key);\n\n    public static IParameters TestAdd(this IParameters p, string key, string value) => p.Add(key, value);\n\n    public static IParameters TestAdd(this IParameters p, string key, object value) => p.Add(key, value);\n\n    public static IParameters TestRemove(this IParameters p, string name) => p.Remove(name);\n\n    public static IParameters TestRemove(this IParameters p, string name, object value) => p.Remove(name, value);\n\n    public static IParameters TestSet(this IParameters p, string name) => p.Set(name);\n    public static IParameters TestSet(this IParameters p, string name, string value) => p.Set(name, value);\n\n    public static IParameters TestSet(this IParameters p, string name, object value) => p.Set(name, value);\n\n    public static IParameters TestToggle(this IParameters p, string name, object value) => p.Toggle(name, value);\n    public static IParameters TestFilter(this IParameters p, string names) => p.Filter(names);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/QueryHelperTests.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Tests.LinksAndImages;\n\n\npublic class QueryHelperTests\n{\n    private static string AddQueryString(string url, NameValueCollection queryParams)\n        => UrlHelpers.AddQueryString(url, queryParams);\n\n    private const string urlRelativeNoParams = \"/xyz/abc.jpg\";\n    private const string urlHttpNoParams = \"http://2sxc.org/xyz/abc.jpg\";\n    private const string urlHttpsNoParams = \"https://2sxc.org/xyz/abc.jpg\";\n    private const string paramOne = \"?param=value\";\n    private const string paramTwo = paramOne + \"&name=iJungleboy\";\n    public const string urlFile27 = \"file:27\";\n    public const string urlPage42 = \"page:42\";\n    public const string fragEmpty = \"#\";\n    public const string fragValueOnly = \"#someFragment\";\n    public const string fragKeyValue = \"#some=fragMEnt\";\n    public const string fragKeyValueMany = \"#Some=fraGMent&othr=OTHR\";\n    public const string fragWithQuestion = \"#some=how-are-you?\";\n\n    private const NameValueCollection addOnNull = null;\n    private static NameValueCollection addOnEmpty = new();\n    private static NameValueCollection addOnOne = new()\n    {\n        {\"added\", \"worked\"}\n    };\n\n    private string paramAddOnOne = \"added=worked\";\n\n    [Fact]\n    public void EmptyUrls()\n    {\n        VerifyUnchangedWithoutAddOn(null);\n        VerifyUnchangedWithoutAddOn(string.Empty);\n        VerifyUnchangedWithoutAddOn(\" \");\n    }\n\n    [Fact]\n    public void FileReferenceUrls()\n    {\n        VerifyUnchangedWithoutAddOn(\"file:27\");\n        VerifyUnchangedWithoutAddOn(\"page:42030\");\n        VerifyUnchangedWithoutAddOn(\"file:305030?test=24\");\n        VerifyUnchangedWithoutAddOn(urlFile27 + fragEmpty);\n        VerifyUnchangedWithoutAddOn(urlPage42 + fragEmpty);\n        VerifyUnchangedWithoutAddOn(urlFile27 + fragValueOnly);\n        VerifyUnchangedWithoutAddOn(urlPage42 + fragValueOnly);\n        VerifyUnchangedWithoutAddOn(urlFile27 + fragKeyValue);\n        VerifyUnchangedWithoutAddOn(urlFile27 + fragKeyValueMany);\n        VerifyUnchangedWithoutAddOn(urlFile27 + fragWithQuestion);\n    }\n    [Fact]\n    public void FileReferenceUrlsWithAddOns()\n    {\n\n        Equal(urlFile27 + \"?\" + paramAddOnOne, AddQueryString(urlFile27, addOnOne));\n        Equal(urlPage42 + \"?\" + paramAddOnOne, AddQueryString(urlPage42, addOnOne));\n        Equal(urlPage42 + \"?\" + paramAddOnOne, AddQueryString(urlPage42, addOnOne));\n\n        var urlFWithParam = urlFile27 + paramOne;\n        Equal(urlFWithParam + \"&\" + paramAddOnOne, AddQueryString(urlFWithParam, addOnOne));\n\n        // With fragment and with empty fragment\n        Equal(urlFile27+ \"?\" + paramAddOnOne, AddQueryString(urlFile27 + fragEmpty, addOnOne));//, \"empty frag is dropped\");\n        Equal(urlFile27 + \"?\" + paramAddOnOne + fragValueOnly, AddQueryString(urlFile27 + fragValueOnly, addOnOne));\n        Equal(urlFile27 + \"?\" + paramAddOnOne + fragKeyValue, AddQueryString(urlFile27 + fragKeyValue, addOnOne));\n        Equal(urlFile27 + \"?\" + paramAddOnOne + fragKeyValueMany, AddQueryString(urlFile27 + fragKeyValueMany, addOnOne));\n        Equal(urlFile27 + \"?\" + paramAddOnOne + fragWithQuestion, AddQueryString(urlFile27 + fragWithQuestion, addOnOne));\n    }\n\n    [Fact]\n    public void EmptyUrlWithExistingParams()\n    {\n        VerifyUnchangedWithoutAddOn(paramOne);\n        VerifyUnchangedWithoutAddOn(paramOne + paramTwo);\n        VerifyUnchangedWithoutAddOn(\" \" + paramOne);\n    }\n\n    [Fact]\n    public void NoParams()\n    {\n        VerifyUnchangedWithoutAddOn(urlRelativeNoParams);\n        VerifyUnchangedWithoutAddOn(urlHttpNoParams);\n        VerifyUnchangedWithoutAddOn(urlHttpsNoParams);\n    }\n\n    [Fact]\n    public void ParamsButNoAdditional()\n    {\n        VerifyUnchangedWithoutAddOn(urlRelativeNoParams + paramOne);\n        VerifyUnchangedWithoutAddOn(urlHttpNoParams + paramOne);\n        VerifyUnchangedWithoutAddOn(urlHttpsNoParams + paramOne);\n        VerifyUnchangedWithoutAddOn(urlRelativeNoParams + paramOne + paramTwo);\n        VerifyUnchangedWithoutAddOn(urlHttpNoParams + paramOne + paramTwo);\n        VerifyUnchangedWithoutAddOn(urlHttpsNoParams + paramOne + paramTwo);\n    }\n\n    [Fact]\n    public void NoParamsButAddOne()\n    {\n        Equal(urlRelativeNoParams + \"?\" + paramAddOnOne, AddQueryString(urlRelativeNoParams, addOnOne));\n        Equal(urlHttpNoParams + \"?\" + paramAddOnOne, AddQueryString(urlHttpNoParams, addOnOne));\n        Equal(urlHttpsNoParams+ \"?\" + paramAddOnOne, AddQueryString(urlHttpsNoParams, addOnOne));\n    }\n\n    [Fact]\n    public void ParamsAndAddOne()\n    {\n        Equal($\"{urlRelativeNoParams}{paramOne}&{paramAddOnOne}\", AddQueryString($\"{urlRelativeNoParams}{paramOne}\", addOnOne));\n        Equal($\"{urlHttpNoParams}{paramOne}&{paramAddOnOne}\", AddQueryString($\"{urlHttpNoParams}{paramOne}\", addOnOne));\n        Equal($\"{urlHttpsNoParams}{paramOne}&{paramAddOnOne}\", AddQueryString($\"{urlHttpsNoParams}{paramOne}\", addOnOne));\n    }\n\n\n\n    private void VerifyUnchangedWithoutAddOn(string url)\n    {\n        Equal(url, AddQueryString(url , addOnNull));//, $\"Initial: {url}\");\n        Equal(url, AddQueryString(url , addOnEmpty));//, $\"Initial {url}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/SrcSetParsePart.cs",
    "content": "﻿using ToSic.Sxc.Images;\nusing ToSic.Sxc.Sys.Plumbing;\n\nnamespace ToSic.Sxc.Tests.LinksAndImages;\n\n\npublic class SrcSetParsePart\n{\n    public record TestSpecs(string Variants, double Size, char SizeType, int? Width, int Height);\n\n    public static TheoryData<TestSpecs> LotsOfTests => [\n        // Basic Number and optional Width only\n        new(\"100\", 100, 'w', 100, 0),\n        new(\"100w\", 100, 'w', 100, 0),\n        new(\"2000.4\", 2000, 'w', 2000, 0),\n        new(\"2000w\", 2000, 'w', 2000, 0),\n        new(\"4w\", 4, 'w', 4, 0),   // Very small number, without the 'w' it would default to x\n\n        // Basic W number with additional width\n        new(\"100=100\", 100, 'w', 100, 0),\n        new(\"100=700\", 100, 'w', 700, 0),\n        new(\"100w=700\", 100, 'w', 700, 0),\n        new(\"100=700.9\", 100, 'w', 701, 0),\n\n        // Basic W number with additional width and height\n        new(\"100=100:50\", 100, 'w', 100, 50),\n        new(\"100=700:300\", 100, 'w', 700, 300),\n        new(\"100w=700:400\", 100, 'w', 700, 400),\n        new(\"100=700.9:201.7\", 100, 'w', 701, 202),\n\n        // Basic W number with no width but height\n        new(\"100=:50\", 100, 'w', 100, 50),\n        new(\"100=:300\", 100, 'w', 100, 300),\n        new(\"100w=:400\", 100, 'w', 100, 400),\n        new(\"100=:201.7\", 100, 'w', 100, 202),\n\n        // Basic X-Factor\n        new(\"1\", 1, 'x', 0, 0),\n        new(\"1x\", 1, 'x', 0, 0),\n        new(\"1.5\", 1.5, 'x', 0, 0),\n        new(\"1.5x\", 1.5, 'x', 0, 0),\n        new(\"2\", 2, 'x', 0, 0),\n        new(\"2x\", 2, 'x', 0, 0),\n        new(\"2.25\", 2.25, 'x', 0, 0),\n        new(\"2.25x\", 2.25, 'x', 0, 0),\n        new(\"12x\", 12, 'x', 0, 0), // vary large X-factor, without x it would default to 'w'\n\n        // X-Factor with Width and maybe height\n        new(\"1=45\", 1, 'x', 45, 0),\n        new(\"1x=45\", 1, 'x', 45, 0),\n        new(\"1.5=77\", 1.5, 'x', 77, 0),\n        new(\"1.5x=77.9\", 1.5, 'x', 78, 0),\n        new(\"1=45:33\", 1, 'x', 45, 33),\n        new(\"1x=45:49\", 1, 'x', 45, 49),\n        new(\"1.5=77:22.1\", 1.5, 'x', 77, 22),\n        new(\"1.5x=77.9:22.9\", 1.5, 'x', 78, 23),\n    ];\n\n    [Theory]\n    [MemberData(nameof(LotsOfTests))]\n    public void ParsePartAsPart(TestSpecs specs)\n        => TestPartOnly(specs);\n\n    [Theory]\n    [MemberData(nameof(LotsOfTests))]\n    public void ParsePartAsSet(TestSpecs specs)\n        => TestSetOnly(specs);\n\n    // * Factor\n    public static TheoryData<TestSpecs> FactorData => [\n        new(\"0.5*\", 0.5, '*', 0, 0),\n        new(\"1/2\", 0.5, '*', 0, 0),\n        new(\"1:2\", 0.5, '*', 0, 0),\n        new(\"3:4\", 0.75, '*', 0, 0),\n        new(\"0.5\", 0.5, '*', 0, 0),\n        new(\"0.33\", 0.33, '*', 0, 0),\n    ];\n\n    [Theory]\n    [MemberData(nameof(FactorData))]\n    public void TestFactorsPart(TestSpecs specs) => TestPartOnly(specs);\n    [Theory]\n    [MemberData(nameof(FactorData))]\n    public void TestFactorsSet(TestSpecs specs) => TestSetOnly(specs);\n\n\n    public static TheoryData<TestSpecs> FaultySourceSets => [\n        new(\"1q\", 0, 'd', 0, 0),\n        new(\"77vh\", 0, 'd', 0, 0),\n        new(\"77vw\", 0, 'w', 0, 0), // this 'w' is picked up, because it's the last character\n    ];\n\n    [Theory]\n    [MemberData(nameof(FaultySourceSets))]\n    public void ParseFaultySourcePartOnly(TestSpecs specs) => TestPartOnly(specs);\n    [Theory]\n    [MemberData(nameof(FaultySourceSets))]\n    public void ParseFaultySourceSetOnly(TestSpecs specs) => TestSetOnly(specs);\n\n    // Some invalid data - should basically result in ignored data\n    public static TheoryData<TestSpecs> FaultySourceSetsWithComma => [\n        new(null, 0, 'd', 0, 0),       // test this as part only, because it would return 0 items when run as a set\n        new(\"\", 0, 'd', 0, 0),         // test this as part only, because it would return 0 items when run as a set\n        new(\"99,9\", 99, 'w', 99, 0),   // comma should never be used, but in production it will just work, because commas are split before\n    ];\n\n    [Theory]\n    [MemberData(nameof(FaultySourceSetsWithComma))]\n    public void ParseFaultySourcePartWithCommaOnly(TestSpecs specs) => TestPartOnly(specs);\n\n\n    [Fact]\n    public void ParseSet()\n    {\n        var variants = \"100,100w,,100=100,100w=100:,d\";\n        var expected100 = BuildExpected(100, 'w', 100, 0);\n        var expDefault = BuildExpected(0, 'd', 0, 0);\n        var result = RecipeVariantsParser.ParseSet(variants);\n        Equal(6, result.Length);\n        CompareSrcSetPart(variants, result.First(), expected100);\n        CompareSrcSetPart(variants, result.Skip(1).First(), expected100);\n        CompareSrcSetPart(variants, result.Skip(2).First(), expDefault);\n        CompareSrcSetPart(variants, result.Skip(3).First(), expected100);\n        CompareSrcSetPart(variants, result.Skip(4).First(), expected100);\n        CompareSrcSetPart(variants, result.Skip(5).First(), expDefault);\n    }\n\n    /// <summary>\n    /// Real test function - standalone to quickly also run a single test if it fails\n    /// </summary>\n    private static void TestPartOnly(TestSpecs specs)\n    {\n        var expected = BuildExpected((float)specs.Size, specs.SizeType, specs.Width, specs.Height);\n        var result = RecipeVariantsParser.ParsePart(specs.Variants);\n        CompareSrcSetPart(specs.Variants, result, expected);\n    }\n\n    private static void TestSetOnly(TestSpecs specs)\n    {\n        var expected = BuildExpected((float)specs.Size, specs.SizeType, specs.Width, specs.Height);\n        var asSet = RecipeVariantsParser.ParseSet(specs.Variants);\n        Single(asSet);//, \"Expect 1 exact hit\");\n        var first = asSet.First();\n        CompareSrcSetPart(specs.Variants, first, expected);\n    }\n\n    private static RecipeVariant BuildExpected(float size, char sizeType, int? width, int height) =>\n        new()\n        {\n            Size = size,\n            SizeType = sizeType,\n            Width = width ?? (int)size,\n            Height = height\n        };\n\n    private static void CompareSrcSetPart(string variants, RecipeVariant result, RecipeVariant expected)\n    {\n        NotNull(result);\n        True(ParseObject.DNearZero(expected.Size - result.Size), $\"Sizes should match on '{variants}'\");\n        Equal(expected.SizeType, result.SizeType);//, $\"Size Types should match on '{variants}'\");\n        Equal(expected.Width, result.Width);//, $\"Widths should match on '{variants}'\");\n        Equal(expected.Height, result.Height);//, $\"Heights should match on '{variants}'\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/UrlHelperTests/MergeNameValueCollectionTests.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Tests.LinksAndImages.UrlHelperTests;\n\n\npublic class MergeNameValueCollectionTests\n{\n    /// <summary>\n    /// Test accessor\n    /// </summary>\n    /// <returns></returns>\n    private NameValueCollection ImportTest(NameValueCollection first, NameValueCollection second, bool replace = false) =>\n        first.Merge(second, replace);\n\n    private const string Same = \"!same!\";\n\n    private void Test(string exp, string expReplace, string first, string second)\n    {\n        var nvc1 = UrlHelpers.ParseQueryString(first);\n        var itemsIn1 = nvc1.Count;\n        var nvc2 = UrlHelpers.ParseQueryString(second);\n        var itemsIn2 = nvc2.Count;\n        var merged = ImportTest(nvc1, nvc2);\n        Equal(itemsIn1, nvc1.Count);//, \"Import shouldn't change first\"); \n        Equal(itemsIn2, nvc2.Count);//, \"Import shouldn't change second\");\n        Equal(exp, UrlHelpers.NvcToString(merged));\n\n        merged = ImportTest(nvc1, nvc2, true);\n        if (expReplace == Same) expReplace = exp;\n        Equal(itemsIn1, nvc1.Count);//, \"Import shouldn't change first\"); \n        Equal(itemsIn2, nvc2.Count);//, \"Import shouldn't change second\");\n        Equal(expReplace, UrlHelpers.NvcToString(merged));\n\n    }\n\n    [Fact] public void BasicMerge() => Test(\"first=1&second=2\", Same, \"first=1\", \"second=2\");\n    [Fact] public void LongerMerge() => Test(\"first=1&a=b&second=2&x=z\", Same, \"first=1&a=b\", \"second=2&x=z\");\n    [Fact] public void EmptyBoth() => Test(\"\", Same, \"\", \"\");\n    [Fact] public void EmptyFirst() => Test(\"second=2&x=z\",Same, \"\", \"second=2&x=z\");\n    [Fact] public void EmptySecond() => Test(\"first=1&a=b\", Same, \"first=1&a=b\", \"\");\n\n    [Fact] public void FirstJustKey() => Test(\"first&second=2&x=z\", Same, \"first\", \"second=2&x=z\");\n\n    [Fact] public void IdenticalKeys() => Test(\n        \"first=a&identical=a&identical=b&second=2&x=z\", \"first=a&identical=b&second=2&x=z\",\n        \"first=a&identical=a\", \"identical=b&second=2&x=z\");\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/UrlHelperTests/Obj2UrlMerge.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Tests.LinksAndImages.UrlHelperTests;\n\n\npublic class Obj2UrlMerge\n{\n    // Test accessor\n    private string SerializeWithChild(object main, object child) =>\n        new ObjectToUrl().SerializeWithChild(main, child, prefix);\n\n    private const string prefix = \"prefix:\";\n\n    [Theory]\n    [InlineData((string)null)]\n    [InlineData(\"\")]\n    [InlineData(\"icon=hello\")]\n    [InlineData(\"icon=hello&value=2\")]\n    public void FirstOnlyString(string ui)\n    {\n        Equal(ui, SerializeWithChild(ui, null));\n    }\n\n    [Theory]\n    [InlineData(null, null)]\n    [InlineData(\"\", \"\")]\n    [InlineData(\"prefix:icon=hello\", \"icon=hello\")]\n    [InlineData(\"prefix:icon=hello&prefix:value=2\", \"icon=hello&value=2\")]\n    public void ChildOnlyString(string exp, string child)\n    {\n        Equal(exp, SerializeWithChild(null, child));\n    }\n\n    [Fact]\n    public void MainObjectChildString() \n        => Equal(\"id=27&name=daniel&prefix:title=title2\", SerializeWithChild(new { id = 27, name = \"daniel\" }, \"title=title2\"));\n\n    [Fact]\n    public void MainStringChildString() \n        => Equal(\"id=27&name=daniel&prefix:title=title2\", SerializeWithChild(\"id=27&name=daniel\", \"title=title2\"));\n\n    [Fact]\n    public void MainStringChildObject() \n        => Equal(\"id=27&name=daniel&prefix:title=title2\", SerializeWithChild(\"id=27&name=daniel\", new { title = \"title2\"}));\n\n    [Fact]\n    public void MainObjectChildObject() \n        => Equal(\"id=27&name=daniel&prefix:title=title2\", SerializeWithChild(new { id = 27, name = \"daniel\" }, new { title = \"title2\"}));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/UrlHelperTests/Obj2UrlTests.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Tests.LinksAndImages.UrlHelperTests;\n\n\npublic class Obj2UrlTests\n{\n    private static readonly object TestCase1 = new\n    {\n        test = 7,\n        name = \"daniel\"\n    };\n    private static readonly string TestCase1Str = \"test=7&name=daniel\";\n\n    private static readonly object TestCase2 = new\n    {\n        lastName = \"mettler\"\n    };\n\n    private static readonly string TestCase2Str = \"lastName=mettler\";\n\n    private string O2uSerialize(object data) => new ObjectToUrl().Serialize(data);\n\n\n    [Fact]\n    public void WithArray()\n    {\n        var obj = new\n        {\n            array = new[] { 32, 16, 8 }\n        };\n        Equal(\"array=32,16,8\", O2uSerialize(obj));\n    }\n\n    [Fact]\n    public void StringOnly() => Equal(TestCase1Str, O2uSerialize(TestCase1Str));\n\n    [Fact]\n    public void StringNull() => Equal(null as string, O2uSerialize(null));\n    [Fact]\n    public void StringEmpty() => Equal(\"\", O2uSerialize(\"\"));\n\n    [Fact]\n    public void StringsInArray() => Equal(TestCase1Str, O2uSerialize( new object[] { TestCase1Str }));\n\n    [Fact]\n    public void StringsInArrayNullOnly() => Equal(\"\", O2uSerialize( new object[] { null }));\n    [Fact]\n    public void StringsInArrayEmptyOnly() => Equal(\"\", O2uSerialize( new object[] { \"\" }));\n\n    [Fact]\n    public void StringsInArrayWithNull() => Equal(TestCase1Str, O2uSerialize( new object[] { TestCase1Str, null }));\n\n    [Fact]\n    public void StringsInArray2() => Equal($\"{TestCase1Str}&{TestCase2Str}\", O2uSerialize( new object[] { TestCase1Str, TestCase2Str }));\n\n    [Fact]\n    public void BasicObj()\n    {\n        Equal(TestCase1Str, O2uSerialize(TestCase1));\n    }\n    [Fact]\n    public void WithSubArray()\n    {\n        var obj = new\n        {\n            prefill = new\n            {\n                array = new int[] { 32, 16, 8 }\n            }\n        };\n        Equal(\"prefill:array=32,16,8\", O2uSerialize(obj));\n    }\n\n\n\n    [Fact]\n    public void MergeObject1And2()\n    {\n        Equal($\"{TestCase1Str}&{TestCase2Str}\", O2uSerialize(new object[] { TestCase1, TestCase2 }));\n    }\n\n    [Fact]\n    public void MergeObject1AndString2()\n    {\n        Equal($\"{TestCase1Str}&{TestCase2Str}\", O2uSerialize(new object[] { TestCase1, TestCase2Str }));\n    }\n\n    [Fact]\n    public void MergeString1AndObject2()\n    {\n        Equal($\"{TestCase1Str}&{TestCase2Str}\", O2uSerialize(new object[] { TestCase1Str, TestCase2 }));\n    }\n\n    [Fact]\n    public void BasicWithPrefix()\n    {\n        var prefix = \"prefix:\";\n        Equal($\"{prefix}test=7&{prefix}name=daniel\", new ObjectToUrl(prefix: prefix).Serialize(TestCase1));\n    }\n\n    [Fact]\n    public void SubObj()\n    {\n        var obj = new\n        {\n            test = 7,\n            name = \"daniel\",\n            prefill = new\n            {\n                title = \"new title\"\n            }\n        };\n        Equal(\"test=7&name=daniel&prefill:title=new%20title\", O2uSerialize(obj));\n    }\n\n    [Fact]\n    public void SubSubObj()\n    {\n        var obj = new\n        {\n            prefill = new\n            {\n                title = \"new title\",\n                entities = new\n                {\n                    name = \"daniel\",\n                    and = \"ok\"\n                }\n            }\n        };\n        Equal(\"prefill:title=new%20title&prefill:entities:name=daniel&prefill:entities:and=ok\", O2uSerialize(obj));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/UrlHelperTests/ParseQueryStringTests.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Sxc.Web.Sys.Url;\nusing static ToSic.Sxc.Tests.LinksAndImages.ParametersTestExtensions;\n\nnamespace ToSic.Sxc.Tests.LinksAndImages.UrlHelperTests;\n\n\npublic class ParseQueryStringTests\n{\n    /// <summary>\n    /// Test accessor\n    /// </summary>\n    /// <param name=\"query\"></param>\n    /// <returns></returns>\n    private NameValueCollection Parse(string query) => UrlHelpers.ParseQueryString(query);\n\n    private const string UseExpected = \"!use-expected!\";\n    private void TestPQS(string expected, int expCount, string query)\n    {\n        query = (query == UseExpected) ? expected : query;\n        var result = Parse(query);\n        Equal(expCount, result.Count);\n        var reStringed = NewParameters(result).ToString();\n        Equal(expected, reStringed);\n    }\n\n    [Fact] public void Null() => TestPQS(\"\", 0, null);\n    [Fact] public void Empty() => TestPQS(\"\", 0, string.Empty);\n    [Fact] public void Spaces() => TestPQS(\"\", 0, \"   \");\n\n    [Fact] public void BasicPair() => TestPQS(\"2sxc=cool\", 1, UseExpected);\n    [Fact] public void BasicPairWithSpaces() => TestPQS(\"2sxc=cool\", 1, \" 2sxc=cool  \");\n\n    // Special prefixes and suffixes\n    [Fact] public void BasicPairWithQuestionPrefix() => TestPQS(\"2sxc=cool\", 1, \"?2sxc=cool\");\n    [Fact] public void BasicPairWithAndPrefix() => TestPQS(\"2sxc=cool\", 1, \"&2sxc=cool\");\n    [Fact] public void BasicPairWithAndSuffix() => TestPQS(\"2sxc=cool\", 1, \"&2sxc=cool&\");\n\n\n    [Fact] public void TwoPairs() => TestPQS(\"2sxc=cool&eav=power\", 2, UseExpected);\n    [Fact] public void SingleValue() => TestPQS(\"2sxc\", 1, UseExpected);\n    [Fact] public void SingleValues() => TestPQS(\"2sxc&eav&test\", 3, UseExpected);\n    [Fact] public void PairWithSingleValue() => TestPQS(\"2sxc=cool&activate\", 2, UseExpected);\n    [Fact] public void PairsWithSingleValues() => TestPQS(\"2sxc=cool&activate&disable&eav=power\", 4, UseExpected);\n\n    [Fact] public void MultipleIdenticalKeys() => TestPQS(\"id=27&id=48&id=72\", 1, UseExpected);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/UrlParts/UrlPartsProtocolAndDomain.cs",
    "content": "﻿namespace ToSic.Sxc.Tests.LinksAndImages;\n\n\npublic class UrlPartsProtocolAndDomain : UrlPartsTestBase\n{\n        \n\n    [Fact]\n    public void ProtocolDetection()\n    {\n        void VerifyProtocol(string url, string protocol, string domain)\n        {\n            var urlParts = UrlParts(url);\n            Equal(protocol, urlParts.Protocol);\n            Equal(domain, urlParts.Domain);\n            Equal(url ?? \"\", urlParts.ToLink());//, \"round trip should be identical except for null\"); \n        }\n        VerifyProtocol(null, \"\", \"\");\n        VerifyProtocol(\"\", \"\", \"\");\n        VerifyProtocol(\"https:\", \"\", \"\");\n        VerifyProtocol(\"//abc.com\", \"//\", \"abc.com\");\n        VerifyProtocol(\"///abc.com\", \"//\", \"\");\n        VerifyProtocol(\"ftp://daniel@abc.com/q\", \"ftp://\", \"daniel@abc.com\");\n        VerifyProtocol(\"http://xyz.com\", \"http://\", \"xyz.com\");\n        VerifyProtocol(\"http//\", \"\", \"\");\n        VerifyProtocol(\"https://\", \"https://\", \"\");\n        VerifyProtocol(\"futureprot://\", \"futureprot://\", \"\");\n        VerifyProtocol(\"https://abc.com/\", \"https://\", \"abc.com\");\n        VerifyProtocol(\"http://abc/home\", \"http://\", \"abc\");\n        VerifyProtocol(\"http/test//\", \"\", \"\");\n        VerifyProtocol(\"../../test\", \"\", \"\");\n        VerifyProtocol(\"/test/abc?test\", \"\", \"\");\n    }\n\n    /// <summary>\n    /// Verify Root Replacement\n    /// </summary>\n    private void VerRepRoot(string expected, string url, string post)\n    {\n        var urlParts = UrlParts(url);\n        urlParts.ReplaceRoot(post);\n        Equal(expected, urlParts.ToLink());\n    }\n\n    [Fact] public void RepRootEmptyOrigUsesReplacement() => VerRepRoot(\"//abc.org\", \"\", \"//abc.org\");\n    [Fact] public void RepRootOnlyDomainWorks() => VerRepRoot(\"//abc.org\", \"\", \"abc.org\");\n    [Fact] public void RepRootPreserveOrigProtocolIfNotNew() => VerRepRoot(\"https://abc.org/\", \"https://xyz/\", \"abc.org\");\n    [Fact] public void RepRootTakeNewProtocolIfGiven() => VerRepRoot(\"//abc.org/\", \"https://xyz/\", \"//abc.org\");\n    [Fact] public void RepRootSkipInvalidProtocol() => VerRepRoot(\"https://xyz/\", \"https://xyz/\", \"ftp:\");\n    [Fact] public void RepRootUseStandaloneProtocol() => VerRepRoot(\"ftp://xyz/\", \"https://xyz/\", \"ftp://\");\n\n    // TODO\n    // VARIOUS combinations of ToLink\n\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/UrlParts/UrlPartsTestBase.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Tests.LinksAndImages;\n\npublic class UrlPartsTestBase\n{\n    protected UrlParts UrlParts(string url) => new(url);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/UrlParts/UrlPartsToLink.cs",
    "content": "﻿namespace ToSic.Sxc.Tests.LinksAndImages;\n\n\npublic class UrlPartsToLink : UrlPartsTestBase\n{\n    // TODO\n    // VARIOUS combinations of ToLink\n    // todo\n    // different casing of full\n    // unknown types\n    // \"absolute\" as alternative to full ?\n    // diff initial setups\n\n\n    private const string Full = \"full\";\n    private const string Path = \"/\";\n    private const string Root = \"//\";\n\n    private const string FullLink = \"https://abcd.com/path/name?param=27#ok=true\";\n    private const string FullPath = \"/path/name?param=27#ok=true\";\n    private const string FullRoot = \"//abcd.com\" + FullPath;\n\n    private void To(string expected, string url, string type)\n    {\n        var result = UrlParts(url).ToLink(type);\n        Equal(expected, result);\n    }\n\n    [Fact] public void DomainAndProtocolToDefault() => To(\"https://abc.org\", \"https://abc.org\", null);\n    [Fact] public void DomainAndProtocolToFull() => To(\"https://abc.org\", \"https://abc.org\", Full);\n    [Fact] public void DomainAndProtocolToRel() => To(\"\", \"https://abc.org\", Path);\n    [Fact] public void DomainAndProtocolToRoot() => To(\"//abc.org\", \"https://abc.org\", Root);\n\n    [Fact] public void EmptyToDefault() => To(\"\", \"\", null);\n    [Fact] public void EmptyToFull() => To(\"\", \"\", Full);\n\n    [Fact] public void FullToDefault() => To(FullLink, FullLink, null);\n    [Fact] public void FullToFull() => To(FullLink, FullLink, Full);\n    [Fact] public void FullToBase() => To(FullPath, FullLink, Path);\n    [Fact] public void FullToRoot() => To(FullRoot, FullLink, Root);\n\n    [Fact] public void PathToDefault() => To(FullPath, FullPath, null);\n    [Fact] public void PathToFull() => To(FullPath, FullPath, Full);\n    [Fact] public void PathToBase() => To(FullPath, FullPath, Path);\n    [Fact] public void PathToRoot() => To(FullPath, FullPath, Root);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/LinksAndImages/UrlParts/UrlPartsTrivial.cs",
    "content": "﻿namespace ToSic.Sxc.Tests.LinksAndImages;\n\n\npublic class UrlPartsTrivial: UrlPartsTestBase\n{\n\n    [Fact]\n    public void TrivialUrls()\n    {\n        VerifyUrlOnly(\"https://www.xyz.org/something.jpg\");\n        VerifyUrlOnly(\"test\");\n        VerifyUrlOnly(\"test.jpg\");\n        VerifyUrlOnly(\"test.x.y.z.jpg\");\n    }\n        \n\n    private void VerifyUrlOnly(string url)\n    {\n        var urlParts = UrlParts(url);\n        Equal(url, urlParts.Url);\n        Equal(url, urlParts.ToLink());\n        Equal(string.Empty, urlParts.Query);\n        Equal(string.Empty, urlParts.Fragment);\n    }\n\n    [Fact]\n    public void UrlsWithFragments()\n    {\n        VerifyUrlAndFragmentOnly(\"test#17\", \"test\", \"17\");\n        VerifyUrlAndFragmentOnly(\"test.jpg#abc=def\", \"test.jpg\", \"abc=def\");\n        VerifyUrlAndFragmentOnly(\"/test.jpg#\", \"/test.jpg\", \"\");\n        VerifyUrlAndFragmentOnly(\"test#first=1&message=hello?\", \"test\", \"first=1&message=hello?\");\n    }\n\n    private void VerifyUrlAndFragmentOnly(string url, string pathExp, string fragmentExp)\n    {\n        var urlParts = UrlParts(url);\n        Equal(url, urlParts.Url);\n        Equal(pathExp, urlParts.Path);\n        Equal(string.Empty, urlParts.Query);\n        Equal(fragmentExp, urlParts.Fragment);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/PageProperty/UpdatePropertyTest.cs",
    "content": "﻿using ToSic.Sxc.Sys.Render.PageContext;\n\nnamespace ToSic.Sxc.PageProperty;\n\n\npublic class UpdatePropertyTest\n{\n    protected const string Suffix = \" - Blog - MySite\";\n\n    private string UpdatePropertyTestAccessor(string original, PagePropertyChange change) =>\n        Helpers.UpdateProperty(original, change);\n\n    [Fact]\n    public void PlaceholderSimple()\n    {\n        var result = UpdatePropertyTestAccessor(\"[placeholder]\" + Suffix,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\" });\n        Equal(\"My Title\" + Suffix, result);\n    }\n\n    [Fact]\n    public void PlaceholderEnd()\n    {\n        var result = UpdatePropertyTestAccessor(Suffix + \"[placeholder]\",\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\" });\n        Equal(Suffix + \"My Title\", result);\n    }\n\n    [Fact]\n    public void PlaceholderMiddle()\n    {\n        var result = UpdatePropertyTestAccessor(\"Before-[placeholder]-After\",\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\" });\n        Equal(\"Before-My Title-After\", result);\n    }\n\n    [Fact]\n    public void PlaceholderOtherCase()\n    {\n        var result = UpdatePropertyTestAccessor(\"[PlaceHolder]\" + Suffix,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\" });\n        Equal(\"My Title\" + Suffix, result);\n    }\n\n    [Fact]\n    public void PlaceholderOnly()\n    {\n        var result = UpdatePropertyTestAccessor(\"[PlaceHolder]\",\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\" });\n        Equal(\"My Title\", result);\n    }\n\n    [Fact]\n    public void PlaceholderNotFound()\n    {\n        var result = UpdatePropertyTestAccessor(Suffix,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\" });\n        Equal(\"My Title\", result);\n    }\n\n    [Fact]\n    public void PlaceholderNotFoundReplace()\n    {\n        var result = UpdatePropertyTestAccessor(Suffix,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\", ChangeMode = PageChangeModes.Replace });\n        Equal(\"My Title\", result);\n    }\n\n    [Fact]\n    public void PlaceholderNotFoundPrepend()\n    {\n        var result = UpdatePropertyTestAccessor(Suffix,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\", ChangeMode = PageChangeModes.Prepend });\n        Equal(\"My Title\" + Suffix, result);\n    }\n\n    [Fact]\n    public void PlaceholderNotFoundAppend()\n    {\n        var result = UpdatePropertyTestAccessor(Suffix,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\", ChangeMode = PageChangeModes.Append });\n        Equal(Suffix + \"My Title\", result);\n    }\n    [Fact]\n    public void PlaceholderNotFoundAuto()\n    {\n        var result = UpdatePropertyTestAccessor(Suffix,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\", ChangeMode = PageChangeModes.Auto });\n        Equal(\"My Title\", result);\n    }\n\n    [Fact]\n    public void NullOriginal()\n    {\n        var result = UpdatePropertyTestAccessor(null,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"My Title\" });\n        Equal(\"My Title\", result);\n    }\n\n    [Fact]\n    public void ValueNull()\n    {\n        var result = UpdatePropertyTestAccessor(\"Some Title\",\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = null });\n        Equal(\"Some Title\", result);\n    }\n\n    [Fact]\n    public void AllNull()\n    {\n        var result = UpdatePropertyTestAccessor(null,\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = null });\n        Equal(null, result);\n    }\n\n    [Fact]\n    public void ValueEmpty()\n    {\n        var result = UpdatePropertyTestAccessor(\"Some Title\",\n            new() { ReplacementIdentifier = \"[placeholder]\", Value = \"\" });\n        Equal(\"\", result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/PlumbingTests/CleanParamTests.cs",
    "content": "﻿using ToSic.Sxc.Sys.Plumbing;\n\nnamespace ToSic.Sxc.Tests.PlumbingTests;\n\n\npublic class CleanParamTests\n{\n    [Theory]\n    // Expected Nulls\n    [InlineData(null, null, \"null\")]\n    // Expected Floats from other number formats\n    [InlineData(0d, 0d, \"double zero\")]\n    [InlineData(0d, 0f, \"float zero\")]\n    //[InlineData(1.1f, 1.1f, \"float 1.1\")] // edge case, conversion results in 1.1000000238418579 rounding errors\n    [InlineData(1.1d, 1.1d, \"double 1.1\")]\n    // Expected Doubles\n    [InlineData(0d, 0, \"int zero\")]\n    [InlineData(0d, \"0\", \"string zero\")]\n    [InlineData(0d, \"0.0\", \"string 0.0\")]\n    [InlineData(7d, 7, \"int 7\")]\n    [InlineData(7d, \"7\", \"string 7\")]\n    [InlineData(7.1d, \"7.1\", \"string 7.1\")]\n    [InlineData(6.9d, \"6.9\", \"string 6.9\")]\n    public void DoubleOrNull(object expected, object data, string message)\n        => Equal(expected, ParseObject.DoubleOrNull(data));\n\n    [Fact]\n    public void DoubleOrNullEdgeCase()\n        => Equal(1.1f, ParseObject.DoubleOrNull(1.1f));\n\n    [Fact]\n    public void FloatOrNullObject()\n        => Equal(null, ParseObject.DoubleOrNull(new()));\n\n    [Fact]\n    public void FloatOrNullOld()\n    {\n        // Expected Nulls\n        Null(ParseObject.DoubleOrNull(null));\n        Null(ParseObject.DoubleOrNull(new()));\n\n        // Expected Floats from other number formats\n        Equal(0f, ParseObject.DoubleOrNull(0d));//, \"double zero\");\n        Equal(0f, ParseObject.DoubleOrNull(0f));//, \"float zero\");\n        Equal(1.1f, ParseObject.DoubleOrNull(1.1f));//, \"float 1.1\");\n        Equal(1.1d, ParseObject.DoubleOrNull(1.1d));//, \"double 1.1\");\n\n        // Expected Floats\n        Equal(0f, ParseObject.DoubleOrNull(0));//, \"int zero\");\n        Equal(0f, ParseObject.DoubleOrNull(\"0\"));//, \"string zero\");\n        Equal(0f, ParseObject.DoubleOrNull(\"0.0\"));//, \"string 0.0\");\n        Equal(7f, ParseObject.DoubleOrNull(7));//, \"int 7\");\n        Equal(7f, ParseObject.DoubleOrNull(\"7\"));//, \"string 7\");\n        Equal(7.1d, ParseObject.DoubleOrNull(\"7.1\"));//, \"string 7.1\");\n        Equal(6.9d, ParseObject.DoubleOrNull(\"6.9\"));//, \"string 6.9\");\n    }\n\n    [Theory]\n    // Check non-calculations\n    [InlineData(0d, 0)]\n    [InlineData(0d, \"0\")]\n    [InlineData(2d, \"2\")]\n    [InlineData(null, \"\")]\n    // Check calculations\n    [InlineData(1d, \"1/1\")]\n    [InlineData(1d, \"1:1\")]\n    [InlineData(0.5, \"1/2\")]\n    [InlineData(0.5, \"1:2\")]\n    [InlineData(2d, \"2/1\")]\n    [InlineData(2d, \"2:1\")]\n    [InlineData(16d / 9, \"16:9\")]\n    [InlineData(16d / 9, \"16/9\")]\n    // Bad calculations\n    [InlineData(null, \"/1\")]\n    [InlineData(null, \":1\")]\n    [InlineData(null, \"1:0\")]\n    [InlineData(null, \"0:0\")]\n    public void DoubleOrNullWithCalculation(double? expected, object data)\n        => Equal(expected, ParseObject.DoubleOrNullWithCalculation(data));\n\n\n    [Theory]\n    [InlineData(null, null, \"null\")]\n    [InlineData(0, 0, \"int zero\")]\n    [InlineData(0, 0f, \"float zero\")]\n    [InlineData(0, 0d, \"double zero\")]\n    [InlineData(0, \"0\", \"string zero\")]\n    [InlineData(0, \"0.0\", \"string 0.0\")]\n    [InlineData(7, 7, \"int 7\")]\n    [InlineData(7, \"7\", \"string 7\")]\n    [InlineData(7, \"7.1\", \"string 7.1\")]\n    [InlineData(7, 7.1f, \"float 7.1\")]\n    [InlineData(7, 7.1d, \"double 7.1\")]\n    [InlineData(7, \"6.9\", \"string 6.9\")]\n    [InlineData(7, 6.9f, \"float 6.9\")]\n    [InlineData(7, 6.9d, \"double 6.9\")]\n    public void IntOrNull(int? expected, object data, string message)\n        => Equal(expected, ParseObject.IntOrNull(data));\n\n    [Fact]\n    public void IntOrNullObject()\n        => Equal(null, ParseObject.IntOrNull(new()));\n\n\n\n    [Theory]\n    [InlineData(null, null, \"null\")]\n    [InlineData(null, 0, \"int zero\")]\n    [InlineData(null, \"0\", \"string zero\")]\n    [InlineData(null, \"0.0\", \"string 0.0\")]\n    [InlineData(null, 0f, \"float zero\")]\n    [InlineData(null, 0d, \"double zero\")]\n    [InlineData(7, 7, \"int 7\")]\n    [InlineData(7, \"7\", \"string 7\")]\n    [InlineData(7, \"7.1\", \"string 7.1\")]\n    [InlineData(7, \"6.9\", \"string 6.9\")]\n    public void IntOrZeroNull(int? expected, object data, string message)\n        => Equal(expected, ParseObject.IntOrZeroAsNull(data));\n\n    [Fact]\n    public void IntOrZeroNullObject()\n        => Equal(null, ParseObject.IntOrZeroAsNull(new()));\n\n\n    [Theory]\n    [InlineData(null, null, \"null\")]\n    [InlineData(\"0\", 0, \"int zero\")]\n    [InlineData(\"0\", \"0\", \"string zero\")]\n    [InlineData(\"0.0\", \"0.0\", \"string 0.0\")]\n    [InlineData(\"0\", 0f, \"float zero\")]\n    [InlineData(\"0\", 0d, \"double zero\")]\n    [InlineData(\"7\", 7, \"int 7\")]\n    [InlineData(\"7\", \"7\", \"string 7\")]\n    [InlineData(\"7.1\", \"7.1\", \"string 7.1\")]\n    [InlineData(\"6.9\", \"6.9\", \"string 6.9\")]\n    public void RealStringOrNull(string expected, object data, string message)\n        => Equal(expected, ParseObject.RealStringOrNull(data));\n\n    [Fact]\n    public void RealStringOrNullWithObject()\n        => Equal(null, ParseObject.RealStringOrNull(new()));\n\n\n    [Theory]\n    [InlineData(true, 0)]\n    [InlineData(true, 0.0001f)]\n    [InlineData(true, -0.009f)]\n    [InlineData(false, 0.2f)]\n    [InlineData(false, 2f)]\n    public void DoubleNearZero(bool expected, double data)\n        => Equal(expected, ParseObject.DNearZero(data));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ServiceTweaks/CmsHtmlTweakTests.cs",
    "content": "﻿using ToSic.Sxc.Services.Tweaks.Sys;\n\nnamespace ToSic.Sxc.Tests.ServiceTweaks;\n\n\npublic class CmsHtmlTweakTests\n{\n    private (TweakInput<string> Tw1, TweakInput<string> Tw2) GetTweakers()\n    {\n        var tw1 = new TweakInput<string>();\n        var tw2 = (TweakInput<string>)tw1.Input(v => v + \"-test\");\n        return (tw1, tw2);\n    }\n\n    [Fact]\n    public void AddingTweakDoesNotAffectOriginal()\n    {\n        var (tw1, tw2) = GetTweakers();\n        Equal(0, tw1.Tweaks.Count);\n        Equal(1, tw2.Tweaks.Count);\n    }\n\n    [Fact]\n    public void AddingTweakIsCorrectType()\n    {\n        var (_, tw2) = GetTweakers();\n        Equal(TweakConfigConstants.NameDefault, tw2.Tweaks[0].NameId);\n        Equal(TweakConfigConstants.StepBefore, tw2.Tweaks[0].Step);\n    }\n\n    [Fact]\n    public void GetPreprocessIsCorrect()\n    {\n        var (_, tw2) = GetTweakers();\n        var preprocess = tw2.Tweaks.GetTweaksByStep(TweakConfigConstants.StepBefore);\n        Equal(1, preprocess.Count);\n        Equal(TweakConfigConstants.NameDefault, preprocess[0].NameId);\n        Equal(TweakConfigConstants.StepBefore, tw2.Tweaks[0].Step);\n    }\n\n    [Fact]\n    public void GetPostProcessIsCorrect()\n    {\n        var (_, tw2) = GetTweakers();\n        var preprocess = tw2.Tweaks.GetTweaksByStep(TweakConfigConstants.StepAfter);\n        Equal(0, preprocess.Count);\n    }\n\n    [Fact]\n    public void Preprocess()\n    {\n        var (_, tw2) = GetTweakers();\n\n        var processed = tw2.Tweaks.Preprocess(\"Hello\");\n        Equal(\"Hello-test\", processed.Value);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ServiceTweaks/TweakListTests.cs",
    "content": "﻿using ToSic.Sxc.Services.Tweaks;\nusing ToSic.Sxc.Services.Tweaks.Sys;\n\nnamespace ToSic.Sxc.Tests.ServiceTweaks;\n\n\npublic class TweakListTests\n{\n    [Fact]\n    public void CloneIsFunctional()\n    {\n        var tw = new TweakConfig(\"dummy-name\");\n        var tw2 = tw with { };\n        NotSame(tw, tw2);\n        //Equal(tw.List.Count, tw2.List.Count);\n        //NotSame(tw.List, tw2.List);\n    }\n\n    //[Fact]\n    //public void CloneHasSameTweaks()\n    //{\n    //    var tw = new TweakConfig<>(null) with { Tweak = new((string)\"test\") };\n    //    tw = new((TweakConfig?)tw, new((string)\"test2\"));\n    //    var tw2 = new TweakConfig(tw);\n    //    NotSame(tw, tw2);\n    //    Equal(tw.List.Count, tw2.List.Count);\n    //    NotSame(tw.List, tw2.List);\n    //    Same(tw.List[0], tw2.List[0]);//, \"tweaks are the same object\");\n    //    Same(tw.List[1], tw2.List[1]);//, \"tweaks are the same object\");\n    //}\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Services/HttpContextServiceTests.cs",
    "content": "#if NETCOREAPP\nusing Microsoft.AspNetCore.Http;\nusing ToSic.Sxc.Services.HttpCtx;\n\nnamespace ToSic.Sxc.Tests.Services;\n\npublic class HttpContextServiceTests\n{\n    [Fact]\n    public void Redirect301_SetsStatusCodeAndLocationHeader()\n    {\n        var httpContext = new DefaultHttpContext();\n        var sut = new HttpContextService(new HttpContextAccessor { HttpContext = httpContext });\n\n        sut.Redirect301(\"/target-page\");\n\n        Equal(301, httpContext.Response.StatusCode);\n        Equal(\"/target-page\", httpContext.Response.Headers.Location.ToString());\n    }\n\n    [Fact]\n    public void Redirect_WithCustomRedirectCode_SetsStatusCodeAndLocationHeader()\n    {\n        var httpContext = new DefaultHttpContext();\n        var sut = new HttpContextService(new HttpContextAccessor { HttpContext = httpContext });\n\n        sut.Redirect(\"/other-target\", 308);\n\n        Equal(308, httpContext.Response.StatusCode);\n        Equal(\"/other-target\", httpContext.Response.Headers.Location.ToString());\n    }\n}\n#endif\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Services/TurnOnTests/PickOrBuildSpecsTests.cs",
    "content": "﻿using System.Diagnostics;\nusing System.Text.Json;\nusing ToSic.Sxc.Services.TurnOn.Sys;\n\nnamespace ToSic.Sxc.Tests.ServicesTests.TurnOnTests;\n\n\npublic class PickOrBuildSpecsTests\n{\n    [Fact]\n    public void RunAnonObject() =>\n        CompareJsonsAndTrace(\n            new() { Run = \"window.run\" },\n            TurnOnTestAccessors.TacPickOrBuildSpecs(new { run = \"window.run\"})\n        );\n\n    [Fact]\n    public void RunOnly() =>\n        CompareJsonsAndTrace(\n            new() { Run = \"window.run\" },\n            TurnOnTestAccessors.TacPickOrBuildSpecs(\"window.run\")\n        );\n\n    [Fact]\n    public void RunArgsOnly() =>\n        CompareJsonsAndTrace(\n            new() { Run = \"window.run\", Args = [\"test\"] },\n            TurnOnTestAccessors.TacPickOrBuildSpecs(\"window.run\", args: new string[] { \"test\" })\n        );\n    [Fact]\n    public void RunArgsAndData() =>\n        CompareJsonsAndTrace(\n            new() { Run = \"window.run\", Args = [\"test\"], Data = 42 },\n            TurnOnTestAccessors.TacPickOrBuildSpecs(\"window.run\", args: new string[] { \"test\" }, data: 42)\n        );\n\n\n    [Fact]\n    public void RunAndDataNumber() =>\n        CompareJsonsAndTrace(\n            new() { Run = \"window.run\", Data = 42 },\n            TurnOnTestAccessors.TacPickOrBuildSpecs(\"window.run\", data: 42)\n        );\n\n    [Fact]\n    public void RunAndDataString() =>\n        CompareJsonsAndTrace(\n            new() { Run = \"window.run\", Data = \"my-data\" },\n            TurnOnTestAccessors.TacPickOrBuildSpecs(\"window.run\", data: \"my-data\")\n        );\n\n    [Fact]\n    public void RunAndRequireString() =>\n        CompareJsonsAndTrace(\n            new() { Run = \"window.run\", Require = \"window.xyz\" },\n            TurnOnTestAccessors.TacPickOrBuildSpecs(\"window.run\", require: \"window.xyz\")\n        );\n\n    [Fact]\n    public void RunAndRequireArray() =>\n        CompareJsonsAndTrace(\n            new() { Run = \"window.run\", Require = new[] { \"window.xyz\", \"window.abc\" } },\n            TurnOnTestAccessors.TacPickOrBuildSpecs(\"window.run\", require: new[] { \"window.xyz\", \"window.abc\" })\n        );\n\n    private static void CompareJsonsAndTrace(TurnOnSpecs expected, object actual)\n    {\n        var expectedJson = JsonSerializer.Serialize(expected);\n        var actualJson = JsonSerializer.Serialize(actual);\n        Trace.WriteLine(\"expected: \" + expectedJson);\n        Trace.WriteLine(\"actual: \" + actualJson);\n        Equal(expectedJson, actualJson);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/Services/TurnOnTests/TurnOnTestAccessors.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Tests.ServicesTests.TurnOnTests;\n\ninternal static class TurnOnTestAccessors\n{\n    public static object TacPickOrBuildSpecs(object runOrSpecs, object require = default, object data = default, object[] args = default, string addContext = default)\n        => TurnOnService.PickOrBuildSpecs(runOrSpecs, require, data, args, addContext);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/ToSic.Sxc.Various.UnitTests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForTestCode.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Custom\\ToSic.Sxc.Custom.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Various.SystemTests\\ToSic.Sxc.Various.SystemTests.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/WebUrlTests/UrlValueCamelCaseTest.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Tests.WebUrlTests;\n\n\npublic class UrlValueCamelCaseTest\n{\n    private UrlValueCamelCase TestProcess() => new();\n\n    [Theory]\n    [InlineData(\"original\", \"original\", \"all lower case\")]\n    [InlineData(\"original\", \"Original\", \"Pascal to lower case\")]\n    [InlineData(\"originalThing\", \"OriginalThing\", \"Pascal to camel case\")]\n    [InlineData(\"oRIGINAL\", \"ORIGINAL\", \"Caps to weird case\")]\n    public void BasicTests(string expected, string name, string message)\n        => Equal(expected, TestProcess().Process(new(name, null)).Name);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Various.UnitTests/WebUrlTests/UrlValueFilterTests.cs",
    "content": "﻿using ToSic.Sxc.Web.Sys.Url;\n\nnamespace ToSic.Sxc.Tests.WebUrlTests;\n\n\npublic class UrlValueFilterTests\n{\n    private UrlValueFilterNames TestFilter(bool defaultSerialize, IEnumerable<string> opposite) =>\n        new(defaultSerialize, opposite);\n\n    [Fact]\n    public void NoFilterKeepAll()\n    {\n        var filter = TestFilter(true, new List<string>());\n        var result = filter.Process(new(\"something\", \"value\"));\n        True(result.Keep);\n    }\n\n    [Fact]\n    public void NoFilterKeepNone()\n    {\n        var filter = TestFilter(false, new List<string>());\n        var result = filter.Process(new(\"something\", \"value\"));\n        False(result.Keep);\n    }\n\n    [Fact]\n    public void FilterSomeKeepRest()\n    {\n        var filter = TestFilter(true, [\"drop\"]);\n        True(filter.Process(new(\"something\", \"value\")).Keep);\n        True(filter.Process(new(\"something2\", \"value\")).Keep);\n        True(filter.Process(new(\"drop2\", \"value\")).Keep);\n        False(filter.Process(new(\"drop\", \"value\")).Keep, \"this is the only one it should drop\");\n        False(filter.Process(new(\"Drop\", \"value\")).Keep, \"this should also fail, case insensitive\");\n    }\n\n    [Fact]\n    public void FilterSomeDropRest()\n    {\n        var filter = TestFilter(false, [\"keep\"]);\n        False(filter.Process(new(\"something\", \"value\")).Keep);\n        False(filter.Process(new(\"something2\", \"value\")).Keep);\n        False(filter.Process(new(\"Drop\", \"value\")).Keep);\n        False(filter.Process(new(\"drop2\", \"value\")).Keep);\n        True(filter.Process(new(\"keep\", \"value\")).Keep, \"this is th only one it should keep\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Apps.Sys.Installation/IPlatformAppInstaller.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Apps.Sys.Installation;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IPlatformAppInstaller : IHasLog\n{\n    string GetAutoInstallPackagesUiUrl(ISite site, IModule module, bool forContentApp);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Apps.Sys.Installation/PlatformAppInstallerUnknown.cs",
    "content": "﻿using ToSic.Eav.Context;\nusing ToSic.Sxc.Context;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Apps.Sys.Installation;\n\ninternal class PlatformAppInstallerUnknown(WarnUseOfUnknown<PlatformAppInstallerUnknown> _)\n    : ServiceBase($\"{LogScopes.NotImplemented}.Instll\"), IIsUnknown, IPlatformAppInstaller\n{\n    public string GetAutoInstallPackagesUiUrl(ISite site, IModule module, bool forContentApp) => \"mvc not implemented #todo #mvc\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Data.Sys.Convert/ConvertToEavLightWithCmsInfo.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Data.Sys.Decorators;\nusing ToSic.Sxc.Edit.Sys;\n\nnamespace ToSic.Sxc.Data.Sys.Convert;\n\n/// <summary>\n/// Convert various types of entities (standalone, dynamic, in streams, etc.) to Dictionaries <br/>\n/// Mainly used for serialization scenarios, like in WebApis.\n/// </summary>\n/// <remarks>\n/// Standard constructor, important for opening this class in dependency-injection\n/// </remarks>\n[PrivateApi(\"Hide implementation; this was never public; the DataToDictionary was with empty constructor, but that's already polyfilled\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\n[method: PrivateApi]\npublic class ConvertToEavLightWithCmsInfo(ConvertToEavLight.Dependencies services) : ConvertToEavLight(services)\n{\n    /// <summary>\n    /// Determines if we should use edit-information\n    /// </summary>\n    [PrivateApi(\"Note: wasn't private till 2sxc 12.04, very low risk of it being published. Set was always internal\")]\n    public bool WithEdit { get; set; }\n\n    [PrivateApi]\n    protected override EavLightEntity GetDictionaryFromEntity(IEntity entity)\n    {\n        // Do groundwork\n        var dictionary = base.GetDictionaryFromEntity(entity);\n\n        AddPresentation(entity, dictionary!);\n\n        // The edit info is an old feature. To phase it out, disable it whenever a $select filter is active.\n        if (PresetFilters.FilterFieldsEnabled != true)\n            AddEditInfo(entity, dictionary!);\n\n        return dictionary;\n    }\n\n    #region to enhance serializable IEntities with 2sxc specific infos\n\n    private void AddPresentation(IEntity entity, IDictionary<string, object> dictionary)\n    {\n        var decorator = entity.GetDecorator<EntityInBlockDecorator>();\n\n        // Add full presentation object if it has one...because there we need more than just id/title\n        if (decorator?.Presentation == null || dictionary.ContainsKey(ViewParts.Presentation)) return;\n\n        // if (entityInGroup.Presentation != null)\n        dictionary.Add(ViewParts.Presentation, GetDictionaryFromEntity(decorator.Presentation));\n    }\n\n    /// <summary>\n    /// Add additional information in case we're in edit mode\n    /// </summary>\n    /// <param name=\"entity\"></param>\n    /// <param name=\"dictionary\"></param>\n    private void AddEditInfo(IEntity entity, IDictionary<string, object> dictionary)\n    {\n        if (!WithEdit) return;\n\n        // 2024-02-29 2dm - this is old, and I believe not used any more, commented out\n        // At least in the Edit-UI it shouldn't be used, \n        // But the key was still found in the inpage, so we're not sure if we can get rid of it\n\n        var title = entity.GetBestTitle(Languages);\n        if (string.IsNullOrEmpty(title))\n            title = \"(no title)\";\n\n        var editDecorator = entity.GetDecorator<EntityInBlockDecorator>();\n\n        dictionary.Add(SxcEditSharedConstants.JsonEntityEditNodeName, editDecorator != null // entity is IHasEditingData entWithEditing\n            ? new\n            {\n                sortOrder = editDecorator.SortOrder,\n                isPublished = entity.IsPublished,\n            }\n            : new\n            {\n                entityId = entity.EntityId,\n                title,\n                isPublished = entity.IsPublished,\n            });\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Linq;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using static ToSic.Sxc.Sys.SxcLogging;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/LookUp/DateTimeLookUp.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sources;\n\nnamespace ToSic.Sxc.LookUp;\n\ninternal class DateTimeLookUp() : LookUpBase(\"DateTime\", \"LookUp in Date-Time\")\n{\n    public override string Get(string key, string format)\n        => key.ToLowerInvariant() switch\n        {\n            \"now\" => DateTime.Now.ToString(format),\n            \"system\" => DateTime.Now.ToString(format),\n            \"utc\" => DateTime.Now.ToUniversalTime().ToString(format),\n            _ => string.Empty\n        };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/LookUp/QueryStringLookUp.cs",
    "content": "﻿using System.Collections.Specialized;\nusing ToSic.Eav.LookUp.Sources;\nusing ToSic.Sxc.LookUp.Sys;\nusing ToSic.Sxc.Web.Sys.Http;\nusing ToSic.Sxc.Web.Sys.Parameters;\n\nnamespace ToSic.Sxc.LookUp;\n\n/// <summary>\n/// LookUp provider for query string parameters.\n/// It handles the normal `key=value` query string parameters and also the special `OriginalParameters` query string parameter.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class QueryStringLookUp(LazySvc<IHttp> httpLazy) : LookUpBase(LookUpConstants.SourceQueryString, \"LookUp in QueryString\")\n{\n    private NameValueCollection? _source;\n    private NameValueCollection? _originalParams;\n\n\n    public override string Get(string key, string format)\n    {\n        _source ??= httpLazy.Value?.QueryStringParams ?? [];\n\n        // Special handling when having original parameters in query string.\n        var originalParametersQueryStringValue = _source[OriginalParameters.NameInUrlForOriginalParameters]!;\n        var overrideParam = GetOverrideParam(key, originalParametersQueryStringValue);\n\n        return !string.IsNullOrEmpty(overrideParam)\n            ? overrideParam!\n            : _source[key] ?? \"\";\n    }\n\n    private string? GetOverrideParam(string key, string originalParametersQueryStringValue)\n    {\n        if (string.IsNullOrEmpty(originalParametersQueryStringValue))\n            return string.Empty;\n\n        _originalParams ??= OriginalParameters.GetOverrideParams(originalParametersQueryStringValue);\n\n        return _originalParams[key];\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/LookUp/TicksLookUp.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sources;\n\n#if NETCOREAPP\nnamespace ToSic.Sxc.LookUp;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class TicksLookUp() : LookUpBase(\"Ticks\", \"LookUp ticks of now, today, TicksPerDay\")\n{\n    public override string Get(string key, string format)\n        => key.ToLowerInvariant() switch\n        {\n            \"now\" => DateTime.Now.Ticks.ToString(format),\n            \"today\" => DateTime.Today.Ticks.ToString(format),\n            \"ticksperday\" => TimeSpan.TicksPerDay.ToString(format),\n            _ => string.Empty\n        };\n}\n\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Polymorphism.Sys/CssFrameworkDetectorUnknown.cs",
    "content": "﻿using Connect.Koi.Detectors;\n\n#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Polymorphism.Sys;\n\ninternal class CssFrameworkDetectorUnknown(WarnUseOfUnknown<CssFrameworkDetectorUnknown> _) : ICssFrameworkDetector\n{\n    public string AutoDetect() => Connect.Koi.CssFrameworks.Unknown;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Polymorphism.Sys/PolymorphismConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Polymorphism.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal class PolymorphismConstants\n{\n    //public const string StaticName = \"3937fa17-ef2d-40a7-b089-64164eb10bab\";\n    //public const string Name = \"2sxcPolymorphismConfiguration\";\n    //public const string ModeField = \"Mode\";\n\n    //public const string UsersWhoMaySwitchEditionsField = \"UsersWhoMaySwitchEditions\";\n\n    //public const string ModeNone = \"\";\n    //public const string ModeKoi = \"Koi?cssFramework\";\n    //public const string ModeSuperuser = \"Permissions?IsSuperUser\";\n\n    //public const string ResolverKoi = \"Koi\";\n    //public const string ResolverPermissions = \"Permissions\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Polymorphism.Sys/PolymorphismKoi.cs",
    "content": "﻿using Connect.Koi;\nusing ToSic.Sys.Utils;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Polymorphism.Sys;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PolymorphismKoi(ICss pageCss) : IPolymorphismResolver\n{\n    public string NameId => \"Koi\";\n\n    public const string ModeCssFramework= \"cssFramework\";\n\n    public string? Edition(PolymorphismConfiguration config, string? overrule, ILog log)\n    {\n        var l = log.Fn<string?>();\n        if (!string.Equals(config.Parameters, ModeCssFramework, InvariantCultureIgnoreCase))\n            return l.Return(overrule, \"unknown param\");\n        // Note: this is still using the global object which we want to get rid of\n        // But to use DI, we must refactor Polymorphism\n        return l.ReturnAndLog(overrule.NullIfNoValue() ?? pageCss.Framework);\n    }\n\n    public bool IsViable() => true;\n\n    public int Priority => 10;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Polymorphism.Sys/PolymorphismPermissions.cs",
    "content": "﻿using ToSic.Sys.Users;\nusing ToSic.Sys.Utils;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Polymorphism.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PolymorphismPermissions(IUser user) : IPolymorphismResolver\n{\n    public string NameId => \"Permissions\";\n\n    /// <summary>\n    /// BTW: when this is configured, the entire config string is \"Permissions?IsSuperUser\"\n    /// so the parameters are \"IsSuperUser\"\n    /// </summary>\n    public const string ModeIsSuperUser = \"IsSuperUser\";\n\n    public string? Edition(PolymorphismConfiguration config, string? overrule, ILog log)\n    {\n        var l = log.Fn<string>();\n        if (!string.Equals(config.Parameters, ModeIsSuperUser, InvariantCultureIgnoreCase))\n            return l.ReturnNull(\"unknown param\");\n        var isSuper = user.IsSystemAdmin;\n\n        // TEMP: for now, site admins can overrule this\n        // They won't see the button, but if the button is added on purpose using .Button(\"edition\") it will work.\n        if (overrule.HasValue() && (isSuper || config.UsersWhoMaySwitch.Contains(user.Id))) \n            return l.Return(overrule, $\"overruled as: '{overrule}'\");\n\n        var result = isSuper ? \"staging\" : \"live\";\n        return l.ReturnAndLog(result);\n    }\n\n    public bool IsViable() => true;\n\n    public int Priority => 0;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/StartupSxcWeb.cs",
    "content": "﻿using Connect.Koi.Detectors;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.LookUp;\nusing ToSic.Sxc.Apps.Sys.Installation;\nusing ToSic.Sxc.Data.Sys.Convert;\nusing ToSic.Sxc.LookUp;\nusing ToSic.Sxc.Polymorphism;\nusing ToSic.Sxc.Polymorphism.Sys;\nusing ToSic.Sxc.Web.Sys.EditUi;\nusing ToSic.Sxc.Web.Sys.Http;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Run.Startup;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcWeb\n{\n    public static IServiceCollection AddSxcWeb(this IServiceCollection services)\n    {\n        // v15 EditUi Resources\n        services.TryAddTransient<EditUiResources>();\n\n        services.AddTransient<ILookUp, QueryStringLookUp>();\n\n        // Add Lookups which are in DNN but not in Oqtane\n        // These could be in any project, but for now we want them as far down as possible, so they are in Sxc.Web\n#if NETCOREAPP\n        services.AddTransient<ILookUp, DateTimeLookUp>();\n        services.AddTransient<ILookUp, TicksLookUp>();\n#endif\n\n        // The top version should be deprecated soon, so we just use DataToDictionary or an Interface instead\n        services.TryAddTransient<ConvertToEavLight, ConvertToEavLightWithCmsInfo>(); // this is needed for all the EAV uses of conversion\n        services.TryAddTransient<ConvertToEavLightWithCmsInfo>(); // WIP, not public, should use interface instead\n        services.TryAddTransient<IConvertToEavLight, ConvertToEavLightWithCmsInfo>();\n\n        // Polymorphism - moved here v17.08\n        services.AddTransient<IPolymorphismResolver, PolymorphismKoi>();\n        services.AddTransient<IPolymorphismResolver, PolymorphismPermissions>();\n\n        // Koi, mainly so tests don't fail\n        services.TryAddTransient<ICssFrameworkDetector, CssFrameworkDetectorUnknown>();\n\n\n        // WIP - add net-core specific stuff\n        services.AddNetVariations();\n\n        // Add possibly missing fallback services\n        // This must always be at the end here so it doesn't accidentally replace something we actually need\n        services.AddKoi();\n\n\n        // basic environment, pages, modules etc.\n        // Note that it's not really part of .Web, but we want it to be quite late so we don't need\n        // to move up dependencies which it has.\n        services.TryAddTransient<IPlatformAppInstaller, PlatformAppInstallerUnknown>();\n\n\n        return services;\n    }\n\n\n    public static IServiceCollection AddKoi(this IServiceCollection services)\n    {\n        services.TryAddTransient<Connect.Koi.KoiCss.Dependencies>();\n        services.TryAddTransient<Connect.Koi.ICss, Connect.Koi.KoiCss>();\n\n        return services;\n    }\n\n    public static IServiceCollection AddNetVariations(this IServiceCollection services)\n    {\n#if NETFRAMEWORK\n        // WebForms implementations\n        services.TryAddScoped<IHttp, HttpHybrid>();\n#else\n        services.TryAddTransient<IHttp, HttpHybrid>();\n#endif\n        return services;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/ToSic.Sxc.Web.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.Web</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.Adam\\ToSic.Sxc.Adam.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Core\\ToSic.Sxc.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Engines\\ToSic.Sxc.Engines.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Reference Include=\"Connect.Koi\">\n      <HintPath>..\\..\\..\\Dependencies\\Koi\\netstandard2.0\\Connect.Koi.dll</HintPath>\n    </Reference>\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net472'\">\n    <Reference Include=\"System.Web\" />\n    <Reference Include=\"System.Web.Http\">\n      <!--<HintPath>..\\..\\..\\Dependencies\\System.Web\\System.Web.Http.dll</HintPath>\n      <SpecificVersion>False</SpecificVersion>\n      <Private>False</Private>-->\n    </Reference>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Web.Sys.EditUi/EditUiResourceSettings.cs",
    "content": "﻿namespace ToSic.Sxc.Web.Sys.EditUi;\n\n/// <summary>\n/// Configuration which icons/fonts are needed by the various edit-UIs\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic struct EditUiResourceSettings\n{\n    public bool IconsMaterial { get; set; }\n\n    public bool FontRoboto { get; set; }\n\n    public static EditUiResourceSettings EditUi => new()\n    {\n        IconsMaterial = true,\n        FontRoboto = true,\n    };\n\n    public static EditUiResourceSettings QuickDialog => new()\n    {\n        IconsMaterial = true,\n        FontRoboto = true,\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Web.Sys.EditUi/EditUiResources.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Sxc.Services;\nusing ToSic.Sxc.Sys.Configuration;\nusing ToSic.Sys.Utils;\nusing static ToSic.Eav.Apps.Sys.AppStack.AppStackConstants;\nusing static ToSic.Sxc.Web.Sys.WebResources.WebResourceConstants;\n\nnamespace ToSic.Sxc.Web.Sys.EditUi;\n\n/// <summary>\n/// Provide all resources (fonts, icons, etc.) needed for the edit-ui\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EditUiResources(AppDataStackService stackServiceHelper, IZoneMapper zoneMapper, IFeaturesService features)\n    : ServiceBase(\"Sxc.EUiRes\", connect: [stackServiceHelper, zoneMapper, features])\n{\n\n    #region Resources / Constants\n\n    public const string LinkTagTemplate = \"<link rel=\\\"stylesheet\\\" href=\\\"{0}\\\">\";\n    public const string RobotoFromGoogle = \"https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap\";\n    public const string RobotoFromAltCdn = \"/google-fonts/roboto/fonts.css\";\n\n    // 2024-08-20 2dm: switching to Material Symbols\n    // not quite done, must finish by ensuring the CDN solution works too...\n    //<link rel = \"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200\" />\n    public const string\n        MaterialIconsGoogle = // \"https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Outlined\";\n            \"https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200\";\n    public const string MaterialIconsAltCdn = \"/google-fonts/material-icons/fonts.css\";\n\n    #endregion\n\n    public EditUiResourcesSpecs GetResources(bool enabled, int? siteId, EditUiResourceSettings settings)\n    {\n        if (!enabled) return new();\n        var cdnRoot = \"\";\n        var useAltCdn = false;\n        var html = \"\";\n\n        if (features.IsEnabled(SxcFeatures.CdnSourceEdit.NameId) && siteId.HasValue)\n        {\n            var zoneId = zoneMapper.GetZoneId(siteId.Value);\n            var stack = stackServiceHelper.InitForPrimaryAppOfZone(zoneId).GetStack(RootNameSettings);\n            var getResult = stack.InternalGetPath($\"{WebResourcesNode}.{CdnSourceEditField}\");\n            cdnRoot = getResult.Result as string;\n            useAltCdn = cdnRoot.HasValue() && cdnRoot != CdnDefault;\n            cdnRoot += VersionSuffix;\n            html += $\"<!-- CDN settings {getResult.IsFinal}, '{getResult.Result}', '{getResult.Result?.GetType()}' '{cdnRoot}', {cdnRoot?.Length} -->\";\n        }\n        else\n            html += \"<!-- CDN Settings: Default (feature not enabled) -->\";\n\n        if (settings.IconsMaterial)\n        {\n            var url = useAltCdn ? cdnRoot + MaterialIconsAltCdn : MaterialIconsGoogle;\n            html += \"\\n\" + string.Format(LinkTagTemplate, url);\n        }\n\n        if (settings.FontRoboto)\n        {\n            var url = useAltCdn ? cdnRoot + RobotoFromAltCdn : RobotoFromGoogle;\n            html += \"\\n\" + string.Format(LinkTagTemplate, url);\n        }\n        html += \"\\n\";\n        return new() { HtmlHead = html };\n    }\n\n    public class EditUiResourcesSpecs\n    {\n        public string HtmlHead { get; set; } = \"\";\n\n        // later we'll also add CSP specs here\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Web.Sys.EditUi/HtmlDialog.cs",
    "content": "﻿using ToSic.Eav.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Web.Sys.EditUi;\n\n/// <summary>\n/// Helper to add resources etc. to the JS dialogs.\n/// It will take the HTML and make necessary changes.\n/// TODO: Rename to HtmlJsDialogHelper\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HtmlDialog\n{\n    public const string PageIdInUrl = \"pageId\";\n    public const string TenantIdInUrl = \"tenantId\";\n    public const string AliasIdInUrl = \"aliasId\";\n    public const string WithPublicKey = \"wpk\";\n\n    public const string BasePlaceholder = \"@base\";\n    public const string CustomBodyPlaceholder = \"@custombody\";\n    public const string CacheBreakPlaceholder = \"@sxcver\";\n    public const string CustomHeadersPlaceholder = \"@customheaders\";\n    public const string JsApiPlaceholder = \"@jsapi\";\n\n    public static string[] Placeholders =\n    [\n        BasePlaceholder,\n        CacheBreakPlaceholder,\n        CustomBodyPlaceholder,\n        CustomHeadersPlaceholder,\n        JsApiPlaceholder\n    ];\n\n    public static string CleanImport(string html)\n    {\n        if (!html.HasValue()) return html;\n\n        // Placeholders may be wrapped in <!-- --> because of angular compiler - we should first strip these\n        foreach (var ph in Placeholders)\n            html = html.Replace($\"<!--{ph}-->\", ph);\n\n        // Correct quotes, as the index-raw will always have double quotes (angular-compiler replaces single quotes)\n        html = html.Replace($\"\\\"{JsApiPlaceholder}\\\"\", $\"'{JsApiPlaceholder}'\");\n\n        return html;\n    }\n\n    public static string UpdatePlaceholders(string html, string content, int pageId, string customBaseParams, string customHeaders, string customBody)\n    {\n        if (!html.HasValue()) return html;\n\n        var result = html;\n\n        // Add context variables\n        result = result.Replace(JsApiPlaceholder, content);\n\n        // Add version cachebreak\n        result = result.Replace(CacheBreakPlaceholder, EavSystemInfo.VersionWithStartUpBuild);\n\n        // Replace base url\n        result = result.Replace(BasePlaceholder, $\"./?{PageIdInUrl}={pageId}{customBaseParams}\");\n\n        // Custom Headers - Experimental WIP\n\n\n        // Add any custom headers / body - like for the Oqtane Request Verification Token\n        result = result.Replace(CustomHeadersPlaceholder, customHeaders);\n        result = result.Replace(CustomBodyPlaceholder, customBody);\n\n        return result;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Web.Sys.Http/HttpAbstractionBase.cs",
    "content": "﻿#if NETFRAMEWORK\nusing System.Web;\n#else\nusing Microsoft.AspNetCore.Http;\n#endif\nusing System.Collections.Specialized;\n\n\nnamespace ToSic.Sxc.Web.Sys.Http;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class HttpAbstractionBase: IHttp\n{\n    /// <inheritdoc />\n    public abstract HttpContext Current { get; }\n\n    #region Request and properties thereof\n\n    /// <inheritdoc />\n    public HttpRequest Request => Current?.Request!;\n\n    /// <inheritdoc />\n    public abstract NameValueCollection QueryStringParams { get; }\n\n    /// <inheritdoc />\n    public List<KeyValuePair<string, string>> QueryStringKeyValuePairs()\n    {\n        if (_queryStringKeyValuePairs != null)\n            return _queryStringKeyValuePairs;\n        var qs = QueryStringParams;\n        _queryStringKeyValuePairs = qs\n                                        ?.AllKeys\n                                        .Select(key => new KeyValuePair<string, string>(key!, qs[key]!))\n                                        .ToList()\n                                    ?? [];\n        return _queryStringKeyValuePairs;\n    }\n    private List<KeyValuePair<string, string>>? _queryStringKeyValuePairs;\n\n\n    public string? GetCookie(string cookieName)\n    {\n        if (Request == null!)\n            return null;\n\n#if NETFRAMEWORK\n        return Request.Cookies[cookieName]?.Value;\n#else\n        return Request.Cookies[cookieName];\n#endif\n    }\n\n    #endregion Request\n\n    //public abstract IDictionary<object, object> Items { get; }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Web.Sys.Http/HttpHybrid-NetCore.cs",
    "content": "﻿#if !NETFRAMEWORK\nusing System.Collections.Specialized;\nusing System.Diagnostics.CodeAnalysis;\nusing Microsoft.AspNetCore.Http;\n\nnamespace ToSic.Sxc.Web.Sys.Http;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HttpHybrid(IHttpContextAccessor contextAccessor) : HttpAbstractionBase, IHttp\n{\n    [field: AllowNull, MaybeNull]\n    public override HttpContext Current => field ??= contextAccessor.HttpContext!;\n\n    [field: AllowNull, MaybeNull]\n    public override NameValueCollection QueryStringParams\n    {\n        get\n        {\n            if (field != null)\n                return field;\n            // ReSharper disable once ConvertIfStatementToReturnStatement\n            if (Request == null!) \n                return field = [];\n\n            var paramList = new NameValueCollection();\n            Request.Query.ToList().ForEach(i => paramList.Add(i.Key, i.Value));\n            return field = paramList;\n        }\n    }\n}\n\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.Web/Web.Sys.Http/HttpHybrid-NetFramework.cs",
    "content": "﻿#if NETFRAMEWORK\nusing System.Collections.Specialized;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Web;\nusing ToSic.Sxc.Web.Sys.Http;\n\nnamespace ToSic.Sxc.Web.Sys.Http;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HttpHybrid: HttpAbstractionBase, IHttp\n{\n    public override HttpContext Current => HttpContext.Current!;\n\n    #region Request and properties thereof\n\n    [field: AllowNull, MaybeNull]\n    public override NameValueCollection QueryStringParams\n        => field ??= Request?.QueryString ?? [];\n\n    #endregion Request\n\n}\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetEditInfo.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\n\nnamespace ToSic.Sxc.Apps.Sys.EditAssets;\n\n/// <summary>\n/// Information class needed by the edit-ui, to provide optimal syntax helpers etc.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AssetEditInfo\n{\n        \n    private static readonly string[] SafeFileWhitelist = \"txt,html,js,md,json,doc,docx,xls,xlsx,xml\".Split(',');\n\n    public string?\n        Name,\n        Code,\n        FileName,\n        TypeContent,\n        TypeContentPresentation,\n        TypeList,\n        TypeListPresentation;\n\n    public string Type = \"Auto\";\n    public bool HasList;\n    public bool HasApp;\n    public int AppId;\n    public bool IsShared;\n    public Dictionary<string, string> Streams = new();\n\n    public string Extension => Path.GetExtension(FileName ?? \"\");\n\n    /// <summary>\n    /// parameter-less constructor for deserialization, to fix \"System.InvalidOperationException\"\n    /// \"Each parameter in the deserialization constructor on type 'ToSic.Sxc.Apps.Assets.AssetEditInfo' must bind to an object property or field on deserialization.\n    /// Each parameter name must match with a property or field on the object. The match can be case-insensitive.\",\n    /// </summary>\n    public AssetEditInfo() { }\n\n    public AssetEditInfo(int appId, string appName, string fileName, bool global)\n    {\n        AppId = appId;\n        FileName = fileName;\n        HasApp = appName != KnownAppsConstants.ContentAppName;\n        IsShared = global;\n    }\n\n    // check if this file is safe - meaning it can be edited by non-host users\n    public bool IsSafe\n    {\n        get\n        {\n            if (string.IsNullOrWhiteSpace(FileName))\n                return true;\n\n            var ext = Extension;\n            if (ext == \"\")  // no extension\n                return true;\n\n            if (SafeFileWhitelist.Contains(ext))\n                return true;\n\n            return false;\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetEditor.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Apps.Sys.EditAssets;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AssetEditor(\n    GenWorkPlus<WorkViews> workViews,\n    IUser user,\n    LazySvc<AppFolderInitializer> appFolderInitializer,\n    ISite site,\n    IAppPathsMicroSvc appPaths)\n    : ServiceBase(\"Sxc.AstEdt\", connect: [user, appFolderInitializer, workViews, site, appPaths])\n{\n\n    #region Constructor / DI\n\n    private IAppSpecs _appSpecs = null!;\n\n    private AssetEditInfo EditInfo { get; set; } = null!;\n\n    private IAppPaths _appPaths = null!;\n\n\n    public AssetEditor Init(IAppReader appReader, string fileName, bool global, int viewId)\n    {\n        _appSpecs = appReader.Specs;\n        _appPaths = appPaths.Get(appReader, site);\n        EditInfo = new(_appSpecs.AppId, _appSpecs.Name, fileName, global);\n        if (viewId == 0)\n            return this;\n\n        var view = workViews.New(appReader).Get(viewId);\n        AddViewDetailsAndTypes(EditInfo, view);\n        return this;\n    }\n\n    #endregion\n\n    public AssetEditInfo EditInfoWithSource\n    {\n        get\n        {\n            EditInfo.Code = Source; // do this later, because it relies on the edit-info to exist\n            return EditInfo;\n        }\n    }\n\n    /// <summary>\n    /// Check permissions and if not successful, give detailed explanation\n    /// </summary>\n    public void EnsureUserMayEditAssetOrThrow(string? fullPath = null)\n    {\n        // check super user permissions - then all is allowed\n        if (user.IsSystemAdmin) return;\n\n        // ensure current user is admin - this is the minimum of not super-user\n        if (!user.IsSiteAdmin) throw new AccessViolationException(\"current user may not edit templates, requires admin rights\");\n\n        // if not super user, check if razor (not allowed; super user only)\n        if (!EditInfo.IsSafe)\n            throw new AccessViolationException(\"current user may not edit razor templates - requires super user\");\n\n        // if not super user, check if cross-portal storage (not allowed; super user only)\n        if (EditInfo.IsShared)\n            throw new AccessViolationException(\n                \"current user may not edit templates in central storage - requires super user\");\n\n        // optionally check if the file is really in the portal\n        if (fullPath == null) return;\n\n        var path = new FileInfo(fullPath);\n        if (path.Directory == null)\n            throw new AccessViolationException(\"path is null\");\n\n        if (path.Directory.FullName.IndexOf(_appPaths.PhysicalPath, StringComparison.InvariantCultureIgnoreCase) != 0)\n            throw new AccessViolationException(\"current user may not edit files outside of the app-scope\");\n    }\n\n    private static AssetEditInfo AddViewDetailsAndTypes(AssetEditInfo template, IView view)\n    {\n        // Template specific properties, not really available in other files\n        template.Type = view.Type;\n        template.Name = view.Name;\n        template.HasList = view.UseForList;\n        template.TypeContent = view.ContentType;\n        template.TypeContentPresentation = view.PresentationType;\n        template.TypeList = view.HeaderType;\n        template.TypeListPresentation = view.HeaderPresentationType;\n        return template;\n    }\n\n    [field: AllowNull, MaybeNull]\n    public string InternalPath => field ??= NormalizePath(Path.Combine(_appPaths.PhysicalPathSwitch(EditInfo.IsShared), EditInfo.FileName ?? \"\"));\n\n    private static string NormalizePath(string path) => Path.GetFullPath(new Uri(path).LocalPath);\n\n    /// <summary>\n    /// Read / Write the source code of the template file\n    /// </summary>\n    public string Source\n    {\n        get\n        {\n            EnsureUserMayEditAssetOrThrow(InternalPath);\n            if (File.Exists(InternalPath))\n                return File.ReadAllText(InternalPath);\n\n            throw new FileNotFoundException(\"could not find file\"\n                                            + (user.IsSystemAdmin ? $\" for superuser - file tried '{InternalPath}'\" : \"\"));\n        }\n        set\n        {\n            EnsureUserMayEditAssetOrThrow(InternalPath);\n            if (File.Exists(InternalPath))\n                File.WriteAllText(InternalPath, value);\n            else\n                throw new FileNotFoundException(\"could not find file\"\n                                                + (user.IsSystemAdmin ? $\" for superuser - file tried '{InternalPath}'\" : \"\"));\n        }\n    }\n\n    public bool Create(string contents)\n    {\n        // don't create if it already exits\n        if (SanitizeFileNameAndCheckIfAssetAlreadyExists()) return false;\n\n        // ensure the web.config exists (usually missing in the global area)\n        appFolderInitializer.Value.EnsureTemplateFolderExists(_appSpecs.Folder, EditInfo.IsShared);\n\n        var absolutePath = InternalPath;\n\n        EnsureFolders(absolutePath);\n\n        // now create the file\n        CreateAsset(absolutePath, contents);\n\n        return true;\n    }\n\n    private void SanitizeFileName()\n    {\n        // todo: maybe add some security for special dangerous file names like .cs, etc.?\n        EditInfo.FileName = Regex.Replace(EditInfo.FileName ?? \"\", @\"[?:\\/*\"\"<>|]\", \"\");\n    }\n\n    // check if the folder already exists, or create it...\n    private static void EnsureFolders(string absolutePath)\n    {\n        var foundFolder = absolutePath.LastIndexOf(\"\\\\\", StringComparison.InvariantCulture);\n        if (foundFolder > -1)\n        {\n            var folderPath = absolutePath.Substring(0, foundFolder);\n\n            if (!Directory.Exists(folderPath))\n                Directory.CreateDirectory(folderPath);\n        }\n    }\n\n    private static void CreateAsset(string absolutePath, string contents)\n    {\n        using var stream = new StreamWriter(File.Create(absolutePath));\n        stream.Write(contents);\n        stream.Flush();\n        stream.Close();\n    }\n\n    public bool SanitizeFileNameAndCheckIfAssetAlreadyExists()\n    {\n        SanitizeFileName();\n        return File.Exists(InternalPath);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetTemplates.Dnn.cs",
    "content": "﻿using ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Apps.Sys.EditAssets;\n\npublic partial class AssetTemplates\n{\n    public const string CsCodeTemplateName = \"PleaseRenameClass\";\n\n    public static readonly TemplateInfo RazorDnn = new(\"cshtml-dnn\", \"Razor Dnn\", \".cshtml\", \"DetailsTemplate\", ForTemplate, TypeRazor)\n    {\n        Body = @\"@inherits Custom.Dnn.Razor12\n@* This inherits statement gets you features like App, CmsContext, Data etc. - you can delete this comment *@\n@using ToSic.Sxc.Services; @* Make it easier to use https://go.2sxc.org/services *@\n\n<div @Edit.TagToolbar(Content)>\n    Put your content here\n</div>\",\n        Description = \"razor page dnn template\",\n    };\n\n//    /// <summary>\n//    /// This only works for Dnn, Hybrid doesn't have this concept as we can't access functions from outside\n//    /// </summary>\n//    public static readonly TemplateInfo DnnCsCode =\n//        new(\"cshtml-code-hybrid\", \"Razor Code (Dnn only)\", \".code.cshtml\", \"DetailsTemplate\", ForTemplate, TypeRazor)\n//        {\n//            Body = @\"@inherits Custom.Dnn.Razor12\n//@* This inherits statement gets you features like App, CmsContext, Data as well as Dnn etc. - you can delete this comment *@\n//@using ToSic.Razor.Blade;\n//@using ToSic.Sxc.Services; @* Make it easier to use https://go.2sxc.org/services *@\n\n//@functions {\n//  public string Hello() {\n//    return \"\"Hello from inner code\"\";\n//  }\n\n//  dynamic MessageHelper(string message) {\n//    return Tag.Div(message + \"\"!\"\");\n//  }\n//}\n//\",\n//            Description = \"razor page c# code hybrid template\",\n//            PlatformTypes = PlatformType.Dnn,\n//        };\n\n\n\n\n    public static readonly TemplateInfo DnnSearch =\n        new(\"cs-code-custom-search-dnn\", \"Dnn Search Integration (c#)\", \".cs\", \"DnnSearch\", ForSearch, TypeNone)\n        {\n            Body = @\"using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Search;\nusing ToSic.Sxc.Services; // Make it easier to use https://go.2sxc.org/services\n\n/*\nCustom code which views use to customize how dnn search treats data of that view.\nIt's meant for customizing the internal indexer of the platform, _not_ for Google Search.\n\nTo use it, create a custom code (.cs) file which implements ICustomizeSearch interface.\nYou can also inherit from a DynamicCode base class (like Code12) if you need more functionality.\n\nFor more guidance on search customizations, see https://go.2sxc.org/customize-search\n*/\npublic class \" + CsCodeTemplateName + @\" : Custom.Hybrid.Code12, ICustomizeSearch\n{\n    /// <summary>\n    /// Populate the search\n    /// </summary>\n    /// <param name=\"\"searchInfos\"\">Dictionary containing the streams and items in the stream for this search.</param>\n    /// <param name=\"\"moduleInfo\"\">Module information with which you can find out what page it's on etc.</param>\n    /// <param name=\"\"beginDate\"\">Last time the indexer ran - because the data you will get is only what was modified since.</param>\n    public void CustomizeSearch(Dictionary<string, List<ISearchItem>> searchInfos, IModule moduleInfo, DateTime beginDate)\n    {\n        // Set this to true if you want to see logs of this search in the insights\n        // Only do this while developing, otherwise you'll flood the logs and never see the important parts\n        Log.Preserve = false;\n        \n        foreach (var si in searchInfos[\"\"AllPosts\"\"])\n        {\n            var entity = AsDynamic(si.Entity);\n            si.Title = \"\"Title: \"\" + entity.Title;\n            si.QueryString = \"\"details=\"\" + entity.UrlKey;\n        }\n\n        // Remove not needed streams\n        var keys = searchInfos.Keys.ToList();\n        foreach (var key in keys)\n        {\n            if (key != \"\"AllPosts\"\")\n            {\n                searchInfos.Remove(key);\n            }\n        }\n    }\n}\n\",\n            Description =\n                \"custom search c# code to customize how dnn search treats data of view, see https://go.2sxc.org/customize-search\",\n            PlatformTypes = PlatformType.Dnn,\n        };\n\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetTemplates.Hybrid.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Apps.Sys.EditAssets;\n\npublic partial class AssetTemplates\n{\n    // Place each definition in an own static variable.\n    // Place the keys, etc. here and use these objects for the constant (don't create separate template-key object etc).\n    public static readonly TemplateInfo RazorHybrid = new(\"cshtml-hybrid\", \"Razor Hybrid\", \".cshtml\", \"DetailsTemplate\", ForTemplate, TypeRazor)\n    {\n        Body = @\"@inherits Custom.Hybrid.Razor14\n@* This inherits statement gets you features like App, CmsContext, Data etc. - you can delete this comment *@\n\n<div @Edit.TagToolbar(Content)>\n    Put your content here\n</div>\",\n        Description = \"razor page hybrid template\",\n    };\n\n    public static readonly TemplateInfo CsHybrid =\n        new(\"cs-code-hybrid\", \"C# Code Hybrid\", \".cs\", \"Helpers\", ForCode, TypeNone)\n        {\n            Body = @\"// Important notes:\n// - This class should have the same name as the file it's in\n// - This inherits from Custom.Hybrid.Code14\n//   which will automatically provide the common objects like App, CmsContext, Data etc.\n//   from the current context to use in your code\nusing ToSic.Sxc.Services; // Make it easier to use https://go.2sxc.org/services\n\npublic class \" + CsCodeTemplateName + @\" : Custom.Hybrid.Code14 {\n  public string SayHello() {\n    return \"\"Hello from shared functions!\"\";\n  }\n}\n\",\n            Description = \"c# code hybrid template\",\n        };\n\n\n\n    public static readonly TemplateInfo ApiHybrid =\n        new(\"cs-api-hybrid\", \"WebApi Hybrid\", \".cs\", \"My\", ForApi, TypeNone)\n        {\n            Body = @\"#if NETCOREAPP // Oqtane\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\n#else // DNN\nusing System.Web.Http;\nusing DotNetNuke.Web.Api;\n#endif\nusing ToSic.Sxc.Services; // Make it easier to use https://go.2sxc.org/services\n\n[AllowAnonymous]      // define that all commands can be accessed without a login\n// Inherit from Custom.Hybrid.Api14 to get features like App, CmsContext, Data etc.\n// see https://docs.2sxc.org/web-api/custom/index.html\npublic class \" + CsApiTemplateControllerName + @\" : Custom.Hybrid.Api14\n{\n    [HttpGet]        // [HttpGet] says we're listening to GET requests\n    public string Hello()\n    {\n        return \"\"Hello from the controller with ValidateAntiForgeryToken in /api\"\";\n    }\n\n    [HttpPost]        // [HttpPost] says we're listening to POST requests\n    [ValidateAntiForgeryToken] // protects from the users not on your site (CSRF protection)\n    public int Sum([FromBody] dynamic bodyJson) // post body { \"\"a\"\": 2, \"\"b\"\": 3 }\n    {\n        int a = bodyJson.a;\n        int b = bodyJson.b;\n        return a + b;\n    }\n}\n\",\n            Description = \"c# WebApi controller hybrid template\",\n            Suffix = EavConstants.ApiControllerSuffix,\n        };\n\n\n\n    public static readonly TemplateInfo DataSourceHybrid =\n        new(\"data-source-hybrid\", \"DataSource Hybrid\", \".cs\", \"MyDataSource\", ForDataSource, TypeNone)\n        {\n            Body = @\"// Template Dynamic DataSource - learn about this on https://go.2sxc.org/DsCustom\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing ToSic.Eav.DataSource;\n\n// Class name must match file name, and must extend Custom.DataSource.DataSource16\npublic class \" + CsDataSourceName + @\" : Custom.DataSource.DataSource16\n{\n  // Constructor: must forward MyServices to the base class\n  public \" + CsDataSourceName + @\"(MyServices services) : base(services)\n  {\n    // ProvideOut will be called when the data is requested\n    // in this example it will return a list on the Default stream\n    ProvideOut(() => {\n            // Dummy list of numbers using the Configuration \"\"AmountOfItems\"\"\n            var listOfNumbers = Enumerable.Range(1, AmountOfItems);\n\n                // Create a list of anonymous objects with some data\n                return listOfNumbers.Select(i => new {\n            Id = i,\n            guid = Guid.NewGuid(),\n            Title = Greeting\n        }).ToList();\n    });\n}\n\n// Configuration ensures that there is a config with the name \"\"Greeting\"\"\n[Configuration(Fallback = \"\"Hello from Template DataSource\"\")]\npublic string Greeting { get { return Configuration.GetThis(); } }\n\n// Another configuration. Since it's an int,\n// we must provide a fallback in the GetThis(3) in case the incoming config is not a number\n[Configuration(Fallback = 10)]\npublic int AmountOfItems { get { return Configuration.GetThis(3); } }\n}\n\",\n            Description = \"c# DataSource hybrid template\",\n            Suffix = \"\",\n            Folder = \"DataSources\",\n        };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetTemplates.Markdown.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.EditAssets;\n\npublic partial class AssetTemplates\n{\n    private static readonly TemplateInfo Markdown = new(\"markdown-readme\", \"Markdown Readme\", \".md\", \"readme\", ForDocs, TypeNone)\n    {\n        Body = @\"# Readme\n\nA standard README file.\n\",\n        Description = \"Markdown text file\",\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetTemplates.Oqtane.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.EditAssets;\n\npublic partial class AssetTemplates;"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetTemplates.Text.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.EditAssets;\n\npublic partial class AssetTemplates\n{\n    private static readonly TemplateInfo EmptyTextFile = new(\"txt\", \"text file\", \".txt\", \"Notes\", ForDocs, TypeNone)\n    {\n        Body = @\"Simple text file.\n\",\n        Description = \"Simple text file\",\n    };\n\n    private static readonly TemplateInfo EmptyFile = new(\"empty\", \"Empty file\", \"\", \"some-file.txt\", ForDocs, TypeNone)\n    {\n        Body = \"\",\n        Description = \"Simple empty file\",\n        PlatformTypes = null,\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetTemplates.Token.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.EditAssets;\n\npublic partial class AssetTemplates\n{\n    public static TemplateInfo Token =\n        new(\"html-token\", \"HTML Token Template\", \".html\", \"DetailsTemplate\", ForTemplate, TypeToken)\n        {\n            Body = @\"\n<p>\n    You successfully created your own template.\n    Start editing it by hovering the \"\"Manage\"\" button and opening the \"\"Edit Template\"\" dialog.\n</p>\",\n            Description = \"html token template\",\n        };\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetTemplates.Typed.cs",
    "content": "﻿using ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Apps.Sys.EditAssets;\n\npublic partial class AssetTemplates\n{\n    // Place each definition in an own static variable.\n    // Place the keys, etc. here and use these objects for the constant (don't create separate template-key object etc).\n    public static readonly TemplateInfo RazorTyped = new(\"cshtml-typed\", \"Razor Typed\", \".cshtml\", \"DetailsTemplate\", ForTemplate, TypeRazor)\n    {\n        Body = @\"@inherits Custom.Hybrid.RazorTyped\n@* FYI: this inherits from RazorTyped to use the latest APIs. Learn more on https://go.2sxc.org/cs-typed *@\n\n<div @Kit.Toolbar.Default(MyItem)>\n    Put your content here\n</div>\",\n        Description = \"razor page hybrid typed template\",\n        \n    };\n\n    \n    public static readonly TemplateInfo CsTyped =\n        new(\"cs-code-typed\", \"C# Code Typed\", \".cs\", \"Helpers\", ForCode, TypeNone)\n        {\n            Body = @\"// Important notes:\n// - This class should have the same name as the file it's in\n// - This inherits from Custom.Hybrid.CodeTyped\n//   which will automatically provide the common objects like App, MyContext, Data etc.\n//   from the current context to use in your code\n//   Learn more on https://go.2sxc.org/cs-typed\nusing ToSic.Sxc.Services; // Make it easier to use https://go.2sxc.org/services\n\npublic class \" + CsCodeTemplateName + @\" : Custom.Hybrid.CodeTyped {\n  public string SayHello() {\n    return \"\"Hello from shared functions!\"\";\n  }\n}\n\",\n            Description = \"c# code typed template\",\n        };\n\n\n\n    public static readonly TemplateInfo ApiTyped =\n        new(\"cs-api-typed\", \"WebApi Typed\", \".cs\", \"My\", ForApi, TypeNone)\n        {\n            Body = @\"#if NETCOREAPP // Oqtane\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\n#else // DNN\nusing System.Web.Http;\nusing DotNetNuke.Web.Api;\n#endif\nusing ToSic.Sxc.Services; // Make it easier to use https://go.2sxc.org/services\n\n[AllowAnonymous]      // define that all commands can be accessed without a login\n// Inherit from Custom.Hybrid.ApiTyped to get features like App, MyContext, Data etc.\n// see https://docs.2sxc.org/web-api/custom/index.html\n// Learn more on https://go.2sxc.org/cs-typed\npublic class \" + CsApiTemplateControllerName + @\" : Custom.Hybrid.ApiTyped\n{\n    [HttpGet]        // [HttpGet] says we're listening to GET requests\n    public string Hello()\n    {\n        return \"\"Hello from the controller with ValidateAntiForgeryToken in /api\"\";\n    }\n\n    [HttpPost]        // [HttpPost] says we're listening to POST requests\n    [ValidateAntiForgeryToken] // protects from the users not on your site (CSRF protection)\n    public int Sum([FromBody] dynamic bodyJson) // post body { \"\"a\"\": 2, \"\"b\"\": 3 }\n    {\n        int a = bodyJson.a;\n        int b = bodyJson.b;\n        return a + b;\n    }\n}\n\",\n            Description = \"c# WebApi controller typed template\",\n            Suffix = EavConstants.ApiControllerSuffix,\n        };\n\n    /*\n    public static readonly TemplateInfo DataSourceTyped =\n        new(\"data-source-typed\", \"DataSource Typed\", \".cs\", \"MyDataSource\", ForDataSource, TypeNone)\n        {\n            Body = @\"// Template Dynamic DataSource - learn about this on https://go.2sxc.org/DsCustom\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing ToSic.Eav.DataSource;\n\n// Class name must match file name, and must extend Custom.DataSource.DataSourceTyped\npublic class \" + CsDataSourceName + @\" : Custom.DataSource.DataSource16\n{\n  // Constructor: must forward MyServices to the base class\n  public \" + CsDataSourceName + @\"(MyServices services) : base(services)\n  {\n    // ProvideOut will be called when the data is requested\n    // in this example it will return a list on the Default stream\n    ProvideOut(() => {\n            // Dummy list of numbers using the Configuration \"\"AmountOfItems\"\"\n            var listOfNumbers = Enumerable.Range(1, AmountOfItems);\n\n                // Create a list of anonymous objects with some data\n                return listOfNumbers.Select(i => new {\n            Id = i,\n            guid = Guid.NewGuid(),\n            Title = Greeting\n        }).ToList();\n    });\n}\n\n// Configuration ensures that there is a config with the name \"\"Greeting\"\"\n[Configuration(Fallback = \"\"Hello from Template DataSource\"\")]\npublic string Greeting { get { return Configuration.GetThis(); } }\n\n// Another configuration. Since it's an int,\n// we must provide a fallback in the GetThis(3) in case the incoming config is not a number\n[Configuration(Fallback = 10)]\npublic int AmountOfItems { get { return Configuration.GetThis(3); } }\n}\n\",\n            Description = \"c# DataSource hybrid template\",\n            Suffix = \"\",\n            Folder = \"DataSources\",\n        };\n    */\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/AssetTemplates.cs",
    "content": "﻿namespace ToSic.Sxc.Apps.Sys.EditAssets;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class AssetTemplates() : ServiceBase(\"SxcAss.Templt\")\n{\n    #region Constants\n\n    internal const string ForTemplate = \"Template\";\n    internal const string ForApi = \"Api\";\n    internal const string ForDataSource = \"DataSource\";\n    private const string ForDocs = \"Documentation\";\n    public const string ForCode = \"Code\";\n    public const string ForSearch = \"Search\";\n\n    internal const string TypeRazor = \"Razor\";\n    internal const string TypeToken = \"Token\";\n    internal const string TypeNone = \"\";\n\n\n    #endregion\n\n\n    public List<TemplateInfo> GetTemplates() => _templates ??=\n    [\n        RazorTyped,\n        RazorHybrid,\n        RazorDnn,\n        CsTyped,\n        CsHybrid,\n        // DnnCsCode,\n        ApiTyped,\n        ApiHybrid,\n        // DataSourceTyped,\n        DataSourceHybrid,\n        Token,\n        DnnSearch,\n        Markdown,\n        EmptyTextFile,\n        EmptyFile\n    ];\n    private static List<TemplateInfo>? _templates;\n\n    public const string CsApiTemplateControllerName = \"PleaseRenameController\";\n    public const string CsDataSourceName = \"PleaseRename\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Apps.Sys.EditAssets/TemplateInfo.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Sxc.Context;\n\nnamespace ToSic.Sxc.Apps.Sys.EditAssets;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class TemplateInfo(\n    string key,\n    string name,\n    string extension,\n    string suggestedFileName,\n    string purpose,\n    string type)\n{\n    public string Key { get; } = key;\n\n    public string Name { get; } = name;\n\n    public string SuggestedFileName { get; } = suggestedFileName;\n\n    public string Extension { get; set; } = extension;\n\n    public string Purpose { get; set; } = purpose;\n\n    public string Type { get; set; } = type;\n\n    public string Folder { get; set; } = string.Empty;\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Body { get; set; }\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Description { get; set; }\n\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Prefix { get; set; }\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? Suffix { get; set; }\n\n    /// <summary>\n    /// Returns an array of platforms this template supports so the UI can pick\n    /// </summary>\n    public IEnumerable<string>? Platforms => PlatformTypes?.ToString().Split(',').Select(p => p.Trim());\n\n    [JsonIgnore]\n    public PlatformType? PlatformTypes { get; set; } = PlatformType.Hybrid | PlatformType.Dnn | PlatformType.Oqtane;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Adam/AdamCode.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys.Work;\nusing ToSic.Sxc.Services.Sys;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing ToSic.Sxc.WebApi;\nusing ToSic.Sys.Capabilities.Features;\nusing static ToSic.Sys.Capabilities.Features.BuiltInFeatures;\n\nnamespace ToSic.Sxc.Backend.Adam;\n\n/// <summary>\n/// Adam Shared Code Across the APIs\n/// See docs of official interface <see cref=\"IDynamicWebApi\"/>\n/// </summary>\n[PrivateApi(\"Used by DynamicApiController and Hybrid.Api12_DynCode\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamCode(Generator<AdamWorkUpload, AdamWorkOptions> adamUploadGenerator, LazySvc<ISysFeaturesService> featuresLazy)\n    : ServiceWithContext(\"AdamCode\", connect: [adamUploadGenerator, featuresLazy])\n{\n    public IFile SaveInAdam(NoParamOrder npo = default,\n        Stream? stream = null,\n        string? fileName = null,\n        string? contentType = null,\n        Guid? guid = null,\n        string? field = null,\n        string subFolder = \"\")\n    {\n        var l = Log.Fn<IFile>();\n\n        if (stream == null || fileName == null || contentType == null || guid == null || field == null)\n            throw new ArgumentException($\"all these arguments must be available: {nameof(stream)}, {nameof(field)}, {nameof(contentType)}, {nameof(guid)}, {nameof(field)}\");\n\n        var feats = new[] { SaveInAdamApi.Guid, PublicUploadFiles.Guid };\n\n        if (!featuresLazy.Value.IsEnabled(feats, \"can't save in ADAM\", out var exp))\n            throw l.Ex(exp);\n\n        var appId = ExCtx.GetBlock()?.AppId\n                    ?? ExCtx.GetApp()?.AppId\n                    ?? throw l.Ex(new Exception(\"Error, SaveInAdam needs an App-Context to work, but the App is not known.\"));\n        var adamUploader = adamUploadGenerator.New(new()\n            {\n                AppId = appId,\n                ContentType = contentType,\n                ItemGuid = guid.Value,\n                Field = field,\n                UsePortalRoot = false,\n            });\n\n        var upload = adamUploader.UploadOne(stream, fileName, subFolder, true);\n        return upload;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Adam/AdamControllerReal.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.Work;\n\nnamespace ToSic.Sxc.Backend.Adam;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamControllerReal<TIdentifier>(\n    Generator<AdamWorkUpload, AdamWorkOptions> adamUpload,\n    Generator<AdamWorkGet, AdamWorkOptions> adamWorkGet,\n    Generator<AdamWorkFolderCreate, AdamWorkOptions> adamFolders,\n    Generator<AdamWorkDelete, AdamWorkOptions> adamDelete,\n    Generator<AdamWorkRename, AdamWorkOptions> adamRename,\n    Generator<IAdamItemDtoMaker, AdamItemDtoMakerOptions> dtoMaker)\n    : ServiceBase(\"Api.Adam\", connect: [adamUpload, adamWorkGet, adamFolders, adamDelete, adamRename])\n{\n    public AdamItemDto Upload(HttpUploadedFile uploadInfo, int appId, string contentType, Guid guid, string field, string subFolder = \"\", bool usePortalRoot = false)\n    {\n        var l = Log.Fn<AdamItemDto>();\n        // wrap all of it in try/catch, to reformat error in better way for js to tell the user\n        try\n        {\n            // Check if the request contains multipart/form-data.\n            if (!uploadInfo.IsMultipart())\n                return l.Return(new(\"doesn't look like a file-upload\"), \"no file multipart\");\n\n            if (!uploadInfo.HasFiles())\n                return l.Return(new(\"No file was uploaded.\"), \"Error, no files\");\n\n            var (fileName, stream) = uploadInfo.GetStream();\n            if (stream == null!)\n                return l.ReturnAsError(new(\"File Stream is empty\"));\n\n            var uploader = adamUpload.New(new()\n            {\n                AppId = appId,\n                ContentType = contentType,\n                ItemGuid = guid,\n                Field = field,\n                UsePortalRoot = usePortalRoot,\n            });//.Value.Setup(appId, contentType, guid, field, usePortalRoot);\n            var file = uploader.UploadOneNew(stream, subFolder, fileName);\n\n            var dtoMake = dtoMaker.New(new() { AdamContext = uploader.AdamContext, });\n            return dtoMake.Create(file);\n        }\n        catch (HttpExceptionAbstraction he)\n        {\n            // Our abstraction places an extra message in the value, not sure if this is right, but that's how it is. \n            return l.ReturnAsError(new(he.Message + \"\\n\" + he.Value));\n        }\n        catch (Exception e)\n        {\n            return l.ReturnAsError(new(e.Message + \"\\n\" + e.Message));\n        }\n    }\n\n    // Note: #AdamItemDto - as of now, we must use object because System.Io.Text.Json will otherwise not convert the object correctly :(\n    public IEnumerable</*AdamItemDto*/object> Items(int appId, string contentType, Guid guid, string field, string subfolder, bool usePortalRoot = false)\n    {\n        var l = Log.Fn<IEnumerable<AdamItemDto>>($\"adam items a:{appId}, i:{guid}, field:{field}, subfolder:{subfolder}, useRoot:{usePortalRoot}\");\n        var adamGet = adamWorkGet.New(new()\n        {\n            AppId = appId,\n            ContentType = contentType,\n            ItemGuid = guid,\n            Field = field,\n            UsePortalRoot = usePortalRoot,\n        });\n        var results = adamGet.ItemsInField(subfolder);\n\n        if (results == null)\n            return l.ReturnAsError([], \"got empty object, user probably restricted\");\n\n        var dto = dtoMaker\n            .New(new() { AdamContext = adamGet.AdamContext })\n            .Convert(results);\n\n        return l.ReturnAsOk(dto);\n    }\n\n    public IEnumerable</*AdamItemDto*/object> Folder(int appId, string contentType, Guid guid, string field, string subfolder, string newFolder, bool usePortalRoot)\n    {\n        var l = Log.Fn<IEnumerable<object>>();\n        adamFolders.New(new()\n            {\n                AppId = appId,\n                ContentType = contentType,\n                ItemGuid = guid,\n                Field = field,\n                UsePortalRoot = usePortalRoot,\n            })\n            .Create(subfolder, newFolder);\n\n        var adamGet = adamWorkGet.New(new()\n        {\n            AppId = appId,\n            ContentType = contentType,\n            ItemGuid = guid,\n            Field = field,\n            UsePortalRoot = usePortalRoot,\n        });\n        var folder = adamGet.ItemsInField(subfolder);\n\n        if (folder == null)\n            return l.ReturnAsError([], \"got empty object, user probably restricted\");\n\n        var dto = dtoMaker\n            .New(new() { AdamContext = adamGet.AdamContext })\n            .Convert(folder);\n        return l.ReturnAsOk(dto);\n    }\n\n    public bool Delete(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, TIdentifier id, bool usePortalRoot)\n        => adamDelete.New(new()\n        {\n            AppId = appId,\n            ContentType = contentType,\n            ItemGuid = guid,\n            Field = field,\n            UsePortalRoot = usePortalRoot,\n        })\n            .Delete(subfolder, isFolder, AdamAssetIdentifier.Create(id),  AdamAssetIdentifier.Create(id));\n\n    public bool Rename(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder, TIdentifier id, string newName, bool usePortalRoot)\n        => adamRename.New(new()\n            {\n                AppId = appId,\n                ContentType = contentType,\n                ItemGuid = guid,\n                Field = field,\n                UsePortalRoot = usePortalRoot,\n            })\n            .Rename(subfolder, isFolder, AdamAssetIdentifier.Create(id), AdamAssetIdentifier.Create(id), newName);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Adam/AdamItemDtoMaker.cs",
    "content": "﻿using ToSic.Eav.Metadata;\nusing ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Adam.Sys.Work;\nusing ToSic.Sxc.Data;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Backend.Adam;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\n#pragma warning disable CS9113 // Parameter is unread. - ignore for now, in case we want dependencies later\npublic class AdamItemDtoMaker<TFolderId, TFileId>(AdamItemDtoMaker<TFolderId, TFileId>.Dependencies settings)\n#pragma warning restore CS9113 // Parameter is unread.\n    : ServiceWithSetup<AdamItemDtoMakerOptions>(\"Adm\"), IAdamItemDtoMaker\n{\n    #region Constructor / DI\n\n    /// <summary>\n    /// ATM no dependencies...\n    /// </summary>\n    public class Dependencies;\n\n\n    [field: AllowNull, MaybeNull]\n    public AdamContext AdamContext => field ??= MyOptions.AdamContext!;\n\n    #endregion\n\n    private const string ThumbnailPattern = \"{0}?w=120&h=120&mode=crop&urlSource=backend\";\n    private const string PreviewPattern = \"{0}?w=800&h=800&mode=max&urlSource=backend\";\n\n    public IEnumerable<AdamItemDto> Convert(AdamFolderFileSet set)\n    {\n        // This will contain the list of items\n        var list = new List<AdamItemDto>();\n\n        if (set.Root != null)\n        {\n            var currentFolderDto = Create(set.Root);\n            currentFolderDto.Name = \".\";\n            list.Insert(0, currentFolderDto);\n        }\n\n        var folders = set.Folders\n            .Select(Create)\n            .ToListOpt();\n        list.AddRange(folders);\n\n        var files = set.Files\n            .Select(Create)\n            .ToListOpt();\n        list.AddRange(files);\n        return list;\n    }\n\n    public virtual AdamItemDto Create(IFile file)\n    {\n        var url = file.Url;\n        // Cast to typed, to access the SysId and ParentSysId\n        var fileAsTyped = (File<TFolderId, TFileId>)file;\n        var item = new AdamItemDto<TFolderId, TFileId>(\n            false,\n            fileAsTyped.SysId,\n            fileAsTyped.ParentSysId,\n            file.FullName, file.Size,\n            file.Created, file.Modified)\n        {\n            Path = file.Path,\n            ThumbnailUrl = string.Format(ThumbnailPattern, url),\n            PreviewUrl = string.Format(PreviewPattern, url),\n            Url = url,\n            ReferenceId = ((IHasMetadata)file).Metadata.Target.KeyString,\n            AllowEdit = CanEditFolder(file),\n            Metadata = GetMetadataOf(file.Metadata),\n            Type = AssetTypeNames.GetTypeName(file.Extension),\n        };\n        return item;\n    }\n\n\n    public virtual AdamItemDto Create(IFolder folder)\n    {\n        // Cast to typed, to access the SysId and ParentSysId\n        var folderAsTyped = (Folder<TFolderId, TFileId>)folder;\n        var item = new AdamItemDto<TFolderId, TFolderId>(\n            true,\n            folderAsTyped.SysId,\n            folderAsTyped.ParentSysId,\n            folder.Name,\n            0,\n            folder.Created,\n            folder.Modified)\n        {\n            Path = folder.Path,\n            AllowEdit = CanEditFolder(folder),\n            ReferenceId = ((IHasMetadata)folder).Metadata.Target.KeyString,\n            //MetadataId = (int)folder.Metadata.EntityId,\n            Metadata = GetMetadataOf(folder.Metadata),\n        };\n        return item;\n    }\n\n    private IEnumerable<MetadataOfDto>? GetMetadataOf(ITypedMetadata? md)\n    {\n        if (md == null)\n            return null;\n\n        var result = ((IHasMetadata)md).Metadata\n            .Select(m => new MetadataOfDto\n            {\n                Id = m.EntityId,\n                Guid = m.EntityGuid,\n                Type = new(m)\n            })\n            .ToArray();\n        return result.Any()\n            ? result\n            : null;\n    }\n\n    private bool CanEditFolder(Eav.Apps.Assets.IAsset original)\n        => AdamContext.UseSiteRoot\n            ? AdamContext.Security.CanEditFolder(original)\n            : ContextAllowsEdit;\n\n    /// <summary>\n    /// Do this check once only, as the result will never change during one lifecycle\n    /// </summary>\n    private bool ContextAllowsEdit\n        => _contextAllowsEdit ??= !AdamContext.Security.UserIsRestricted || AdamContext.Security.FieldPermissionOk(GrantSets.WriteSomething);\n    private bool? _contextAllowsEdit;\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Adam/AdamPrefetchHelper.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Work;\n\nnamespace ToSic.Sxc.Backend.Adam;\n\n/// <summary>\n/// Backend for the API\n/// Is meant to be transaction based - so create a new one for each thing as the initializers set everything for the transaction\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AdamPrefetchHelper(Generator<AdamWorkGet, AdamWorkOptions> adamGet, Generator<IAdamItemDtoMaker, AdamItemDtoMakerOptions> dtoMaker)\n    : ServiceWithSetup<AdamWorkOptions>(\"Adm.TrnItm\"),\n        IAdamPrefetchHelper\n{\n    public ICollection<AdamItemDto> GetAdamItemsForPrefetch(string subFolderName, bool autoCreate = true)\n    {\n        var l = Log.Fn<ICollection<AdamItemDto>>($\"subFolderName:{subFolderName}, autoCreate:{autoCreate}\");\n        var adamGetReady = adamGet.New(MyOptions);\n        var items = adamGetReady.ItemsInField(subFolderName, autoCreate);\n        \n        if (items == null)\n            return l.ReturnAsError([], \"got empty object, user is probably restricted\");\n\n        var maker = dtoMaker.New(new() { AdamContext = adamGetReady.AdamContext, });\n        var result = maker.Convert(items)\n            .ToListOpt();\n        return l.ReturnAsOk(result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Adam/IAdamController.cs",
    "content": "﻿namespace ToSic.Eav.WebApi.PublicApi;\n\n/// <summary>\n/// Contract for WebApi controllers supporting ADAM calls\n/// </summary>\npublic interface IAdamController<in TId>\n{\n    /// <summary>\n    /// POST or PUT Upload a file to ADAM\n    /// </summary>\n    /// <param name=\"appId\">App ID</param>\n    /// <param name=\"contentType\">Content type of the field we're adding something to</param>\n    /// <param name=\"guid\">Entity Guid we're adding a file to</param>\n    /// <param name=\"field\">Field where the file is added to</param>\n    /// <param name=\"subfolder\">Folder information within that field</param>\n    /// <param name=\"usePortalRoot\">If we should add something to the portal root instead of the field</param>\n    /// <returns></returns>\n\n    // Note: #AdamItemDto - as of now, we must use object because System.Io.Text.Json will otherwise not convert the object correctly :(\n    // Wip #2902 - ATM must return object, otherwise the result isn't perfectly JSON serialized\n    /*AdamItemDto*/ object Upload(int appId, string contentType, Guid guid, string field, string subfolder = \"\", bool usePortalRoot = false);\n\n    /// <summary>\n    /// GET all the ADAM items for an entity, within that folder etc.\n    /// </summary>\n    /// <param name=\"appId\">App ID</param>\n    /// <param name=\"contentType\">Content type of the field we're adding something to</param>\n    /// <param name=\"guid\">Entity Guid we're adding a file to</param>\n    /// <param name=\"field\">Field where the file is added to</param>\n    /// <param name=\"subfolder\">Folder information within that field</param>\n    /// <param name=\"usePortalRoot\">If we should add something to the portal root instead of the field</param>\n    /// <returns></returns>\n    IEnumerable</*AdamItemDto*/object> Items(int appId, string contentType, Guid guid, string field, string subfolder, bool usePortalRoot = false);\n\n    /// <summary>\n    /// POST create a folder.\n    /// </summary>\n    /// <param name=\"appId\">App ID</param>\n    /// <param name=\"contentType\">Content type of the field we're adding something to</param>\n    /// <param name=\"guid\">Entity Guid we're adding a file to</param>\n    /// <param name=\"field\">Field where the file is added to</param>\n    /// <param name=\"subfolder\">Folder information within that field</param>\n    /// <param name=\"newFolder\">name of the new folder</param>\n    /// <param name=\"usePortalRoot\">If we should add something to the portal root instead of the field</param>\n    /// <returns></returns>\n    IEnumerable</*AdamItemDto*/object> Folder(int appId, string contentType, Guid guid, string field, string subfolder,\n        string newFolder, bool usePortalRoot);\n\n    /// <summary>\n    /// DELETE an item (folder, file) in ADAM\n    /// </summary>\n    /// <param name=\"appId\">App ID</param>\n    /// <param name=\"contentType\">Content type of the field we're adding something to</param>\n    /// <param name=\"guid\">Entity Guid we're adding a file to</param>\n    /// <param name=\"field\">Field where the file is added to</param>\n    /// <param name=\"subfolder\">Folder information within that field</param>\n    /// <param name=\"isFolder\">true/false if we're deleting a folder</param>\n    /// <param name=\"id\">ID of the item to delete</param>\n    /// <param name=\"usePortalRoot\">If we should add something to the portal root instead of the field</param>\n    /// <returns></returns>\n    bool Delete(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder,\n        TId id, bool usePortalRoot);\n\n    /// <summary>\n    /// GET rename an item. \n    /// </summary>\n    /// <param name=\"appId\">App ID</param>\n    /// <param name=\"contentType\">Content type of the field we're adding something to</param>\n    /// <param name=\"guid\">Entity Guid we're adding a file to</param>\n    /// <param name=\"field\">Field where the file is added to</param>\n    /// <param name=\"subfolder\">Folder information within that field</param>\n    /// <param name=\"isFolder\">true/false if we're deleting a folder</param>\n    /// <param name=\"id\">ID of the item to delete</param>\n    /// <param name=\"newName\">New name for the item</param>\n    /// <param name=\"usePortalRoot\">If we should add something to the portal root instead of the field</param>\n    /// <returns></returns>\n    bool Rename(int appId, string contentType, Guid guid, string field, string subfolder, bool isFolder,\n        TId id, string newName, bool usePortalRoot);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Adam/IAdamItemDtoMaker.cs",
    "content": "﻿using ToSic.Sxc.Adam;\nusing ToSic.Sxc.Adam.Sys.Work;\n\nnamespace ToSic.Sxc.Backend.Adam;\n\npublic interface IAdamItemDtoMaker: IServiceWithSetup<AdamItemDtoMakerOptions>\n{\n    IEnumerable<AdamItemDto> Convert(AdamFolderFileSet set);\n    AdamItemDto Create(IFile file);\n    AdamItemDto Create(IFolder folder);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Adam/IAdamPrefetchHelper.cs",
    "content": "﻿using ToSic.Sxc.Adam.Sys.Work;\n\nnamespace ToSic.Sxc.Backend.Adam;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IAdamPrefetchHelper : /*IAdamWork,*/ IServiceWithSetup<AdamWorkOptions>, IHasOptions<AdamWorkOptions>\n{\n    /// <summary>\n    /// Get a DTO list of items in a field\n    /// </summary>\n    /// <param name=\"subFolderName\">Optional sub folder, when browsing a sub-folder</param>\n    /// <param name=\"autoCreate\">Auto-create the folder requested - default is true</param>\n    /// <returns></returns>\n    ICollection<AdamItemDto> GetAdamItemsForPrefetch(string subFolderName, bool autoCreate = true);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppControllerReal.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Eav.Apps.Sys.Caching;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.DataSources.Sys;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Eav.WebApi.Sys.Languages;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Backend.AppStack;\nusing ToSic.Sxc.Backend.ImportExport;\nusing ToSic.Sxc.Services;\nusing ToSic.Sys.Configuration;\nusing Services_ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n/// <summary>\n/// Experimental new class\n/// Goal is to reduce code in the Dnn and Oqtane controllers, which basically does the same thing, mostly DI work\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppControllerReal(\n    LazySvc<AppsBackend> appsBackendLazy,\n    LazySvc<WorkAppsRemove> workAppsRemove,\n    LazySvc<ExportApp> exportAppLazy,\n    LazySvc<ImportApp> importAppLazy,\n    LazySvc<AppCreator> appBuilderLazy,\n    LazySvc<AppStateSyncSave> appStateSyncSave,\n    LazySvc<AppStateSyncRestore> appStateSyncRestore,\n    LazySvc<AppCachePurger> systemManagerLazy,\n    LazySvc<LanguagesBackend> languagesBackendLazy,\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    LazySvc<AppStackBackend> appStackBackendLazy,\n    LazySvc<IJsonService> json,\n    IGlobalConfiguration globalConfiguration)\n    : Services_ServiceBase($\"{EavLogs.WebApi}.{LogSuffix}Rl\",\n        connect:\n        [\n            appsBackendLazy, workAppsRemove, exportAppLazy, importAppLazy, appBuilderLazy, appStateSyncRestore, appStateSyncSave,\n            systemManagerLazy, languagesBackendLazy, appReadersLazy, appStackBackendLazy, json, globalConfiguration\n        ])\n{\n    public const string LogSuffix = \"AppCon\";\n\n    public ICollection<AppDto> List(int zoneId)\n        => appsBackendLazy.Value.Apps();\n\n    public ICollection<AppDto> InheritableApps()\n        => appsBackendLazy.Value.GetInheritableApps();\n\n    public void App(int zoneId, int appId, bool fullDelete = true)\n        => workAppsRemove.Value.RemoveAppInSiteAndEav(zoneId, appId, fullDelete);\n\n    public void App(int zoneId, string name, int? inheritAppId = null)\n    {\n        var l = Log.Fn($\"{nameof(zoneId)}:{zoneId}, {nameof(name)}:{name}, {nameof(inheritAppId)}:{inheritAppId}\");\n        l.A(\"create default new app without template\");\n        appBuilderLazy.Value.Init(zoneId).Create(name, null, inheritAppId);\n        l.Done(\"ok\");\n    }\n\n    public List<SiteLanguageDto> Languages(int appId)\n        => languagesBackendLazy.Value.GetLanguagesOfApp(appReadersLazy.Value.Get(appId), true);\n\n    public AppExportInfoDto Statistics(int zoneId, int appId) => exportAppLazy.Value.GetAppInfo(zoneId, appId);\n\n    public bool FlushCache(int zoneId, int appId)\n    {\n        var l = Log.Fn<bool>($\"{zoneId}, {appId}\");\n        systemManagerLazy.Value.Purge(zoneId, appId);\n        return l.ReturnTrue(\"ok\");\n    }\n\n    public FileToUploadToClient Export(AppExportSpecs specs)\n        => exportAppLazy.Value.Export(specs);\n\n    public Task<ActionData<bool>> SaveData(AppExportSpecs specs)\n        => appStateSyncSave.Value.Run(new(), new(specs));\n\n    public List<AppStackDataRaw> GetStack(int appId, string? part, string? key = null, Guid? view = null)\n        => appStackBackendLazy.Value.GetAll(appId, part ?? AppStackConstants.RootNameSettings, key, view);\n\n    public async Task<ImportResultDto> Reset(int zoneId, int appId, string defaultLanguage, bool withPortalFiles)\n        => (await appStateSyncRestore.Value.Run(new(), new(new(zoneId, appId, defaultLanguage, withPortalFiles)))).Data;\n\n    /// <summary>\n    /// Import App from import zip.\n    /// </summary>\n    /// <param name=\"uploadInfo\">file upload</param>\n    /// <param name=\"zoneId\">int</param>\n    /// <param name=\"renameApp\">optional new name for app, provide to rename the app</param>\n    /// <returns></returns>\n    public ImportResultDto Import(HttpUploadedFile uploadInfo, int zoneId, string renameApp)\n    {\n        var l = Log.Fn<ImportResultDto>();\n\n        if (!uploadInfo.HasFiles())\n            return l.Return(new(false, \"no file uploaded\"), \"no file uploaded\");\n\n        var (_, stream) = uploadInfo.GetStream(0);\n        if (stream == null!)\n            throw new NullReferenceException(\"File Stream is null, upload canceled\");\n\n        var result = importAppLazy.Value.Import(stream, zoneId, renameApp);\n\n        return l.ReturnAsOk(result);\n    }\n\n    /// <summary>\n    /// List all app folders in the 2sxc which:\n    /// - are not installed as apps yet\n    /// - have a App_Data/app.xml\n    /// </summary>\n    /// <param name=\"zoneId\"></param>\n    /// <returns></returns>\n    public IEnumerable<PendingAppDto> GetPendingApps(int zoneId)\n    {\n        var l = Log.Fn<IEnumerable<PendingAppDto>>();\n        var result = importAppLazy.Value.GetPendingApps(zoneId);\n        return l.ReturnAsOk(result);\n    }\n\n    /// <summary>\n    /// Install pending apps\n    /// </summary>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"pendingApps\"></param>\n    /// <returns></returns>\n    public ImportResultDto InstallPendingApps(int zoneId, IEnumerable<PendingAppDto> pendingApps)\n    {\n        var l = Log.Fn<ImportResultDto>();\n        var result = importAppLazy.Value.InstallPendingApps(zoneId, pendingApps);\n        return l.ReturnAsOk(result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppExtensionsControllerReal.cs",
    "content": "using ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Backend.App;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppExtensionsControllerReal(\n    LazySvc<ExtensionReaderBackend> readerLazy,\n    LazySvc<ExtensionWriterBackend> writerLazy,\n    LazySvc<ExtensionInstallBackend> zipLazy,\n    LazySvc<ExtensionInspectBackend> inspectorLazy,\n    LazySvc<ExtensionDeleteBackend> deleteLazy,\n    LazySvc<ExtensionExportService> exportExtensionLazy,\n    LazySvc<ExtensionDownloadBackend> downloadLazy)\n    : ServiceBase(\"Api.ExtsRl\", connect: [readerLazy, writerLazy, zipLazy, inspectorLazy, deleteLazy, exportExtensionLazy, downloadLazy])\n{\n    public const string LogSuffix = \"ApiExts\";\n\n    /// <summary>\n    /// Get all App Extensions and their configuration (if any).\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <returns>Object with property \"extensions\" containing an array of extensions</returns>\n    public ExtensionsResultDto Extensions(int appId)\n        => readerLazy.Value.GetExtensions(appId);\n\n    /// <summary>\n    /// Preflight install of an extension zip to report current state and options.\n    /// </summary>\n    /// <param name=\"uploadInfo\">Uploaded ZIP file containing the extension package</param>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"editions\">Optional list of editions to install into (empty or null = root)</param>\n    /// <returns>Preflight result describing detected state and installation options</returns>\n    public PreflightResultDto InstallPreflight(HttpUploadedFile uploadInfo, int appId, string editions = \"\")\n    {\n        var l = Log.Fn<PreflightResultDto>($\"a:{appId}, editions:'{editions}'\");\n\n        if (!uploadInfo.HasFiles())\n            throw l.Ex(new ArgumentException(\"no file uploaded\", nameof(uploadInfo)));\n\n        var (fileName, stream) = uploadInfo.GetStream();\n        if (stream == null!)\n            throw l.Ex(new NullReferenceException(\"File Stream is null, upload canceled\"));\n\n        var result = zipLazy.Value.InstallPreflight(appId, stream, originalZipFileName: fileName, editions: editions);\n        return l.Return(result, \"ok\");\n    }\n\n    /// <summary>\n    /// Install app extension zip.\n    /// </summary>\n    /// <param name=\"uploadInfo\">Uploaded ZIP file containing the extension package</param>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"editions\">Optional list of editions to install into (empty or null = root)</param>\n    /// <param name=\"overwrite\">Overwrite existing files if true</param>\n    /// <returns>true if installation succeeded</returns>\n    public bool Install(HttpUploadedFile uploadInfo, int zoneId, int appId, string editions = \"\", bool overwrite = false)\n    {\n        var l = Log.Fn<bool>($\"a:{appId}, editions:'{editions}', overwrite:{overwrite}\");\n\n        if (!uploadInfo.HasFiles())\n            throw l.Ex(new ArgumentException(\"no file uploaded\", nameof(uploadInfo)));\n\n        var (fileName, stream) = uploadInfo.GetStream();\n        if (stream == null!)\n            throw l.Ex(new NullReferenceException(\"File Stream is null, upload canceled\"));\n\n        var ok = zipLazy.Value.InstallExtensionZip(zoneId, appId, stream, overwrite, originalZipFileName: fileName, editions: editions);\n        return l.ReturnAsOk(ok);\n    }\n\n    /// <summary>\n    /// Preflight install of an extension zip downloaded from the provided URL(s).\n    /// </summary>\n    public PreflightResultDto InstallPreflightFrom(string[] urls, int appId, string editions = \"\")\n    {\n        var l = Log.Fn<PreflightResultDto>($\"a:{appId}, editions:'{editions}'\");\n\n        var download = downloadLazy.Value.DownloadFirstAvailable(urls);\n        using var stream = download.Stream;\n\n        // Run preflight on the downloaded zip and return the backend result.\n        var result = zipLazy.Value.InstallPreflight(appId, stream, originalZipFileName: download.FileName, editions: editions);\n        return l.Return(result, $\"ok from '{download.Url}'\");\n    }\n\n    /// <summary>\n    /// Install app extension zip downloaded from the provided URL(s).\n    /// </summary>\n    public bool InstallFrom(string[] urls, int zoneId, int appId, string editions = \"\", bool overwrite = false)\n    {\n        var l = Log.Fn<bool>($\"a:{appId}, editions:'{editions}', overwrite:{overwrite}\");\n\n        var download = downloadLazy.Value.DownloadFirstAvailable(urls);\n        using var stream = download.Stream;\n\n        // Install the downloaded package into the target app/edition(s).\n        var ok = zipLazy.Value.InstallExtensionZip(zoneId, appId, stream, overwrite, originalZipFileName: download.FileName, editions: editions);\n        return l.Return(ok, $\"url:'{download.Url}'\");\n    }\n\n    /// <summary>\n    /// Inspect endpoint\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"name\">Extension folder name</param>\n    /// <param name=\"edition\">Optional edition name</param>\n    public ExtensionInspectResultDto Inspect(int appId, string name, string? edition = null)\n        => inspectorLazy.Value.Inspect(appId, name, edition);\n\n    /// <summary>\n    /// Create or replace the configuration of a specific App Extension.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"name\">Extension folder name under \"/extensions\"</param>\n    /// <param name=\"manifest\">JSON to write as App_Data/extension.json</param>\n    /// <returns>true if saved</returns>\n    public bool Configuration(int appId, string name, ExtensionManifest manifest)\n        => writerLazy.Value.SaveConfiguration(appId, name, manifest);\n\n    /// <summary>\n    /// Download (export) a specific extension as a ZIP file.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"name\">Extension folder name</param>\n    /// <returns>HTTP response containing the file data.</returns>\n    public FileToUploadToClient Download(int appId, string name)\n        => exportExtensionLazy.Value.Export(appId, name);\n\n    /// <summary>\n    /// Delete an extension and optionally its data.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"name\">Extension folder name</param>\n    /// <param name=\"edition\">Optional edition name</param>\n    /// <param name=\"force\">Force deletion even when files or data changed.</param>\n    /// <param name=\"withData\">Delete related data when true (requires force).</param>\n    /// <returns>true if deleted</returns>\n    public bool Delete(int appId, string name, string? edition = null, bool force = false, bool withData = false)\n        => deleteLazy.Value.DeleteExtension(appId, name, edition, force, withData);\n}\n\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/AppFileDto.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Admin.AppFiles;\n\n/// <summary>\n/// helper class with all the info to identify a file in the app folder\n/// </summary>\npublic record AppFileDto\n{\n    public int AppId { get; init; }\n\n    public required string Path { get; init; }\n\n    public bool Global { get; init; }\n\n    public required string TemplateKey { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/AppFilesControllerReal.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Sxc.Apps.Sys.EditAssets;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sys.Users;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Backend.Admin.AppFiles;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class AppFilesControllerReal(\n    ISite site,\n    IUser user,\n    Generator<AssetEditor> assetEditorGenerator,\n    IAppReaderFactory appReaders,\n    LazySvc<CodeControllerReal> codeController,\n    LazySvc<AppCodeLoader> appCodeLoader,\n    AssetTemplates assetTemplates,\n    IAppPathsMicroSvc appPathsFactoryTemp)\n    : ServiceBase(\"Bck.Assets\",\n        connect:\n        [\n            assetEditorGenerator, assetTemplates, appReaders, codeController, appCodeLoader, appPathsFactoryTemp\n        ]), IAppFilesController\n{\n    public const string LogSuffix = \"AppAss\";\n\n    /// <summary>\n    /// Get details and source code\n    /// </summary>\n    public AssetEditInfo Asset(int appId, int templateId = 0, string? path = null, bool global = false)\n    {\n        var l = Log.Fn<AssetEditInfo>($\"asset templ:{templateId}, path:{path}, global:{global}\");\n        var assetEditor = GetAssetEditorOrThrowIfInsufficientPermissions(appId, templateId, global, path);\n        assetEditor.EnsureUserMayEditAssetOrThrow();\n        return l.Return(assetEditor.EditInfoWithSource);\n    }\n\n    /// <summary>\n    /// Save operation - but must be called Asset to match public REST API\n    /// </summary>\n    public bool Asset(int appId, AssetEditInfo template, int templateId, string? path, bool global)\n    {\n        var l = Log.Fn<bool>($\"templ:{templateId}, global:{global}, path:{path}\");\n        var assetEditor = GetAssetEditorOrThrowIfInsufficientPermissions(appId, templateId, global, path);\n        assetEditor.Source = template.Code!;\n        return l.ReturnTrue();\n    }\n\n    /// <summary>\n    /// Create a new file (if it doesn't exist yet) and optionally prefill it with content\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"path\"></param>\n    /// <param name=\"global\">this determines, if the app-file store is the global in _default or the local in the current app</param>\n    /// <param name=\"templateKey\"></param>\n    /// <returns></returns>\n    public bool Create(int appId, string path, bool global, string templateKey)\n    {\n        var assetFromTemplateDto = new AppFileDto\n        {\n            AppId = appId,\n            Path = path,\n            Global = global,\n            TemplateKey = templateKey,\n        };\n        var l = Log.Fn<bool>($\"create a#{assetFromTemplateDto.AppId}, path:{assetFromTemplateDto.Path}, global:{assetFromTemplateDto.Global}, key:{assetFromTemplateDto.TemplateKey}\");\n\n        assetFromTemplateDto = EnsureRequiredFolder(assetFromTemplateDto);\n\n        var assetEditor = GetAssetEditorOrThrowIfInsufficientPermissions(assetFromTemplateDto);\n\n        // get and prepare template content\n        var body = GetTemplateContent(assetFromTemplateDto) ?? \"\";\n\n        return l.Return(assetEditor.Create(body), \"Created\");\n    }\n\n    private static AppFileDto EnsureRequiredFolder(AppFileDto assetFromTemplateDto)\n    {\n        assetFromTemplateDto = assetFromTemplateDto with { Path = assetFromTemplateDto.Path.Replace(\"/\", \"\\\\\") };\n\n        // ensure that DataSource is in DataSources folder\n        if (assetFromTemplateDto.TemplateKey == AssetTemplates.DataSourceHybrid.Key)\n        {\n            var directoryName = Path.GetDirectoryName(assetFromTemplateDto.Path) ?? string.Empty;\n            var fileName = Path.GetFileName(assetFromTemplateDto.Path) ?? string.Empty;\n            if (!directoryName.StartsWith(AssetTemplates.DataSourceHybrid.Folder) &&\n                !directoryName.Contains(AssetTemplates.DataSourceHybrid.Folder))\n                assetFromTemplateDto = assetFromTemplateDto with\n                {\n                    Path = Path.Combine(AssetTemplates.DataSourceHybrid.Folder, fileName)\n                };\n        }\n\n        return assetFromTemplateDto;\n    }\n\n    /// <summary>\n    /// Get all asset template types\n    /// </summary>\n    /// <param name=\"purpose\">filter by Purpose when provided</param>\n    /// <param name=\"type\"></param>\n    /// <returns></returns>\n    public TemplatesDto GetTemplates(string? purpose, string? type)\n    {\n        var templateInfos = assetTemplates.GetTemplates();\n\n        // TBD: future purpose implementation\n        purpose = (purpose ?? AssetTemplates.ForTemplate).ToLowerInvariant().Trim();\n        var defId = AssetTemplates.RazorTyped.Key;\n        if (purpose.Equals(AssetTemplates.ForApi, InvariantCultureIgnoreCase))\n            defId = AssetTemplates.ApiHybrid.Key;\n        if (purpose.Equals(AssetTemplates.ForDataSource, InvariantCultureIgnoreCase))\n            defId = AssetTemplates.DataSourceHybrid.Key;\n        if (purpose.Equals(AssetTemplates.ForSearch, InvariantCultureIgnoreCase))\n            defId = AssetTemplates.DnnSearch.Key;\n\n        // For templates we also check the type\n        if (purpose.Equals(AssetTemplates.ForTemplate, InvariantCultureIgnoreCase))\n        {\n            type = type?.ToLowerInvariant().Trim() ?? \"\";\n            if (type.Equals(AssetTemplates.TypeToken, InvariantCultureIgnoreCase))\n                defId = AssetTemplates.Token.Key;\n        }\n\n        return new()\n        {\n            Default = defId,\n            Templates = templateInfos\n        };\n    }\n\n    private AssetEditor GetAssetEditorOrThrowIfInsufficientPermissions(int appId, int templateId, bool global, string? path)\n    {\n        var l = Log.Fn<AssetEditor>($\"{appId}, {templateId}, {global}, {path}\");\n        var app = appReaders.Get(appId);\n        var assetEditor = assetEditorGenerator.New();\n\n        assetEditor.Init(app, path! /* not sure about this, but ignore for now 2026-06-23 2dm */, global, templateId);\n        assetEditor.EnsureUserMayEditAssetOrThrow();\n        return l.Return(assetEditor);\n    }\n\n    private AssetEditor GetAssetEditorOrThrowIfInsufficientPermissions(AppFileDto assetFromTemplateDto)\n    {\n        var l = Log.Fn<AssetEditor>($\"a#{assetFromTemplateDto.AppId}, path:{assetFromTemplateDto.Path}, global:{assetFromTemplateDto.Global}, key:{assetFromTemplateDto.TemplateKey}\");\n        var app = appReaders.Get(assetFromTemplateDto.AppId);\n        var assetEditor = assetEditorGenerator.New().Init(app, assetFromTemplateDto.Path, assetFromTemplateDto.Global, 0);\n        assetEditor.EnsureUserMayEditAssetOrThrow(assetEditor.InternalPath);\n        return l.Return(assetEditor);\n    }\n\n    public TemplatePreviewDto Preview(int appId, string path, string templateKey, bool b)\n    {\n        var l = Log.Fn<TemplatePreviewDto>($\"create a#{appId}, path:{path}, global:{b}, key:{templateKey}\");\n\n        try\n        {\n            var assetFromTemplateDto = new AppFileDto\n            {\n                AppId = appId,\n                Path = path?.Replace(\"/\", \"\\\\\") ?? string.Empty,\n                Global = b,\n                TemplateKey = templateKey,\n            };\n\n            assetFromTemplateDto = EnsureRequiredFolder(assetFromTemplateDto);\n\n            // check if file can be created\n            var assetEditor = GetAssetEditorOrThrowIfInsufficientPermissions(assetFromTemplateDto);\n\n            // check if file already exists\n            if (assetEditor.SanitizeFileNameAndCheckIfAssetAlreadyExists())\n                return l.Return(new() { Error = \"Asset already exists.\" }, \"GetPreview\");\n\n            // get and prepare template content\n            var templatePreviewDto = new TemplatePreviewDto\n            {\n                Preview = GetTemplateContent(assetFromTemplateDto)\n            };\n            return l.Return(templatePreviewDto);\n        }\n        catch (Exception e)\n        {\n            return l.Return(new() { Error = e.Message }, \"GetPreview\");\n        }\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/AppFilesControllerReal_ApiExplorer.cs",
    "content": "﻿using System.Reflection;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.ApiExplorer;\nusing ToSic.Sxc.Code.Sys.HotBuild;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Admin.AppFiles;\n\npartial class AppFilesControllerReal : Eav.WebApi.Sys.Admin.IAppExplorerControllerDependency\n{\n    /// <summary>\n    /// Get all api controller files from AppCode for all editions\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <returns>used by ApiExplorerControllerReal.AppApiFiles</returns>\n    [PrivateApi]\n    public ICollection<AllApiFileDto> AllApiFilesInAppCodeForAllEditions(int appId)\n    {\n        var l = Log.Fn<List<AllApiFileDto>>($\"list all in AppCode a#{appId}\");\n\n        const string mask = $\"*{EavConstants.ApiControllerSuffix}.cs\";\n\n        var appPath = ResolveAppPath(appId, global: false);\n        var app = appReaders.Get(appId).Specs;\n        var editions = codeController.Value.GetEditions(appId).Editions;\n        l.A($\"{nameof(app.Folder)}:'{app.Folder}', appPath:'{appPath}', editions:{editions.Count}\");\n\n        List<AllApiFileDto> appCodeApiControllerFiles = [];\n        foreach (var editionDto in editions)\n        {\n            var edition = editionDto.Name;\n            l.A($\"collect ApiController files in AppCode for edition:'{edition}'\");\n\n            if (!Directory.Exists(Path.Combine(appPath, edition, FolderConstants.AppCodeFolder)))\n            {\n                l.A($\"edition:'{edition}' folder or '{FolderConstants.AppCodeFolder}' subfolder do not exist in app\");\n                continue;\n            }\n\n            Assembly? appCodeAssembly = null;\n            try\n            {\n                // get AppCode assembly\n                var spec = new HotBuildSpec(appId, edition: edition, app.Folder, app.RuntimeKey);\n                l.A($\"{spec}\");\n                var (result, _) = appCodeLoader.Value.GetAppCode(spec);\n                appCodeAssembly = result?.Assembly;\n            }\n            catch (Exception e)\n            {\n                l.Ex(e);\n            }\n            l.A($\"has appCode assembly:{appCodeAssembly != null}\");\n\n            var codeApiControllerFiles = ApiControllerFilesInAppCode(mask, appPath, edition, appCodeAssembly);\n            l.A($\"ApiController files in AppCode for edition:'{edition}': {codeApiControllerFiles.Count}\");\n\n            appCodeApiControllerFiles.AddRange(\n                codeApiControllerFiles\n                    .Select(f => new AllApiFileDto\n                    {\n                        Path = f,\n                        EndpointPath = ApiExplorerControllerReal.AppCodeEndpointPath(edition, Path.GetFileNameWithoutExtension(f)),\n                        IsCompiled = true,\n                        Edition = edition\n                    })\n            );\n        }\n\n        return l.Return(appCodeApiControllerFiles, $\"ok, count:{appCodeApiControllerFiles.Count}\");\n    }\n\n    private ICollection<string> ApiControllerFilesInAppCode(string mask, string appPath, string edition, Assembly? appCodeAssembly)\n    {\n        var l = Log.Fn<ICollection<string>>(\n            $\"list ApiController files, {nameof(mask)}:'{mask}', {nameof(appPath)}:'{appPath}', {nameof(edition)}:'{edition}', has appCode assembly:{appCodeAssembly != null}\");\n\n        // 1. Check for AppCode assembly\n        if (appCodeAssembly == null)\n            return l.Return([], \"nothing to do, AppCode assembly is missing\");\n\n        // 2. Check for AppCode directory\n        var fullPath = Path.Combine(appPath, edition, FolderConstants.AppCodeFolder);\n        // if the edition directory doesn't exist, optional fallback to root edition AppCode\n        if (!Directory.Exists(fullPath))\n        {\n            l.A($\"AppCode folder do not exist on fullPath:'{fullPath}'\");\n\n            // if is root edition, then nothing to do\n            if (string.IsNullOrEmpty(edition))\n                return l.Return([], \"nothing to do, root edition AppCode folder do not exits\");\n\n            // fallback to root edition AppCode\n            fullPath = Path.Combine(appPath, FolderConstants.AppCodeFolder);\n            l.A($\"fallback to root edition AppCode:'{fullPath}'\");\n\n            // if the root edition directory doesn't exist, then nothing to do\n            if (!Directory.Exists(fullPath))\n                return l.Return([], \"nothing to do, fallback root edition AppCode folder do not exits\");\n        }\n\n        // try to collect all files, ignoring long paths errors and similar etc.\n        var di = new DirectoryInfo(fullPath);\n        var (_, files) = FullDirList(di, mask, withSubfolders: true); // List that will hold the files and sub-files in path\n\n        // ApiController files with subfolders, when has its type in AppCode assembly\n        var filesAfterCheck = files\n            .Where(f => CheckForControllerTypeInAppCodeAssembly(Path.GetFileNameWithoutExtension(f.Name), appCodeAssembly));\n        var apiControllerFilesInAppCode = filesAfterCheck\n            .Select(f => f.FullName)\n            .Select(p => EnsurePathMayBeAccessed(p, appPath, user.IsSystemAdmin)) // do another security check\n            .Select(x => x.Replace(appPath + \"\\\\\", \"\")) // truncate / remove internal server root path\n            .Select(x => x.ForwardSlash()) // tip the slashes to web-convention (old template entries used \"\\\")\n            .ToListOpt();\n\n        return l.Return(apiControllerFilesInAppCode, $\"ok, count:{apiControllerFilesInAppCode.Count}\");\n    }\n\n    private bool CheckForControllerTypeInAppCodeAssembly(string controllerTypeName, Assembly appCodeAssembly)\n    {\n        var l = Log.Fn<bool>($\"({nameof(controllerTypeName)}:'{controllerTypeName}'\");\n\n        // Check if name ends with \"Controller\" - if not, then no need to look in assembly\n        return controllerTypeName.EndsWith(EavConstants.ApiControllerSuffix, StringComparison.OrdinalIgnoreCase)\n            ? l.ReturnTrue($\"'{controllerTypeName}' does not end with '{EavConstants.ApiControllerSuffix}'\")\n            : l.ReturnAndLog(appCodeAssembly.FindControllerTypeByName(controllerTypeName) != null);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/AppFilesControllerReal_Directory.cs",
    "content": "﻿using ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Backend.Admin.AppFiles;\n\npartial class AppFilesControllerReal\n{\n    private readonly string _appCodeFolder = $\"{Path.DirectorySeparatorChar}{FolderConstants.AppCodeFolder}{Path.DirectorySeparatorChar}\".ToLower();\n\n    private (List<DirectoryInfo> Folders, List<FileInfo> Files) FullDirList(DirectoryInfo dir, string searchPattern, bool withSubfolders, int level = 0)\n    {\n        var l = Log.Fn<(List<DirectoryInfo> Folders, List<FileInfo> Files)>($\"'{dir.FullName}', '{searchPattern}', {nameof(withSubfolders)}: {withSubfolders}, level:{level}\");\n\n        // detect special case when searching for api controller files\n        var isApiControllerSearch = searchPattern.Equals($\"*{EavConstants.ApiControllerSuffix}.cs\", StringComparison.OrdinalIgnoreCase);\n\n        List<DirectoryInfo> folders = [];\n        List<FileInfo> files = [];\n\n        // list the files\n        try\n        {\n            if (!isApiControllerSearch\n                || (EavConstants.Api.Equals(dir.Name, StringComparison.OrdinalIgnoreCase) // controller files in \"api\" folder\n                    || FolderConstants.AppCodeFolder.Equals(dir.Name, StringComparison.OrdinalIgnoreCase) // controller files directly in \"AppCode\" folder\n                    || dir.FullName.ToLower().Contains(_appCodeFolder) // controller files in any \"AppCode\" subfolder\n                    )\n                )\n                foreach (var f in dir.GetFiles(searchPattern))\n                    try\n                    {\n                        files.Add(f);\n                    }\n                    catch\n                    {\n                        // ignored\n                    }\n        }\n        catch\n        {\n            // We already got an error trying to access dir so don't try to access it again\n            return l.Return((folders, files), $\"files:{files.Count}, folders:{folders.Count}\");\n        }\n\n        // process each directory\n        // If I have been able to see the files in the directory I should also be able \n        // to look at its directories, so I don't think I should place this in a try catch block\n        if (!withSubfolders)\n            return l.Return((folders, files), $\"files:{files.Count}, folders:{folders.Count}\");\n\n        foreach (var d in dir.GetDirectories())\n        {\n            try\n            {\n                // todo: possibly re-include subfolders with \".data\"\n                if (Settings.ExcludeFolders.Contains(d.Name))\n                    continue;\n                \n                if (isApiControllerSearch)\n                {\n                    //  we need to skip \"AppCode\" because it is handled differently in AllApiControllerFilesInAppCodeForAllEditions\n                    if (FolderConstants.AppCodeFolder.Equals(d.Name, StringComparison.OrdinalIgnoreCase))\n                        continue;\n\n                    // we skip any folder that is deeper more than 2 levels (except \"AppCode\" and its subfolders),\n                    // because \"api\" folder can't be deeper than 2 levels\n                    // 2025-09-02 2dm - changed this, because extensions in the 'AppCode/System' folder will have a deeper structure\n                    if (level > 1 && !d.FullName.Contains($\"{FolderConstants.AppCodeFolder}{Path.DirectorySeparatorChar}System\", StringComparison.InvariantCultureIgnoreCase))\n                        continue; // level is zero based\n                }\n\n                folders.Add(d);\n                var (newFolders, newFiles) = FullDirList(d, searchPattern, withSubfolders, level + 1);\n                folders.AddRange(newFolders);\n                files.AddRange(newFiles);\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n        return l.Return((folders, files), $\"files:{files.Count}, folders:{folders.Count}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/AppFilesControllerReal_List.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Admin.AppFiles;\n\npartial class AppFilesControllerReal\n{\n    public ICollection<string> All(int appId, bool global, string? path = null, string mask = \"*.*\", bool withSubfolders = false, bool returnFolders = false)\n    {\n        var l = Log.Fn<ICollection<string>>(\n            $\"list a#{appId}, {nameof(global)}:{global}, {nameof(path)}:'{path}', {nameof(mask)}:'{mask}', withSub:{withSubfolders}, {nameof(returnFolders)}:{returnFolders}\"\n        );\n\n        // set global access security if ok...\n        if (global && !user.IsSystemAdmin)\n            throw l.Ex(new NotSupportedException(\"only host user may access global files\"));\n\n        // make sure the folder-param is not null if it's missing\n        if (string.IsNullOrEmpty(path))\n            path = \"\";\n        var appPath = ResolveAppPath(appId, global);\n        var fullPath = Path.Combine(appPath, path);\n        l.A($\"fullPath:'{fullPath}'\");\n\n        // make sure the resulting path is still inside 2sxc\n        if (!user.IsSystemAdmin && !fullPath.Contains(\"2sxc\"))\n            throw l.Ex(new DirectoryNotFoundException(\"the folder is not inside 2sxc-scope any more and the current user doesn't have the permissions - must cancel\"));\n\n        // if the directory doesn't exist, return empty list\n        if (!Directory.Exists(fullPath))\n            return l.Return([], \"directory doesn't exist\");\n\n        // try to collect all files, ignoring long paths errors and similar etc.\n        var di = new DirectoryInfo(fullPath);\n        var (folders, files) = FullDirList(di, mask, withSubfolders); // List that hold directories that cannot be accessed\n\n        // List that will hold the files and sub-files in path\n        // return folders or files (depending on setting) with/without subfolders\n        var all = (returnFolders\n            ? folders.Select(f => f.FullName)\n            : files.Select(f => f.FullName)\n            )\n            .Select(p => EnsurePathMayBeAccessed(p, appPath, user.IsSystemAdmin))  // do another security check\n            .Select(x => x.Replace(appPath + \"\\\\\", \"\"))           // truncate / remove internal server root path\n            .Select(x => x.ForwardSlash()) // tip the slashes to web-convention (old template entries used \"\\\")\n            .ToListOpt();\n\n        return l.Return(all, $\"ok, count:{all.Count}\");\n    }\n\n    public AllFilesDto AppFiles(int appId, string? path, string? mask)\n    {\n        mask = mask ?? \"*.*\";\n        var l = Log.Fn<AllFilesDto>($\"list all files a#{appId}, path:'{path}', mask:'{mask}'\");\n\n        var localFiles =\n            All(appId, global: false, path: path, mask: mask, withSubfolders: true, returnFolders: false)\n                .Select(f => new AllFileDto { Path = f }).ToArray();\n        l.A($\"local files:{localFiles.Length}\");\n\n        var globalFiles = user.IsSystemAdmin\n            ? All(appId, global: true, path: path, mask: mask, withSubfolders: true, returnFolders: false)\n                .Select(f => new AllFileDto { Path = f, Shared = true }).ToArray()\n            : [];\n        l.A($\"global files:{globalFiles.Length}\");\n\n        return l.ReturnAsOk(new() { Files = localFiles.Union(globalFiles) });\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/AppFilesControllerReal_Path.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys;\n\nnamespace ToSic.Sxc.Backend.Admin.AppFiles;\n\npartial class AppFilesControllerReal\n{\n    private string ResolveAppPath(int appId, bool global) =>\n        (\n            _appPaths ??= appPathsFactoryTemp.Get(appReaders.Get(appId), site)\n        )\n        .PhysicalPathSwitch(global);\n    private IAppPaths? _appPaths;\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/AppFilesControllerReal_Security.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys.EditAssets;\n\nnamespace ToSic.Sxc.Backend.Admin.AppFiles;\n\npartial class AppFilesControllerReal\n{\n    private string? GetTemplateContent(AppFileDto assetFromTemplateDto)\n    {\n        var name = Path.GetFileName(assetFromTemplateDto.Path);\n        var ext = Path.GetExtension(assetFromTemplateDto.Path);\n        var nameWithoutExt = name.Substring(0, name.Length - ext.Length);\n\n        var body = assetTemplates.GetTemplates()\n            .FirstOrDefault(t =>\n                t.Key.Equals(assetFromTemplateDto.TemplateKey, StringComparison.InvariantCultureIgnoreCase))\n            ?.Body;\n        return body?\n            .Replace(AssetTemplates.CsApiTemplateControllerName, nameWithoutExt)\n            .Replace(AssetTemplates.CsCodeTemplateName, nameWithoutExt)\n            .Replace(AssetTemplates.CsDataSourceName, nameWithoutExt);\n    }\n        \n\n    private string EnsurePathMayBeAccessed(string p, string appPath, bool allowFullAccess)\n    {\n        if (appPath == null)\n            throw new ArgumentNullException(nameof(appPath));\n        // security check, to ensure no results leak from outside the app\n\n        if (!allowFullAccess && !p.StartsWith(appPath))\n            throw new DirectoryNotFoundException(\"Result was not inside the app any more - must cancel\");\n        return p;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/IAppFilesController.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys.EditAssets;\n\nnamespace ToSic.Sxc.Backend.Admin.AppFiles;\n\npublic interface IAppFilesController\n{\n    ICollection<string> All(int appId, bool global, string? path = null, string mask = \"*.*\", bool withSubfolders = false, bool returnFolders = false);\n\n    /// <summary>\n    /// Get details and source code\n    /// </summary>\n    /// <param name=\"templateId\"></param>\n    /// <param name=\"global\">this determines, if the app-file store is the global in _default or the local in the current app</param>\n    /// <param name=\"path\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    AssetEditInfo Asset(int appId, \n        int templateId = 0, string? path = null, // identifier is always one of these two\n        bool global = false);\n\n    /// <summary>\n    /// Update an asset with POST\n    /// </summary>\n    /// <param name=\"template\"></param>\n    /// <param name=\"templateId\"></param>\n    /// <param name=\"global\">this determines, if the app-file store is the global in _default or the local in the current app</param>\n    /// <param name=\"path\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    bool Asset(\n        int appId, \n        AssetEditInfo template,\n        int templateId = 0, \n        string? path = null, // identifier is either template Id or path\n        // todo w/SPM - global never seems to be used - must check why and if we remove or add to UI\n        bool global = false);\n\n    /// <summary>\n    /// Create a new file (if it doesn't exist yet) and optionally prefill it with content\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"path\"></param>\n    /// <param name=\"global\">this determines, if the app-file store is the global in _default or the local in the current app</param>\n    /// <param name=\"templateKey\"></param>\n    /// <returns></returns>\n    bool Create(\n        int appId,\n        string path,\n        bool global,\n        string templateKey // as of 2021-12, all create calls include templateKey\n    );\n\n    /// <summary>\n    /// Get all asset template types\n    /// </summary>\n    /// <param name=\"purpose\">filter by Purpose when provided</param>\n    /// <returns></returns>\n    TemplatesDto GetTemplates(string? purpose = null, string? type = null);\n\n    TemplatePreviewDto Preview(int appId, string path, string templateKey, bool global = false);\n\n    AllFilesDto AppFiles(int appId, string? path = null, string? mask = null);\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppFiles/TemplatesDto.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys.EditAssets;\n\nnamespace ToSic.Sxc.Backend.Admin.AppFiles;\n\npublic class TemplatesDto\n{\n    public required string Default { get; set; }\n    public required List<TemplateInfo> Templates;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/AppPartsControllerReal.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Sxc.Backend.ImportExport;\nusing Services_ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppPartsControllerReal(\n    LazySvc<IContextOfSite> context,\n    LazySvc<ExportContent> exportContent,\n    Generator<ImportContent> importContent)\n    : Services_ServiceBase(\"Api.APartsRl\", connect: [context, exportContent, importContent]), IAppPartsController\n{\n    public const string LogSuffix = \"AParts\";\n\n\n    #region Parts Export/Import\n\n    /// <inheritdoc />\n    public ExportPartsOverviewDto Get(int zoneId, int appId, string scope) => exportContent.Value.PreExportSummary(zoneId: zoneId, appId: appId, scope: scope);\n\n\n    /// <inheritdoc />\n    public THttpResponseType Export(int zoneId, int appId, string contentTypeIdsString, string entityIdsString, string templateIdsString)\n        => exportContent.Value.Export(zoneId: zoneId, appId: appId, contentTypeIdsString: contentTypeIdsString, entityIdsString: entityIdsString, templateIdsString: templateIdsString);\n\n\n    /// <summary>\n    /// This method is not implemented for ControllerReal, because ControllerReal implements Import(HttpUploadedFile uploadInfo, int zoneId, int appId)\n    /// </summary>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"NotImplementedException\"></exception>\n    public ImportResultDto Import(int zoneId, int appId)\n    {\n        throw new NotImplementedException();\n    }\n\n\n    /// <summary>\n    /// This implementation is special ControllerReal, instead of ImportResultDto Import(int zoneId, int appId) that is not implemented.\n    /// </summary>\n    /// <param name=\"uploadInfo\"></param>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"ArgumentException\"></exception>\n    public ImportResultDto Import(HttpUploadedFile uploadInfo, int zoneId, int appId)\n    {\n        var l = Log.Fn<ImportResultDto>();\n\n        if (!uploadInfo.HasFiles()) \n            return l.Return(new(false, \"no file uploaded\"), \"no file uploaded\");\n\n        var (fileName, stream) = uploadInfo.GetStream(0);\n\n        var result = importContent.New()\n            .Import(zoneId: zoneId, appId: appId, fileName: fileName, stream: stream!, defaultLanguage: context.Value.Site.DefaultCultureCode);\n\n        return l.ReturnAsOk(result);\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/CodeControllerReal.cs",
    "content": "﻿using System.Reflection;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sxc.Code.Sys.Documentation;\nusing ToSic.Sys.Utils;\nusing ToSic.Sys.Utils.Assemblies;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CodeControllerReal(FileSaver fileSaver, LazySvc<IEnumerable<IFileGenerator>> generators, LazySvc<IAppJsonConfigurationService> appJsonService, LazySvc<IAppReaderFactory> appReaders) \n    : ServiceBase(\"Api.CodeRl\", connect: [appJsonService, appReaders])\n{\n    public const string LogSuffix = \"Code\";\n    private const string DataCopilotConfigurationContentType = \"DataCopilotConfiguration\";\n\n    public class HelpItem\n    {\n        // the name of the class\n        public required string Term { get; set; }\n        // message from the attribute\n        public required string[] Help { get; set; }\n    }\n\n    public IEnumerable<HelpItem> InlineHelp(string language)\n    {\n        var l = Log.Fn<IEnumerable<HelpItem>>($\"InlineHelp:l:{language}\", timer: true);\n\n        if (_inlineHelp != null)\n            return l.ReturnAsOk(_inlineHelp);\n\n        // TODO: stv# how to use languages?\n\n        try\n        {\n            _inlineHelp = AssemblyHandling.GetTypes(Log)\n                .Where(t => t != null!)\n                .Where(t => t.IsDefined(typeof(DocsAttribute)))\n                .Select(t => new HelpItem\n                {\n                    Term = t.Name,\n                    Help = t.GetCustomAttribute<DocsAttribute>()?.GetMessages(t.FullName) ?? []\n                })\n                .ToArray();\n            return l.ReturnAsOk(_inlineHelp);\n        }\n        catch (Exception e)\n        {\n            l.A(\"Exception in inline help.\");\n            l.Ex(e);\n            return l.ReturnAsError([]);\n        }\n    }\n    private static IEnumerable<HelpItem>? _inlineHelp;\n\n    public RichResult GenerateDataModels(int appId, string? edition, string generator, int configurationId = 0)\n    {\n        var l = Log.Fn<RichResult>($\"{nameof(appId)}:{appId};{nameof(edition)}:{edition}\", timer: true);\n\n        try\n        {\n            // Determine the specs to generate with\n            var specs = new FileGeneratorSpecs\n            {\n                AppId = appId,\n                Edition = edition ?? \"\"\n            };\n\n            var generatorName = generator;\n            if (configurationId > 0)\n            {\n                var configuration = appReaders.Value.Get(appId).List.GetOne(configurationId);\n                if (configuration == null)\n                    return l.Return(new RichResult\n                        {\n                            Ok = false,\n                            Message = $\"Configuration '{configurationId}' not found in app '{appId}'.\",\n                        }\n                        .WithTime(l)\n                    );\n\n                // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n                if (!DataCopilotConfigurationContentType.EqualsInsensitive(configuration.Type?.Name))\n                    return l.Return(new RichResult\n                        {\n                            Ok = false,\n                            Message = $\"Configuration '{configurationId}' is not a '{DataCopilotConfigurationContentType}' entity.\",\n                        }\n                        .WithTime(l)\n                    );\n\n                var configuredGenerator = Sanitize(configuration.Get<string>(\"CodeGenerator\"));\n                if (configuredGenerator.HasValue())\n                    generatorName = configuredGenerator;\n\n                specs = specs with\n                {\n                    Configuration = $\"{configurationId} {configuration.GetBestTitle()}\",\n                    Namespace = Sanitize(configuration.Get<string>(\"Namespace\")),\n                    TargetPath = Sanitize(configuration.Get<string>(\"TargetFolder\")),\n                    ContentTypes = Normalize(configuration.Get<string>(\"ContentTypes\")),\n                    Prefix = Sanitize(configuration.Get<string>(\"Prefix\")),\n                    Suffix = Sanitize(configuration.Get<string>(\"Suffix\")),\n                    Edition = Sanitize(configuration.Get<string>(\"Edition\")) ?? edition,\n                };\n            }\n\n            // find the generator\n            var gen = generators.Value.FirstOrDefault(g => g.Name == generatorName);\n            if (gen == null)\n                return l.Return(new RichResult\n                    {\n                        Ok = false,\n                        Message = $\"Generator '{generatorName}' not found.\",\n                    }\n                    .WithTime(l)\n                );\n\n            // Make sure the generator has the logger - if supported\n            (gen as IHasLog)?.LinkLog(Log);\n\n            // generate and save files\n            fileSaver.GenerateAndSaveFiles(gen, specs);\n\n            return l.Return(new RichResult\n                {\n                    Ok = true,\n                    Message = $\"Data models generated in {specs.Edition}/{specs.TargetPath ?? \"AppCode/Data\"}.\",\n                }\n                .WithTime(l)\n            );\n        }\n        catch (Exception e)\n        {\n            return l.Return(new RichResult\n                {\n                    Ok = false,\n                    Message = $\"Error generating data models in {edition}/AppCode/Data. {e.GetType().FullName} - {e.Message}\",\n                }\n                .WithTime(l)\n            );\n        }\n    }\n\n    private static string? Sanitize(string? value) => value.HasValue() ? value?.Trim() : null;\n\n    private static ICollection<string>? Normalize(string? raw)\n    {\n        var cleaned = Sanitize(raw);\n        return cleaned == null ? null : Normalize([cleaned]);\n    }\n\n    private static ICollection<string>? Normalize(IEnumerable<string>? raw)\n    {\n        if (raw == null)\n            return null;\n\n        var cleaned = raw\n            .SelectMany(item => item?\n                .Split([',', ';', '\\n', '\\r'], StringSplitOptions.RemoveEmptyEntries)\n                ?? [])\n            .Where(item => !string.IsNullOrWhiteSpace(item))\n            .Select(item => item.Trim())\n            .Distinct(StringComparer.OrdinalIgnoreCase)\n            .ToList();\n\n        return cleaned.Any() ? cleaned : null;\n    }\n\n    // #MigrateSimpleDataToSysDataAccess\n    // TODO: @STV this is not used the way it was intended anymore.\n    // Pls\n    // - slim down to only provide Editions (which is the only thing still used)\n    // - consider moving that functionality away from this controller - either standalone or elsewhere\n    public EditionsDto GetEditions(int appId)\n    {\n        var l = Log.Fn<EditionsDto>($\"{nameof(appId)}:{appId}\");\n\n        // get generators\n        var fileGenerators = generators.Value\n            .Select(g => new GeneratorDto(g))\n            .ToListOpt();\n\n        var appJson = appJsonService.Value.GetAppJson(appId);\n        // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n        if (appJson?.Editions?.Count > 0)\n        {\n            l.A($\"has editions in app.json: {appJson.Editions.Count}\");\n            return l.ReturnAsOk(appJson.ToEditionsDto(fileGenerators));\n        }\n\n        l.A(\"editions are not specified, so using default edition data\");\n        // default data\n        var nothingSpecified = new EditionsDto\n        {\n            Ok = true,\n            IsConfigured = false,\n            Editions = [ new() { Name = \"\", Description = \"Root edition\", IsDefault = true } ],\n            Generators = fileGenerators\n        };\n\n        return l.Return(nothingSpecified, \"editions not specified in app.json\");\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/DataControllerReal.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Persistence.File;\nusing ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Eav.Security.Files;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Eav.WebApi.Sys.Security;\nusing ToSic.Sxc.Backend.ImportExport;\nusing ToSic.Sys.Users;\nusing Services_ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DataControllerReal(\n    ISite site,\n    IAppPathsMicroSvc appPathSvc,\n    AppWorkContextService appWorkCtxSvc,\n    LazySvc<IContextOfSite> context,\n    LazySvc<ContentExportApi> contentExportLazy,\n    Generator<ImportContent> importContent,\n    LazySvc<IUser> userLazy,\n    GenWorkDb<WorkEntityRecycle> recycle)\n    : Services_ServiceBase(\"Api.DtaCtlRl\",\n        connect: [site, appPathSvc, appWorkCtxSvc, context, contentExportLazy, importContent, userLazy, recycle])/*, IAdminDataController*/\n{\n    public const string LogSuffix = \"DataCtrl\";\n\n    public THttpResponseType BundleExport(int appId, Guid exportConfiguration, int indentation)\n        => contentExportLazy.Value.Init(appId).JsonBundleExport(userLazy.Value, exportConfiguration, indentation);\n\n    public ImportResultDto BundleImport(HttpUploadedFile uploadInfo, int zoneId, int appId)\n    {\n        var l = Log.Fn<ImportResultDto>();\n\n        SecurityHelpers.ThrowIfNotSiteAdmin(userLazy.Value, l);\n\n        if (!uploadInfo.HasFiles())\n            return l.Return(new(false, \"no file uploaded\", Message.MessageTypes.Error), \"no file uploaded\");\n\n        var streams = new List<FileUploadDto>();\n        for (var i = 0; i < uploadInfo.Count; i++)\n        {\n            var (fileName, stream) = uploadInfo.GetStream(i);\n            streams.Add(new() { Name = fileName, Stream = stream! });\n        }\n        var result = importContent.New()\n            .ImportJsonFiles(zoneId, appId, streams, context.Value.Site.DefaultCultureCode);\n\n        return l.ReturnAsOk(result);\n    }\n\n    public bool BundleSave(int appId, Guid exportConfiguration, int indentation = 0)\n        => contentExportLazy.Value.Init(appId).BundleSave(userLazy.Value, exportConfiguration, indentation);\n\n    public bool BundleRestore(string fileName, int zoneId, int appId)\n    {\n        var l = Log.Fn<bool>();\n\n        SecurityHelpers.ThrowIfNotSiteAdmin(userLazy.Value, l);\n\n        var fileNameSafe = FileNames.SanitizeFileName(fileName);\n        if (fileName != fileNameSafe) l.A($\"File name sanitized:'{fileName}' => '{fileNameSafe}'\");\n\n        var appPaths = appPathSvc.Get(appWorkCtxSvc.Context(appId).AppReader, site);\n        var filePath = Path.Combine(appPaths.PhysicalPath, FolderConstants.DataFolderProtected, AppDataFoldersConstants.BundlesFolder, fileNameSafe);\n\n        if (!File.Exists(filePath))\n            return l.ReturnFalse($\"File not found: {filePath}\");\n\n        var result = importContent.New()\n            .ImportJsonFiles(zoneId, appId, [new() { Name = fileName, Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read) }], context.Value.Site.DefaultCultureCode);\n\n        var message = string.Join(\", \", result.Messages.Select(m => m.Text));\n\n        return l.Return(result.Success, message);\n    }\n\n    public void Recycle(int appId, int transactionId)\n    {\n        var l = Log.Fn($\"appId:{appId}, tx:{transactionId}\");\n\n        recycle\n            .New(appId)\n            .Recycle(transactionId);\n\n        l.Done();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/DialogControllerReal.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Sys;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class DialogControllerReal(\n    ISxcCurrentContextService ctxService,\n    IUiContextBuilder uiContextBuilder,\n    Generator<MultiPermissionsApp, MultiPermissionsApp.Options> appPermissions)\n    : ServiceBase($\"{EavLogs.WebApi}.{LogSuffix}Rl\", connect: [ctxService, uiContextBuilder, appPermissions]),\n        IDialogController\n{\n    public const string LogSuffix = \"Dialog\";\n\n    ///<inheritdoc />\n    public DialogContextStandaloneDto Settings(int appId)\n    {            \n        // reset app-id if we get a info-token like -100\n        if (appId < 0)\n            appId = KnownAppsConstants.AppIdEmpty;\n\n        var appContext = appId != KnownAppsConstants.AppIdEmpty\n            ? ctxService.GetExistingAppOrSet(appId)\n            : null;\n\n        // if we have an appid (we don't have it in an install-new-apps-scenario) check permissions\n        if (appContext != null)\n        {\n            var appAndPerms = appPermissions.New(new() { SiteContext = appContext, App = appContext.AppReaderRequired });\n            if (!appAndPerms.ZoneIsOfCurrentContextOrUserIsSuper(out var error))\n                throw HttpException.PermissionDenied(error);\n        }\n\n        var cb = uiContextBuilder.InitApp(appContext?.AppReaderRequired);\n\n        return new()\n        {\n            Context = cb.Get(Ctx.General, CtxEnable.All),\n        };\n    }\n\n}\n\npublic class DialogContextStandaloneDto\n{\n    public required ContextDto Context { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/EditionsDto.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Sxc.Code.Generate.Sys;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n/// <summary>\n/// Used to serialize 'editions' to json for UI\n/// </summary>\npublic class EditionsDto: RichResult\n{\n    public bool IsConfigured { get; init; }\n    public ICollection<EditionDto> Editions { get; init; } = [];\n\n    public ICollection<GeneratorDto> Generators { get; init; } = [];\n}\n\npublic class EditionDto\n{\n    public required string Name { get; init; }\n    public string? Description { get; init; }\n\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]\n    public bool IsDefault { get; set; }\n}\n\npublic class GeneratorDto(IFileGenerator generator)\n{\n    public string Name => generator.Name;\n    public string Version => generator.Version;\n    public string Description => generator.Description;\n    public string DescriptionHtml => generator.DescriptionHtml;\n    public string OutputLanguage => generator.OutputLanguage;\n    public string OutputType => generator.OutputType;\n}\n\npublic static class EditionsJsonExtension\n{\n    public static EditionsDto ToEditionsDto(this AppJsonConfiguration appJson, ICollection<GeneratorDto> generators)\n        => new()\n        {\n            Ok = true,\n            IsConfigured = true,\n            Editions = appJson.Editions\n                .Select(e => new EditionDto\n                {\n                    Name = e.Key,\n                    Description = e.Value.Description,\n                    IsDefault = e.Value.IsDefault\n                })\n                .ToListOpt(),\n            Generators = generators\n        };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/ExtensionsDto.cs",
    "content": "using System.Text.Json.Serialization;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionsResultDto\n{\n    [JsonPropertyName(\"extensions\")]\n    public ICollection<ExtensionDto> Extensions { get; init; } = [];\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionDto\n{\n    [JsonPropertyName(\"folder\")]\n    public required string Folder { get; init; }\n\n    [JsonPropertyName(\"edition\")]\n    public required string Edition { get; init; } = \"\";\n\n    [JsonPropertyName(\"configuration\")]\n    public required ExtensionManifest Configuration { get; init; }\n\n    [JsonPropertyName(\"icon\")]\n    public string Icon { get; init; } = \"\";\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/IAdminDataController.cs",
    "content": "﻿\nnamespace ToSic.Sxc.Backend.Admin;\n\npublic interface IAdminDataController\n{\n    /// <summary>\n    /// Bundle Export\n    /// </summary>\n    THttpResponseType BundleExport(int appId, Guid exportConfiguration, int indentation = 0);\n\n    /// <summary>\n    /// Bundle Import\n    /// </summary>\n    ImportResultDto BundleImport(int zoneId, int appId);\n\n    /// <summary>\n    /// Bundle Save\n    /// </summary>\n    bool BundleSave(int appId, Guid exportConfiguration, int indentation = 0);\n\n    /// <summary>\n    /// Bundle Restore\n    /// </summary>\n    bool BundleRestore(string fileName, int zoneId, int appId);\n\n    ///// <summary>\n    ///// Return all history entries, which can be recycled\n    ///// </summary>\n    ///// <param name=\"appId\"></param>\n    ///// <returns></returns>\n    ///// <exception cref=\"NotImplementedException\"></exception>\n    //public IReadOnlyList<RecycleBinItem> GetRecycleBin(int appId);\n\n    /// <summary>\n    /// Recycle a specific item\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"transactionId\"></param>\n    /// <exception cref=\"NotImplementedException\"></exception>\n    void Recycle(int appId, int transactionId);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/IAppExtensionsController.cs",
    "content": "using ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Sxc.Backend.App;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n/// <summary>\n/// Controller interface for App Extensions endpoints separated from the main App controller.\n/// </summary>\npublic interface IAppExtensionsController\n{\n    /// <summary>\n    /// Get all App Extensions and their configuration (if any).\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <returns>Object with property \"extensions\" containing an array of extensions</returns>\n    ExtensionsResultDto Extensions(int appId);\n\n    /// <summary>\n    /// Preflight installation of an extension zip to report current state and options.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"editions\">Optional comma-delimited list of editions to install into (empty or null = root).</param>\n    PreflightResultDto InstallPreflight(int appId, string editions = \"\");\n\n    /// <summary>\n    /// Install app extension zip.\n    /// </summary>\n    /// <param name=\"zoneId\">Zone identifier</param>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"editions\">Optional comma-delimited list of editions to install into (empty or null = root).</param>\n    /// <param name=\"overwrite\">Overwrite existing files if true</param>\n    /// <returns>true if installation succeeded</returns>\n    bool Install(int zoneId, int appId, string editions = \"\", bool overwrite = false);\n\n    /// <summary>\n    /// Preflight installation of an extension zip downloaded from a URL.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"urls\">Remote URLs to extension packages (first is used)</param>\n    /// <param name=\"editions\">Optional comma-delimited list of editions to install into (empty or null = root).</param>\n    PreflightResultDto InstallPreflightFrom(int appId, string[] urls, string editions = \"\");\n\n    /// <summary>\n    /// Install app extension zip downloaded from a URL.\n    /// </summary>\n    /// <param name=\"zoneId\">Zone identifier</param>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"urls\">Remote URLs to extension packages (first is used)</param>\n    /// <param name=\"editions\">Optional comma-delimited list of editions to install into (empty or null = root).</param>\n    /// <param name=\"overwrite\">Overwrite existing files if true</param>\n    /// <returns>true if installation succeeded</returns>\n    bool InstallFrom(int zoneId, int appId, string[] urls, string editions = \"\", bool overwrite = false);\n\n    /// <summary>\n    /// Inspect endpoint.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"name\">Extension folder name</param>\n    /// <param name=\"edition\">Optional edition name</param>\n    ExtensionInspectResultDto Inspect(int appId, string name, string? edition = null);\n\n    /// <summary>\n    /// Create or replace the configuration of a specific App Extension.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"name\">Extension folder name under \"/extensions\"</param>\n    /// <param name=\"configuration\">JSON to write as App_Data/extension.json</param>\n    /// <returns>true if saved</returns>\n    bool Configuration(int appId, string name, ExtensionManifest configuration);\n\n    /// <summary>\n    /// Download (export) a specific extension as a ZIP file.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"name\">Extension folder name</param>\n    /// <returns>HTTP response containing the file data.</returns>\n    THttpResponseType Download(int appId, string name);\n\n    /// <summary>\n    /// Delete an extension and optionally its data.\n    /// </summary>\n    /// <param name=\"appId\">App identifier</param>\n    /// <param name=\"name\">Extension folder name</param>\n    /// <param name=\"edition\">Optional edition name</param>\n    /// <param name=\"force\">Force deletion even when files or data changed.</param>\n    /// <param name=\"withData\">Delete related data when true (requires force).</param>\n    /// <returns>true if deleted</returns>\n    bool Delete(int appId, string name, string? edition = null, bool force = false, bool withData = false);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/IDialogController.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Admin;\n\npublic interface IDialogController\n{\n    /// <summary>\n    /// This is the subsystem which delivers the getting-started app-iframe with instructions etc.\n    /// Used to be GET System/DialogSettings\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    DialogContextStandaloneDto Settings(int appId);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/IViewController.cs",
    "content": "﻿using ToSic.Sxc.Backend.Views;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n/// <summary>\n/// Provide information about views and manage views as needed.\n/// This should also work on Oqtane once released May the 4th 2021 :)\n/// </summary>\n/// <remarks>\n/// Because download JSON call is made in a new window, they won't contain any http-headers like module-id or security token. \n/// So we can't use the classic protection attributes to the class like:\n/// - [SupportedModules(\"2sxc,2sxc-app\")]\n/// - [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Admin)]\n/// - [ValidateAntiForgeryToken]\n/// Instead, each method must have all attributes, or do additional security checking.\n/// Security checking is possible, because the cookie still contains user information\n/// </remarks>\npublic interface IViewController\n{\n    /// <summary>\n    /// Get the views of this App\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    IEnumerable<ViewDetailsDto> All(int appId);\n\n    /// <summary>\n    /// Delete a View\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"id\"></param>\n    /// <returns></returns>\n    bool Delete(int appId, int id);\n\n    /// <summary>\n    /// Download / export a view as JSON to easily re-import into another App.\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"viewId\"></param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New in 2sxc 11.07\n    /// </remarks>\n    THttpResponseType Json(int appId, int viewId);\n\n    /// <summary>\n    /// Used to be POST ImportExport/ImportContent\n    /// </summary>\n    /// <remarks>\n    /// New in 2sxc 11.07\n    /// </remarks>\n    /// <returns></returns>\n    ImportResultDto Import(int zoneId, int appId);\n\n    /// <summary>\n    /// Get usage statistics for entities so the UI can guide the user\n    /// to find out if data is being used or if it can be safely deleted.\n    /// </summary>\n    /// <param name=\"appId\">App ID</param>\n    /// <param name=\"guid\">Guid of the Entity</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// New in 2sxc 11.11\n    /// </remarks>\n    IEnumerable<ViewDto> Usage(int appId, Guid guid);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/Query/QueryControllerReal.cs",
    "content": "﻿using ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Eav.WebApi.Sys;\nusing ToSic.Eav.WebApi.Sys.Admin.Query;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.LookUp.Sys;\n\nnamespace ToSic.Sxc.Backend.Admin.Query;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class QueryControllerReal(\n    QueryControllerBase.Dependencies services,\n    GenWorkPlus<WorkViews> workViews,\n    ISxcCurrentContextService currentContextService,\n    Generator<IAppDataConfigProvider> tokenEngineWithContext)\n    : QueryControllerBase(services, \"Api.\" + LogSuffix, connect: [workViews, currentContextService, tokenEngineWithContext])\n{\n    public const string LogSuffix = \"Query\";\n    public const string LogGroup = EavWebApiConstants.HistoryNameWebApi + \"-query\";\n\n    /// <summary>\n    /// Delete a Pipeline with the Pipeline Entity, Pipeline Parts and their Configurations.\n    /// Stops if the Pipeline Entity has relationships to other Entities or is in use in a 2sxc-Template.\n    /// </summary>\n    public bool DeleteIfUnused(int appId, int id)\n    {\n        var l = Log.Fn<bool>($\"{nameof(appId)}: {appId}; {nameof(id)}: {id}\");\n\n        // Stop if views still use this Query\n        var viewUsingQuery = workViews.New(appId)\n            .GetAll()\n            .Where(t => t.Query?.Id == id)\n            .Select(t => t.Id)\n            .ToArray();\n\n        if (viewUsingQuery.Any())\n            throw l.Done(new Exception($\"Query is used by Views and can't be deleted. Query ID: {id}. TemplateIds: {string.Join(\", \", viewUsingQuery)}\"));\n\n        var queryMod = Services.WorkUnitQueryMod.New(appId: appId);\n        return l.Return( queryMod.Delete(id));\n    }\n        \n\n\n    public QueryRunDto DebugStream(int appId, int id, string from, string @out, int top = 25) =>\n        DebugStream(appId, id, top, LookUpEngineWithBlockRequired(), from, @out);\n\n    /// <summary>\n    /// Query the Result of a Pipeline using Test-Parameters\n    /// </summary>\n    public QueryRunDto RunDev(int appId, int id, int top) =>\n        RunDevInternal(appId, id, LookUpEngineWithBlockRequired(), top, builtQuery => builtQuery.Main);\n\n    private ILookUpEngine LookUpEngineWithBlockRequired()\n    {\n        var block = currentContextService.BlockRequired();\n        var specs = new SxcAppDataConfigSpecs { BlockForLookupOrNull = block };\n        var lookUps = tokenEngineWithContext.New()\n            .GetDataConfiguration((SxcAppBase)block.App, specs)\n            .LookUpEngine;\n        return lookUps;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/ScopeDetailsDto.cs",
    "content": "﻿using System.Text.Json.Serialization;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\npublic class ScopeDetailsDto\n{\n    [JsonPropertyName(\"name\")]\n    public required string Name { get; set; }\n    [JsonPropertyName(\"label\")]\n    public required string Label { get; set; }\n    [JsonPropertyName(\"typesTotal\")]\n    public required int TypesTotal { get; set; }\n    [JsonPropertyName(\"typesOfApp\")]\n    public required int TypesOfApp { get; set; }\n    [JsonPropertyName(\"typesInherited\")]\n    public required int TypesInherited { get; set; }\n}\n\npublic class ScopesDto\n{\n    [JsonPropertyName(\"old\")]\n    public required IDictionary<string, string> Old { get; set; }\n    [JsonPropertyName(\"scopes\")]\n    public required List<ScopeDetailsDto> Scopes { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/TypeControllerReal.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Ancestors;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Eav.WebApi.Sys;\nusing ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Backend.ImportExport;\nusing ToSic.Sys.Users;\nusing Services_ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class TypeControllerReal(\n    LazySvc<IContextOfSite> context,\n    LazySvc<ContentTypeDtoService> ctApiLazy,\n    LazySvc<ContentExportApi> contentExportLazy,\n    GenWorkDb<WorkContentTypesMod> typeMod,\n    LazySvc<IUser> userLazy,\n    IAppReaderFactory appReaders,\n    Generator<ImportContent> importContent)\n    : Services_ServiceBase(\"Api.TypesRl\",\n        connect: [appReaders, context, ctApiLazy, contentExportLazy, userLazy, typeMod, importContent]), ITypeController\n{\n    public const string LogSuffix = \"Types\";\n\n\n    public IEnumerable<ContentTypeDto> List(int appId, string? scope = null, bool withStatistics = false)\n    {\n        var l = Log.Fn<IEnumerable<ContentTypeDto>>($\"{appId}, scope:{scope}, stats:{withStatistics}\");\n        var list = ctApiLazy.Value.List(appId, scope, withStatistics);\n        return l.Return(list);\n    }\n\n    /// <summary>\n    /// Used to be GET ContentTypes/Scopes\n    /// </summary>\n    public ScopesDto Scopes(int appId)\n    {\n        var l = Log.Fn<ScopesDto>($\"{appId}\");\n        var reader = appReaders.Get(appId);\n        var dic = reader.ContentTypes.GetAllScopesWithLabels();\n        var infos = dic\n            .Select(pair =>\n            {\n                var typesInScope = reader.ContentTypes\n                    .OfScope(pair.Key, includeAttributeTypes: true)\n                    .ToList();\n\n                var withAncestor = typesInScope\n                    .Where(AncestorExtensions.HasAncestor)\n                    .ToList();\n\n                var count = typesInScope.Count;\n                return new ScopeDetailsDto\n                {\n                    Name = pair.Key,\n                    Label = pair.Value ?? pair.Key,\n                    TypesTotal = count,\n                    TypesInherited = withAncestor.Count,\n                    TypesOfApp = count - withAncestor.Count\n                };\n            })\n            .ToList();\n        return l.Return(new() { Old = dic, Scopes = infos });\n    }\n\n    /// <summary>\n    /// Used to be GET ContentTypes/Scopes\n    /// </summary>\n    public ContentTypeDto Get(int appId, string contentTypeId, string? scope = null)\n        => ctApiLazy.Value.GetSingle(appId, contentTypeId, scope);\n\n\n    public bool Delete(int appId, string staticName)\n        => typeMod.New(appId).Delete(staticName);\n\n\n    // 2019-11-15 2dm special change: item to be Dictionary<string, object> because in DNN 9.4\n    // it causes problems when a content-type has additional metadata, where a value then is a deeper object\n    // in the future, the JS front-end should send something clearer and not the whole object\n    public bool Save(int appId, Dictionary<string, object>? item)\n    {\n        var l = Log.Fn<bool>();\n            \n        if (item == null)\n            return l.ReturnFalse(\"item was null, will cancel\");\n\n        var dic = item.ToDictionary(\n            i => i.Key,\n            i => i.Value?.ToString()\n        );\n        var result = typeMod.New(appId).AddOrUpdate(dic[\"StaticName\"]!, dic[\"Scope\"]!, dic[\"Name\"]!, null, false);\n            \n        return l.ReturnAndLog(result);\n    }\n\n    /// <summary>\n    /// Used to be GET ContentType/CreateGhost\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"sourceNameId\"></param>\n    /// <returns></returns>\n    public bool AddGhost(int appId, string sourceNameId)\n        => typeMod.New(appId).CreateGhost(sourceNameId);\n\n\n    public void SetTitle(int appId, int contentTypeId, int attributeId)\n        => typeMod.New(appId).SetTitle(contentTypeId, attributeId);\n\n    /// <summary>\n    /// Used to be GET ContentExport/DownloadTypeAsJson\n    /// </summary>\n    public THttpResponseType Json(int appId, string name)\n        => contentExportLazy.Value.Init(appId).DownloadTypeAsJson(userLazy.Value, name);\n\n    /// <summary>\n    /// This method is not implemented for ControllerReal, because ControllerReal implements Import(HttpUploadedFile uploadInfo, int zoneId, int appId)\n    /// </summary>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"NotSupportedException\"></exception>\n    public ImportResultDto Import(int zoneId, int appId)\n        => throw new NotSupportedException(\"This is not supported on ControllerReal, use overload.\");\n\n    /// <summary>\n    /// This implementation is special ControllerReal, instead of ImportResultDto Import(int zoneId, int appId) that is not implemented.\n    /// </summary>\n    /// <param name=\"uploadInfo\"></param>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"ArgumentException\"></exception>\n    public ImportResultDto Import(HttpUploadedFile uploadInfo, int zoneId, int appId)\n    {\n        var l = Log.Fn<ImportResultDto>();\n\n        if (!uploadInfo.HasFiles())\n            return l.Return(new(false, \"no file uploaded\", Message.MessageTypes.Error), \"no file uploaded\");\n\n        var streams = new List<FileUploadDto>();\n        for (var i = 0; i < uploadInfo.Count; i++)\n        {\n            var (fileName, stream) = uploadInfo.GetStream(i);\n            streams.Add(new() { Name = fileName, Stream = stream! });\n        }\n        var result = importContent.New()\n            .ImportJsonFiles(zoneId, appId, streams, context.Value.Site.DefaultCultureCode);\n\n        return l.ReturnAsOk(result);\n    }\n\n    /// <summary>\n    /// Used to be GET ContentExport/DownloadTypeAsJson\n    /// </summary>\n\n    public THttpResponseType JsonBundleExport(int appId, Guid exportConfiguration, int indentation)\n        => contentExportLazy.Value.Init(appId).JsonBundleExport(userLazy.Value, exportConfiguration, indentation);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Admin/ViewControllerReal.cs",
    "content": "﻿using ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Sxc.Backend.Usage;\nusing ToSic.Sxc.Backend.Views;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing Services_ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Backend.Admin;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ViewControllerReal(\n    LazySvc<IContextOfSite> context,\n    LazySvc<ViewsBackend> viewsBackend,\n    LazySvc<ViewsExportImport> viewExportImport,\n    LazySvc<UsageBackend> usageBackend)\n    : Services_ServiceBase(\"Api.ViewRl\", connect: [context, usageBackend, viewsBackend, viewExportImport]),\n        IViewController\n{\n    public const string LogSuffix = \"View\";\n\n    /// <inheritdoc />\n    public IEnumerable<ViewDetailsDto> All(int appId) => viewsBackend.Value.GetAll(appId);\n\n    /// <inheritdoc />\n    public bool Delete(int appId, int id) => viewsBackend.Value.Delete(appId, id);\n\n    /// <inheritdoc />\n    public THttpResponseType Json(int appId, int viewId) => viewExportImport.Value.DownloadViewAsJson(appId, viewId);\n\n    /// <summary>\n    /// This method is not implemented for ControllerReal, because ControllerReal implements Import(HttpUploadedFile uploadInfo, int zoneId, int appId)\n    /// </summary>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"NotImplementedException\"></exception>\n    public ImportResultDto Import(int zoneId, int appId) => throw new NotImplementedException();\n\n    /// <summary>\n    /// This implementation is special ControllerReal, instead of ImportResultDto Import(int zoneId, int appId) that is not implemented.\n    /// </summary>\n    /// <param name=\"uploadInfo\"></param>\n    /// <param name=\"zoneId\"></param>\n    /// <param name=\"appId\"></param>\n    /// <returns></returns>\n    /// <exception cref=\"ArgumentException\"></exception>\n    public ImportResultDto Import(HttpUploadedFile uploadInfo, int zoneId, int appId)\n    {\n        var l = Log.Fn<ImportResultDto>();\n            \n        if (!uploadInfo.HasFiles())\n            return l.Return(new(false, \"no file uploaded\", Message.MessageTypes.Error), \"no file uploaded\");\n\n        var streams = new List<FileUploadDto>();\n        for (var i = 0; i < uploadInfo.Count; i++)\n        {\n            var (fileName, stream) = uploadInfo.GetStream(i);\n            streams.Add(new() { Name = fileName, Stream = stream! });\n        }\n        var result = viewExportImport.Value.ImportView(zoneId, appId, streams, context.Value.Site.DefaultCultureCode);\n\n        return l.ReturnAsOk(result);\n    }\n\n    /// <inheritdoc />\n    public IEnumerable<ViewDto> Usage(int appId, Guid guid)\n    {\n        if (FinalBuilder == null)\n        {\n            Log.A(\"Error, FinalBuilder implementation is not set.\");\n            throw new ArgumentException(\"FinalBuilder implementation is not set.\");\n        }\n        return usageBackend.Value.ViewUsage(appId, guid, FinalBuilder);\n    }\n    public ViewControllerReal UsagePreparations(Func<ICollection<IView>, ICollection<BlockConfiguration>, IEnumerable<ViewDto>> finalBuilder)\n    {\n        FinalBuilder = finalBuilder;\n        return this;\n    }\n    private Func<ICollection<IView>, ICollection<BlockConfiguration>, IEnumerable<ViewDto>>? FinalBuilder { get; set; }\n\n    /// <summary>\n    /// Helper method to get SiteId for ControllerReal proxy class.\n    /// </summary>\n    public int SiteId => context.Value.Site.Id;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/ApiForBlockHelpers.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Backend;\ninternal static class ApiForBlockHelpers\n{\n    public static void ThrowIfNotAllowedInApp(this Generator<MultiPermissionsApp, MultiPermissionsApp.Options> multiPermissionsApp,\n        IContextOfBlock context,\n        List<Grants> requiredGrants,\n        IAppIdentity? alternateApp = null)\n    {\n        var permCheck = multiPermissionsApp.New(new() { SiteContext = context, App = alternateApp ?? context.AppReaderRequired });\n        if (!permCheck.EnsureAll(requiredGrants, out var error))\n            throw HttpException.PermissionDenied(error);\n    }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/AppCacheFlushSpecs.cs",
    "content": "namespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppCacheFlushSpecs\n{\n    // Null or empty means app-wide LightSpeed invalidation; otherwise only the named dependencies are touched.\n    public string[]? Dependencies { get; set; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/AppContent.cs",
    "content": "﻿using System.Text.Json;\nusing System.Text.Json.Nodes;\nusing ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.Metadata;\nusing ToSic.Eav.Metadata.Targets;\nusing ToSic.Eav.WebApi.Sys.App;\nusing ToSic.Eav.WebApi.Sys.Entities;\nusing ToSic.Sxc.Apps.Sys.Api01;\nusing ToSic.Sxc.Data.Sys.Convert;\nusing ToSic.Sys.OData;\nusing ToSic.Sys.Security.Permissions;\nusing ToSic.Sys.Utils;\nusing static ToSic.Eav.Apps.Sys.Api01.SaveApiAttributes;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppContent(\n    EntityApi api,\n    LazySvc<IConvertToEavLight> entToDicLazy,\n    ISxcCurrentContextService ctxService,\n    Generator<MultiPermissionsTypes, MultiPermissionsTypes.Options> typesPermissions,\n    Generator<MultiPermissionsItems, MultiPermissionsItems.Options> itemsPermissions,\n    GenWorkDb<WorkFieldList> workFieldList,\n    LazySvc<SimpleDataEditService> dataControllerLazy)\n    : ServiceBase(\"Sxc.ApiApC\",\n        connect:\n        [\n            workFieldList, api, entToDicLazy, ctxService, typesPermissions, itemsPermissions, dataControllerLazy\n        ])\n{\n    #region Constructor / DI\n\n    public AppContent Init(string? appName)\n    {\n        // if app-path specified, use that app, otherwise use from context\n        Context = ctxService.AppNameRouteBlock(appName);\n        return this;\n    }\n\n    protected IContextOfApp Context = null!;\n\n    protected IAppReader AppReader => Context?.AppReaderRequired ??\n                                   throw new(\"Can't access AppState before Context is ready. Did you forget to call Init(...)?\");\n\n    #endregion\n\n\n    #region Get Items\n\n    public IEnumerable<IDictionary<string, object>> GetItems(string contentType, string? appPath = default, Uri? fullRequest = null)\n    {\n        var l = Log.Fn<IEnumerable<IDictionary<string, object>>>($\"get entities type:{contentType}, path:{appPath}\");\n\n        // verify that read-access to these content-types is permitted\n        var permCheck = ThrowIfNotAllowedInType(contentType, GrantSets.ReadSomething, AppReader);\n\n        var includeDrafts = permCheck.EnsureAny(GrantSets.ReadDraft);\n        var result = api\n            .GetEntities(AppReader, contentType, includeDrafts, fullRequest)\n            .ToListOpt();\n        return l.Return(result, \"found: \" + result.Count);\n    }\n\n\n    #endregion\n\n    #region Get One \n\n    /// <summary>\n    /// Preprocess security / context, then get the item based on an passed in method, \n    /// ...then process/finish\n    /// </summary>\n    /// <returns></returns>\n    public IDictionary<string, object> GetOne(string contentType, Func<IEnumerable<IEntity>, IEntity> getOne, string? appPath, Uri? uri = null)\n    {\n        Log.A($\"get and serialize after security check type:{contentType}, path:{appPath}\");\n\n        // first try to find in all entities incl. drafts\n        var itm = getOne(AppReader.List);\n        var permCheck = ThrowIfNotAllowedInItem(itm, GrantSets.ReadSomething, AppReader);\n\n        // in case draft wasn't allow, get again with more restricted permissions \n        if (!permCheck.EnsureAny(GrantSets.ReadDraft))\n            itm = getOne(AppReader.GetListPublished());\n\n        return InitEavAndSerializer(AppReader.AppId, Context.Permissions.IsContentAdmin, uri).Convert(itm)!;\n    }\n\n\n    #endregion\n\n    #region CreateOrUpdate\n\n\n    public IDictionary<string, object> CreateOrUpdate(string contentType, Dictionary<string, object?> newContentItem, int? id = null, string? appPath = null)\n    {\n        Log.A($\"create or update type:{contentType}, id:{id}, path:{appPath}\");\n\n        // if app-path specified, use that app, otherwise use from context\n\n        // Check that this ID is actually of this content-type,\n        // this throws an error if it's not the correct type\n        var itm = id == null\n            ? null\n            : AppReader.List.GetOrThrow(contentType, id.Value);\n\n        if (itm == null) ThrowIfNotAllowedInType(contentType, GrantSets.CreateSomething, AppReader);\n        else ThrowIfNotAllowedInItem(itm, GrantSets.WriteSomething, AppReader);\n\n        // Convert to case-insensitive dictionary just to be safe!\n        var rawValuesCaseInsensitive = newContentItem.ToInvariant();\n\n        // Now create the cleaned up import-dictionary so we can create a new entity\n        var cleanedNewItem = new AppContentEntityBuilder(Log)\n            .CreateEntityDictionary(contentType, rawValuesCaseInsensitive, AppReader)\n            .ToInvariant();\n\n        // add owner\n        if (!cleanedNewItem.ContainsKey(AttributeNames.EntityFieldOwner))\n            cleanedNewItem.Add(AttributeNames.EntityFieldOwner, Context.User.IdentityToken);\n\n        var dataController = DataController(AppReader);\n        if (id == null)\n        {\n            // Get Metadata - not sure why we're using the raw values, but maybe there were removed in cleaned?\n            Log.A($\"create new entity because id is null\");\n            var metadata = GetMetadata(rawValuesCaseInsensitive);\n            Log.A($\"metadata: {metadata}\");\n\n            var ids = dataController.Create(contentType, new List<Dictionary<string, object?>> { cleanedNewItem! }, metadata);\n            id = ids.FirstOrDefault();\n\n            Log.A($\"new entity id: {id}\");\n            // Get Metadata - not sure why we're using the raw values, but maybe there were removed in cleaned?\n            var added = AddParentRelationship(rawValuesCaseInsensitive!, id.Value);\n        }\n        else\n            dataController.Update(id.Value, cleanedNewItem!);\n\n        return InitEavAndSerializer(AppReader.AppId, Context.Permissions.IsContentAdmin, null)\n            .Convert(AppReader.List.GetOne(id.Value)!)!;\n    }\n\n    private bool AddParentRelationship(IDictionary<string, object?> valuesCaseInsensitive, int addedEntityId)\n    {\n        var l = Log.Fn<bool>($\"item dictionary key count: {valuesCaseInsensitive.Count}\");\n\n        if (!valuesCaseInsensitive.Keys.Contains(ParentRelationship))\n            return l.ReturnFalse($\"'{ParentRelationship}' key is missing\");\n\n        var objectOrNull = valuesCaseInsensitive[ParentRelationship];\n        if (objectOrNull == null) \n            return l.ReturnFalse($\"'{ParentRelationship}' value is null\");\n\n        if (objectOrNull is not JsonObject parentRelationship)\n            return l.ReturnNull($\"'{ParentRelationship}' value is not JsonObject\");\n\n        var parentGuid = (Guid?)parentRelationship[ParentRelParent];\n        if (!parentGuid.HasValue) \n            return l.ReturnFalse($\"'{ParentRelParent}' guid is missing\");\n\n        var parentEntity = AppReader.GetDraftOrPublished(parentGuid.Value);\n        if (parentEntity == null) \n            return l.ReturnFalse(\"Parent entity is missing\");\n\n        var ids = new[] { addedEntityId as int? };\n        var index = (int)parentRelationship[ParentRelIndex]!;\n\n        var field = (string)parentRelationship[ParentRelField]!;\n        var fields = new[] { field };\n\n        workFieldList.New(AppReader).FieldListAdd(parentEntity, fields, index, ids, asDraft: false, forceAddToEnd: false);\n\n        return l.ReturnTrue($\"new ParentRelationship p:{parentGuid},f:{field},i:{index}\");\n    }\n\n    private Target? GetMetadata(Dictionary<string, object?> newContentItemCaseInsensitive)\n    {\n        var l = Log.Fn<Target>($\"count: {newContentItemCaseInsensitive.Count}\");\n        if (!newContentItemCaseInsensitive.Keys.Contains(AttributeNames.JsonKeyMetadataFor))\n            return l.ReturnNull($\"'{AttributeNames.JsonKeyMetadataFor}' key is missing\");\n\n        var objectOrNull = newContentItemCaseInsensitive[AttributeNames.JsonKeyMetadataFor];\n        if (objectOrNull == null) \n            return l.ReturnNull($\"'{AttributeNames.JsonKeyMetadataFor}' value is null\");\n\n        if (objectOrNull is not JsonObject metadataFor)\n            return l.ReturnNull($\"'{AttributeNames.JsonKeyMetadataFor}' value is not JsonObject\");\n\n        var targetTypeName = metadataFor[AttributeNames.TargetNiceName]?.AsValue();\n        if (targetTypeName == null)\n            return l.ReturnNull($\"'{AttributeNames.TargetNiceName}' value is null\");\n        var metaData = new Target(GetTargetType(targetTypeName), null,\n            \n            keyGuid: (Guid?)metadataFor[AttributeNames.GuidNiceName],\n            keyNumber: (int?)metadataFor[AttributeNames.NumberNiceName],\n            keyString: (string)metadataFor[AttributeNames.StringNiceName]!\n        );\n        return l.Return(metaData, $\"new metadata g:{metaData.KeyGuid},n:{metaData.KeyNumber},s:{metaData.KeyString}\");\n\n    }\n\n    private static int GetTargetType(JsonValue target) =>\n        target.GetValue<JsonElement>().ValueKind switch\n        {\n            JsonValueKind.Number => (int)target,\n            JsonValueKind.String when Enum.TryParse<TargetTypes>((string)target!, out var targetTypes)\n                => (int)targetTypes,\n            _ => throw new ArgumentOutOfRangeException(AttributeNames.TargetNiceName,\n                @\"Value is not 'int' or TargetTypes 'string'.\")\n        };\n\n    private SimpleDataEditService DataController(IAppIdentity app) => _dataController ??= dataControllerLazy.Value.Init(app.ZoneId, app.AppId);\n    private SimpleDataEditService? _dataController;\n\n    #endregion\n\n    #region helpers / initializers to prep the EAV and Serializer\n\n    private IConvertToEavLight InitEavAndSerializer(int appId, bool userMayEdit, Uri? uri)\n    {\n        var l = Log.Fn<IConvertToEavLight>($\"init eav for a#{appId}\");\n        // Improve the serializer so it's aware of the 2sxc-context (module, portal etc.)\n        var ser = entToDicLazy.Value;\n        ser.WithGuid = true;\n        var converter = (ConvertToEavLightWithCmsInfo)ser;\n        converter.WithEdit = userMayEdit;\n        if (uri is not null)\n            converter.AddSelectFields([.. SystemQueryOptionsParser.Parse(uri).Select]);\n\n        return l.Return(ser);\n    }\n    #endregion\n\n\n    #region Delete\n\n    public void Delete(string contentType, int id, string? appPathForLogOnly)\n    {\n        var l = Log.Fn($\"id:{id}, type:{contentType}, path:{appPathForLogOnly}\");\n        // Note: if app-path specified, use that app, otherwise use from context - probably automatic based on headers?\n\n        // don't allow type \"any\" on this\n        if (contentType == \"any\")\n            throw l.Done(new Exception(\"type any not allowed with id-only, requires guid\"));\n\n        var entityApi = api.Init(AppReader.AppId);\n        var itm = AppReader.List.GetOrThrow(contentType, id);\n        ThrowIfNotAllowedInItem(itm, Grants.Delete.AsSet(), AppReader);\n        entityApi.Delete(itm.Type.Name, id);\n        l.Done();\n    }\n\n    public void Delete(string? contentType, Guid guid, string? appPathForLogOnly)\n    {\n        var l = Log.Fn($\"guid:{guid}, type:{contentType}, path:{appPathForLogOnly}\");\n        // Note: if app-path specified, use that app, otherwise use from context - probably automatic based on headers?\n\n        var entityApi = api.Init(AppReader.AppId);\n        var itm = AppReader.List.GetOrThrow(contentType == \"any\" ? null : contentType, guid);\n\n        ThrowIfNotAllowedInItem(itm, Grants.Delete.AsSet(), AppReader);\n\n        entityApi.Delete(itm.Type.Name, guid);\n        l.Done();\n    }\n\n\n    #endregion\n\n    #region Permission Checks\n\n    protected MultiPermissionsTypes ThrowIfNotAllowedInType(string contentType, List<Grants> requiredGrants, IAppIdentity appIdentity)\n    {\n        var permCheck = typesPermissions.New(new() { SiteContext = Context, App = appIdentity, ContentTypes = [contentType] });\n        if (!permCheck.EnsureAll(requiredGrants, out var error))\n            throw HttpException.PermissionDenied(error);\n        return permCheck;\n    }\n\n    protected MultiPermissionsItems ThrowIfNotAllowedInItem(IEntity itm, List<Grants> requiredGrants, IAppIdentity appIdentity)\n    {\n        if (itm == null)\n            throw new ArgumentNullException(nameof(itm), @\"Item must not be null to check it's security.\");\n        var permCheck = itemsPermissions.New(new() { SiteContext = Context, App = appIdentity, Entities = [itm] });\n        if (!permCheck.EnsureAll(requiredGrants, out var error))\n            throw HttpException.PermissionDenied(error);\n        return permCheck;\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/AppDataControllerReal.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.WebApi.Sys.App;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <inheritdoc cref=\"IAppDataController\" />\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppDataControllerReal(LazySvc<AppContent> appContentLazy)\n    : ServiceBase(\"Api.DataRl\", connect: [appContentLazy])/*, IAppDataController*/\n{\n    public const string LogSuffix = \"Data\";\n\n\n    #region Get List / all of a certain content-type\n\n    /// <inheritdoc />\n    public IEnumerable<IDictionary<string, object>> GetEntities(string contentType, string? appPath = default, Uri? uri = null)\n        => appContentLazy.Value.Init(appPath).GetItems(contentType, appPath, uri);\n\n    #endregion\n\n\n    #region GetOne by ID / GUID\n\n    /// <inheritdoc />\n    public IDictionary<string, object> GetOne(string contentType, string id, string? appPath = default, Uri? uri = null)\n    {\n        if(int.TryParse(id, out var intId))\n            return GetAndSerializeOneAfterSecurityChecks(contentType,\n                entityApi => entityApi.GetOrThrow(contentType, intId), appPath, uri);\n\n        if (Guid.TryParse(id, out var guid))\n            return GetAndSerializeOneAfterSecurityChecks(contentType,\n                entityApi => entityApi.GetOrThrow(contentType, guid), appPath, uri);\n\n#pragma warning disable S112 // General exceptions should never be thrown\n        throw new(\"id neither int/guid, can't process\");\n#pragma warning restore S112 // General exceptions should never be thrown\n    }\n\n    /// <summary>\n    /// Preprocess security / context, then get the item based on an passed in method,\n    /// ...then process/finish\n    /// </summary>\n    /// <param name=\"contentType\"></param>\n    /// <param name=\"getOne\"></param>\n    /// <param name=\"appPath\"></param>\n    /// <param name=\"oDataSelect\"></param>\n    /// <param name=\"uri\"></param>\n    /// <returns></returns>\n    private IDictionary<string, object> GetAndSerializeOneAfterSecurityChecks(string contentType, Func<IEnumerable<IEntity>, IEntity> getOne, string? appPath, Uri? uri)\n        => appContentLazy.Value.Init(appPath).GetOne(contentType, getOne, appPath, uri);\n\n    #endregion\n\n\n    #region Create\n\n    /// <inheritdoc />\n    public IDictionary<string, object> CreateOrUpdate(string contentType, Dictionary<string, object?> newContentItem, int? id = null,\n        string? appPath = null)\n        => appContentLazy.Value.Init(appPath)\n            .CreateOrUpdate(contentType, newContentItem, id, appPath);\n\n    #endregion\n\n\n    #region Delete\n\n    /// <inheritdoc />\n    public void Delete(string contentType, string id, string? appPath = null)\n    {\n        if (int.TryParse(id, out var intId))\n        {\n            appContentLazy.Value.Init(appPath).Delete(contentType, intId, appPath);\n            return;\n        }\n\n        if (Guid.TryParse(id, out var guid))\n        {\n            appContentLazy.Value.Init(appPath).Delete(contentType, guid, appPath);\n            return;\n        }\n\n#pragma warning disable S112 // General exceptions should never be thrown\n        throw new(\"id neither int/guid, can't process\");\n#pragma warning restore S112 // General exceptions should never be thrown\n    }\n\n    #endregion\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/AppExtensionRelease.cs",
    "content": "﻿using ToSic.Eav.Models;\n\n// ReSharper disable UnusedMember.Global\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ModelSpecs(ContentType = ContentTypeId)]\ninternal record AppExtensionRelease: ModelFromEntity\n{\n    public const string ContentTypeId = \"1d91a2c0-4d5d-4197-8cb8-d4bfebf72f15\";\n    public const string ContentTypeName = \"AppExtensionRelease\";\n    private const string DefaultVersion = \"00.00.01\";\n\n    public string ReleaseNotes => GetThis(\"\");\n\n    public string Version => GetThis(DefaultVersion);\n\n    public bool IsBreaking => GetThis(false);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/AppQueryControllerReal.cs",
    "content": "﻿using System.Net;\nusing ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.DataSource.Sys.Convert;\nusing ToSic.Eav.LookUp.Sys.Engines;\nusing ToSic.Eav.WebApi.Sys.Admin.App;\nusing ToSic.Eav.WebApi.Sys.Admin.Query;\nusing ToSic.Sxc.Data.Sys.Convert;\nusing ToSic.Sys.OData;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// In charge of delivering Pipeline-Queries on the fly\n/// They will only be delivered if the security is confirmed - it must be publicly available\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppQueryControllerReal(\n    LazySvc<AppQueryODataHelper> oDataHelper,\n    ISxcCurrentContextService ctxService,\n    Generator<IConvertToEavLight> dataConverter,\n    Generator<AppPermissionCheck> appPermissionCheck,\n    LazySvc<QueryManager> queryManager,\n    LazySvc<ILookUpEngineResolver> lookupResolver)\n    : ServiceBase(\"Sxc.ApiApQ\",\n        connect: [oDataHelper, lookupResolver, ctxService, dataConverter, appPermissionCheck, queryManager]), IAppQueryController\n{\n    public const string LogSuffix = \"AppQry\";\n\n    //private const string AllStreams = \"*\";\n\n    #region In-Container-Context Queries\n\n    public IDictionary<string, IEnumerable<EavLightEntity>> Query(string name, int? appId, string? stream = null, bool? includeGuid = false)\n        => QueryPost(name, null, appId, stream, includeGuid);\n\n    public IDictionary<string, IEnumerable<EavLightEntity>> QueryPost(string name, QueryParametersDtoFromClient? more, int? appId, string? stream = null, bool? includeGuid = false)\n    {\n        var l = Log.Fn<IDictionary<string, IEnumerable<EavLightEntity>>>($\"'{name}', inclGuid: {includeGuid}, stream: {stream}\");\n        var appCtx = appId != null\n            ? ctxService.GetExistingAppOrSet(appId.Value)\n            : ctxService.BlockContextRequired();\n\n        // If the appId wasn't specified or == to the Block-AppId, then also include block info to enable more data-sources like CmsBlock\n        var maybeBlock = appId == null || appId == appCtx.AppReaderRequired.AppId\n            ? ctxService.BlockOrNull()\n            : null;\n\n        // If no app available from context, check if an app-id was supplied in url\n        // Note that it may only be an app from the current portal\n        // and security checks will run internally\n        var blockLookupOrNull = maybeBlock is { DataIsReady: true }\n            ? maybeBlock.Data.Configuration.LookUpEngine\n            : null;\n\n        var result = BuildQueryAndRun(appCtx.AppReaderRequired, name, stream, includeGuid ?? false, appCtx, more, blockLookupOrNull);\n        return l.Return(result);\n    }\n\n    #endregion\n\n    #region Public Queries\n\n    public IDictionary<string, IEnumerable<EavLightEntity>> PublicQuery(string appPath, string name, string? stream)\n        => PublicQueryPost(appPath, name, null, stream);\n\n\n    public IDictionary<string, IEnumerable<EavLightEntity>> PublicQueryPost(string appPath, string name, QueryParametersDtoFromClient? more, string? stream) \n    {\n        var l = Log.Fn<IDictionary<string, IEnumerable<EavLightEntity>>>($\"path:{appPath}, name:{name}, stream: {stream}\");\n        if (string.IsNullOrEmpty(name))\n            throw l.Ex(HttpException.MissingParam(nameof(name)));\n\n        var appCtx = ctxService.SetAppOrGetBlock(appPath);\n\n        var blockLookupOrNull = ctxService.BlockOrNull()?.Data?.Configuration?.LookUpEngine;\n\n        // now just run the default query check and serializer\n        var result = BuildQueryAndRun(appCtx.AppReaderRequired, name, stream, false, appCtx, more, blockLookupOrNull);\n        return l.Return(result);\n    }\n\n\n    #endregion\n\n\n    private IDictionary<string, IEnumerable<EavLightEntity>> BuildQueryAndRun(\n        IAppIdentity app,\n        string name,\n        string? stream,\n        bool includeGuid,\n        IContextOfApp context,\n        QueryParametersDtoFromClient? more,\n        ILookUpEngine? preparedLookup = null)\n    {\n        var modId = (context as IContextOfBlock)?.Module.Id ?? -1;\n\n        var l = Log.Fn<IDictionary<string, IEnumerable<EavLightEntity>>>($\"name:{name}, stream:{stream}, withModule:{(context as IContextOfBlock)?.Module.Id}\");\n\n        var lookups = preparedLookup ?? lookupResolver.Value.GetLookUpEngine(modId);\n        var query = queryManager.Value.TryGetQuery(app, name, lookups, recurseParents: 3);\n\n        if (query == null)\n        {\n            var msg = $\"query '{name}' not found\";\n            throw l.Done(new HttpExceptionAbstraction(HttpStatusCode.NotFound, msg, \"query not found\"));\n        }\n\n        l.A($\"Check permission on query {query.Definition.Id}\");\n        var permissionChecker = appPermissionCheck.New()\n            .ForItem(context, app, (query.Definition as ICanBeEntity).Entity);\n        var readExplicitlyAllowed = permissionChecker.UserMay(GrantSets.ReadSomething).Allowed;\n\n        var isAdmin = context.User.IsContentAdmin;\n\n        // Only return query if permissions ok\n        if (!(readExplicitlyAllowed || isAdmin))\n        {\n            var msg = $\"Request not allowed. User does not have read permissions for query '{name}'\";\n            throw l.Done(new HttpExceptionAbstraction(HttpStatusCode.Unauthorized, msg, \"Request not allowed\"));\n        }\n\n\n        if (stream == DataSourceConstants.AllStreams)\n            stream = null;\n\n        var streamNames = DataSourceConvertHelper.GetBestStreamNames(query, stream);\n\n        // Pass the originally requested stream so QueryODataParams can map bare OData options\n        // to that stream when exactly one stream was explicitly selected.\n        var streamOptions = QueryODataParams.CreateMany(query.Configuration.Parse, streamNames, stream);\n\n        // New v17 experimental with special fields\n        var systemQueryOptions = QueryODataParams.Create(query.Configuration.Parse);\n\n        // v21 support OData filtering, sorting...\n        var mustUseOData = streamOptions.Any(so => !so.Value.IsEmptyExceptForSelect());\n        if (mustUseOData)\n        {\n            var oDataResult = oDataHelper.Value.ApplyOData(query, streamOptions, more?.Guids, includeGuid, context.Permissions.IsContentAdmin);\n            return l.Return(oDataResult, \"processed with OData\");\n        }\n\n        // Classic, lightweight conversion\n        var selectFields = streamOptions.ToDictionary(\n            pair => pair.Key,\n            ICollection<string> (pair) => pair.Value.Select.ToListOpt(),\n            StringComparer.OrdinalIgnoreCase\n        );\n        var dc = PrepareDataConverter(includeGuid, context.Permissions.IsContentAdmin, systemQueryOptions);\n        var result = dc.Convert(query, streamNames, more?.Guids, selectFields);\n        return l.Return(result, \"classic convert\");\n    }\n\n    private IConvertToEavLight PrepareDataConverter(bool withGuid, bool isEditor, ODataOptions options)\n    {\n        var dc = dataConverter.New();\n        dc.WithGuid = withGuid;\n        if (dc is ConvertToEavLightWithCmsInfo serializerWithEdit)\n            serializerWithEdit.WithEdit = isEditor;\n        if (dc is ConvertToEavLight serializerWithOData)\n            serializerWithOData.AddSelectFields(options.Select.ToListOpt());\n        return dc;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/AppQueryODataHelper.cs",
    "content": "﻿using ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.OData;\nusing ToSic.Eav.DataSource.Sys.Convert;\nusing ToSic.Eav.DataSources;\nusing ToSic.Eav.Services;\nusing ToSic.Sxc.Data.Sys.Convert;\nusing ToSic.Sys.OData;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Helper to apply odata to a query.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppQueryODataHelper(Generator<IConvertToEavLight> dataConverter, IDataSourcesService dataSourcesService)\n    : ServiceBase(\"Sxc.ApiApQ\", connect: [dataConverter, dataSourcesService])\n{\n\n\n    internal IDictionary<string, IEnumerable<EavLightEntity>> ApplyOData(IDataSource query, IDictionary<string, ODataOptions> streams, string[]? filterGuids, bool withGuid = false, bool withEdit = false)\n    {\n        var l = Log.Fn<IDictionary<string, IEnumerable<EavLightEntity>>>();\n        var oDataEngine = new ODataQueryEngine(dataSourcesService);\n\n        var guidFilter = DataSourceConvertHelper.SafeParseGuidList(filterGuids);\n\n        // only apply odata to the \"Default\" stream or the first one.\n        var streamToFilter = streams.ContainsKey(DataSourceConstants.StreamDefaultName)\n            ? DataSourceConstants.StreamDefaultName\n            : streams.Keys.First();\n\n        var filtered = streams\n            .Select(stream =>\n            {\n                var streamName = stream.Key;\n                var sourceStream = query.GetStream(streamName, nullIfNotFound: true);\n\n                // Null-check - not really expected, but just in case...\n                if (sourceStream == null)\n                {\n                    l.A($\"Stream '{streamName}' not found, skip OData.\");\n                    return (streamName, []);\n                }\n\n                // If it's not the one to apply OData to, exit here.\n                if (!streamName.EqualsInsensitive(streamToFilter))\n                    return (name: streamName, list: PrepareConverter(stream.Value).Convert(sourceStream));\n\n                // Apply OData to this stream\n                // For the internal processing, we need it to be in an IDataSource\n                var oDataQuery = stream.Value.ToQuery();\n                var wrapper = dataSourcesService.Create<PassThrough>(sourceStream);\n                var execution = oDataEngine.Execute(wrapper, oDataQuery);\n                var entities = guidFilter.Any()\n                    ? execution.Items.Where(e => guidFilter.Contains(e.EntityGuid))\n                    : execution.Items;\n\n                // The filtered OData path must still honor that stream's $select,\n                // otherwise adding $filter/$orderby/$top causes the selected fields to be lost.\n                var converted = PrepareConverter(stream.Value).Convert(entities);\n                return (name: streamName, list: converted);\n            })\n            .Where(pair => pair.list != null)\n            .ToDictionary(\n                kvp => kvp.name,\n                kvp => kvp.list,\n                StringComparer.OrdinalIgnoreCase\n            );\n        return l.Return(filtered!);\n\n        IConvertToEavLight PrepareConverter(ODataOptions options)\n        {\n            var converter = dataConverter.New();\n            converter.WithGuid = withGuid;\n            if (converter is ConvertToEavLightWithCmsInfo serializerWithEdit)\n                serializerWithEdit.WithEdit = withEdit;\n            if (converter is ConvertToEavLight serializerWithOData)\n                serializerWithOData.AddSelectFields(options.Select.ToListOpt());\n            return converter;\n        }\n\n        // Old, not functional, not ideal\n        //var results = new Dictionary<string, IEnumerable<EavLightEntity>>(StringComparer.OrdinalIgnoreCase);\n\n        //foreach (var streamName in streams)\n        //{\n        //    var sourceStream = query.GetStream(streamName, nullIfNotFound: true);\n        //    if (sourceStream == null)\n        //    {\n        //        l.A($\"Stream '{streamName}' not found, skip OData.\");\n        //        continue;\n        //    }\n\n        //    var wrapper = dataSourcesService.Create<PassThrough>(sourceStream);\n        //    var execution = engine.Execute(wrapper, oDataQuery);\n        //    var entities = guidFilter.Any()\n        //        ? execution.Items.Where(e => guidFilter.Contains(e.EntityGuid))\n        //        : execution.Items;\n\n        //    results[streamName] = dataConverter.Convert(entities);\n        //}\n\n        //return l.Return(results);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/AppsBackend.cs",
    "content": "﻿using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Apps.Sys.State;\nusing ToSic.Sxc.Apps.Sys.Assets;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sys.Code.InfoSystem;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppsBackend(\n    WorkApps workApps,\n    IContextOfSite context,\n    CodeInfoStats codeStats,\n    Generator<IAppPathsMicroSvc> appPathsGen,\n    LazySvc<GlobalPaths> globalPaths)\n    : ServiceBase(\"Bck.Apps\", connect: [workApps, codeStats, context, appPathsGen, globalPaths])\n{\n    public ICollection<AppDto> Apps()\n    {\n        var list = workApps.GetApps(context.Site);\n        return list.Select(CreateAppDto).ToListOpt();\n    }\n\n    public ICollection<AppDto> GetInheritableApps()\n    {\n        var list = workApps.GetInheritableApps(context.Site);\n        return list.Select(CreateAppDto).ToListOpt();\n    }\n\n    private AppDto CreateAppDto(IAppReader appReader)\n    {\n        AppMetadataDto? lightspeed = null;\n        var lightSpeedDeco = LightSpeedDecorator.GetFromAppStatePiggyBack(appReader/*, Log*/);\n        if ((lightSpeedDeco as ICanBeEntity)?.Entity != null! /* paranoid */)\n            lightspeed = new () { Id = lightSpeedDeco.Id, Title = lightSpeedDeco.Title, IsEnabled = lightSpeedDeco.IsEnabled };\n\n        var paths = appPathsGen.New().Get(appReader, context.Site);\n        var thumbnail = AppAssetThumbnail.GetUrl(appReader, paths, globalPaths);\n        var specs = appReader.Specs;\n        return new ()\n        {\n            Id = appReader.AppId,\n            IsApp = specs.NameId != KnownAppsConstants.DefaultAppGuid &&\n                    specs.NameId != KnownAppsConstants.PrimaryAppGuid, // #SiteApp v13\n            Guid = specs.NameId,\n            Name = specs.Name,\n            Folder = specs.Folder,\n            AppRoot = paths.Path,\n            IsHidden = specs.Configuration.IsHidden,\n            ConfigurationId = specs.Configuration.Id,\n            Items = appReader.List.Count,\n            Thumbnail = thumbnail,\n            Version = specs.VersionSafe(),\n            IsGlobal = appReader.IsShared(),\n            IsInherited = appReader.IsInherited(),\n            Lightspeed = lightspeed,\n            HasCodeWarnings = codeStats.AppHasWarnings(appReader.AppId),\n        };\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/CacheControllerReal.cs",
    "content": "using ToSic.Sxc.Services.OutputCache;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CacheControllerReal(\n    ISxcCurrentContextService ctxService,\n    LazySvc<IOutputCacheManagementService> outputCacheManagement)\n    : ServiceBase(\"Sxc.ApiApCac\", connect: [ctxService, outputCacheManagement])\n{\n    public const string LogSuffix = \"AppCac\";\n\n    public bool Flush(string appPath, AppCacheFlushSpecs? request)\n        => FlushInternal(ctxService.SetAppOrGetBlock(appPath).AppReaderRequired.AppId, request);\n\n    public bool FlushAuto(int? appId, AppCacheFlushSpecs? request)\n        => FlushInternal(\n            appId ?? ctxService.BlockContextRequired().AppReaderRequired.AppId,\n            request\n        );\n\n    private bool FlushInternal(int appId, AppCacheFlushSpecs? specs)\n    {\n        var l = Log.Fn<bool>($\"app:{appId}\");\n\n        //if (!context.User.IsContentAdmin)\n        //{\n        //    const string message = \"Request not allowed. Cache flush requires admin permissions.\";\n        //    throw l.Done(new HttpExceptionAbstraction(HttpStatusCode.Unauthorized, message, \"Request not allowed\"));\n        //}\n\n        var touched = OutputCacheManagement.Flush(appId, dependencies: specs?.Dependencies);\n        return touched == 0\n            ? l.ReturnTrue(\"app-wide cache dependency touched\")\n            : l.ReturnTrue($\"{touched} dependencies touched\");\n    }\n\n    private IOutputCacheManagementService OutputCacheManagement => outputCacheManagement.Value;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionDeleteBackend.cs",
    "content": "using ToSic.Eav.Apps.Sys.Caching;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.Entities;\nusing ToSic.Sxc.ImportExport.Package.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionDeleteBackend(\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    ISite site,\n    IAppPathsMicroSvc appPathSvc,\n    ExtensionManifestService manifestService,\n    LazySvc<ExtensionInspectBackend> inspectorLazy,\n    LazySvc<EntityApi> entityApiLazy,\n    LazySvc<AppCachePurger> appCachePurgerLazy)\n    : ServiceBase(\"Bck.ExtDel\", connect: [appReadersLazy, site, appPathSvc, manifestService, inspectorLazy, entityApiLazy, appCachePurgerLazy])\n{\n    private ReadOnlyFileHelper ReadOnlyHelper => field ??= new(Log);\n\n    public bool DeleteExtension(int appId, string name, string? edition, bool force, bool withData)\n    {\n        var l = Log.Fn<bool>($\"a:{appId}, name:{name}, edition:{edition}, force:{force}, withData:{withData}\");\n\n        if (string.IsNullOrWhiteSpace(name) || !ExtensionFolderNameValidator.IsValid(name))\n            throw l.Ex(new ArgumentException(\"invalid extension name\", nameof(name)));\n\n        var editionSegment = ExtensionEditionHelper.NormalizeEdition(edition);\n        var appReader = appReadersLazy.Value.Get(appId);\n        var appPaths = appPathSvc.Get(appReader, site);\n        var extensionPath = ExtensionEditionHelper.GetExtensionRoot(appPaths, name, editionSegment);\n\n        if (!Directory.Exists(extensionPath))\n            throw l.Ex(new DirectoryNotFoundException($\"Extension folder not found: {name}\"));\n\n        var manifestFile = manifestService.GetManifestFile(new DirectoryInfo(extensionPath));\n        if (!manifestFile.Exists)\n            throw l.Ex(new FileNotFoundException($\"{FolderConstants.AppExtensionJsonFile} not found in extension '{name}'\"));\n\n        var manifest = manifestService.LoadManifest(manifestFile)\n            ?? throw l.Ex(new InvalidOperationException($\"{FolderConstants.AppExtensionJsonFile} could not be loaded\"));\n\n        if (manifest.IsInstalled != true)\n            throw l.Ex(new InvalidOperationException(\"Extension is not marked as installed; delete manually.\"));\n\n        var inspect = inspectorLazy.Value.Inspect(appId, name, editionSegment);\n        if (!inspect.FoundLock)\n            throw l.Ex(new InvalidOperationException($\"{PackageIndexFile.LockFileName} missing; delete manually.\"));\n\n        var summary = inspect.Summary ?? new ExtensionInspectSummaryDto();\n        var hasFileChanges = summary.Changed > 0 || summary.Added > 0 || summary.Missing > 0;\n        if (hasFileChanges && !force)\n            throw l.Ex(new InvalidOperationException(\"Extension has file changes; use force to delete.\"));\n\n        var contentTypesWithData = inspect.Data?.ContentTypes ?? [];\n        var hasData = contentTypesWithData.Any(ct => ct.LocalEntities > 0);\n        if (hasData && !force)\n            throw l.Ex(new InvalidOperationException(\"Extension has data; use force to delete.\"));\n\n        if (hasData && withData && force)\n            DeleteData(appReader, appId, contentTypesWithData);\n\n        DeleteFiles(appPaths.PhysicalPath, editionSegment, name);\n\n        // app-state refresh should happen on every uninstall\n        appCachePurgerLazy.Value.Purge(appReader.ZoneId, appId);\n\n        return l.ReturnTrue(\"deleted\");\n    }\n\n    private void DeleteData(IAppReader appReader, int appId, IEnumerable<ExtensionInspectContentTypeDto> types)\n    {\n        var l = Log.Fn($\"delete data app:{appId}\");\n\n        var typeNames = new HashSet<string>(types\n            .Select(t => t.Guid)\n            .Where(n => n.HasValue()), StringComparer.OrdinalIgnoreCase);\n\n        if (typeNames.Count == 0)\n        {\n            l.Done(\"no type names to delete\");\n            return;\n        }\n\n        var entityApi = entityApiLazy.Value.Init(appId, showDrafts: true);\n\n        var entityIds = appReader.List\n            .Where(e => e.EntityId > 0 && typeNames.Any(t => e.Type.Is(t)))\n            .Select(e => new { e.EntityId, e.Type.NameId })\n            .DistinctBy(e => e.EntityId)\n            .ToList();\n\n        foreach (var entity in entityIds)\n            entityApi.Delete(entity.NameId, entity.EntityId, force: true);\n\n        l.Done($\"deleted:{entityIds.Count}\");\n    }\n\n    private void DeleteFiles(string appRoot, string edition, string extensionName)\n    {\n        var l = Log.Fn($\"del files ext:{extensionName}, edition:{edition}\");\n\n        var extensionPath = ExtensionEditionHelper.GetExtensionRoot(appRoot, extensionName, edition);\n        DeleteDirectorySafe(extensionPath);\n\n        var appCodePath = ExtensionEditionHelper.GetExtensionAppCodePath(appRoot, extensionName, edition);\n        if (appCodePath.HasValue())\n            DeleteDirectorySafe(appCodePath);\n\n        var appCodeExtensionFolderNamePath = ExtensionEditionHelper.GetExtensionAppCodePath(appRoot, ExtensionValidationHelper.AppCodeExtensionFolderName(extensionName), edition);\n        if (appCodeExtensionFolderNamePath.HasValue())\n            DeleteDirectorySafe(appCodeExtensionFolderNamePath);\n\n        l.Done();\n    }\n\n    private void DeleteDirectorySafe(string path)\n    {\n        var l = Log.Fn();\n        if (path.IsEmpty())\n        {\n            l.Done(\"path empty\");\n            return;\n        }\n        if (!Directory.Exists(path))\n        {\n            l.Done(\"path not exist\");\n            return;\n        }\n\n        Log.A($\"clear readonly + delete: '{Path.GetFileName(path)}'\");\n        ReadOnlyHelper.RemoveReadOnlyRecursive(path);\n        Directory.Delete(path, recursive: true);\n        Log.A($\"deleted: '{Path.GetFileName(path)}'\");\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionDownloadBackend.cs",
    "content": "using System.Net.Http;\nusing ToSic.Eav.Security.Files;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Downloads extension packages from remote URLs and returns a stream plus a sanitized filename.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionDownloadBackend() : ServiceBase(\"Bck.ExtDl\")\n{\n    public (Stream Stream, string FileName, string Url) DownloadFirstAvailable(string[] urls)\n    {\n        // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract\n        var l = Log.Fn<(Stream, string, string)>($\"urls:{urls?.Length ?? 0}\");\n\n        if (urls == null || urls.Length == 0)\n            throw l.Ex(new ArgumentException(\"no urls provided\"));\n\n        var candidates = urls.Where(u => u.HasValue()).ToList();\n        if (candidates == null || candidates.Count == 0)\n            throw l.Ex(new ArgumentException(\"no valid urls provided\"));\n\n        l.A($\"download candidates:{candidates.Count}\");\n\n        Exception? lastError = null;\n        foreach (var url in candidates)\n        {\n            try\n            {\n                l.A($\"try download url:'{url}'\");\n                var result = DownloadSingleUrl(url);\n                return l.Return((result.Stream, result.FileName, url), $\"ok '{url}'\");\n            }\n            catch (Exception ex)\n            {\n                lastError = ex;\n                l.A($\"download failed for '{url}': {ex.Message}\");\n            }\n        }\n\n        throw l.Ex(new InvalidOperationException(\"Could not download extension package from provided URLs.\", lastError));\n    }\n\n    private (Stream Stream, string FileName) DownloadSingleUrl(string url)\n    {\n        var l = Log.Fn<(Stream, string)>($\"url:'{url}'\");\n\n        MemoryStream? stream = null;\n        try\n        {\n            var fileName = BuildFileName(url);\n\n            using var httpClient = new HttpClient();\n            httpClient.DefaultRequestHeaders.Add(\"User-Agent\", \"2sxc-extension-installer\");\n            httpClient.Timeout = TimeSpan.FromMinutes(5);\n            using var response = httpClient.GetAsync(url).Result;\n            response.EnsureSuccessStatusCode();\n\n            stream = new MemoryStream();\n            response.Content.CopyToAsync(stream).Wait();\n            stream.Position = 0;\n\n            return l.ReturnAsOk((stream, fileName));\n        }\n        catch (HttpRequestException ex)\n        {\n            stream?.Dispose();\n            var wrapped = new InvalidOperationException($\"Could not download extension package from '{url}'.\", ex);\n            l.Ex(wrapped);\n            throw wrapped;\n        }\n        catch (Exception ex)\n        {\n            stream?.Dispose();\n            l.Ex(ex);\n            throw;\n        }\n    }\n\n    private static string BuildFileName(string url)\n    {\n        const string defaultName = \"extension-remote.zip\";\n\n        var fileName = defaultName;\n        if (Uri.TryCreate(url, UriKind.Absolute, out var uri))\n        {\n            var candidate = Path.GetFileName(uri.LocalPath);\n            if (candidate.HasValue())\n                fileName = FileNames.SanitizeFileName(candidate);\n        }\n\n        if (!fileName.HasValue())\n            fileName = defaultName;\n\n        if (FileNames.IsKnownRiskyExtension(fileName))\n            throw new ArgumentException($\"File {fileName} has risky file type.\");\n\n        return fileName;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionEditionHelper.cs",
    "content": "using ToSic.Eav.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Shared helpers for resolving extension-related paths and edition segments.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static class ExtensionEditionHelper\n{\n    internal static List<string> NormalizeEditions(string? editions)\n    {\n        var segments = (editions ?? string.Empty)\n            .Split(',')\n            .DefaultIfEmpty(string.Empty);\n\n        var normalized = segments\n            .Select(NormalizeEdition)\n            .ToList();\n\n        if (normalized.Count == 0)\n            normalized.Add(string.Empty);\n\n        return normalized\n            .Distinct(StringComparer.OrdinalIgnoreCase)\n            .ToList();\n    }\n\n    /// <summary>\n    /// Normalize an edition segment and guard against path traversal.\n    /// </summary>\n    internal static string NormalizeEdition(string? edition)\n    {\n        if (edition.IsEmpty())\n            return string.Empty;\n\n        var normalized = edition.Trim().TrimPrefixSlash().TrimLastSlash();\n        return normalized.ContainsPathTraversal()\n            ? throw new ArgumentException(\"edition contains invalid path traversal\", nameof(edition))\n            : normalized;\n    }\n\n    internal static List<string> MergeEditions(List<string> requested, List<string> installed)\n        => requested\n            .Concat(installed)\n            .Distinct(StringComparer.OrdinalIgnoreCase)\n            .ToList();\n\n    internal static string GetEditionRoot(IAppPaths appPaths, string edition)\n        => GetEditionRoot(appPaths.PhysicalPath, edition);\n\n    internal static string GetEditionRoot(string appRoot, string edition)\n        => edition.HasValue()\n            ? Path.Combine(appRoot, edition)\n            : appRoot;\n\n    internal static string GetExtensionRoot(IAppPaths appPaths, string extensionName, string edition)\n        => GetExtensionRoot(appPaths.PhysicalPath, extensionName, edition);\n\n    internal static string GetExtensionRoot(string appRoot, string extensionName, string edition)\n        => Path.Combine(GetEditionRoot(appRoot, edition), FolderConstants.AppExtensionsFolder, extensionName);\n\n    internal static string GetExtensionAppCodePath(string appRoot, string extensionName, string edition)\n    {\n        var editionAppCode = Path.Combine(appRoot, edition, FolderConstants.AppCodeFolder);\n        return Directory.Exists(editionAppCode)\n            ? Path.Combine(editionAppCode, FolderConstants.AppExtensionsFolder, extensionName)\n            : Path.Combine(appRoot, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, extensionName);\n    }\n\n    internal static List<string> DetectInstalledEditions(string appRoot, List<string> availableEditions, string extensionName)\n    {\n        var list = new List<string>();\n        var rootPath = Path.Combine(appRoot, FolderConstants.AppExtensionsFolder, extensionName);\n        if (Directory.Exists(rootPath))\n            list.Add(string.Empty);\n\n        foreach (var dir in Directory.GetDirectories(appRoot))\n        {\n            var name = Path.GetFileName(dir);\n            if (!availableEditions.Contains(name, StringComparer.OrdinalIgnoreCase))\n                continue;\n            var editionExtPath = Path.Combine(dir, FolderConstants.AppExtensionsFolder, extensionName);\n            if (Directory.Exists(editionExtPath))\n                list.Add(name);\n        }\n\n        return list;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionExportService.cs",
    "content": "using System.IO.Compression;\nusing System.Text;\nusing System.Text.Json;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.ImportExport.Sys.Zip;\nusing ToSic.Eav.Models;\nusing ToSic.Eav.Persistence.File;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys;\nusing ToSic.Sxc.ImportExport.Package.Sys;\nusing ToSic.Sys.Security.Encryption;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionExportService(\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    ISite site,\n    IAppPathsMicroSvc appPathSvc,\n    LazySvc<ContentExportApi> contentExport,\n    ExtensionManifestService manifestService\n    )\n    : ServiceBase(\"Bck.ExtExp\", connect: [appReadersLazy, site, appPathSvc, contentExport, manifestService])\n{\n    /// <summary>\n    /// ZIP file name format, with placeholders for name and version\n    /// </summary>\n    private const string ZipFileNameFormat = \"app-extension-{0}-v{1}.zip\";\n\n    /// <summary>\n    /// Default value for version if none is found in extension.json\n    /// </summary>\n    private const string DefaultVersion = \"00.00.01\";\n\n    public FileToUploadToClient Export(int appId, string name)\n    {\n        var l = Log.Fn<FileToUploadToClient>($\"export extension a#{appId}, name:'{name}'\");\n\n        if (string.IsNullOrWhiteSpace(name))\n            throw l.Ex(new ArgumentException(@\"Extension name is required\", nameof(name)));\n\n        // Basic validation to ensure folder is a simple directory name\n        name = name.Trim();\n        if (!ExtensionFolderNameValidator.IsValid(name))\n            throw l.Ex(new ArgumentException(@\"Invalid extension name\", nameof(name)));\n\n        // 1. Validate and get paths\n        var appReader = appReadersLazy.Value.Get(appId);\n        var appPaths = appPathSvc.Get(appReader, site);\n        var extensionsRoot = Path.Combine(appPaths.PhysicalPath, FolderConstants.AppExtensionsFolder);\n        var extensionPath = ExtensionValidationHelper.GetActualCasedPath(extensionsRoot, name);\n\n        if (!Directory.Exists(extensionPath))\n            throw l.Ex(new DirectoryNotFoundException($\"Extension folder not found: {name}\"));\n        l.A($\"extension '{name}' folder found: '{extensionPath}'\");\n\n        var extensionManifestFile = manifestService.GetManifestFile(new(extensionPath));\n\n        if (!extensionManifestFile.Exists)\n            throw l.Ex(new FileNotFoundException($\"{FolderConstants.AppExtensionJsonFile} not found in extension: {name}\"));\n\n        l.A($\"{FolderConstants.AppExtensionJsonFile} found: '{extensionManifestFile.FullName}'\");\n\n        // 2. Read manifest\n        var manifest = manifestService.LoadManifest(extensionManifestFile)\n                       ?? throw l.Ex(new InvalidOperationException(\n                           $\"{FolderConstants.AppExtensionJsonFile} could not be loaded\"));\n        l.A($\"{FolderConstants.AppExtensionJsonFile} loaded: version:'{manifest.Version}'\");\n\n        // 3. Determine all extensions to export (primary + bundled)\n        // Note: ExtensionsBundled is stored as a comma-separated string (no spaces) in the manifest.\n        var bundled = manifest.ExtensionsBundled\n            .UseFallbackIfNoValue(string.Empty)\n            .Split([','], StringSplitOptions.RemoveEmptyEntries)\n            .Select(s => s.Trim())\n            .Where(x => !string.IsNullOrWhiteSpace(x))\n            .Select(bundledName => ExtensionFolderNameValidator.IsValid(bundledName)\n                ? bundledName\n                : throw l.Ex(new ArgumentException($@\"Invalid bundled extension name: {bundledName}\", nameof(name))))\n            .OrderBy(s => s, StringComparer.OrdinalIgnoreCase)\n            .ToList();\n\n        var allExtensions = new[] { name }\n            .Concat(bundled)\n            .Distinct(StringComparer.OrdinalIgnoreCase)\n            .ToList();\n\n        // Old, less functional way:\n        //var allExtensions = new List<string> { name };\n        //foreach (var bundledName in bundled)\n        //{\n        //    if (string.IsNullOrWhiteSpace(bundledName))\n        //        continue;\n\n        //    var cleaned = bundledName.Trim();\n        //    if (cleaned.Equals(name, StringComparison.OrdinalIgnoreCase))\n        //        continue;\n        //    if (!ExtensionFolderNameValidator.IsValid(cleaned))\n        //        throw l.Ex(new ArgumentException($@\"Invalid bundled extension name: {cleaned}\", nameof(name)));\n        //    if (allExtensions.Any(e => e.Equals(cleaned, StringComparison.OrdinalIgnoreCase)))\n        //        continue;\n\n        //    allExtensions.Add(cleaned);\n        //}\n\n        // 4. Build export specs for each extension\n        // Primary extension must exist; bundled extensions are best-effort (skip missing)\n        var exports = new List<ExtensionExportSpec>();\n        foreach (var ext in allExtensions)\n        {\n            try\n            {\n                exports.Add(BuildExtensionExport(appId, ext, appPaths));\n            }\n            catch (Exception ex) when (ext != name && ex is DirectoryNotFoundException or FileNotFoundException)\n            {\n                l.A($\"Skipping bundled extension '{ext}' because it wasn't found or is incomplete. Details: {ex.Message}\");\n            }\n        }\n\n        // 5. Create ZIP using Zipping helper (file name based on the primary extension)\n        var primaryVersionString = exports.First().VersionString;\n        var fileName = string.Format(ZipFileNameFormat, name, primaryVersionString);\n\n        using var memoryStream = CreateZipArchive(exports, name, primaryVersionString);\n        memoryStream.Position = 0;\n        var fileBytes = memoryStream.ToArray();\n\n        var totalFiles = exports.Sum(e => e.FilesToInclude.Count);\n        l.A($\"Created ZIP with {exports.Count} extensions and {totalFiles} files, size: {fileBytes.Length} bytes\");\n\n        return l.ReturnAsOk(new()\n        {\n            FileName = fileName,\n            ContentType = MimeTypeConstants.FallbackType,\n            FileBytes = fileBytes\n        });\n    }\n\n    private sealed record ExtensionExportSpec(\n        string ExtensionName,\n        string VersionString,\n        List<(string sourcePath, string zipPath)> FilesToInclude,\n        List<(string sourcePath, string zipPath, string content)> Bundles,\n        string ExtensionJsonZipPath,\n        string ExtensionJsonContent,\n        string LockJsonZipPath,\n        string LockJsonContent\n    );\n\n    private JsonSerializerOptions JsonSerializationIndented => field ??= new(JsonOptions.UnsafeJsonWithoutEncodingHtml)\n    {\n        WriteIndented = true,\n        PropertyNamingPolicy = JsonNamingPolicy.CamelCase\n    };\n\n    private string ToNiceJson(object data) => JsonSerializer.Serialize(data, JsonSerializationIndented);\n\n    private MemoryStream CreateZipArchive(\n        List<ExtensionExportSpec> exports,\n        string primaryExtensionName,\n        string primaryVersionString)\n    {\n        var l = Log.Fn<MemoryStream>($\"exts:{exports.Count}, primary:{primaryExtensionName}\");\n\n        var memoryStream = new MemoryStream();\n        using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))\n        {\n            var zipping = new Zipping(l);\n\n            // Add collected files using helper (deduplicate zip paths)\n            //var allFiles = new List<(string sourcePath, string zipPath)>();\n            //var addedZipPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);\n            //foreach (var export in exports)\n            //{\n            //    foreach (var file in export.FilesToInclude)\n            //    {\n            //        if (!addedZipPaths.Add(file.zipPath))\n            //            continue;\n            //        allFiles.Add(file);\n            //    }\n            //}\n\n            // 2026-02-09 2dm - simpler and functional\n            var allFiles = exports\n                .SelectMany(export => export.FilesToInclude)\n                .DistinctBy(t => t.zipPath, StringComparer.OrdinalIgnoreCase)\n                .ToList();\n\n            zipping.AddFiles(archive, allFiles);\n            l.A($\"Added {allFiles.Count} files to ZIP\");\n\n            // Add extension.json + bundles + lock files for each extension\n            foreach (var export in exports)\n            {\n                zipping.AddTextEntry(archive, export.ExtensionJsonZipPath, export.ExtensionJsonContent, new UTF8Encoding(false));\n\n                foreach (var (_, zipPath, content) in export.Bundles)\n                    zipping.AddTextEntry(archive, zipPath, content, new UTF8Encoding(false));\n\n                zipping.AddTextEntry(archive, export.LockJsonZipPath, export.LockJsonContent, new UTF8Encoding(false));\n            }\n\n            // Create and add package-install.json listing all extensions\n            var packageData = CreatePackageInstallFile(exports);\n            var packageJson = ToNiceJson(packageData);\n            zipping.AddTextEntry(archive, PackageInstallFile.FileName, packageJson, new UTF8Encoding(false));\n        }\n\n        return l.ReturnAsOk(memoryStream);\n    }\n\n    private ExtensionExportSpec BuildExtensionExport(int appId, string extensionName, IAppPaths appPaths)\n    {\n        var l = Log.Fn<ExtensionExportSpec>($\"a#{appId}, ext:'{extensionName}'\");\n\n        var extensionsRoot = Path.Combine(appPaths.PhysicalPath, FolderConstants.AppExtensionsFolder);\n        var extensionPath = ExtensionValidationHelper.GetActualCasedPath(extensionsRoot, extensionName);\n        var extensionDirectory = new DirectoryInfo(extensionPath);\n        if (!extensionDirectory.Exists)\n            throw l.Ex(new DirectoryNotFoundException($\"Extension folder not found: {extensionName}\"));\n\n        // use actual casing from file system to preserve paths in the export\n        extensionPath = extensionDirectory.FullName;\n        var extensionFolderName = extensionDirectory.Name;\n\n        var extensionManifestFile = manifestService.GetManifestFile(new(extensionPath));\n        if (!extensionManifestFile.Exists)\n            throw l.Ex(new FileNotFoundException($\"{FolderConstants.AppExtensionJsonFile} not found in extension: {extensionName}\"));\n\n        var originalManifest = manifestService.LoadManifest(extensionManifestFile)\n                              ?? throw l.Ex(new InvalidOperationException(\n                                  $\"{FolderConstants.AppExtensionJsonFile} could not be loaded\"));\n\n        // Decide if we should modify (for export / installation) or keep as-is\n        // - if not installed -> modify (set isInstalled=true and expand release references)\n        // - if installed -> keep exact json + lock (if present)\n        var isInstalled = originalManifest.IsInstalled ?? false;\n        var effectiveManifest = isInstalled\n            ? originalManifest\n            : ModifyExtensionManifest(originalManifest, appId);\n\n        var versionString = effectiveManifest.Version.UseFallbackIfNoValue(DefaultVersion);\n        var extensionDataPath = Path.Combine(extensionPath, FolderConstants.DataFolderProtected);\n\n        // Read extension.json content (exact for installed extensions)\n        var extensionJsonDiskPath = Path.Combine(extensionDataPath, FolderConstants.AppExtensionJsonFile);\n        var extensionJsonContent = isInstalled\n            ? File.ReadAllText(extensionJsonDiskPath)\n            : ExtensionManifestSerializer.Serialize(effectiveManifest, JsonSerializationIndented);\n\n        // Collect files to include (never include extension.json or package-index.json from disk)\n        var filesToInclude = CollectFilesToInclude(extensionPath, effectiveManifest, appPaths, extensionFolderName);\n\n        // Handle data bundles\n        var bundles = ExportDataBundlesIfNeeded(effectiveManifest, extensionDataPath, extensionFolderName, appId);\n\n        // Lock file content (exact for installed extensions if it exists)\n        var basePath = $\"{FolderConstants.AppExtensionsFolder}/{extensionFolderName}/{FolderConstants.DataFolderProtected}\";\n        var extensionJsonZipPath = $\"{basePath}/{FolderConstants.AppExtensionJsonFile}\";\n        var lockJsonZipPath = $\"{basePath}/{PackageIndexFile.LockFileName}\";\n\n        var lockJsonDiskPath = Path.Combine(extensionDataPath, PackageIndexFile.LockFileName);\n        var lockJsonContent = isInstalled && File.Exists(lockJsonDiskPath)\n            ? File.ReadAllText(lockJsonDiskPath)\n            : ToNiceJson(CreatePackageIndexFile(filesToInclude, bundles, versionString, extensionJsonZipPath, extensionJsonContent));\n\n        return l.ReturnAsOk(new ExtensionExportSpec(\n            ExtensionName: extensionFolderName,\n            VersionString: versionString,\n            FilesToInclude: filesToInclude,\n            Bundles: bundles,\n            ExtensionJsonZipPath: extensionJsonZipPath,\n            ExtensionJsonContent: extensionJsonContent,\n            LockJsonZipPath: lockJsonZipPath,\n            LockJsonContent: lockJsonContent\n        ));\n    }\n\n    private ExtensionManifest ModifyExtensionManifest(ExtensionManifest manifest, int appId)\n    {\n        var l = Log.Fn<ExtensionManifest>();\n\n        l.A($\"Modifying {FolderConstants.AppExtensionJsonFile}\");\n\n        // Set isInstalled to true\n        var modified = manifest with { IsInstalled = true };\n        l.A(\"set isInstalled to true\");\n\n        // Process releases if they exist\n        if (manifest.Releases.ValueKind != JsonValueKind.Array)\n            return l.ReturnAsOk(modified);\n\n        var releases = manifest.Releases.EnumerateArray().ToList();\n        if (releases.Count <= 0)\n            return l.ReturnAsOk(modified);\n\n        var appReader = appReadersLazy.Value.Get(appId);\n\n        l.A($\"Processing {releases.Count} release references\");\n        var expandedReleases = releases\n            .Select(releaseRef =>\n            {\n                var lr = Log.Fn<AppExtensionRelease>();\n                if (releaseRef.ValueKind != JsonValueKind.String)\n                    return lr.ReturnNull($\"Skipping non-string release reference: {releaseRef.ValueKind}\");\n\n                var guidString = releaseRef.GetString();\n                if (string.IsNullOrEmpty(guidString) || !Guid.TryParse(guidString, out var guid))\n                    return lr.ReturnNull($\"Skipping invalid release GUID: {guidString}\");\n\n                // Look up release entity from app data\n                var releaseEntity = appReader.List.FirstOrDefault(e => e.EntityGuid == guid);\n\n                return releaseEntity == null\n                    ? lr.ReturnNull($\"Release entity not found for GUID: {guid}\")\n                    : lr.Return(releaseEntity.ToModel<AppExtensionRelease>()!, \"found\");\n            })\n            .Where(r => r != null)!\n            .ToList();\n\n        // Serialize expanded releases back to JsonElement\n        var expandedJson = JsonSerializer.Serialize(expandedReleases, JsonSerializationIndented);\n        using var expandedDoc = JsonDocument.Parse(expandedJson);\n        var expandedElement = expandedDoc.RootElement.Clone();\n        modified = modified with { Releases = expandedElement };\n\n        l.A($\"Expanded {expandedReleases.Count} releases\");\n\n        return l.ReturnAsOk(modified);\n    }\n\n    private List<(string sourcePath, string zipPath)> CollectFilesToInclude(\n        string extensionPath,\n        ExtensionManifest manifest,\n        IAppPaths appPaths,\n        string extensionName)\n    {\n        var l = Log.Fn<List<(string sourcePath, string zipPath)>>();\n\n        l.A(\"Collecting files to include\");\n\n        // 1. Always include /extensions/[name] folder (except App_Data/extension.json and App_Data/package-index.json which we handle separately)\n        var files = AddDirectoryFiles(extensionPath, extensionPath,\n            $\"{FolderConstants.AppExtensionsFolder}/{extensionName}\",\n            exclude:\n            [\n                $\"{FolderConstants.DataFolderProtected}\\\\{FolderConstants.AppExtensionJsonFile}\",\n                $\"{FolderConstants.DataFolderProtected}\\\\{PackageIndexFile.LockFileName}\",\n            ]);\n\n        // 2. Check for hasAppCode setting\n        if (manifest.AppCodeInside)\n        {\n            l.A($\"Extension has AppCode, including AppCode/{FolderConstants.AppExtensionsFolder} folder\");\n            files = TryAddAppCodeFiles(files, appPaths, extensionName);\n\n            // Also check for hyphen-less version of extension name for AppCode folder, since C# would have that convention\n            files = TryAddAppCodeFiles(files, appPaths, ExtensionValidationHelper.AppCodeExtensionFolderName(extensionName));\n        }\n\n        l.A($\"Collected {files.Count} files\");\n        return l.ReturnAsOk(files);\n    }\n\n    private List<(string, string)> TryAddAppCodeFiles(List<(string, string)> files, IAppPaths appPaths, string extensionName)\n    {\n        var appCodeExtensionsRoot = Path.Combine(appPaths.PhysicalPath, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder);\n        var appCodeExtPath = ExtensionValidationHelper.GetActualCasedPath(appCodeExtensionsRoot, extensionName);\n        var appCodeExtDir = new DirectoryInfo(appCodeExtPath);\n        if (!appCodeExtDir.Exists)\n            return files;\n\n        var more = AddDirectoryFiles(appCodeExtPath, appCodeExtPath,\n            $\"{FolderConstants.AppCodeFolder}/{FolderConstants.AppExtensionsFolder}/{appCodeExtDir.Name}\");\n        return more.Any()\n            ? files.Concat(more).ToList()\n            : files;\n    }\n\n    private List<(string bundlePath, string zipFile, string fileContents)> ExportDataBundlesIfNeeded(\n        ExtensionManifest manifest,\n        string extensionDataPath,\n        string extensionName,\n        int appId)\n    {\n        var l = Log.Fn<List<(string, string, string)>>();\n\n        if (!manifest.DataInside)\n            return l.Return([], \"no data bundles\");\n\n        var bundles = manifest.DataBundles;\n        if (bundles.ValueKind is JsonValueKind.Undefined or JsonValueKind.Null)\n            return l.Return([], \"dataBundles is null/undefined\");\n\n        // Convert to list of GUIDs\n        var guidList = new List<Guid>();\n        switch (bundles.ValueKind)\n        {\n            // TODO: WHY DO WE have two scenarios? I think the JSON should be standardized to always be an array.\n            case JsonValueKind.String:\n                // Single bundle as string\n                var singleGuidStr = bundles.GetString();\n                if (!string.IsNullOrEmpty(singleGuidStr) && Guid.TryParse(singleGuidStr, out var singleGuid))\n                {\n                    guidList = [singleGuid];\n                    l.A($\"Single bundle found: {singleGuid}\");\n                }\n                break;\n            case JsonValueKind.Array:\n                // Array of bundles\n                var dataToUse = bundles.EnumerateArray()\n                    .Where(bundleRef => bundleRef.ValueKind == JsonValueKind.String)\n                    .Select(bundleRef => bundleRef.GetString())\n                    .Select(guidString => !string.IsNullOrEmpty(guidString) && Guid.TryParse(guidString, out var guid) ? guid : Guid.Empty)\n                    .Where(guid => guid != Guid.Empty)\n                    .ToList();\n\n                guidList = guidList.Concat(dataToUse).ToList();\n\n                // old, less functional way:\n                //foreach (var bundleRef in bundles.EnumerateArray())\n                //{\n                //    if (bundleRef.ValueKind == JsonValueKind.String)\n                //    {\n                //        var guidString = bundleRef.GetString();\n                //        if (!string.IsNullOrEmpty(guidString) && Guid.TryParse(guidString, out var guid))\n                //            guidList.Add(guid);\n                //    }\n                //}\n                l.A($\"Found {guidList.Count} bundle references\");\n                break;\n            default:\n                l.A($\"Unexpected bundles type: {bundles.ValueKind}, skipping\");\n                break;\n        }\n\n        if (guidList.Count == 0)\n            return l.Return([], \"no valid bundle GUIDs\");\n\n        l.A($\"Exporting {guidList.Count} data bundles\");\n        var bundlesExport = contentExport.Value.Init(appId);\n        var bundlesDir = Path.Combine(extensionDataPath, FolderConstants.DataSubFolderSystem,\n            AppDataFoldersConstants.BundlesFolder);\n\n        var files = guidList\n            .Select(guid =>\n            {\n                try\n                {\n                    // Export bundle entity as JSON\n                    var (export, fileContent) = bundlesExport.CreateBundleExport(guid, 2);\n                    var bundlePath = Path.Combine(bundlesDir, export.FileName);\n                    var zipPath = $\"{FolderConstants.AppExtensionsFolder}/{extensionName}/\" +\n                                  $\"{FolderConstants.DataFolderProtected}/{FolderConstants.DataSubFolderSystem}/\" +\n                                  $\"{AppDataFoldersConstants.BundlesFolder}/{export.FileName}\";\n                    return (bundlePath, zipPath, fileContent);\n                }\n                catch (KeyNotFoundException ex)\n                {\n                    var wrapped = new KeyNotFoundException(\n                        $\"Data bundle '{guid}' referenced by extension '{extensionName}' was not found in app {appId}. \" +\n                        $\"Update or remove the entry in extension.json:dataBundles. Details: {ex.Message}\", ex);\n                    l.Ex(wrapped);\n                    throw wrapped;\n                }\n            })\n            .ToList();\n\n        // Old, non functional way:\n        //foreach (var guid in guidList)\n        //{\n        //    try\n        //    {\n        //        // Export bundle entity as JSON\n        //        var (export, fileContent) = bundlesExport.CreateBundleExport(guid, 2);\n        //        var bundlePath = Path.Combine(bundlesDir, export.FileName);\n        //        var zipPath =\n        //            $\"{FolderConstants.AppExtensionsFolder}/{extensionName}/{FolderConstants.DataFolderProtected}/{FolderConstants.DataSubFolderSystem}/{AppDataFoldersConstants.BundlesFolder}/{export.FileName}\";\n        //        files.Add((bundlePath, zipPath, fileContent));\n        //    }\n        //    catch (KeyNotFoundException ex)\n        //    {\n        //        var wrapped = new KeyNotFoundException(\n        //            $\"Data bundle '{guid}' referenced by extension '{extensionName}' was not found in app {appId}. \" +\n        //            $\"Update or remove the entry in extension.json:dataBundles. Details: {ex.Message}\", ex);\n        //        l.Ex(wrapped);\n        //        throw wrapped;\n        //    }\n        //}\n\n        return l.ReturnAsOk(files);\n    }\n\n    private List<(string, string)> AddDirectoryFiles(string sourcePath, string baseSourcePath, string baseZipPath, string[]? exclude = null)\n    {\n        var l = Log.Fn<List<(string, string)>>($\"source:{sourcePath}, base:{baseSourcePath}, zipBase:{baseZipPath}\");\n\n        if (!Directory.Exists(sourcePath))\n            return l.Return([], \"Directory doesn't exist, returning\");\n\n        var allFiles = Directory.GetFiles(sourcePath, \"*.*\", SearchOption.AllDirectories);\n        l.A($\"Found {allFiles.Length} files\");\n\n        var filePathList = allFiles\n            .Select(file =>\n            {\n                // Use string manipulation instead of Path.GetRelativePath for .NET Framework compatibility\n                var relativePath = file.StartsWith(baseSourcePath)\n                    ? file.Substring(baseSourcePath.Length).TrimStart('\\\\', '/')\n                    : file;\n\n                // Check exclusions\n                if (exclude != null && exclude.Any(f => relativePath.StartsWith(f, StringComparison.OrdinalIgnoreCase)))\n                {\n                    l.A($\"Excluding: {relativePath}\");\n                    return (null!, null!);\n                }\n\n                var zipPath = Path.Combine(baseZipPath, relativePath).Replace(\"\\\\\", \"/\");\n                l.A($\"Add file '{file}' to ZIP as '{zipPath}'\");\n                return (file, zipPath);\n            })\n            .Where(pair => pair.file != null)\n            .ToList();\n\n        return l.Return(filePathList!, $\"Added {filePathList.Count} files to collection\");\n        \n    }\n\n    // Old, less functional way:\n    //private void AddDirectoryFiles(string sourcePath, string baseSourcePath, string baseZipPath,\n    //    List<(string, string)> files, string[]? exclude = null)\n    //{\n    //    var l = Log.Fn($\"source:{sourcePath}, base:{baseSourcePath}, zipBase:{baseZipPath}\");\n\n    //    if (!Directory.Exists(sourcePath))\n    //    {\n    //        l.Done(\"Directory doesn't exist, returning\");\n    //        return;\n    //    }\n\n    //    var allFiles = Directory.GetFiles(sourcePath, \"*.*\", SearchOption.AllDirectories);\n    //    l.A($\"Found {allFiles.Length} files\");\n\n    //    foreach (var file in allFiles)\n    //    {\n    //        // Use string manipulation instead of Path.GetRelativePath for .NET Framework compatibility\n    //        var relativePath = file.StartsWith(baseSourcePath)\n    //            ? file.Substring(baseSourcePath.Length).TrimStart('\\\\', '/')\n    //            : file;\n\n    //        // Check exclusions\n    //        if (exclude != null && exclude.Any(f => relativePath.StartsWith(f, StringComparison.OrdinalIgnoreCase)))\n    //        {\n    //            l.A($\"Excluding: {relativePath}\");\n    //            continue;\n    //        }\n\n    //        var zipPath = Path.Combine(baseZipPath, relativePath).Replace(\"\\\\\", \"/\");\n    //        files.Add((file, zipPath));\n    //        l.A($\"Add file '{file}' to ZIP as '{zipPath}'\");\n    //    }\n\n    //    l.Done($\"Added {files.Count} files to collection\");\n    //}\n\n    private PackageIndexFile CreatePackageIndexFile(\n        List<(string sourcePath, string zipPath)> files,\n        List<(string sourcePath, string zipPath, string content)> bundles,\n        string version,\n        string extensionJsonZipPath,\n        string finalExtensionJson)\n    {\n        var l = Log.Fn<PackageIndexFile>($\"Creating {PackageIndexFile.LockFileName} file\");\n\n        l.A($\"{nameof(version)}:{version}\");\n\n        var fileList = files\n            .Select(f => new PackageIndexFileEntry\n            {\n                File = \"/\" + f.zipPath,\n                Hash = Sha256.Hash(File.ReadAllBytes(f.sourcePath))\n            })\n            .ToList();\n\n        // Include bundles\n        fileList.AddRange(\n            bundles\n                .Select(b => new PackageIndexFileEntry\n                {\n                    File = \"/\" + b.zipPath,\n                    Hash = Sha256.Hash(b.content)\n                })\n        );\n\n        // Also add the (final) extension.json hash\n        fileList.Add(new()\n        {\n            File = $\"/{extensionJsonZipPath}\",\n            Hash = Sha256.Hash(finalExtensionJson)\n        });\n\n        l.A($\"{PackageIndexFile.LockFileName} file created with {fileList.Count} entries\");\n\n        return l.ReturnAsOk(new()\n        {\n            Version = version,\n            Files = fileList\n        });\n    }\n\n    private PackageInstallFile CreatePackageInstallFile(List<ExtensionExportSpec> exports)\n    {\n        var l = Log.Fn<PackageInstallFile>();\n\n        // Create the package object\n        var package = new PackageInstallFile\n        {\n            Header = new()\n            {\n                PackageType = PackageTypes.AppExtension,\n            },\n            About = new()\n            {\n                Title = \"2sxc App Extension (standalone)\",\n                Description = \"A standalone app extension, exported directly from 2sxc\",\n            },\n            Extensions =\n            [\n                .. exports.Select(e => new PackageInstallExtension(\n                    Name: e.ExtensionName,\n                    DefinitionFile: e.ExtensionJsonZipPath,\n                    IndexFile: e.LockJsonZipPath,\n                    IndexFileHash: Sha256.Hash(e.LockJsonContent)\n                )),\n            ],\n        };\n\n        return l.Return(package, $\"Created package object for {exports.Count} extensions\");\n    }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionExtractionHelper.cs",
    "content": "using ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.ImportExport.Sys.Zip;\nusing ToSic.Eav.Sys;\nusing ToSic.Sys.Configuration;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Prepares extraction and validation of extension zip packages.\n/// </summary>\ninternal class ExtensionExtractionHelper(\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    ISite site,\n    IAppPathsMicroSvc appPathSvc,\n    IGlobalConfiguration globalConfiguration,\n    ExtensionValidationHelper validation,\n    ILog? parentLog)\n    : HelperBase(parentLog, \"Bck.ExtPrep\")\n{\n    internal ExtensionExtractionResult PrepareExtraction(int appId, Stream zipStream, string editions)\n    {\n        var l = Log.Fn<ExtensionExtractionResult>($\"prep a:{appId}\");\n\n        var appReader = appReadersLazy.Value.Get(appId);\n        var appPaths = appPathSvc.Get(appReader, site);\n        var appRoot = appPaths.PhysicalPath;\n        var editionList = ExtensionEditionHelper.NormalizeEditions(editions).ToArray();\n\n        var tempDir = Path.Combine(globalConfiguration.TemporaryFolder(), Guid.NewGuid().ToString(\"N\"));\n        Directory.CreateDirectory(tempDir);\n\n        try\n        {\n            new Zipping(Log).ExtractZipStream(zipStream, tempDir, allowCodeImport: true);\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            throw new InvalidOperationException(\"invalid zip\", ex);\n        }\n\n        var extensionsDir = Path.Combine(tempDir, FolderConstants.AppExtensionsFolder);\n        if (!Directory.Exists(extensionsDir))\n            return l.Return(new(false, $\"zip missing top-level '{FolderConstants.AppExtensionsFolder}' folder\", tempDir, appRoot, editionList, new(), new()));\n\n        var candidateDirs = Directory.GetDirectories(extensionsDir, \"*\", SearchOption.TopDirectoryOnly);\n        if (candidateDirs.Length == 0)\n            return l.Return(new(false, $\"'{FolderConstants.AppExtensionsFolder}' folder empty\", tempDir, appRoot, editionList, new(), new()));\n\n        var (error, lockResults, manifestResults) = validation.ValidateCandidateSubfolders(tempDir, candidateDirs);\n        if (error != null)\n            return l.Return(new(false, error, tempDir, appRoot, editionList, lockResults, manifestResults));\n\n        return l.Return(new(true, null, tempDir, appRoot, editionList, lockResults, manifestResults));\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionFolderNameValidator.cs",
    "content": "using ToSic.Eav.Security.Files;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static class ExtensionFolderNameValidator\n{\n    public static bool IsValid(string name)\n    {\n        // Not empty\n        if (string.IsNullOrWhiteSpace(name))\n            return false;\n\n        // No path characters or structures or traversal\n        if (name.Contains(Path.DirectorySeparatorChar) || name.Contains(Path.AltDirectorySeparatorChar))\n            return false;\n        if (name.Equals(\".\") || name.Contains(\"..\"))\n            return false;\n        if (name != Path.GetFileName(name))\n            return false;\n\n        // No spaces anywhere (not expected in extension-names)\n        if (name.Contains(' '))\n            return false;\n\n        // Sanitization should not change the name or return empty\n        var sanitized = FileNames.SanitizeFileName(name);\n        if (string.IsNullOrWhiteSpace(sanitized) || sanitized == FileNames.SafeChar)\n            return false;\n        if (!string.Equals(sanitized, name, StringComparison.Ordinal))\n            return false;\n\n        // No risky extensions\n        if (FileNames.IsKnownRiskyExtension(name))\n            return false;\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionInspectBackend.cs",
    "content": "using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.ImportExport.Package.Sys;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Backend.App.ExtensionLockHelper;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionInspectBackend(\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    ISite site,\n    IAppPathsMicroSvc appPathSvc)\n    : ServiceBase(\"Bck.ExtInsp\", connect: [appReadersLazy, site, appPathSvc])\n{\n    public ExtensionInspectResultDto Inspect(int appId, string name, string? edition)\n    {\n        var l = Log.Fn<ExtensionInspectResultDto>($\"app:{appId}, name:{name}, edition:{edition}\");\n        if (!ExtensionFolderNameValidator.IsValid(name))\n            throw l.Ex(new ArgumentException(\"invalid extension name\", nameof(name)));\n\n        var editionSegment = ExtensionEditionHelper.NormalizeEdition(edition);\n        var appReader = appReadersLazy.Value.Get(appId);\n        var appPaths = appPathSvc.Get(appReader, site);\n        var appRoot = appPaths.PhysicalPath;\n        var editionRoot = ExtensionEditionHelper.GetEditionRoot(appPaths, editionSegment);\n\n        var extensionRoot = ExtensionEditionHelper.GetExtensionRoot(appPaths, name, editionSegment);\n        var lockPath = Path.Combine(extensionRoot, FolderConstants.DataFolderProtected, PackageIndexFile.LockFileName);\n        var foundLock = File.Exists(lockPath);\n\n        var statuses = new List<ExtensionFileStatusDto>();\n        var changed = 0;\n        var missing = 0;\n        var added = 0;\n\n        var lockRead = ReadLockFile(lockPath, l);\n        var expected = lockRead.ExpectedWithHash;\n\n        if (expected is not null)\n        {\n            var basePathFull = EnsureTrailingBackslash(Path.GetFullPath(editionRoot));\n\n            foreach (var kvp in expected)\n            {\n                var rel = kvp.Key;\n                var fullPath = Path.GetFullPath(Path.Combine(editionRoot, rel.Backslash()));\n\n                if (!fullPath.StartsWith(basePathFull, StringComparison.OrdinalIgnoreCase) || !File.Exists(fullPath))\n                {\n                    statuses.Add(new() { Path = rel, Status = \"missing\" });\n                    missing++;\n                    continue;\n                }\n\n                var actualHash = CalculateHash(fullPath);\n                if (!string.Equals(actualHash, kvp.Value, StringComparison.OrdinalIgnoreCase))\n                {\n                    statuses.Add(new() { Path = rel, Status = \"changed\" });\n                    changed++;\n                }\n                else\n                {\n                    statuses.Add(new() { Path = rel, Status = \"unchanged\" });\n                }\n            }\n\n            added = AddAddedFiles(appRoot: appRoot,\n                edition: editionSegment,\n                extensionName: name,\n                basePathFull: basePathFull,\n                expectedPaths: lockRead.AllowedFiles ?? [],\n                statuses: statuses);\n        }\n\n        var result = new ExtensionInspectResultDto\n        {\n            FoundLock = foundLock,\n            Files = statuses,\n            Summary = new()\n            {\n                Total = statuses.Count,\n                Changed = changed,\n                Added = added,\n                Missing = missing\n            },\n            Data = BuildData(appId, name)\n        };\n        return l.Return(result, $\"files:{statuses.Count}, changed:{changed}, added:{added}, missing:{missing}\");\n    }\n\n    private static int AddAddedFiles(string appRoot, string edition, string extensionName, string basePathFull,\n        HashSet<string> expectedPaths, List<ExtensionFileStatusDto> statuses)\n    {\n        var added = 0;\n        var seen = new HashSet<string>(statuses.Select(s => s.Path), StringComparer.OrdinalIgnoreCase);\n        \n        var ownRoots = new[]\n        {\n            ExtensionEditionHelper.GetExtensionRoot(appRoot, extensionName, edition),\n            ExtensionEditionHelper.GetExtensionAppCodePath(appRoot, extensionName, edition),\n        };\n\n        foreach (var ownRoot in ownRoots)\n        {\n            foreach (var file in EnumerateFilesSafe(ownRoot))\n            {\n                var normalizedFile = Path.GetFullPath(file);\n                if (!normalizedFile.StartsWith(basePathFull, StringComparison.OrdinalIgnoreCase))\n                    continue;\n\n                var rel = normalizedFile\n                    .Substring(basePathFull.Length)\n                    .TrimPrefixSlash()\n                    .ForwardSlash();\n\n                if (expectedPaths.Contains(rel))\n                    continue;\n\n                if (rel.EndsWith(PackageIndexFile.LockFileName, StringComparison.OrdinalIgnoreCase))\n                    continue;\n\n                if (!seen.Add(rel))\n                    continue;\n\n                statuses.Add(new() { Path = rel, Status = \"added\" });\n                added++;\n            }\n        }\n\n        return added;\n    }\n\n    private ExtensionInspectDataDto? BuildData(int appId, string extensionName)\n    {\n        var l = Log.Fn<ExtensionInspectDataDto?>($\"app:{appId}, ext:{extensionName}\");\n\n        try\n        {\n            var appReader = appReadersLazy.Value.Get(appId);\n            var extensionTypes = appReader.ContentTypes\n                .Where(ct => IsContentTypeFromExtension(ct, extensionName))\n                .ToList();\n\n            var localEntityCounts = appReader.GetListNotHavingDrafts()\n                .Where(IsLocalEntity)\n                .GroupBy(e => e.Type.NameId, StringComparer.OrdinalIgnoreCase)\n                .ToDictionary(g => g.Key, g => g.Count(), StringComparer.OrdinalIgnoreCase);\n\n            var contentTypes = extensionTypes\n                .Select(ct =>\n                {\n                    var hasData = localEntityCounts.TryGetValue(ct.NameId, out var count);\n                    return new ExtensionInspectContentTypeDto\n                    {\n                        Name = ct.Name,\n                        Guid = ct.NameId,\n                        LocalEntities = hasData ? count : 0\n                    };\n                })\n                .ToList();\n\n            return l.Return(new () { ContentTypes = contentTypes }, $\"types:{contentTypes.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnNull(\"error\");\n        }\n    }\n\n    private static bool IsContentTypeFromExtension(IContentType contentType, string extensionName)\n    {\n        var address = contentType.RepositoryAddress;\n        if (address.IsEmptyOrWs())\n            return false;\n\n        var normalizedPath = address.ForwardSlash();\n        return ContainsExtensionPath(normalizedPath, FolderConstants.AppExtensionsFolder, extensionName)\n               || ContainsExtensionPath(normalizedPath, FolderConstants.AppExtensionsLegacyFolder, extensionName)\n               || ContainsExtensionPath(normalizedPath,\n                   $\"{FolderConstants.AppCodeFolder}/{FolderConstants.AppExtensionsFolder}\", extensionName);\n    }\n\n    private static bool ContainsExtensionPath(string normalizedPath, string containerFolder, string extensionName)\n    {\n        var needle = $\"/{containerFolder.Trim('/')}/{extensionName}/\";\n        return normalizedPath.Contains(needle, StringComparison.OrdinalIgnoreCase);\n    }\n\n    private static bool IsLocalEntity(IEntity entity)\n        => entity.EntityId > 0;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionInspectDtos.cs",
    "content": "using System.Text.Json.Serialization;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionInspectResultDto\n{\n    [JsonPropertyName(\"foundLock\")]\n    public bool FoundLock { get; init; }\n\n    [JsonPropertyName(\"files\")]\n    public List<ExtensionFileStatusDto>? Files { get; init; }\n\n    [JsonPropertyName(\"summary\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public ExtensionInspectSummaryDto? Summary { get; init; }\n\n    [JsonPropertyName(\"data\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public ExtensionInspectDataDto? Data { get; init; }\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionFileStatusDto\n{\n    [JsonPropertyName(\"path\")]\n    public required string Path { get; init; }\n\n    [JsonPropertyName(\"status\")]\n    public required string Status { get; init; } // unchanged | changed | added | missing\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionInspectSummaryDto\n{\n    [JsonPropertyName(\"total\")]\n    public int Total { get; init; }\n\n    [JsonPropertyName(\"changed\")]\n    public int Changed { get; init; }\n\n    [JsonPropertyName(\"added\")]\n    public int Added { get; init; }\n\n    [JsonPropertyName(\"missing\")]\n    public int Missing { get; init; }\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionInspectDataDto\n{\n    [JsonPropertyName(\"contentTypes\")]\n    public List<ExtensionInspectContentTypeDto> ContentTypes { get; init; } = [];\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionInspectContentTypeDto\n{\n    [JsonPropertyName(\"name\")]\n    public required string Name { get; init; }\n\n    [JsonPropertyName(\"guid\")]\n    public required string Guid { get; init; }\n\n    [JsonPropertyName(\"localEntities\")]\n    public int LocalEntities { get; init; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionInstallBackend.cs",
    "content": "using ToSic.Eav.Apps.Sys.Caching;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.ImportExport.Sys.Zip;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sys.Configuration;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionInstallBackend(\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    ISite site,\n    IAppPathsMicroSvc appPathSvc,\n    IGlobalConfiguration globalConfiguration,\n    ExtensionManifestService manifestService,\n    LazySvc<ExtensionInspectBackend> inspectorLazy,\n    LazySvc<CodeControllerReal> codeLazy,\n    LazySvc<AppCachePurger> appCachePurgerLazy)\n    : ServiceBase(\"Bck.ExtZip\", connect: [appReadersLazy, site, appPathSvc, globalConfiguration, manifestService, inspectorLazy, codeLazy, appCachePurgerLazy])\n{\n    private ReadOnlyFileHelper ReadOnlyHelper => field ??= new(Log);\n    private ExtensionValidationHelper Validation => field ??= new(manifestService, Log);\n    private ExtensionExtractionHelper Extraction => field ??= new(appReadersLazy, site, appPathSvc, globalConfiguration, Validation, Log);\n    private ExtensionInstallHelper Copier => field ??= new(ReadOnlyHelper, Log);\n    private ExtensionPreflightHelper Preflight => field ??= new(manifestService, inspectorLazy, Log);\n\n    public bool InstallExtensionZip(int zoneId, int appId, Stream zipStream, bool overwrite = false, string? originalZipFileName = null, string editions = null!)\n    {\n        var l = Log.Fn<bool>($\"a:{appId}, overwrite:{overwrite}, ofn:'{originalZipFileName}'\");\n\n        string? tempDir = null;\n        try\n        {\n            var prep = Extraction.PrepareExtraction(appId, zipStream, editions);\n            tempDir = prep.TempDir;\n            if (!prep.Success)\n                throw new InvalidOperationException(prep.Error ?? \"error\");\n\n            var appRoot = prep.AppRoot;\n            var editionList = prep.Editions;\n            var extensionsRoot = Path.Combine(appRoot, FolderConstants.AppExtensionsFolder);\n            Directory.CreateDirectory(extensionsRoot);\n            var manifestResults = prep.ManifestResults;\n\n            var installed = new List<string>();\n\n            foreach (var lockResult in prep.LockResults)\n            {\n                var folderName = lockResult.Key;\n                var lockValidation = lockResult.Value;\n\n                l.A($\"prepare install:'{folderName}'\");\n\n                if (!manifestResults.TryGetValue(folderName, out var manifestValidation))\n                    throw new InvalidOperationException($\"missing manifest info for '{folderName}'\");\n\n                var editionSupportError = EnsureEditionsSupported(manifestValidation.EditionsSupported, editionList);\n                if (editionSupportError != null)\n                    throw new InvalidOperationException(editionSupportError);\n\n                foreach (var edition in editionList)\n                {\n                    var editionRoot = ExtensionEditionHelper.GetEditionRoot(appRoot, edition);\n\n                    var editionExtensionsRoot = Path.Combine(editionRoot, FolderConstants.AppExtensionsFolder);\n                    Directory.CreateDirectory(editionExtensionsRoot);\n\n                    var installResult = Copier.InstallSingleExtension(\n                        folderName: folderName,\n                        lockValidation: lockValidation,\n                        tempDir: tempDir,\n                        extensionsRoot: editionExtensionsRoot,\n                        appRoot: editionRoot,\n                        overwrite: overwrite);\n\n                    if (!installResult.Success)\n                        throw new InvalidOperationException(installResult.Error ?? $\"install failed:'{folderName}'\");\n                }\n\n                // app-state refresh should happen on every install\n                appCachePurgerLazy.Value.Purge(zoneId, appId);\n\n                installed.Add(folderName);\n            }\n            return l.ReturnTrue($\"installed '{string.Join(\"','\", installed)}' from '{originalZipFileName}'\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            throw;\n        }\n        finally\n        {\n            if (tempDir != null)\n                Zipping.TryToDeleteDirectory(tempDir, l);\n        }\n    }\n\n    public PreflightResultDto InstallPreflight(int appId, Stream zipStream, string? originalZipFileName = null, string editions = null!)\n    {\n        var l = Log.Fn<PreflightResultDto>($\"a:{appId}, ofn:'{originalZipFileName}'\");\n\n        string? tempDir = null;\n        try\n        {\n            var prep = Extraction.PrepareExtraction(appId, zipStream, editions);\n            tempDir = prep.TempDir;\n            if (!prep.Success)\n                throw new InvalidOperationException(prep.Error ?? \"error\");\n\n            var appRoot = prep.AppRoot;\n            var requestedEditions = prep.Editions;\n            var availableEditions = codeLazy.Value.GetEditions(appId).Editions.Select(e => e.Name).ToList();\n            var lockResults = prep.LockResults;\n            var manifestResults = prep.ManifestResults;\n\n            var result = new PreflightResultDto();\n\n            foreach (var kvp in lockResults)\n            {\n                var folderName = kvp.Key;\n                var lockValidation = kvp.Value;\n\n                if (!manifestResults.TryGetValue(folderName, out var manifestValidation) || manifestValidation.Manifest == null)\n                    throw new InvalidOperationException($\"missing manifest info for '{folderName}'\");\n\n                var manifest = manifestValidation.Manifest;\n                var editionSupportError = EnsureEditionsSupported(manifestValidation.EditionsSupported, requestedEditions);\n                if (editionSupportError != null)\n                    throw new InvalidOperationException(editionSupportError);\n\n                var editionTargets = ExtensionEditionHelper.MergeEditions(requestedEditions.ToList(), ExtensionEditionHelper.DetectInstalledEditions(appRoot, availableEditions, folderName));\n                var allEditionTargets = ExtensionEditionHelper.MergeEditions(editionTargets, availableEditions);\n                var extDto = new PreflightExtensionDto\n                {\n                    Name = folderName,\n                    Version = manifest.Version,\n                    EditionsSupported = manifestValidation.EditionsSupported,\n                    FileCount = lockValidation.AllowedFiles?.Count ?? 0,\n                    Features = Preflight.MapFeatures(manifest)\n                };\n\n                foreach (var edition in allEditionTargets)\n                {\n                    var editionInfo = Preflight.BuildEditionInfo(appId, appRoot, folderName, edition, manifest);\n                    if (editionInfo is not null)\n                    {\n                        extDto.Editions.Add(editionInfo);\n                        continue;\n                    }\n\n                    var editionRoot = ExtensionEditionHelper.GetEditionRoot(appRoot, edition);\n                    var extensionExists = Directory.Exists(Path.Combine(editionRoot, FolderConstants.AppExtensionsFolder, folderName));\n                    if (extensionExists)\n                        continue;\n\n                    extDto.Editions.Add(new ExtensionEditionDto\n                    {\n                        Edition = edition,\n                        IsInstalled = false\n                    });\n                }\n\n                result.Extensions.Add(extDto);\n            }\n\n            return l.Return(result, $\"extensions:{result.Extensions.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            throw;\n        }\n        finally\n        {\n            if (tempDir != null)\n                Zipping.TryToDeleteDirectory(tempDir, l);\n        }\n    }\n\n    private static string? EnsureEditionsSupported(bool editionsSupported, string[] editionList)\n        => editionList.Any(e => e.HasValue()) && !editionsSupported\n            ? \"extension does not support editions\"\n            : null;\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionInstallHelper.cs",
    "content": "using ToSic.Eav.ImportExport.Sys.Zip;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.ImportExport.Package.Sys;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Backend.App.ExtensionLockHelper;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Handles safe copying of extension files from extracted temp folders into the target app.\n/// </summary>\ninternal class ExtensionInstallHelper(ReadOnlyFileHelper readOnlyHelper, ILog? parentLog) : HelperBase(parentLog, \"Bck.ExtCopy\")\n{\n    internal ValidationResult InstallSingleExtension(string folderName, LockValidationResult lockValidation, string tempDir, string extensionsRoot, string appRoot, bool overwrite)\n    {\n        var l = Log.Fn<ValidationResult>($\"folder:'{folderName}'\");\n\n        if (!ExtensionFolderNameValidator.IsValid(folderName))\n            return l.ReturnAsError(new(false, $\"invalid folder name:'{folderName}'\"));\n\n        if (!lockValidation.Success)\n            return l.ReturnAsError(new(false, lockValidation.Error ?? $\"lock validation failed:'{folderName}'\"));\n\n        var allowedFiles = lockValidation.AllowedFiles;\n        if (allowedFiles == null || allowedFiles.Count == 0)\n            return l.ReturnAsError(new(false, $\"no files allowed for '{folderName}'\"));\n\n        var tempExtensionFolder = Path.Combine(tempDir, FolderConstants.AppExtensionsFolder, folderName);\n        var tempAppCodeFolder = Path.Combine(tempDir, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, folderName);\n        var tempAppCodeExtensionFolderName = Path.Combine(tempDir, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, ExtensionValidationHelper.AppCodeExtensionFolderName(folderName));\n\n        var extensionTarget = Path.Combine(extensionsRoot, folderName);\n        var appCodeTarget = Path.Combine(appRoot, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, folderName);\n\n        var extensionTargetValidation = EnsureTargetReadyForCopy(tempExtensionFolder, extensionTarget, overwrite, FolderConstants.AppExtensionsFolder);\n        if (!extensionTargetValidation.Success)\n            return l.ReturnAsError(extensionTargetValidation);\n\n        var appCodeTargetValidation = EnsureTargetReadyForCopy(tempAppCodeFolder, appCodeTarget, overwrite, FolderConstants.AppCodeFolder);\n        if (!appCodeTargetValidation.Success)\n            return l.ReturnAsError(appCodeTargetValidation);\n\n        var appCodeExtensionFolderNameTargetValidation = EnsureTargetReadyForCopy(tempAppCodeExtensionFolderName, appCodeTarget, overwrite, FolderConstants.AppCodeFolder);\n        if (!appCodeExtensionFolderNameTargetValidation.Success)\n            return l.ReturnAsError(appCodeExtensionFolderNameTargetValidation);\n\n        var copyResult = CopyAllowedFiles(tempDir, appRoot, folderName, allowedFiles);\n        if (!copyResult.Success)\n            return l.ReturnAsError(copyResult);\n\n        return l.ReturnAsOk(new(true, null));\n    }\n\n    // Ensure the destination directory is ready to receive new files, deleting previous content when required.\n    private ValidationResult EnsureTargetReadyForCopy(string tempSourcePath, string targetPath, bool overwrite, string areaName)\n    {\n        var l = Log.Fn<ValidationResult>($\"area:{areaName}\");\n\n        var sourceExists = Directory.Exists(tempSourcePath);\n        var targetExists = Directory.Exists(targetPath);\n\n        if (!sourceExists && !targetExists)\n            return l.ReturnAsOk(new(true, null));\n\n        if (targetExists)\n        {\n            if (!overwrite)\n                return l.ReturnAsError(new(false, $\"'{targetPath}' target exists - set overwrite\"));\n\n            l.A($\"cleanup target:'{targetPath}'\");\n            Zipping.TryToDeleteDirectory(targetPath, l);\n        }\n\n        return l.ReturnAsOk(new(true, null));\n    }\n\n    private ValidationResult CopyAllowedFiles(string sourceRoot, string targetRoot, string folderName, HashSet<string> allowedFiles)\n    {\n        var l = Log.Fn<ValidationResult>($\"copy:'{folderName}'\");\n\n        var sourceRootFull = EnsureTrailingBackslash(Path.GetFullPath(sourceRoot));\n        var targetRootFull = EnsureTrailingBackslash(Path.GetFullPath(targetRoot));\n\n        var sources = new[]\n        {\n            Path.Combine(sourceRoot, FolderConstants.AppExtensionsFolder, folderName),\n            Path.Combine(sourceRoot, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, folderName),\n            ExtensionValidationHelper.GetActualCasedPath(Path.Combine(sourceRoot, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, ExtensionValidationHelper.AppCodeExtensionFolderName(folderName))),\n        };\n\n        foreach (var source in sources)\n        {\n            foreach (var file in EnumerateFilesSafe(source))\n            {\n                var rel = file\n                    .Substring(sourceRootFull.Length)\n                    .TrimPrefixSlash()\n                    .ForwardSlash();\n\n                var isLockFile = rel.EndsWith(PackageIndexFile.LockFileName, StringComparison.OrdinalIgnoreCase);\n                if (!isLockFile && !allowedFiles.Contains(rel))\n                    continue;\n\n                var destinationPath = Path.GetFullPath(Path.Combine(targetRoot, rel.Backslash()));\n                if (!destinationPath.StartsWith(targetRootFull, StringComparison.OrdinalIgnoreCase))\n                    return l.ReturnAsError(new(false, $\"illegal destination path:'{rel}'\"));\n\n                Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)!);\n                readOnlyHelper.RemoveReadOnlyIfNeeded(destinationPath, rel);\n                File.Copy(file, destinationPath, overwrite: true);\n                readOnlyHelper.EnsureReadOnly(destinationPath, rel);\n                l.A($\"copied:'{rel}'\");\n            }\n        }\n\n        return l.ReturnAsOk(new(true, null));\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionLockHelper.cs",
    "content": "using System.Text.Json;\nusing ToSic.Sxc.ImportExport.Package.Sys;\nusing ToSic.Sys.Security.Encryption;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Shared helpers to read and work with extension lock files.\n/// </summary>\ninternal static class ExtensionLockHelper\n{\n    // TODO: @2rb - change to use the typed PackageIndexFile instead of the raw JsonDocument\n    internal static LockFileReadResult ReadLockFile(string lockFilePath, ILog? parentLog)\n    {\n        var l = parentLog.Fn<LockFileReadResult>();\n        try\n        {\n            var json = File.ReadAllText(lockFilePath);\n            using var doc = JsonDocument.Parse(json);\n            var root = doc.RootElement;\n            if (!root.TryGetProperty(\"files\", out var filesProp) || filesProp.ValueKind != JsonValueKind.Array)\n                return l.Return(new(false, $\"{PackageIndexFile.LockFileName} missing 'files' array\", null, null));\n\n            var expectedWithHash = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);\n            var allowed = new HashSet<string>(StringComparer.OrdinalIgnoreCase);\n\n            foreach (var item in filesProp.EnumerateArray())\n            {\n                if (item.ValueKind != JsonValueKind.Object)\n                    return l.Return(new(false, $\"invalid {PackageIndexFile.LockFileName} entry: {item.ValueKind}\", null, null));\n\n                if (!item.TryGetProperty(\"file\", out var f) || f.ValueKind != JsonValueKind.String)\n                    return l.Return(new(false, $\"{PackageIndexFile.LockFileName} entry missing 'file'\", null, null));\n\n                if (!item.TryGetProperty(\"hash\", out var h) || h.ValueKind != JsonValueKind.String)\n                    return l.Return(new(false, $\"{PackageIndexFile.LockFileName} entry missing 'hash'\", null, null));\n\n                var file = f.GetString()!.Trim().TrimPrefixSlash().ForwardSlash();\n                var hash = h.GetString()!.Trim();\n\n                if (file.ContainsPathTraversal())\n                    return l.Return(new(false, $\"illegal path:'{file}' in {PackageIndexFile.LockFileName}\", null, null));\n\n                allowed.Add(file);\n                expectedWithHash[file] = hash;\n                l.A($\"added lock entry:'{file}'\");\n            }\n\n            return l.Return(new(true, null, expectedWithHash, allowed), $\"entries:{expectedWithHash.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return(new(false, $\"{PackageIndexFile.LockFileName} parse error\", null, null));\n        }\n    }\n\n    internal static IEnumerable<string> EnumerateFilesSafe(string? path)\n        => !string.IsNullOrWhiteSpace(path) && Directory.Exists(path)\n            ? Directory.GetFiles(path, \"*\", SearchOption.AllDirectories)\n            : [];\n\n    internal static string EnsureTrailingBackslash(string path)\n        => path.SuffixSlash().Backslash();\n\n    internal static string CalculateHash(string path)\n        => Sha256.Hash(File.ReadAllBytes(path));\n}\n\ninternal record LockFileReadResult(bool Success, string? Error, Dictionary<string, string>? ExpectedWithHash, HashSet<string>? AllowedFiles);\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionManifestSerializer.cs",
    "content": "using System.Text.Json;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic static class ExtensionManifestSerializer\n{\n    private static readonly JsonElement JsonNullElement = JsonDocument.Parse(\"null\").RootElement.Clone();\n\n    private static readonly JsonSerializerOptions DefaultOptions = new()\n    {\n        WriteIndented = true\n    };\n\n    private static JsonElement Sanitize(JsonElement el) => el.ValueKind == JsonValueKind.Undefined ? JsonNullElement : el;\n\n    /// <summary>\n    /// Serialize manifest ensuring undefined JsonElements become null to prevent System.Text.Json exceptions.\n    /// </summary>\n    public static string Serialize(ExtensionManifest manifest, JsonSerializerOptions? options = null)\n    {\n        var sanitized = manifest with\n        {\n            DataBundles = Sanitize(manifest.DataBundles),\n            //InputTypeAssets = Sanitize(manifest.InputTypeAssets),\n            InputFieldAssets = Sanitize(manifest.InputFieldAssets),\n            Releases = Sanitize(manifest.Releases),\n        };\n        return JsonSerializer.Serialize(sanitized, options ?? DefaultOptions);\n    }\n\n    public static string Serialize(JsonElement manifest, JsonSerializerOptions? options = null)\n        => JsonSerializer.Serialize(manifest, options ?? DefaultOptions);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionPreflightDtos.cs",
    "content": "using System.Text.Json.Serialization;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PreflightResultDto\n{\n    [JsonPropertyName(\"extensions\")]\n    public List<PreflightExtensionDto> Extensions { get; init; } = [];\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class PreflightExtensionDto\n{\n    [JsonPropertyName(\"name\")]\n    public required string Name { get; init; }\n\n    [JsonPropertyName(\"version\")]\n    public string? Version { get; init; }\n\n    [JsonPropertyName(\"editionsSupported\")]\n    public bool EditionsSupported { get; init; }\n\n    [JsonPropertyName(\"fileCount\")]\n    public int FileCount { get; init; }\n\n    [JsonPropertyName(\"features\")]\n    public ExtensionFeaturesDto Features { get; init; } = new();\n\n    [JsonPropertyName(\"editions\")]\n    public List<ExtensionEditionDto> Editions { get; init; } = [];\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionEditionDto\n{\n    [JsonPropertyName(\"edition\")]\n    public string Edition { get; init; } = string.Empty;\n\n    [JsonPropertyName(\"isInstalled\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public bool? IsInstalled { get; init; } = null;\n\n    [JsonPropertyName(\"currentVersion\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public string? CurrentVersion { get; init; } = null;\n\n    [JsonPropertyName(\"hasFileChanges\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public bool? HasFileChanges { get; init; } = null;\n\n    [JsonPropertyName(\"dataInside\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public bool? DataInside { get; init; } = null;\n\n    [JsonPropertyName(\"breakingChanges\")]\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public bool? BreakingChanges { get; init; } = null;\n}\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionFeaturesDto\n{\n    [JsonPropertyName(\"inputFieldInside\")]\n    public bool InputFieldInside { get; init; }\n\n    [JsonPropertyName(\"razorInside\")]\n    public bool RazorInside { get; init; }\n\n    [JsonPropertyName(\"appCodeInside\")]\n    public bool AppCodeInside { get; init; }\n\n    [JsonPropertyName(\"webApiInside\")]\n    public bool WebApiInside { get; init; }\n\n    [JsonPropertyName(\"contentTypesInside\")]\n    public bool ContentTypesInside { get; init; }\n\n    //[JsonPropertyName(\"dataBundlesInside\")]\n    //public bool DataBundlesInside { get; init; }\n\n    [JsonPropertyName(\"queriesInside\")]\n    public bool QueriesInside { get; init; }\n\n    [JsonPropertyName(\"viewsInside\")]\n    public bool ViewsInside { get; init; }\n\n    [JsonPropertyName(\"dataInside\")]\n    public bool DataInside { get; init; }\n\n    //[JsonPropertyName(\"inputTypeInside\")]\n    //public bool InputTypeInside { get; init; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionPreflightHelper.cs",
    "content": "using System.Text.Json;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Builds preflight information for extension zip installations.\n/// </summary>\ninternal class ExtensionPreflightHelper(\n    ExtensionManifestService manifestService,\n    LazySvc<ExtensionInspectBackend> inspectorLazy,\n    ILog? parentLog)\n    : HelperBase(parentLog, \"Bck.ExtPre\")\n{\n    internal ExtensionEditionDto? BuildEditionInfo(int appId, string appRoot, string extensionName, string edition, ExtensionManifest incomingManifest)\n    {\n        var l = Log.Fn<ExtensionEditionDto>();\n\n        var editionRoot = ExtensionEditionHelper.GetEditionRoot(appRoot, edition);\n\n        l.A($\"prep edition:'{edition}', root:'{editionRoot}', ext:'{extensionName}'\");\n\n        if (!Directory.Exists(Path.Combine(editionRoot, FolderConstants.AppExtensionsFolder, extensionName)))\n            return l.ReturnNull($\"extension not found:'{extensionName}'\");\n\n        var installedManifest = LoadInstalledManifest(editionRoot, extensionName);\n        if (installedManifest is null)\n            return l.Return(new ExtensionEditionDto\n            {\n                Edition = edition\n            }, $\"extension without manifest:'{extensionName}'\");\n\n        var currentVersion = installedManifest.Version;\n        var isInstalled = installedManifest.IsInstalled == true;\n\n        var inspectEdition = inspectorLazy.Value.Inspect(appId, extensionName, edition.HasValue() ? edition : null);\n        var hasFileChanges = inspectEdition.FoundLock && inspectEdition.Summary != null\n            && (inspectEdition.Summary.Changed > 0 || inspectEdition.Summary.Added > 0 || inspectEdition.Summary.Missing > 0);\n        var hasData = inspectEdition.Data?.ContentTypes.Any(ct => ct.LocalEntities > 0) == true;\n        var breakingChanges = HasBreakingChanges(incomingManifest, currentVersion);\n\n        l.A($\"state installed:{isInstalled}, ver:'{currentVersion}', changes:{hasFileChanges}, data:{hasData}, breaking:{breakingChanges}\");\n\n        return l.ReturnAsOk(new ExtensionEditionDto\n        {\n            Edition = edition,\n            IsInstalled = isInstalled,\n            CurrentVersion = currentVersion,\n            HasFileChanges = hasFileChanges,\n            DataInside = hasData,\n            BreakingChanges = breakingChanges\n        });\n    }\n\n    internal ExtensionFeaturesDto MapFeatures(ExtensionManifest manifest)\n        => new()\n            {\n                InputFieldInside = manifest.InputFieldInside,\n                RazorInside = manifest.RazorInside,\n                AppCodeInside = manifest.AppCodeInside,\n                WebApiInside = manifest.WebApiInside,\n                ContentTypesInside = manifest.ContentTypesInside,\n                //DataBundlesInside = manifest.HasDataBundles,\n                QueriesInside = manifest.QueriesInside,\n                ViewsInside = manifest.ViewsInside,\n                DataInside = manifest.DataInside,\n                //InputTypeInside = manifest.InputTypeInside.HasValue()\n            };\n\n    private bool HasBreakingChanges(ExtensionManifest incomingManifest, string? currentVersion)\n    {\n        if (incomingManifest.Releases.ValueKind != JsonValueKind.Array)\n            return false;\n\n        var current = new Version();\n        var hasCurrent = currentVersion.HasValue() && Version.TryParse(currentVersion, out current);\n\n        foreach (var release in incomingManifest.Releases.EnumerateArray())\n        {\n            if (release.ValueKind != JsonValueKind.Object)\n                continue;\n\n            var breaking = release.TryGetProperty(\"breaking\", out var breakingProp)\n                           && breakingProp.ValueKind == JsonValueKind.True;\n            if (!breaking)\n                continue;\n\n            if (!hasCurrent)\n                return false;\n\n            if (release.TryGetProperty(\"version\", out var versionProp)\n                && versionProp.ValueKind == JsonValueKind.String\n                && Version.TryParse($\"{versionProp}\", out var releaseVersion))\n            {\n                if (releaseVersion > current)\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    private ExtensionManifest? LoadInstalledManifest(string editionRoot, string extensionName)\n    {\n        var manifestPath = Path.Combine(editionRoot, FolderConstants.AppExtensionsFolder, extensionName, FolderConstants.DataFolderProtected, FolderConstants.AppExtensionJsonFile);\n        return File.Exists(manifestPath)\n            ? manifestService.LoadManifest(new FileInfo(manifestPath))\n            : null;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionReaderBackend.cs",
    "content": "using ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Services;\nusing ToSic.Sys.Utils;\nusing System.Text.Json;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionReaderBackend(\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    ISite site,\n    IAppPathsMicroSvc appPathSvc,\n    LazySvc<IJsonService> jsonLazy,\n    ExtensionManifestService manifestService,\n    LazySvc<CodeControllerReal> codeLazy)\n    : ServiceBase(\"Bck.ExtRead\", connect: [appReadersLazy, site, appPathSvc, jsonLazy, manifestService, codeLazy])\n{\n    private const string IconFileName = \"icon.png\";\n\n    public ExtensionsResultDto GetExtensions(int appId)\n    {\n        var l = Log.Fn<ExtensionsResultDto>($\"a#{appId}\");\n        var appReader = appReadersLazy.Value.Get(appId);\n        var appPaths = appPathSvc.Get(appReader, site);\n        var editionNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)\n        {\n            string.Empty\n        };\n\n        foreach (var edition in codeLazy.Value.GetEditions(appId).Editions.Select(e => e.Name))\n            editionNames.Add(edition);\n\n        var availableEditions = editionNames\n            .OrderBy(name => name.IsEmpty() ? 0 : 1)\n            .ThenBy(name => name, StringComparer.OrdinalIgnoreCase)\n            .ToList();\n\n        Log.A($\"available editions: {string.Join(\", \", availableEditions.Select(EditionLabel))}\");\n\n        var list = new List<ExtensionDto>();\n        var primaryManifests = new Dictionary<string, ExtensionManifest>(StringComparer.OrdinalIgnoreCase);\n        var primaryInputTypes = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);\n\n        foreach (var editionName in availableEditions)\n        {\n            var editionExtensionsDir = Path.Combine(appPaths.PhysicalPath, editionName.IsEmpty()\n                ? FolderConstants.AppExtensionsFolder\n                : Path.Combine(editionName, FolderConstants.AppExtensionsFolder));\n            if (!Directory.Exists(editionExtensionsDir))\n            {\n                Log.A($\"edition {EditionLabel(editionName)} has no extensions folder at '{editionExtensionsDir}'\");\n                continue;\n            }\n\n            foreach (var dir in Directory.GetDirectories(editionExtensionsDir))\n            {\n                var folderName = Path.GetFileName(dir);\n                var manifestFile = manifestService.GetManifestFile(new(dir));\n                //if (!manifestFile.Exists)\n                //{\n                //    Log.A($\"skip extension '{folderName}' in {EditionLabel(editionName)} because manifest file missing\");\n                //    continue;\n                //}\n\n                var configuration = manifestService.LoadManifest(manifestFile) ?? new();\n                //if (configuration == null)\n                //{\n                //    Log.A($\"skip extension '{folderName}' in {EditionLabel(editionName)} because manifest couldn't be parsed\");\n                //    continue;\n                //}\n\n                var inputTypeInside = ReadInputType(manifestFile);\n\n                if (editionName.IsEmpty())\n                {\n                    list.Add(new ExtensionDto\n                    {\n                        Folder = folderName,\n                        Edition = editionName,\n                        Configuration = configuration,\n                        Icon = GetIconUrl(appPaths, editionName, dir)\n                    });\n\n                    primaryManifests[folderName] = configuration;\n                    primaryInputTypes[folderName] = inputTypeInside;\n                    Log.A($\"registered primary extension '{folderName}', supports editions: {configuration?.EditionsSupported}\");\n                    continue;\n                }\n\n                //if (!primaryManifests.TryGetValue(folderName, out var primaryManifest) || !primaryManifest.EditionsSupported)\n                //{\n                //    Log.A($\"skip edition '{EditionLabel(editionName)}' for '{folderName}' because primary manifest missing or not edition-enabled\");\n                //    continue;\n                //}\n\n                //if (!primaryInputTypes.TryGetValue(folderName, out var primaryInputType))\n                //{\n                //    Log.A($\"skip edition '{EditionLabel(editionName)}' for '{folderName}' because base input type was not recorded\");\n                //    continue;\n                //}\n\n                //if (inputTypeInside.IsEmpty())\n                //{\n                //    Log.A($\"skip edition '{EditionLabel(editionName)}' for '{folderName}' because edition manifest lacks inputTypeInside\");\n                //    continue;\n                //}\n\n                //if (!string.Equals(primaryInputType, inputTypeInside, StringComparison.OrdinalIgnoreCase))\n                //{\n                //    Log.A($\"skip edition '{EditionLabel(editionName)}' for '{folderName}' due to inputType mismatch '{inputTypeInside}' != '{primaryInputType}'\");\n                //    continue;\n                //}\n\n                list.Add(new ExtensionDto\n                {\n                    Folder = folderName,\n                    Edition = editionName,\n                    Configuration = configuration,\n                    Icon = GetIconUrl(appPaths, editionName, dir)\n                });\n                Log.A($\"registered edition '{EditionLabel(editionName)}' for extension '{folderName}'\");\n            }\n        }\n        Log.A($\"extensions discovered: {list.Count}\");\n        return l.ReturnAsOk(new ExtensionsResultDto { Extensions = list });\n\n        string EditionLabel(string editionName) => editionName.IsEmpty() ? \"(primary)\" : editionName;\n    }\n\n    // TODO: @STV - WARNING - THIS CODE LOOKS EXTREMELY SIMILAR TO AppFileSystemInputTypesLoader.BuildUiAssets\n    // PLS CHECK AGAIN TO AVOID DUPLICATE CODE\n\n    /// <summary>\n    /// Detect and build edition information for an extension.\n    /// </summary>\n    private List<ExtensionDto> DetectEditions(string appRootPath, string extensionFolderName, ExtensionManifest primaryManifest)\n    {\n        var l = Log.Fn<List<ExtensionDto>>($\"extension:'{extensionFolderName}'\");\n        \n        var appRoot = new DirectoryInfo(appRootPath);\n        var editions = new List<ExtensionDto>();\n\n        // Look for edition folders at the app root level (e.g., /staging, /live, /dev)\n        foreach (var editionFolder in appRoot.GetDirectories())\n        {\n            // Skip the primary extensions folder\n            if (editionFolder.Name.Equals(FolderConstants.AppExtensionsFolder, StringComparison.OrdinalIgnoreCase))\n                continue;\n\n            // Check if this edition folder has a matching extensions subfolder\n            var editionExtensionsPath = Path.Combine(editionFolder.FullName, FolderConstants.AppExtensionsFolder);\n            if (!Directory.Exists(editionExtensionsPath))\n                continue;\n\n            // Check if the specific extension exists in this edition\n            var editionExtensionPath = Path.Combine(editionExtensionsPath, extensionFolderName);\n            if (!Directory.Exists(editionExtensionPath))\n                continue;\n\n            // Load the edition manifest\n            var editionManifestFile = manifestService.GetManifestFile(new DirectoryInfo(editionExtensionPath));\n            if (!editionManifestFile.Exists)\n                continue;\n\n            var editionManifest = manifestService.LoadManifest(editionManifestFile);\n            //if (editionManifest?.InputTypeInside.IsEmpty() ?? true)\n            if (editionManifest?.InputFieldInside ?? true)\n                continue;\n\n            // Ensure the edition manifest references the same input type\n            //if (!editionManifest.InputTypeInside.Equals(primaryManifest.InputTypeInside, StringComparison.OrdinalIgnoreCase))\n            if (editionManifest.InputFieldInside != primaryManifest.InputFieldInside)\n            {\n                //l.A($\"Edition {editionFolder.Name} has mismatched inputTypeInside: {editionManifest.InputTypeInside} != {primaryManifest.InputTypeInside}\");\n                l.A($\"Edition {editionFolder.Name} has mismatched inputTypeInside: {editionManifest.InputFieldInside} != {primaryManifest.InputFieldInside}\");\n                continue;\n            }\n\n            editions.Add(new()\n            {\n                Folder = extensionFolderName,\n                Edition = editionFolder.Name,\n                Configuration = editionManifest\n            });\n        }\n\n        return l.Return(editions, $\"found:{editions.Count}\");\n    }\n\n    private static string? ReadInputType(FileInfo manifestFile)\n    {\n        if (!manifestFile.Exists)\n            return null;\n\n        using var json = JsonDocument.Parse(File.ReadAllText(manifestFile.FullName));\n        return json.RootElement.TryGetProperty(\"inputTypeInside\", out var inputType)\n            && inputType.ValueKind == JsonValueKind.String\n            ? inputType.GetString()\n            : null;\n    }\n\n    private string GetIconUrl(IAppPaths appPaths, string editionName, string extensionDir)\n    {\n        var iconPath = Path.Combine(extensionDir, IconFileName);\n        if (!File.Exists(iconPath))\n            return \"\";\n\n        var folderName = Path.GetFileName(extensionDir);\n        var relativePath = BuildRelativeIconPath(appPaths, editionName, folderName);\n        return relativePath;\n    }\n\n    private static string BuildRelativeIconPath(IAppPaths appPaths, string editionName, string folderName)\n    {\n        var baseRelative = appPaths.RelativePath.ForwardSlash().Trim('/');\n\n        var parts = new List<string>();\n        if (!baseRelative.IsEmpty())\n            parts.Add(baseRelative);\n        if (!editionName.IsEmpty())\n            parts.Add(editionName);\n\n        parts.Add(FolderConstants.AppExtensionsFolder);\n        parts.Add(folderName);\n        parts.Add(IconFileName);\n\n        var relativePath = string.Join(\"/\", parts)\n            .TrimPrefixSlash()\n            .PrefixSlash();\n\n        return relativePath;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionValidationHelper.cs",
    "content": "using ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.ImportExport.Package.Sys;\nusing ToSic.Sys.Utils;\nusing static ToSic.Sxc.Backend.App.ExtensionLockHelper;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Validation helper for incoming extension zip archives.\n/// </summary>\ninternal class ExtensionValidationHelper(ExtensionManifestService manifestSvc, ILog? parentLog) : HelperBase(parentLog, \"Bck.ExtVal\")\n{\n    internal (string? error, Dictionary<string, LockValidationResult> lockResults, Dictionary<string, ManifestValidationResult> manifestResults) ValidateCandidateSubfolders(string tempDir,\n        string[] candidateDirs)\n    {\n        var l = Log.Fn<(string? error, Dictionary<string, LockValidationResult> lockResults, Dictionary<string, ManifestValidationResult> manifestResults)>();\n\n        var issues = new List<string>();\n        var lockResults = new Dictionary<string, LockValidationResult>(StringComparer.OrdinalIgnoreCase);\n        var manifestResults = new Dictionary<string, ManifestValidationResult>(StringComparer.OrdinalIgnoreCase);\n\n        foreach (var dir in candidateDirs)\n        {\n            var folder = Path.GetFileName(dir);\n            l.A($\"validate:'{folder}'\");\n\n            var appDataDir = Path.Combine(dir, FolderConstants.DataFolderProtected);\n\n            var folderIssues = new List<string>();\n\n            var extensionJsonPath = Path.Combine(appDataDir, FolderConstants.AppExtensionJsonFile);\n            if (!File.Exists(extensionJsonPath))\n                folderIssues.Add($\"missing {FolderConstants.AppExtensionJsonFile}\");\n\n            var lockJsonPath = Path.Combine(appDataDir, PackageIndexFile.LockFileName);\n            if (!File.Exists(lockJsonPath))\n                folderIssues.Add($\"missing {PackageIndexFile.LockFileName}\");\n\n            // Validate extension.json contents if present\n            LockValidationResult? lockValidation = null;\n            if (File.Exists(extensionJsonPath))\n            {\n                var extVal = ValidateExtensionJsonFile(extensionJsonPath);\n                if (!extVal.Success)\n                    folderIssues.Add(extVal.Error ?? \"extension.json invalid\");\n                else\n                    manifestResults[folder] = extVal;\n            }\n\n            // Validate lock file contents restricted to this candidate\n            if (File.Exists(lockJsonPath))\n            {\n                lockValidation = ValidateLockFile(lockJsonPath, tempDir, dir);\n                if (!lockValidation.Success)\n                    folderIssues.Add(lockValidation.Error ?? $\"{PackageIndexFile.LockFileName} invalid\");\n            }\n\n            if (folderIssues.Any())\n                issues.Add($\"{folder}: {string.Join(\", \", folderIssues)}\");\n            else if (lockValidation != null)\n                lockResults[folder] = lockValidation;\n        }\n\n        return l.ReturnAndLog((issues.Any() ? $\"invalid extension subfolder(s): {string.Join(\"; \", issues)}\" : null, lockResults, manifestResults));\n    }\n\n    internal ManifestValidationResult ValidateExtensionJsonFile(string extensionJsonFilePath)\n    {\n        var l = Log.Fn<ManifestValidationResult>();\n\n        try\n        {\n            var manifest = manifestSvc.LoadManifest(new FileInfo(extensionJsonFilePath));\n            if (manifest == null)\n                return l.ReturnAsError(new(false, $\"{FolderConstants.AppExtensionJsonFile} parse error\", false, null));\n\n            if (manifest.IsInstalled != true)\n                return l.ReturnAsError(new(false, $\"{FolderConstants.AppExtensionJsonFile} missing 'isInstalled' True\", false, manifest));\n\n            var editionsSupported = manifest.EditionsSupported;\n\n            return l.ReturnAsOk(new(true, null, editionsSupported, manifest));\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.ReturnAsError(new(false, $\"{FolderConstants.AppExtensionJsonFile} parse error\", false, null));\n        }\n    }\n\n    // Validate lock file against a single candidate folder only\n    internal LockValidationResult ValidateLockFile(string lockFilePath, string tempDir, string candidatePath)\n    {\n        var l = Log.Fn<LockValidationResult>();\n\n        var lockRead = ReadLockFile(lockFilePath, l);\n        if (!lockRead.Success || lockRead.ExpectedWithHash == null || lockRead.AllowedFiles == null)\n            return l.ReturnAsError(new(false, lockRead.Error ?? $\"{PackageIndexFile.LockFileName} invalid\", null));\n\n        var allowed = lockRead.AllowedFiles;\n        var expectedWithHash = lockRead.ExpectedWithHash;\n        var folderName = Path.GetFileName(candidatePath);\n        var tmpAppCodeExtensionDirectory = Path.Combine(tempDir, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, folderName);\n        var tmpAppCodeExtensionFolderNameDirectory = Path.Combine(tempDir, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, AppCodeExtensionFolderName(folderName));\n\n        var actualFiles = EnumerateFilesSafe(candidatePath)\n            .Union(EnumerateFilesSafe(tmpAppCodeExtensionDirectory)) // Old JS folder format, lowercase with dashes\n            .Union(EnumerateFilesSafe(tmpAppCodeExtensionFolderNameDirectory)) // CamelCase format, without dashes\n            .Select(f => f\n                .Substring(tempDir.Length)\n                .TrimPrefixSlash()\n                .ForwardSlash())\n            .Where(f => !string.Equals(Path.GetFileName(f), PackageIndexFile.LockFileName, StringComparison.OrdinalIgnoreCase))\n            .ToHashSet(StringComparer.OrdinalIgnoreCase);\n\n        var missing = allowed\n            .Where(a => !actualFiles.Contains(a))\n            .ToList();\n        if (missing.Any())\n            return l.ReturnAsError(new(false, $\"missing files:'{string.Join(\"','\", missing)}'\", null));\n\n        var extras = actualFiles\n            .Where(a => !allowed.Contains(a))\n            .ToList();\n        if (extras.Any())\n            return l.ReturnAsError(new(false, $\"unexpected files:'{string.Join(\"','\", extras)}'\", null));\n\n        foreach (var rel in allowed)\n        {\n            var full = Path.Combine(tempDir, rel.Backslash());\n            if (!File.Exists(full))\n                return l.ReturnAsError(new(false, $\"file for hash missing:{rel}\", null));\n\n            var actualHash = CalculateHash(full);\n            var expected = expectedWithHash[rel];\n            if (!string.Equals(actualHash, expected, StringComparison.OrdinalIgnoreCase))\n                return l.ReturnAsError(new(false, $\"hash mismatch: {rel}\", null));\n        }\n\n        return l.ReturnAsOk(new(true, null, allowed));\n    }\n\n    /// <summary>\n    /// Converts a JS folder name to a format suitable for the app code folder (without dashes).\n    /// </summary>\n    /// <param name=\"folderName\"></param>\n    /// <returns></returns>\n    internal static string AppCodeExtensionFolderName(string folderName) => folderName.Replace(\"-\", \"\");\n\n    /// <summary>\n    /// Return the actual on-disk cased path casing for a given full path.\n    /// </summary>\n    /// <param name=\"fullPath\"></param>\n    /// <returns></returns>\n    internal static string GetActualCasedPath(string fullPath)\n    {\n        var dir = new DirectoryInfo(fullPath);\n        var parent = dir.Parent;\n        if (parent == null || !parent.Exists)\n            return fullPath;\n\n        return GetActualCasedPath(parent.FullName, dir.Name);\n    }\n\n    /// <summary>\n    /// Return the actual on-disk cased path casing for a given parent path and folder name.\n    /// </summary>\n    /// <param name=\"parentPath\"></param>\n    /// <param name=\"folderName\"></param>\n    /// <returns></returns>\n    internal static string GetActualCasedPath(string parentPath, string folderName)\n    {\n        var parent = new DirectoryInfo(parentPath);\n        if (!parent.Exists)\n            return Path.Combine(parentPath, folderName);\n\n        // Important: constructing DirectoryInfo from a string does NOT correct casing.\n        // To get the actual on-disk casing (Windows/macOS case-insensitive FS), we must\n        // ask the filesystem for existing entries and use the returned Name/FullName.\n        //\n        // EnumerateDirectories() is lazy (streaming): it doesn't allocate an array like\n        // GetDirectories(), and it can stop early once FirstOrDefault finds a match.\n        var match = parent.EnumerateDirectories()\n            .FirstOrDefault(d => d.Name.Equals(folderName, StringComparison.OrdinalIgnoreCase));\n\n        return match?.FullName ?? Path.Combine(parentPath, folderName);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionValidationModels.cs",
    "content": "using ToSic.Eav.Apps.Sys.FileSystemState;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Shared validation results for extension zip operations.\n/// </summary>\ninternal record ValidationResult(bool Success, string? Error);\n\ninternal record LockValidationResult(bool Success, string? Error, HashSet<string>? AllowedFiles) : ValidationResult(Success, Error);\n\ninternal record ManifestValidationResult(bool Success, string? Error, bool EditionsSupported, ExtensionManifest? Manifest) : ValidationResult(Success, Error);\n\ninternal record ExtensionExtractionResult(\n    bool Success,\n    string? Error,\n    string TempDir,\n    string AppRoot,\n    string[] Editions,\n    Dictionary<string, LockValidationResult> LockResults,\n    Dictionary<string, ManifestValidationResult> ManifestResults);\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionWriterBackend.cs",
    "content": "using System.Text;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExtensionWriterBackend(\n    LazySvc<IAppReaderFactory> appReadersLazy,\n    ISite site,\n    IAppPathsMicroSvc appPathSvc)\n    : ServiceBase(\"Bck.ExtWrite\", connect: [appReadersLazy, site, appPathSvc])\n{\n    // Remove previous local serializer & use shared helper\n    public bool SaveConfiguration(int appId, string name, ExtensionManifest manifest)\n    {\n        var l = Log.Fn<bool>($\"a:{appId}, f:'{name}'\");\n        if (name.IsEmpty())\n            return l.ReturnFalse(\"no folder\");\n        name = name.Trim();\n        if (!ExtensionFolderNameValidator.IsValid(name))\n            return l.ReturnFalse($\"invalid folder name:'{name}'\");\n        var appReader = appReadersLazy.Value.Get(appId);\n        var appPaths = appPathSvc.Get(appReader, site);\n        var dir = Path.Combine(appPaths.PhysicalPath, FolderConstants.AppExtensionsFolder, name);\n        \n        // Create extension folder if it doesn't exist\n        Directory.CreateDirectory(dir);\n        \n        var appData = Path.Combine(dir, FolderConstants.DataFolderProtected);\n        var jsonPath = Path.Combine(appData, FolderConstants.AppExtensionJsonFile);\n        try\n        {\n            Directory.CreateDirectory(appData);\n            var json = ExtensionManifestSerializer.Serialize(manifest);\n            File.WriteAllText(jsonPath, json, new UTF8Encoding(false));\n            return l.ReturnTrue(\"saved\");\n        }\n        catch (Exception ex)\n        {\n            Log.Ex(ex);\n            return l.ReturnFalse(\"error\");\n        }\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ExtensionsForIApp.cs",
    "content": "﻿//using System.Text.RegularExpressions;\n//using ToSic.Eav.Apps.Internal.Specs;\n\n//namespace ToSic.Sxc.Backend.App;\n\n//[ShowApiWhenReleased(ShowApiMode.Never)]\n//public static class ExtensionsForIApp\n//{\n//    //public static string VersionSafe(this IAppSpecs app)\n//    //    => app.Configuration.Version?.ToString() ?? \"\";\n\n//    public static string NameWithoutSpecialChars(this IAppSpecs app)\n//        => Regex.Replace(app.Name, \"[^a-zA-Z0-9-_]\", \"\");\n\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/App/ReadOnlyFileHelper.cs",
    "content": "using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.App;\n\n/// <summary>\n/// Helper to manage readonly flags on files and directories.\n/// </summary>\ninternal class ReadOnlyFileHelper(ILog? parentLog) : HelperBase(parentLog, \"Bck.RoHlp\")\n{\n    internal void RemoveReadOnlyRecursive(string directory)\n    {\n        var l = Log.Fn();\n        if (!Directory.Exists(directory))\n        {\n            l.Done(\"path not exist\");\n            return;\n        }\n\n        foreach (var file in Directory.GetFiles(directory, \"*\", SearchOption.AllDirectories))\n            RemoveReadOnlyIfNeeded(file);\n\n        foreach (var dir in Directory.GetDirectories(directory, \"*\", SearchOption.AllDirectories))\n            ClearDirectoryReadOnly(dir);\n\n        ClearDirectoryReadOnly(directory);\n        l.Done();\n    }\n\n    internal void RemoveReadOnlyIfNeeded(string path, string? relPath = null)\n    {\n        var l = Log.Fn();\n\n        if (!File.Exists(path))\n        {\n            l.Done(relPath.HasValue() ? $\"file not found: {relPath}\" : \"file do not exist\");\n            return;\n        }\n\n        var attributes = File.GetAttributes(path);\n        if (!attributes.HasFlag(FileAttributes.ReadOnly))\n        {\n            l.Done(relPath.HasValue() ? $\"file is not readonly: {relPath}\" : \"file is not readonly\");\n            return;\n        }\n\n        File.SetAttributes(path, attributes & ~FileAttributes.ReadOnly);\n        l.Done($\"cleared readonly:'{relPath ?? path}'\");\n    }\n\n    internal void EnsureReadOnly(string path, string relPath)\n    {\n        var l = Log.Fn();\n\n        if (!File.Exists(path))\n        {\n            l.Done($\"file not found: {relPath}\");\n            return;\n        }\n\n        var attributes = File.GetAttributes(path);\n        if (attributes.HasFlag(FileAttributes.ReadOnly))\n        {\n            l.Done($\"file is already readonly: {relPath}\");\n            return;\n        }\n\n        File.SetAttributes(path, attributes | FileAttributes.ReadOnly);\n        l.Done($\"set readonly:'{relPath}'\");\n    }\n\n    internal void ClearDirectoryReadOnly(string directory)\n    {\n        var l = Log.Fn();\n        var info = new DirectoryInfo(directory);\n        var attributes = info.Attributes;\n        if (!attributes.HasFlag(FileAttributes.ReadOnly))\n        {\n            l.Done(\"directory is not readonly\");\n            return;\n        }\n\n        info.Attributes = attributes & ~FileAttributes.ReadOnly;\n        l.Done($\"cleared readonly dir:'{directory}'\");\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/AppStack/AppStackBackend.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.Data.Sys.PropertyDump;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.DataSources.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing static ToSic.Eav.Apps.Sys.AppStack.AppStackConstants;\n\nnamespace ToSic.Sxc.Backend.AppStack;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppStackBackend(\n    AppDataStackService dataStackService,\n    IZoneCultureResolver zoneCulture,\n    IAppReaderFactory appReaders,\n    Generator<QueryDefinitionFactory> qDefBuilder,\n    IPropertyDumpService dumperService)\n    : ServiceBase(\"Sxc.ApiApQ\", connect: [dataStackService, zoneCulture, appReaders, dumperService])\n{\n    public List<AppStackDataRaw> GetAll(int appId, string part, string? key, Guid? viewGuid)\n    {\n        // Correct languages\n        //if (languages == null || !languages.Any())\n        var languages = zoneCulture.SafeLanguagePriorityCodes();\n        // Get app \n        var appReader = appReaders.Get(appId);\n        // Ensure we have the correct stack name\n        var partName = SystemStackHelpers.GetStackNameOrNull(part);\n        if (partName == null)\n            throw new($\"Parameter '{nameof(part)}' must be {RootNameSettings} or {RootNameResources}\");\n        var viewMixin = GetViewSettingsForMixin(viewGuid, languages, appReader, partName);\n        var results = GetStackDump(appReader, partName, languages, viewMixin);\n        \n        results = SystemStackHelpers.ApplyKeysFilter(results, key);\n        if (!results.Any())\n            return [];\n\n        var final = SystemStackHelpers.ReducePropertiesToRelevantOnes(results);\n\n                \n\n        return final.Select(r => new AppStackDataRaw(r))\n            .ToList();\n    }\n\n\n\n    public List<PropertyDumpItem> GetStackDump(IAppReader appReader, string partName, string?[] languages, IEntity? viewSettingsMixin)\n    {\n        // Build Sources List\n        var settings = dataStackService.Init(appReader).GetStack(partName, viewSettingsMixin);\n\n        var results = dumperService.Dump(settings, new(null!, languages, true, Log), null!);\n        return results;\n    }\n\n\n    private IEntity? GetViewSettingsForMixin(Guid? viewGuid, string?[] languages, IAppReadEntities appState, string realName)\n    {\n        if (viewGuid == null)\n            return null;\n\n        var viewEnt = appState.List.GetOne(viewGuid.Value)\n                      ?? throw new($\"Tried to get view but not found. Guid was {viewGuid}\");\n        \n        var view = new View(viewEnt, languages, qDefBuilder);\n        var viewStackPart = realName == RootNameSettings\n            ? view.Settings\n            : view.Resources;\n\n        return viewStackPart;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Block/BlockControllerReal.cs",
    "content": "﻿using ToSic.Eav.Sys;\nusing ToSic.Sxc.Apps.Sys.Ui;\nusing ToSic.Sxc.Backend.ContentBlocks;\nusing ToSic.Sxc.Backend.InPage;\nusing Services_ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class BlockControllerReal(\n    LazySvc<IContextOfSite> context,\n    LazySvc<ContentBlockBackend> blockBackend,\n    LazySvc<AppViewPickerBackend> viewsBackend,\n    LazySvc<WorkApps> workApps)\n    : Services_ServiceBase($\"{EavLogs.WebApi}.{LogSuffix}Rl\", connect: [context, blockBackend, viewsBackend, workApps]),\n        IBlockController\n{\n    public const string LogSuffix = \"Block\";\n\n\n    #region Block\n\n    [field: AllowNull, MaybeNull]\n    private ContentBlockBackend Backend => field ??= blockBackend.Value;\n\n    /// <inheritdoc />\n    public string Block(int parentId, string field, int index, string app = \"\", Guid? guid = null)\n        => Backend.NewBlockAndRender(parentId, field, index, app, guid).Html ?? \"\";\n    #endregion\n\n    #region BlockItems\n    /// <summary>\n    /// used to be GET Module/AddItem\n    /// </summary>\n    public void Item(int? index = null)\n        => Backend.AddItem(index);\n\n    #endregion\n\n\n    #region App\n\n    /// <summary>\n    /// used to be GET Module/SetAppId\n    /// </summary>\n    /// <param name=\"appId\"></param>\n\n    public void App(int? appId)\n        => viewsBackend.Value.SetAppId(appId);\n\n    /// <summary>\n    /// used to be GET Module/GetSelectableApps\n    /// </summary>\n    /// <param name=\"apps\"></param>\n    /// <returns></returns>\n    public IEnumerable<AppUiInfo> Apps(string? apps = null)\n    {\n        // Note: we must get the zone-id from the tenant, since the app may not yet exist when inserted the first time\n        var site = context.Value.Site;\n        return [.. workApps.Value.GetSelectableApps(site, apps)];\n    }\n\n    #endregion\n\n    #region Types\n\n    /// <inheritdoc />\n    public IEnumerable<ContentTypeUiInfo> ContentTypes() => viewsBackend.Value.ContentTypes();\n\n    #endregion\n\n    #region Templates\n\n    /// <summary>\n    /// used to be GET Module/GetSelectableTemplates\n    /// </summary>\n    /// <returns></returns>\n    public IEnumerable<TemplateUiInfo> Templates() => viewsBackend.Value.Templates();\n\n    /// <summary>\n    /// Used in InPage.js\n    /// used to be GET Module/SaveTemplateId\n    /// </summary>\n    /// <param name=\"templateId\"></param>\n    /// <param name=\"forceCreateContentGroup\"></param>\n    /// <returns></returns>\n    public Guid? Template(int templateId, bool forceCreateContentGroup)\n        => viewsBackend.Value\n            .SaveTemplateId(templateId, forceCreateContentGroup);\n\n    #endregion\n\n    /// <inheritdoc />\n    public AjaxRenderDto Render(int templateId, string lang, string edition)\n        => Backend.RenderForAjax(templateId, lang, _moduleRoot, edition);\n\n    public BlockControllerReal Set(string moduleRoot)\n    {\n        _moduleRoot = moduleRoot;\n        return this;\n    }\n\n    private string _moduleRoot = null!;\n\n\n    /// <inheritdoc />\n    public bool Publish(string part, int index)\n        => Backend.PublishPart(part, index);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Block/IBlockController.cs",
    "content": "﻿using ToSic.Sxc.Apps.Sys.Ui;\nusing ToSic.Sxc.Backend.InPage;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\npublic interface IBlockController\n{\n    /// <summary>\n    /// used to be GET Module/GenerateContentBlock\n    /// </summary>\n    string Block(int parentId, string field, int index, string app = \"\", Guid? guid = null);\n\n    /// <summary>\n    /// used to be GET Module/AddItem\n    /// </summary>\n    void Item(int? index = null);\n\n    /// <summary>\n    /// used to be GET Module/SetAppId\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /*new*/\n    void App(int? appId);\n\n    /// <summary>\n    /// used to be GET Module/GetSelectableApps\n    /// </summary>\n    /// <param name=\"apps\"></param>\n    /// <returns></returns>\n    IEnumerable<AppUiInfo> Apps(string? apps = null);\n\n    /// <summary>\n    /// used to be GET Module/GetSelectableContentTypes\n    /// </summary>\n    /// <returns></returns>\n    IEnumerable<ContentTypeUiInfo> ContentTypes();\n\n    /// <summary>\n    /// used to be GET Module/GetSelectableTemplates\n    /// </summary>\n    /// <returns></returns>\n    IEnumerable<TemplateUiInfo> Templates();\n\n    /// <summary>\n    /// Used in InPage.js\n    /// used to be GET Module/SaveTemplateId\n    /// </summary>\n    /// <param name=\"templateId\"></param>\n    /// <param name=\"forceCreateContentGroup\"></param>\n    /// <returns></returns>\n    Guid? Template(int templateId, bool forceCreateContentGroup);\n\n    /// <summary>\n    /// used to be GET Module/RenderTemplate\n    /// js changed\n    /// </summary>\n    /// <summary>\n    /// Used in InPage.js\n    /// </summary>\n    AjaxRenderDto Render(int templateId, string lang, string edition);\n\n    /// <summary>\n    /// Used to be GET Module/Publish\n    /// </summary>\n    bool Publish(string part, int index);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/EditControllerReal.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Sxc.Backend.InPage;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EditControllerReal(\n    LazySvc<EditLoadBackend> loadBackend,\n    LazySvc<EditSaveBackend> saveBackendLazy,\n    LazySvc<HyperlinkBackend> linkBackendLazy,\n    LazySvc<AppViewPickerBackend> appViewPickerBackendLazy)\n    : ServiceBase(\"Api.EditRl\", connect: [loadBackend, saveBackendLazy, linkBackendLazy, appViewPickerBackendLazy]),\n        IEditController\n{\n    public const string LogSuffix = \"Edit\";\n\n    public async Task<EditLoadDto> Load(List<ItemIdentifier> items, int appId)\n        => await loadBackend.Value.Load(appId, items);\n\n    public async Task<Dictionary<Guid, int>> Save(EditSaveDto package, int appId, bool partOfPage)\n        => await saveBackendLazy.Value.Save(appId, package, partOfPage);\n\n\n    public LinkInfoDto LinkInfo(string link, int appId, string? contentType = default, Guid guid = default, string? field = default)\n        => linkBackendLazy.Value.LookupHyperlink(appId, link, contentType, guid, field);\n\n    // TODO: we will need to make simpler implementation\n    public bool Publish(int id)\n        => appViewPickerBackendLazy.Value.Publish(id);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/EditLoadBackend.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.WebApi.Sys.Entities;\nusing ToSic.Sxc.Backend.Cms.Load.Activities;\nusing ToSic.Sxc.Backend.SaveHelpers;\nusing ToSic.Sys.Security.Permissions;\n\n\nnamespace ToSic.Sxc.Backend.Cms;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EditLoadBackend(\n    AppWorkContextService workCtxSvc,\n    EditLoadActionGetForEditing actGetForEditing,\n    ISxcCurrentContextService ctxService,\n    Generator<MultiPermissionsTypes, MultiPermissionsTypes.Options> typesPermissions,\n    LazySvc<DataValidatorContentTypeDataStore> valContentTypeDataStore,\n\n    EditLoadActivityCleanupRequest actCleanupRequest,\n    EditLoadActivityConvertRequest actConvertRequest,\n    EditLoadActivityAddContentTypes actAddContentTypes,\n    EditLoadActivityAddNecessaryInputTypes actAddNecessaryInputTypes,\n    EditLoadActivityAddContext actAddContext,\n    EditLoadActivityAddRequiredFeatures actAddRequiredFeatures,\n    EditLoadActivityAddPrefetch actAddPrefetch,\n    EditLoadActivitySettingsHelper actAddActivitySettings\n)\n    : ServiceBase(\"Cms.LoadBk\",\n        connect:\n        [\n            workCtxSvc, actGetForEditing, ctxService, typesPermissions, valContentTypeDataStore, actAddPrefetch, actAddActivitySettings,\n            actCleanupRequest,\n            actConvertRequest,\n            actAddContentTypes,\n            actAddNecessaryInputTypes,\n            actAddContext,\n            actAddRequiredFeatures,\n        ])\n{\n    public async Task<EditLoadDto> Load(int appId, List<ItemIdentifier> items)\n    {\n        var l = Log.Fn<EditLoadDto>($\"load many a#{appId}, items⋮{items.Count}\");\n\n        var appContext = ctxService.GetExistingAppOrSet(appId);\n\n        // Note 2026-02-26 2dm - changed this to use from context, should be identical, but maybe it's not? keep an eye on this till 2026-Q2\n        var appReader = appContext.AppReaderRequired; // appReaders.Get(appId);\n        var actContext = new LowCodeActionContext\n        {\n            Context = new(StringComparer.OrdinalIgnoreCase)\n            {\n                [EditLoadContextConstants.AppId] = appId,\n                [EditLoadContextConstants.AppReader] = appReader,\n                [EditLoadContextConstants.AppContext] = appContext,\n            }\n        };\n\n        var itemsData = await actCleanupRequest.Run(actContext, ActionData.Create(items));\n\n        // Security check\n        // do early permission check - but at this time it may be that we don't have the types yet\n        // because they may be group/id combinations, without type information which we'll look up afterward\n\n        // Special Edge Case\n        // If the user is Module-Admin then we can skip the remaining checks\n        // This is important because the main context may not contain the module\n\n        // Look up the types, and repeat security check with type-names\n        l.A($\"Will do permission check; app has {appReader.List.Count} items\");\n        var usedContentTypes = new SavePermissionDataHelper(Log).ExtractTypeNamesFromItems(appReader, itemsData.Data);\n        var permCheck = typesPermissions.New(new()\n        {\n            SiteContext = appContext,\n            App = appReader,\n            ContentTypes = usedContentTypes,\n        });\n        if (!permCheck.EnsureAll(GrantSets.WriteSomething, out var error))\n            throw HttpException.PermissionDenied(error);\n\n        // load items - similar\n        var showDrafts = permCheck.EnsureAny(GrantSets.ReadDraft);\n        var appWorkCtx = workCtxSvc.ContextPlus(appId, showDrafts: showDrafts);\n\n        actContext = actContext.With(EditLoadContextConstants.AppCtxWork, appWorkCtx);\n\n        var list = actGetForEditing.Run(actContext, itemsData.Data);\n\n        // Do special PreLoad checks\n        for (var index = 0; index < list.Count; index++)\n        {\n            var ent = list[index].Entity;\n            if (ent == null)\n                continue; // new item, so no need to check\n            var preEdit = await valContentTypeDataStore.Value.PreEdit(index, ent);\n            if (preEdit.Exception != null)\n                throw preEdit.Exception;\n        }\n\n        var result = await actConvertRequest.Run(actContext, ActionData.Create(list));\n\n        // since we're retrieving data - make sure we're allowed to\n        // this is to ensure that if public forms only have \"create\" permissions, they can't access existing data\n        // important, this code is shared/duplicated in the EntitiesController.GetManyForEditing\n        if (list.Any(set => set.Entity != null))\n            if (!permCheck.EnsureAll(GrantSets.ReadSomething, out error))\n                throw l.Ex(HttpException.PermissionDenied(error));\n\n\n        var usedTypes = UsedTypes(actContext, list);\n        actContext = actContext.With(EditLoadContextConstants.UsedTypes, usedTypes);\n\n        var actions = new List<ILowCodeAction<EditLoadDto, EditLoadDto>>\n        {\n            actAddContentTypes,         // Add Content Types information\n            actAddNecessaryInputTypes,  // load input-field configurations\n            actAddContext,              // Attach context, but only the minimum needed for the UI\n            actAddActivitySettings,     // Load settings for the front-end\n            actAddPrefetch,             // Prefetch additional data\n            actAddRequiredFeatures      // Determine required features for the UI\n        };\n\n        // Loop through the actions and run each one\n        foreach (var lowCodeAction in actions)\n            result = await lowCodeAction.Run(actContext, result);\n\n        // done\n        var final = result.Data;\n        var finalMsg = $\"items:{final.Items.Count}, types:{final.ContentTypes.Count}, inputs:{final.InputTypes.Count}, feats:{final.Context.Features?.Count}\";\n        return l.Return(final, finalMsg);\n    }\n        \n\n\n    private List<IContentType> UsedTypes(LowCodeActionContext context, List<BundleWithHeaderOptional<IEntity>> list)\n        => list.Select(i\n                // try to get the entity type, but if there is none (new), look it up according to the header\n                => i.Entity?.Type\n                   ?? context.Get<IAppReader>(EditLoadContextConstants.AppReader)\n                       .GetContentType(i.Header!.ContentTypeName!))\n            .ToList();\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/EditSaveBackend.cs",
    "content": "﻿using ToSic.Eav.Data.Build.Sys;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.ImportExport.Json.Sys;\nusing ToSic.Eav.Serialization.Sys;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Sxc.Backend.SaveHelpers;\nusing ToSic.Sys.Security.Permissions;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EditSaveBackend(\n    SxcPagePublishing pagePublishing,\n    GenWorkPlus<WorkEntities> workEntities,\n    ISxcCurrentContextService ctxService,\n    JsonSerializer jsonSerializer,\n    SaveSecurity saveSecurity,\n    SaveEntities saveBackendHelper,\n    LazySvc<DataValidatorContentTypeDataStore> valContentTypeDataStore,\n    DataAssembler dataAssembler)\n    : ServiceBase(\"Cms.SaveBk\", connect: [pagePublishing, workEntities, ctxService, jsonSerializer, saveSecurity, saveBackendHelper, dataAssembler, valContentTypeDataStore])\n{\n    public async Task<Dictionary<Guid, int>> Save(int appId, EditSaveDto package, bool partOfPage)\n    {\n        var l = Log.Fn<Dictionary<Guid, int>>($\"save started with a#{appId}, i⋮{package.Items.Count}, partOfPage:{partOfPage}\");\n\n        // The context should be from the block if there is one, because it affects saving/publishing\n        // Basically it can result in things being saved draft or titles being updated\n        var context = ctxService.GetExistingAppOrSet(appId);\n\n\n        // perform some basic validation checks\n        var containsOnlyExpectedNodesException = new SaveDataPackageValidator(Log).ContainsOnlyExpectedNodes(package);\n        if (containsOnlyExpectedNodesException != null)\n            throw containsOnlyExpectedNodesException;\n\n        // todo: unsure about this - thought I should check contentblockappid in group-header, because this is where it should be saved!\n        //var contextAppId = appId;\n        //var targetAppId = package.Items.First().Header.Group.ContentBlockAppId;\n        //if (targetAppId != 0)\n        //{\n        //    Log.A($\"detected content-block app to use: {targetAppId}; in context of app {contextAppId}\");\n        //    appId = targetAppId;\n        //}\n\n        // new API WIP\n        var appEntities = workEntities.New(appId);\n        var appCtx = appEntities.AppWorkCtx;\n\n        var ser = jsonSerializer.SetApp(appCtx.AppReader);\n        // Since we're importing directly into this app, we would prefer local content-types\n        ser.PreferLocalAppTypes = true;\n\n        #region check if it's an update, and do more security checks then - shared with EntitiesController.Save\n\n        // basic permission checks\n        var permCheck = saveSecurity.DoPreSaveSecurityCheck(context, package.Items);\n\n        var foundItems = package.Items\n            .Where(i => i.Entity.Id != 0 || i.Entity.Guid != Guid.Empty)\n            .Select(i => i.Entity.Guid != Guid.Empty\n                    ? appEntities.Get(i.Entity.Guid) // prefer guid access if available\n                    : appEntities.Get(i.Entity.Id) // otherwise id\n            );\n        if (foundItems.Any(i => i != null) && !permCheck.EnsureAll(GrantSets.UpdateSomething, out var error))\n            throw HttpException.PermissionDenied(error);\n\n        #endregion\n\n\n        var itemsToProcess = package.Items\n            .Where(i => !i.Header.IsEmpty && i.Header.EditInfo?.ReadOnly != true)\n            .ToList();\n\n        l.A($\"items to process: {itemsToProcess.Count} of {package.Items.Count}\");\n\n        var saveValidator = new SaveDataValidator(Log);\n        var updateValidator = new SaveDataUpdateValidator(Log);\n        var items = await Task.WhenAll(itemsToProcess\n            .Select(async (i, index) => // index is helpful in case of errors\n            {\n                var ent = ser.Deserialize(i.Entity, false, false);\n\n                // Check basic entity integrity\n                var isOkException = saveValidator.EntityNotNullAndAttributeCountOk(index, ent);\n                if (isOkException != null)\n                    throw isOkException;\n\n                // Check if Save is disabled because of content-type metadata (new v21)\n                // This should prevent entities from being put in the DB, where the UI was only meant for some other configuration\n                var (returnEntity, _ /* Decorator */, procException, processor) = await valContentTypeDataStore.Value\n                    .PreSave(index, ent);\n\n                if (procException != null)\n                    throw procException;\n\n                ent = returnEntity ?? throw HttpException.BadRequest($\"Failed to process entity on index {index}\");\n\n                // If update check everything is ok, and if the ID needs to be reset\n                var validatorResult = updateValidator.IfUpdateValidateAndCorrectIds(appEntities, index, ent);\n                if (validatorResult.Exception != null)\n                    throw validatorResult.Exception;\n\n                // Reconstruct the entity, with possible ID reset, and with the correct owner and published state\n                ent = dataAssembler.Entity.CreateFrom(ent,\n                    id: validatorResult.ResetId,\n                    isPublished: package.IsPublished, // the published state is only in the header, not per entity, so we need to set it here\n                    owner: ent.Owner.NullIfNoValue() ?? context.User.IdentityToken\n                );\n\n                // new in 11.01\n                if (i.Header.Parent != null)\n                {\n                    // Check if Add was true, and fix if it had already been saved (EntityId != 0)\n                    // the entityId is reset by the validator if it turns out to be an update\n                    // todo: verify use - maybe it's to set before we save, as maybe afterward it's always != 0?\n                    var add = i.Header.AddSafe;\n                    i.Header.Add = add;\n                    if (ent.EntityId > 0 && add)\n                        i.Header.Add = false;\n                }\n\n                return (\n                    Bundle: new BundleWithHeader<IEntity>\n                    {\n                        Header = i.Header,\n                        Entity = ent\n                    },\n                    Processor: processor\n                );\n            })\n            .ToList());\n\n        l.A(\"items to save generated, all data tests passed\");\n\n        if (!items.Any())\n            return l.Return([], \"returning: 0\");\n\n        var itemsWithoutProcessor = items\n            .Select(i => i.Bundle)\n            .ToList();\n\n        var result = pagePublishing.SaveInPagePublishing(\n            context,\n            ctxService.BlockOrNull(),\n            appId,\n            itemsWithoutProcessor,\n            partOfPage,\n            forceSaveAsDraft => DoSave(appEntities, itemsWithoutProcessor, package.DraftShouldBranch || forceSaveAsDraft),\n            permCheck\n        );\n\n        var itemsWithProcessor = items\n            .Where(i => i.Processor != null)\n            .ToList();\n\n        if (!itemsWithProcessor.Any())\n            return l.Return(result, $\"returning: {result.Count}, no {DataProcessingEvents.PostSave}\");\n\n        l.A($\"Will run processors for {itemsWithProcessor.Count} items\");\n        foreach (var item in itemsWithProcessor)\n        {\n            try\n            {\n                var post = await item.Processor!.Process(DataProcessingEvents.PostSave, new() { Data = item.Bundle.Entity });\n            }\n            catch (Exception ex)\n            {\n                l.Ex(ex, $\"Error running processor for entity {item.Bundle.Entity.EntityGuid} ({item.Bundle.Entity.EntityId})\");\n            }\n        }\n\n        return l.Return(result, $\"returning: {result.Count}\");\n    }\n\n\n    private Dictionary<Guid, int> DoSave(WorkEntities workAppEntities, List<BundleWithHeader<IEntity>> items, bool forceSaveAsDraft)\n    {\n        // only save entities that are\n        // a. not in a group\n        // b. in a group where the slot isn't marked as empty\n        var entitiesToSave = items\n            .Where(e => !e.Header.IsContentBlockMode || !e.Header.IsEmpty)\n            .ToList();\n\n        saveBackendHelper.UpdateGuidAndPublishedAndSaveMany(workAppEntities.AppWorkCtx, entitiesToSave, forceSaveAsDraft);\n        return saveBackendHelper.GenerateIdList(workAppEntities, items);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/IUiPicker.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Cms;\n\n/// <summary>\n/// Raw properties for a UI Picker like string-picker or entity-picker.\n/// Not complete yet, just the fields currently used in the backend.\n/// Later we probably need a IUiPickerString, IUiPickerEntity etc.\n/// </summary>\ninternal interface IUiPicker\n{\n    string DataSources { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/IUiPickerSourceEntity.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Cms;\n\n/// <summary>\n/// Raw properties of a UiPickerSourceEntity - also applies to UiPickerSourceQuery\n/// Not complete, ATM just the props used in the code.\n/// Later should probably split into IUiPickerSourceEntity and IUiPickerSourceQuery\n/// </summary>\ninternal interface IUiPickerSourceEntity\n{\n    IEnumerable<IEntity> Query { get; }\n    string CreateTypes { get; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityAddContentTypes.cs",
    "content": "﻿using ToSic.Eav.Data.Processing;\nusing ToSic.Eav.ImportExport.Json.Sys;\nusing ToSic.Eav.Serialization.Sys;\nusing ToSic.Eav.WebApi.Sys.Entities;\nusing ToSic.Sxc.Data.Sys;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\npublic class EditLoadActivityAddContentTypes(Generator<JsonSerializer> jsonSerializerGenerator)\n    : ILowCodeAction<EditLoadDto, EditLoadDto>\n{\n    public async Task<ActionData<EditLoadDto>> Run(LowCodeActionContext mainCtx, ActionData<EditLoadDto> result)\n    {\n        var serSettings = new JsonSerializationSettings\n        {\n            CtIncludeInherited = true,\n            CtAttributeIncludeInheritedMetadata = true\n        };\n\n        var serializerForTypes = jsonSerializerGenerator.New().SetApp(mainCtx.Get<IAppReader>(EditLoadContextConstants.AppReader));\n        serializerForTypes.ValueConvertHyperlinks = true;\n\n        var jsonTypes = mainCtx.Get<List<IContentType>>(EditLoadContextConstants.UsedTypes)\n            .Select(t => serializerForTypes.ToPackage(t, serSettings))\n            .ToListOpt();\n\n        // Fix not-supported input-type names; map to correct name\n        jsonTypes = jsonTypes\n            .Select(jt =>\n            {\n                jt = jt with\n                {\n                    ContentType = jt.ContentType == null\n                        ? null\n                        : jt.ContentType with\n                        {\n                            Attributes = (jt.ContentType.Attributes ?? [])\n                            .Select(a => a with\n                            {\n                                // ensure that the input-type is set, otherwise it will be null\n                                InputType = InputTypes.MapInputTypeV10(a.InputType! /* it can't really be null, only in very old imports, and this is not an import */)\n                            })\n                            .ToListOpt(),\n                        }\n                };\n                return jt;\n            })\n            .ToListOpt();\n\n        result = result with\n        {\n            Data = result.Data with\n            {\n                ContentTypes = jsonTypes\n                    .Select(t => t.ContentType!)\n                    .ToList(),\n\n                // Also add global Entities like Formulas which would not be included otherwise\n                ContentTypeItems = jsonTypes\n                    .SelectMany(t => t.Entities!)\n                    .ToList(),\n            },\n        };\n\n        return result;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityAddContext.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.WebApi.Sys.Entities;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\npublic class EditLoadActivityAddContext(IUiContextBuilder contextBuilder): ServiceBase(\"UoW.AddCtx\", connect: [contextBuilder]),\n    ILowCodeAction<EditLoadDto, EditLoadDto>\n{\n    public async Task<ActionData<EditLoadDto>> Run(LowCodeActionContext actionCtx, ActionData<EditLoadDto> result)\n    {\n        var l = Log.Fn<ActionData<EditLoadDto>>();\n        var isSystemType = actionCtx.Get<List<IContentType>>(EditLoadContextConstants.UsedTypes).Any(t => t.AppId == KnownAppsConstants.PresetAppId);\n        l.A($\"isSystemType: {isSystemType}\");\n\n        // Attach context, but only the minimum needed for the UI\n        result = result with\n        {\n            Data = result.Data with\n            {\n                Context = contextBuilder.InitApp(actionCtx.Get<IAppReader>(EditLoadContextConstants.AppReader))\n                    .Get(Ctx.AppBasic | Ctx.AppEdit | Ctx.Language | Ctx.Site | Ctx.System | Ctx.User | Ctx.UserRoles |\n                         Ctx.Features |\n                         (isSystemType ? Ctx.FeaturesForSystemTypes : Ctx.Features), CtxEnable.EditUi),\n\n            },\n        };\n        return l.Return(result);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityAddNecessaryInputTypes.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.ImportExport.Json.V1;\nusing ToSic.Eav.WebApi.Sys.Entities;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\npublic class EditLoadActivityAddNecessaryInputTypes(GenWorkPlus<WorkInputTypes> inputTypes) : ServiceBase(\"UoW.InpTyp\"),\n    ILowCodeAction<EditLoadDto, EditLoadDto>\n{\n    public async Task<ActionData<EditLoadDto>> Run(LowCodeActionContext mainCtx, ActionData<EditLoadDto> result) =>\n        result with\n        {\n            Data = result.Data with\n            {\n                InputTypes = GetNecessaryInputTypes(result.Data.ContentTypes, mainCtx.Get<IAppWorkCtxPlus>(EditLoadContextConstants.AppCtxWork)),\n            },\n        };\n\n    private List<InputTypeInfo> GetNecessaryInputTypes(List<JsonContentType> contentTypes, IAppWorkCtxPlus appCtx)\n    {\n        var l = Log.Fn<List<InputTypeInfo>>($\"{nameof(contentTypes)}: {contentTypes.Count}\");\n        var fields = contentTypes\n            .SelectMany(t => t.AttributesSafe())\n            .Select(a => a.InputType)\n            .Distinct()\n            .ToList();\n\n        l.A(\"Found these input types to load: \" + string.Join(\", \", fields));\n\n        var allInputType = inputTypes.New(appCtx).GetInputTypes();\n\n        var found = allInputType\n            .Where(it => fields.Contains(it.Type))\n            .ToList();\n\n        if (found.Count == fields.Count)\n            l.A(\"Found all\");\n        else\n        {\n            l.A($\"It seems some input types were not found. Needed {fields.Count}, found {found.Count}. Will try to log details for this.\");\n            try\n            {\n                var notFound = fields.Where(field => found.All(fnd => fnd.Type != field));\n                l.A(\"Didn't find: \" + string.Join(\",\", notFound));\n            }\n            catch (Exception ex)\n            {\n                l.Ex(ex);\n                l.A(\"Ran into problems logging missing input types.\");\n            }\n        }\n\n        return l.Return(found, $\"{found.Count}\");\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityAddPrefetch.cs",
    "content": "﻿using ToSic.Eav.Data.Processing;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Eav.WebApi.Sys.Entities;\nusing ToSic.Sxc.Adam.Sys.Work;\nusing ToSic.Sxc.Backend.Adam;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class EditLoadActivityAddPrefetch(\n    Generator<HyperlinkBackend> hyperlinkBackend,\n    Generator<IAdamPrefetchHelper, AdamWorkOptions> adamTransGetItems,\n    EntityPickerApi entityPickerBackend)\n    : ServiceBase(SxcLogName + \".Prefetch\", connect: [adamTransGetItems, hyperlinkBackend, entityPickerBackend]),\n        ILowCodeAction<EditLoadDto, EditLoadDto>\n{\n    public async Task<ActionData<EditLoadDto>> Run(LowCodeActionContext actionCtx, ActionData<EditLoadDto> result)\n    {\n        var l = Log.Fn<ActionData<EditLoadDto>>();\n        try\n        {\n            result = result with\n            {\n                Data = result.Data with\n                {\n                    Prefetch = TryToPrefectAdditionalData(actionCtx.Get<int>(EditLoadContextConstants.AppId), result.Data)\n                }\n            };\n            return l.Return(result, \"prefetched\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return(result, \"error prefetching\");\n        }\n    }\n\n    public EditPrefetchDto TryToPrefectAdditionalData(int appId, EditLoadDto editData)\n        => Log.Quick(() => new EditPrefetchDto\n        {\n            Links = PrefetchLinks(appId, editData),\n            Entities = PrefetchEntities(appId, editData),\n            Adam = PrefetchAdam(appId, editData),\n        });\n\n\n    private ICollection<EntityForPickerDto> PrefetchEntities(int appId, EditLoadDto editData)\n    {\n        var l = Log.Fn<ICollection<EntityForPickerDto>>();\n        try\n        {\n            // Step 1: try to find entity fields\n            var bundlesHavingEntities = editData.Items\n                // Only these with entity fields\n                .Where(b => b.Entity?.Attributes?.Entity?.Any() ?? false)\n                .Select(b => new\n                {\n                    b.Entity!.Guid,\n                    b.Entity.Attributes.Entity\n                })\n                .ToListOpt();\n\n            var entities = bundlesHavingEntities\n                .SelectMany(set => set.Entity!\n                    .SelectMany(e => e.Value\n                        ?.SelectMany(entityAttrib => entityAttrib.Value) ?? []\n                    )\n                )\n                .Where(guid => guid != null)\n                .Select(guid => guid.ToString()!)\n                // Step 2: Check which ones have a link reference\n                .ToListOpt();\n\n            // stop here if nothing found, otherwise the backend will return all entities\n            if (!entities.Any())\n                return l.Return([], \"none found\");\n\n            var items = entityPickerBackend.GetForEntityPicker(appId, entities, null, allowFromAllScopes: true);\n            return l.Return(items, $\"{items.Count}\");\n        }\n        catch\n        {\n            return l.Return([new() { Id = -1, Text = \"Error occurred pre-fetching entities\", Value = Guid.Empty }], \"error\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityAddRequiredFeatures.cs",
    "content": "﻿using ToSic.Eav.Data.Processing;\nusing ToSic.Eav.WebApi.Sys.Entities;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\npublic class EditLoadActivityAddRequiredFeatures(IUiContextBuilder contextBuilder): ServiceBase(\"UoW.AddCtx\", connect: [contextBuilder]),\n    ILowCodeAction<EditLoadDto, EditLoadDto>\n{\n    public async Task<ActionData<EditLoadDto>> Run(LowCodeActionContext actionCtx, ActionData<EditLoadDto> result)\n    {\n        var l = Log.Fn<ActionData<EditLoadDto>>();\n\n        // Determine required features for the UI WIP 18.02\n        var inheritedFields = actionCtx.Get<List<IContentType>>(EditLoadContextConstants.UsedTypes)\n            .SelectMany(t => t.Attributes\n                .Where(a => a.SysSettings?.InheritMetadata == true)\n                .Select(a => new { a.Name, Type = t }))\n            .ToList();\n\n        if (!inheritedFields.Any())\n            return l.Return(result, \"none found\");\n\n        result = result with\n        {\n            Data = result.Data with\n            {\n                RequiredFeatures = new()\n                {\n                    {\n                        BuiltInFeatures.ContentTypeFieldsReuseDefinitions.NameId,\n                        inheritedFields.Select(f => $\"Used in fields: {f.Type.Name}.{f.Name}\").ToArray()\n                    },\n                }\n            },\n        };\n\n        return l.Return(result, \"added some req features\");\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityCleanupRequest.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.Metadata;\nusing ToSic.Eav.Metadata.Targets;\nusing ToSic.Eav.WebApi.Sys.Entities;\nusing ToSic.Sxc.Backend.SaveHelpers;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\npublic class EditLoadActivityCleanupRequest(ContentGroupList contentGroupList, ITargetTypeService mdTargetTypes)\n    : ServiceBase(\"UoW.AddCtx\", connect: [contentGroupList, mdTargetTypes]),\n        ILowCodeAction<List<ItemIdentifier>, List<ItemIdentifier>>\n{\n    public async Task<ActionData<List<ItemIdentifier>>> Run(LowCodeActionContext actionCtx, ActionData<List<ItemIdentifier>> data)\n    {\n        var l = Log.Fn<List<ItemIdentifier>>();\n\n        var items = data.Data;\n        var appReader = actionCtx.Get<IAppReader>(EditLoadContextConstants.AppReader);\n        items = contentGroupList.Init(appReader.PureIdentity())\n            .ConvertGroup(items)\n            .ConvertListIndexToId(items);\n        items = TryToAutoFindMetadataSingleton(items, appReader.Metadata);\n\n\n        return ActionData.Create(l.Return(items));\n    }\n\n\n    /// <summary>\n    /// new 2020-12-08 - correct entity-id with lookup of existing if marked as singleton\n    /// </summary>\n    // ReSharper disable once UnusedMethodReturnValue.Local\n    private List<ItemIdentifier> TryToAutoFindMetadataSingleton(List<ItemIdentifier> list, IMetadataSource appMdSource)\n    {\n        var l = Log.Fn<List<ItemIdentifier>>();\n        var headersWithMetadataFor = list\n            .Where(header => header.For?.Singleton == true && header.ContentTypeName.HasValue())\n            .ToListOpt();\n\n        foreach (var header in headersWithMetadataFor)\n        {\n            l.A(\"Found an entity with the auto-lookup marker\");\n            // try to find metadata for this\n            var mdFor = header.For;\n            // #TargetTypeIdInsteadOfTarget\n            var type = mdFor!.TargetType != 0\n                ? mdFor.TargetType\n                : mdTargetTypes.GetId(mdFor.Target!);\n            var mds = mdFor.Guid != null\n                ? appMdSource.GetMetadata(type, mdFor.Guid.Value, header.ContentTypeName)\n                : mdFor.Number != null\n                    ? appMdSource.GetMetadata(type, mdFor.Number.Value, header.ContentTypeName)\n                    : appMdSource.GetMetadata(type, mdFor.String, header.ContentTypeName);\n\n            var mdList = mds.ToArray();\n            if (mdList.Length > 1)\n            {\n                l.A($\"Warning - looking for best metadata but found too many {mdList.Length}, will use first\");\n                // must now sort by ID otherwise the order may be different after a few save operations\n                mdList = [.. mdList.OrderBy(e => e.EntityId)];\n            }\n            header.EntityId = !mdList.Any() ? 0 : mdList.First().EntityId;\n        }\n\n        return l.Return(list);\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityConvertRequest.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.Data.Build.Sys;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.ImportExport.Json.Sys;\nusing ToSic.Eav.ImportExport.Json.V1;\nusing ToSic.Eav.Serialization.Sys;\nusing ToSic.Eav.WebApi.Sys.Entities;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\npublic class EditLoadActivityConvertRequest(Generator<JsonSerializer> jsonSerializerGenerator, EntityAssembler entityAssembler)\n    : ServiceBase(\"UoW.AddCtx\", connect: [jsonSerializerGenerator, entityAssembler]),\n        ILowCodeAction<List<BundleWithHeaderOptional<IEntity>>, EditLoadDto>\n{\n    public async Task<ActionData<EditLoadDto>> Run(LowCodeActionContext actionCtx, ActionData<List<BundleWithHeaderOptional<IEntity>>> data)\n    {\n        var l = Log.Fn<EditLoadDto>();\n\n        var appReader = actionCtx.Get<IAppReader>(EditLoadContextConstants.AppReader);\n        var appWorkCtxPlus = actionCtx.Get<IAppWorkCtxPlus>(EditLoadContextConstants.AppCtxWork);\n        var jsonSerializer = jsonSerializerGenerator.New().SetApp(appReader);\n\n        var list = data.Data;\n        var result = new EditLoadDto\n        {\n            Items = list\n                .Select(bundle => new BundleWithHeaderOptional<JsonEntity>\n                {\n                    Header = bundle.Header,\n                    Entity = GetSerializeAndMdAssignJsonEntity(actionCtx.Get<int>(\"AppId\"), bundle, jsonSerializer, appReader, appWorkCtxPlus)\n                })\n                .ToList(),\n        };\n\n        // set published if some data already exists\n        if (list.Any())\n        {\n            var entity = list.First().Entity;\n            var isPublished = entity?.IsPublished ?? true; // Entity could be null (new), then true\n            result = result with\n            {\n                IsPublished = isPublished,\n                // only set draft-should-branch if this draft already has a published item\n                DraftShouldBranch = !isPublished && (appReader.GetPublished(entity)) != null\n            };\n        }\n        return ActionData.Create(l.Return(result));\n    }\n\n    /// <summary>\n    /// Get Serialized entity or create a new one, and assign metadata\n    /// based on the header (if none already existed)\n    /// </summary>\n    /// <returns></returns>\n    private JsonEntity GetSerializeAndMdAssignJsonEntity(int appId, BundleWithHeaderOptional<IEntity> bundle,\n        JsonSerializer jsonSerializer, IAppReader appReader, IAppWorkCtx appSysCtx)\n    {\n        var l = Log.Fn<JsonEntity>();\n        // attach original metadata assignment when creating a new one\n        JsonEntity ent;\n        if (bundle.Entity != null)\n        {\n            ent = jsonSerializer.ToJson(bundle.Entity, 1);\n\n        }\n        else\n        {\n            ent = jsonSerializer.ToJson(ConstructEmptyEntity(appId, bundle.Header!, appSysCtx), metadataDepth: 0);\n\n            // only attach metadata, if no metadata already exists\n            if (ent.For == null && bundle.Header?.For != null)\n                ent = ent with { For = bundle.Header.For };\n        }\n\n        // new UI doesn't use this anymore, reset it\n        if (bundle.Header != null)\n            bundle.Header.For = null;\n\n        try\n        {\n            if (ent.For != null)\n            {\n                var eFor = ent.For;\n                // #TargetTypeIdInsteadOfTarget\n                var targetType = eFor.TargetType != 0\n                    ? eFor.TargetType\n                    : jsonSerializer.MetadataTargets.GetId(eFor.Target!);\n                ent = ent with\n                {\n                    For = eFor with\n                    {\n                        Title = appReader.FindTargetTitle(targetType, eFor.String ?? eFor.Guid?.ToString() ?? eFor.Number?.ToString()),\n                    }\n                };\n            }\n        }\n        catch { /* ignore experimental */ }\n\n        return l.Return(ent);\n    }\n    private IEntity ConstructEmptyEntity(int appId, ItemIdentifier header, IAppWorkCtx appSysCtx)\n    {\n        var l = Log.Fn<IEntity>();\n        var type = appSysCtx.AppReader.GetContentType(header.ContentTypeName!);\n        var ent = entityAssembler.EmptyOfType(appId, header.Guid, header.EntityId, type);\n        return l.Return(ent);\n    }\n\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityPrefetchHelper_Adam.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\npartial class EditLoadActivityAddPrefetch\n{\n    private Dictionary<string, Dictionary<string, IEnumerable< /*AdamItemDto*/object>>> PrefetchAdam(int appId, EditLoadDto editData)\n    {\n        var l = Log.Fn<Dictionary<string, Dictionary<string, IEnumerable<object>>>>();\n\n        // Step 1: try to find hyperlink fields\n        var bundlesHavingLinks = BundleWithLinkFields(editData, true);\n\n        var bundlesWithAllKeys = bundlesHavingLinks\n            .Select(set =>\n            {\n                var keys = new List<string>();\n                var hKeys = set.HyperlinkFields?.Select(h => h.Key);\n                if (hKeys != null) keys.AddRange(hKeys);\n                var sKeys = set.StringFields?.Select(s => s.Key);\n                if (sKeys != null) keys.AddRange(sKeys);\n                return new\n                {\n                    Set = set,\n                    Keys = keys\n                };\n            })\n            .ToList();\n\n        var links = bundlesWithAllKeys\n            .GroupBy(b => b.Set.Guid)\n            .ToDictionary(\n                b => b.Key.ToString(),\n                b => b\n                    .SelectMany(selector: bundle => bundle.Keys\n                        .Select(key => new\n                        {\n                            Key = key,\n                            Dic = GetAdamListOfItems(appId, bundle.Set, key) as IEnumerable<object>,\n                        })\n                    )\n                    // skip empty bits to avoid UI from relying on these nodes to always exist\n                    .Where(r => r.Dic.Any())\n                    // Step 2: Check which ones have a link reference\n                    .ToDictionary(r => r.Key, r => r.Dic)\n            );\n\n        return l.Return(links);\n    }\n\n    private IEnumerable<AdamItemDto> GetAdamListOfItems(int appId, BundleWithLinkField set, string key)\n    {\n        var l = Log.Fn<IEnumerable<AdamItemDto>>();\n        var adamListMaker = adamTransGetItems.New(new()\n        {\n            AppId = appId,\n            ContentType = set.ContentTypeName,\n            ItemGuid = set.Guid,\n            Field = key,\n            UsePortalRoot = false,\n        });\n        //adamListMaker.Setup(appId, set.ContentTypeName, set.Guid, key, false);\n        var list = adamListMaker.GetAdamItemsForPrefetch(string.Empty, false);\n        return l.Return(list);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivityPrefetchHelper_Links.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.ValueConverter;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\npartial class EditLoadActivityAddPrefetch\n{\n    private Dictionary<string, LinkInfoDto> PrefetchLinks(int appId, EditLoadDto editData)\n    {\n        try\n        {\n            // Step 1: try to find hyperlink fields\n            var bundlesHavingLinks = BundleWithLinkFields(editData);\n\n            var links = bundlesHavingLinks\n                .SelectMany(set => (set.HyperlinkFields ?? [])\n                    .SelectMany(h => (h.Value ?? [])\n                        .Select(linkAttrib => new\n                    {\n                        Link = linkAttrib.Value,\n                        Converted = TryToConvertOrErrorText(appId, set.ContentTypeName, h.Key, linkAttrib.Value, set.Guid),\n                    })))\n                //.Where(set => set != null)\n                // Step 2: Check which ones have a link reference\n                .Where(set => ValueConverterBase.CouldBeReference(set.Link))\n                // Make distinct by Link\n                .GroupBy(l => l.Link)\n                .Select(g => g.First())\n                .ToList();\n\n\n            // Step 3: Look them up\n            // Step 4: return dictionary with these\n            return links.ToDictionary(\n                s => s.Link,\n                s => s.Converted);\n        }\n        catch (Exception ex)\n        {\n            return new()\n            {\n                {\"Error\", new() { Value = \"An error occurred pre-fetching the links \" + ex.Message } }\n            };\n        }\n    }\n\n    private LinkInfoDto TryToConvertOrErrorText(int appId, string contentType, string field, string value, Guid entityGuid)\n    {\n        try\n        {\n            var linkBackend = _hyperlinkBackend.Get(hyperlinkBackend.New)!;\n            var result = linkBackend.LookupHyperlink(appId, value, contentType, entityGuid, field);\n            return result;\n        }\n        catch\n        {\n            return new() { Value = \"error\" };\n        }\n    }\n    private readonly GetOnce<HyperlinkBackend> _hyperlinkBackend = new();\n\n\n    private static List<BundleWithLinkField> BundleWithLinkFields(EditLoadDto editData, bool includeStringFields = false)\n    {\n        var bundlesHavingLinks = editData.Items\n            // Only these with hyperlinks\n            .Where(b =>\n            {\n                var hasLinks = b.Entity?.Attributes?.Hyperlink?.Any() ?? false;\n                var hasString = includeStringFields && (b.Entity?.Attributes?.String?.Any() ?? false);\n                return hasLinks || hasString;\n            })\n            .Select(b => new BundleWithLinkField\n            {\n                Guid = b.Entity!.Guid,\n                HyperlinkFields = b.Entity.Attributes.Hyperlink!,\n                StringFields = b.Entity.Attributes.String!,\n                ContentTypeName = b.Entity.Type.Name,\n            });\n        return bundlesHavingLinks.ToList();\n    }\n\n    private class BundleWithLinkField\n    {\n        //public int AppId;\n        public required Guid Guid;\n        public required string ContentTypeName;\n        public required Dictionary<string, Dictionary<string, string>>? HyperlinkFields;\n        public required Dictionary<string, Dictionary<string, string>>? StringFields;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Activities/EditLoadActivitySettingsHelper.cs",
    "content": "﻿using System.Collections;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Eav.ImportExport.Json.Sys;\nusing ToSic.Eav.ImportExport.Json.V1;\nusing ToSic.Eav.Serialization.Sys;\nusing ToSic.Eav.WebApi.Sys.Entities;\nusing ToSic.Sxc.Backend.Cms.Load.Settings;\nusing ToSic.Sys.Utils;\nusing static System.StringComparer;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Activities;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class EditLoadActivitySettingsHelper(\n    Generator<JsonSerializer> jsonSerializerGenerator,\n    IEnumerable<ILoadSettingsProvider> loadSettingsProviders,\n    IEnumerable<ILoadSettingsContentTypesProvider> loadSettingsTypesProviders,\n    GenWorkPlus<WorkEntities> appEntities)\n    : ServiceBase(SxcLogName + \".LodSet\",\n        connect: [jsonSerializerGenerator, loadSettingsProviders, appEntities]),\n        ILowCodeAction<EditLoadDto, EditLoadDto>\n{\n    public record ActionContext(List<IContentType> UsedTypes);\n\n    public async Task<ActionData<EditLoadDto>> Run(LowCodeActionContext actionCtx, ActionData<EditLoadDto> result) =>\n        result with\n        {\n            Data = result.Data with\n            {\n                Settings = GetSettings(actionCtx.Get<IContextOfApp>(EditLoadContextConstants.AppContext),\n                    actionCtx.Get<List<IContentType>>(EditLoadContextConstants.UsedTypes),\n                    result.Data.ContentTypes,\n                    actionCtx.Get<IAppWorkCtxPlus>(EditLoadContextConstants.AppCtxWork)),\n            },\n        };\n\n    /// <summary>\n    /// WIP v15.\n    /// Later it should be built using a list of services that provide settings to the UI.\n    /// - put gps coordinates in static\n    /// - later get from settings\n    /// </summary>\n    /// <returns></returns>\n    private EditSettingsDto GetSettings(IContextOfApp contextOfApp, List<IContentType> contentTypes, List<JsonContentType> jsonTypes, IAppWorkCtxPlus appWorkCtx)\n    {\n        var l = Log.Fn<EditSettingsDto>();\n        var allInputTypes = jsonTypes\n            .SelectMany(ct => ct.AttributesSafe()\n                .Select(at => at.InputType! /* never null here, only on very old imports */)\n            )\n            .Distinct()\n            .ToList();\n\n        var lspParameters = new LoadSettingsProviderParameters\n        {\n            ContextOfApp = contextOfApp,\n            ContentTypes = contentTypes,\n            InputTypes = allInputTypes\n        };\n\n        var settings = new EditSettingsDto\n        {\n            Values = GetOrEmptyOnError(() => GetValues(lspParameters), () => nameof(GetValues)),\n            Entities = GetSettingsEntities(appWorkCtx, allInputTypes),\n            ContentTypes = GetOrEmptyOnError(() => GetContentTypes(lspParameters), () => nameof(GetContentTypes))\n        };\n        return l.Return(settings);\n    }\n\n    private TList GetOrEmptyOnError<TList>(Func<TList> getList, Func<string> errMessage) where TList : class, IEnumerable, new()\n    {\n        var l = Log.Fn<TList>();\n        try\n        {\n            return l.ReturnAsOk(getList());\n        }\n        catch (Exception e)\n        {\n            l.E($\"Error: {errMessage()}\");\n            l.Ex(e);\n            return l.ReturnAsError(new());\n        }\n    }\n\n    private Dictionary<string, object> GetValues(LoadSettingsProviderParameters lspParameters)\n    {\n        var l = Log.Fn<Dictionary<string, object>>();\n\n        // Get all settings from all providers\n        var settingsFromProviders = loadSettingsProviders\n            .Select(lsp => GetOrEmptyOnError(\n                () => lsp.LinkLog(Log).GetSettings(lspParameters),\n                () => $\"Error on {lsp.GetType().Name}\")\n            )\n            .ToList();\n\n        // Merge all settings into one dictionary\n        var finalSettings = new Dictionary<string, object>(InvariantCultureIgnoreCase);\n        foreach (var pair in settingsFromProviders.SelectMany(sfp => sfp))\n            finalSettings[pair.Key] = pair.Value;\n        return l.Return(finalSettings, $\"{finalSettings.Count}\");\n    }\n\n    private List<JsonContentTypeWithTitleWip> GetContentTypes(LoadSettingsProviderParameters parameters)\n    {\n        var l = Log.Fn<List<JsonContentTypeWithTitleWip>>();\n\n        // Load all types from the providers\n        var typesFromProviders = loadSettingsTypesProviders\n            .SelectMany(lsp => GetOrEmptyOnError(\n                () => lsp.LinkLog(Log).GetContentTypes(parameters),\n                () => $\"Error GetContentTypes of {lsp.GetType().Name}\")\n            )\n            .ToList();\n\n        // Setup Type Serializer - same as EditLoadBackend\n        var serializerForTypes = jsonSerializerGenerator.New().SetApp(parameters.ContextOfApp.AppReaderRequired);\n        var serSettings = new JsonSerializationSettings\n        {\n            CtIncludeInherited = true,\n            CtAttributeIncludeInheritedMetadata = true,\n            CtWithEntities = false,\n        };\n\n\n        var nameMap = typesFromProviders\n            .Select(t =>\n            {\n                var normal = serializerForTypes.ToPackage(t, serSettings).ContentType!;\n                var title = t.DetailsOrNull()?.Title;\n                return new JsonContentTypeWithTitleWip\n                {\n                    Id = normal.Id,\n                    Name = normal.Name,\n                    Scope = normal.Scope,\n                    Sharing = normal.Sharing,\n                    Metadata = normal.Metadata,\n                    Attributes = normal.Attributes,\n                    Assets = normal.Assets,\n                    Title = title.NullIfNoValue() ?? normal.Name,\n                };\n            })\n            .ToList();\n\n        return l.Return(nameMap, $\"all ok, found {nameMap.Count}\");\n    }\n\n\n\n    private List<JsonEntity> GetSettingsEntities(IAppWorkCtxPlus appWorkCtx, IEnumerable<string> allInputTypes)\n    {\n        var l = Log.Fn<List<JsonEntity>>();\n        try\n        {\n            var hasWysiwyg = allInputTypes.Any(it => it.ContainsInsensitive(\"wysiwyg\"));\n            if (!hasWysiwyg)\n                return l.Return([], \"no wysiwyg field\");\n\n            var entities = appEntities.New(appWorkCtx)\n                .GetWithParentAppsExperimental(\"StringWysiwygConfiguration\")\n                .ToList();\n\n            var jsonSerializer = jsonSerializerGenerator.New().SetApp(appWorkCtx.AppReader);\n            var result = entities.Select(e => jsonSerializer.ToJson(e)).ToList();\n\n            return l.Return(result, $\"{result.Count}\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            return l.Return([], \"error\");\n        }\n    }\n        \n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/ILoadSettingsContentTypesProvider.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\n/// <summary>\n/// Load Settings Provider which supply additional content-types which the UI needs for editing.\n/// Eg when the UI needs to know which content-types are available for a picker.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ILoadSettingsContentTypesProvider: IHasLog\n{\n    List<IContentType> GetContentTypes(LoadSettingsProviderParameters parameters);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/ILoadSettingsProvider.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface ILoadSettingsProvider: IHasLog\n{\n    Dictionary<string, object> GetSettings(LoadSettingsProviderParameters parameters);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/LoadSettingsApiKeys.cs",
    "content": "﻿using ToSic.Sxc.Services;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\ninternal class LoadSettingsApiKeys(LazySvc<ISecureDataService> secureDataService)\n    : LoadSettingsProviderBase($\"{SxcLogName}.StApiK\"), ILoadSettingsProvider\n{\n    public Dictionary<string, object> GetSettings(LoadSettingsProviderParameters parameters) \n    {\n        var l = Log.Fn<Dictionary<string, object>>();\n        var stack = parameters.ContextOfApp.AppSettings;\n\n        var apiKeyNames = new List<string>\n        {\n            \"Settings.GoogleMaps.ApiKey\",\n            \"Settings.GoogleTranslate.ApiKey\"\n        };\n\n        var result = apiKeyNames\n            .Select(key =>\n            {\n                var prop = stack.InternalGetPath(key, Log);\n                if (prop.Result is not string strResult)\n                    return null;\n\n                var decrypted = secureDataService.Value.Parse(strResult);\n                return new\n                {\n                    Key = key,\n                    Value = new ContextApiKeyDto\n                    {\n                        NameId = key,\n                        ApiKey = decrypted.Value,\n                        IsDemo = decrypted.IsSecured\n                    }\n                };\n            })\n            .Where(v => v?.Value != null)\n            .ToDictionary(\n                k => k!.Key,\n                object (k) => k!.Value\n            );\n\n        return l.Return(result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/LoadSettingsForBase.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Models;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\ninternal abstract class LoadSettingsForBase(string logName, object[]? connect = default)\n    : ServiceBase(logName, connect: connect), ILoadSettingsProvider\n{\n    public abstract Dictionary<string, object> GetSettings(LoadSettingsProviderParameters parameters);\n\n    public Dictionary<string, object> GetSettings<TData, TModel>(\n        LoadSettingsProviderParameters parameters,\n        TData defaults,\n        bool forceDefaults,\n        string lookupPath,\n        string outputPath,\n        Func<TModel, TData> modelConverter)\n        where TModel : class, IModelFromEntity\n    {\n        var l = Log.Fn<Dictionary<string, object>>();\n        var data = defaults;\n\n        if (!forceDefaults)\n        {\n            var getSettings = parameters.ContextOfApp.AppSettings.InternalGetPath(lookupPath);\n            if (getSettings?.GetFirstResultEntity() is { } mapsEntity)\n            {\n                var model = mapsEntity.ToModel<TModel>();\n                if (model != null)\n                    data = modelConverter(model);\n            }\n        }\n\n        var result = new Dictionary<string, object>\n        {\n            [outputPath] = data!,\n        };\n        return l.Return(result, $\"{result.Count}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/LoadSettingsForContentType.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Sys.Utils;\nusing static System.String;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\ninternal class LoadSettingsForContentType()\n    : LoadSettingsProviderBase($\"{SxcLogName}.LdStCT\"), ILoadSettingsProvider\n{\n    public Dictionary<string, object> GetSettings(LoadSettingsProviderParameters parameters)\n    {\n        var l = Log.Fn<Dictionary<string, object>>();\n        // find all keys which may be necessary\n        var settingsKeys = parameters.ContentTypes\n            .SelectMany(ct =>\n                (ct.DetailsOrNull()?.AdditionalSettings ?? \"\").CsvToArrayWithoutEmpty()\n            )\n            .Where(c => !IsNullOrWhiteSpace(c))\n            // Only include settings which have the full path\n            // so in future we can add other roots like resources\n            .Where(s => s.StartsWith($\"{AppStackConstants.RootNameSettings}.\"))\n            .ToList();\n\n        // Try to find each setting\n        var settings = SettingsByKeys(parameters.ContextOfApp.AppSettings, settingsKeys);\n\n        return l.Return(settings, $\"{settings.Count}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/LoadSettingsForGpsDefaults.cs",
    "content": "﻿using ToSic.Sxc.Cms.Settings;\nusing ToSic.Sys.Capabilities.Features;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\ninternal class LoadSettingsForGpsDefaults(LazySvc<Services.IFeaturesService> features)\n    : LoadSettingsForBase($\"{SxcLogName}.LdGpsD\", connect: [features])\n{\n    public override Dictionary<string, object> GetSettings(LoadSettingsProviderParameters parameters) =>\n        GetSettings<MapsCoordinates, GoogleMaps>(\n            parameters,\n            MapsCoordinates.Defaults,\n            !features.Value.IsEnabled(BuiltInFeatures.EditUiGpsCustomDefaults.NameId),\n            GoogleMaps.SettingsPath,\n            $\"{GoogleMaps.SettingsPath}.{nameof(GoogleMaps.DefaultCoordinates)}\",\n            model => model.DefaultCoordinates);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/LoadSettingsForPickerSources.cs",
    "content": "﻿using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\n/// <summary>\n/// Load additional content-type definitions which are used by pickers.\n/// This is so the UI can determine the best names for the create-new buttons.\n/// </summary>\ninternal class LoadSettingsForPickerSources() : LoadSettingsProviderBase($\"{SxcLogName}.LdPikS\"), ILoadSettingsContentTypesProvider\n{\n    public static string[] PickerNames = [\"entity-picker\", \"string-picker\"];\n    \n    public List<IContentType> GetContentTypes(LoadSettingsProviderParameters parameters)\n    {\n        var l = Log.Fn<List<IContentType>>();\n\n        // Find all attributes which show a picker\n        var pickerAttributes = parameters.ContentTypes\n            .SelectMany(ct => ct.Attributes\n                .Where(a => PickerNames.Contains(a.InputType))\n            )\n            .ToListOpt();\n\n        if (pickerAttributes.Count == 0) return l.Return([], \"no picker fields\");\n\n        // For each picker, find all the data-sources.\n        // Normally just one, but data model allows many.\n        var pickerSources = pickerAttributes\n            .SelectMany(a =>\n            {\n                // Find all entities which define a data-source\n                var dsEntities = a.Metadata\n                    .SelectMany(e => e.Children(nameof(IUiPicker.DataSources)));\n\n                // Flatten and remember the attribute for debugging\n                return dsEntities\n                    .Select(ds => new\n                    {\n                        Attribute = a,\n                        DataSource = ds\n                    });\n            })\n            .Where(ps => ps?.DataSource != null)\n            .ToListOpt();\n\n        // Find all the NameIds which the DataSource says it can create\n        var createTypes = pickerSources\n            .Select(p => p.DataSource!.Get<string>(nameof(IUiPickerSourceEntity.CreateTypes), languages: []))\n            .Where(s => s.HasValue())\n            // TODO: INFO @SDV - he probably has comma separated values\n            .SelectMany(s => s!\n                // TODO!!! NEW-LINES seem to be saved wrong!\n                .Replace(\"\\\\n\", \"\\n\")\n                .LinesToArrayWithoutEmpty())\n            .ToListOpt();\n\n        // Look up the types in the app-state\n        var typesToEnableCreate = createTypes\n            // Do distinct first, no eliminate duplicate keys - like when there are many pickers with the same create-new-type\n            .DistinctBy(s => s.ToLowerInvariant())\n            .Select(nameId => new\n            {\n                NameId = nameId,\n                Type = parameters.ContextOfApp.AppReaderRequired.TryGetContentType(nameId)\n            })\n            .Where(t => t.Type != null)\n            .ToListOpt();\n\n        if (typesToEnableCreate.Count == 0)\n            return l.Return([], \"no types to enable create\");\n\n        var typesOnly = typesToEnableCreate\n            .Select(t => t.Type!)\n            .ToList();\n        return l.Return(typesOnly, $\"{typesOnly.Count}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/LoadSettingsForWysiwygDefaults.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Cms.Settings;\nusing ToSic.Sxc.Cms.Settings.InputFields;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\ninternal class LoadSettingsForWysiwygDefaults()\n    : LoadSettingsForBase($\"{SxcLogName}.LdGpsD\", connect: [])\n{\n    public override Dictionary<string, object> GetSettings(LoadSettingsProviderParameters parameters) =>\n        GetSettings<StringWysiwyg, StringWysiwyg>(\n            parameters,\n            StringWysiwyg.Defaults,\n            false,\n            StringWysiwyg.SettingsPath,\n            StringWysiwyg.SettingsPath,\n            model => model\n        );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/LoadSettingsProviderBase.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.PropertyStack;\n\nnamespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic abstract class LoadSettingsProviderBase(string logName) : ServiceBase(logName)\n{\n    protected Dictionary<string, object> SettingsByKeys(PropertyStack appSettings, List<string> keys)\n    {\n        var l = Log.Fn<Dictionary<string, object>>();\n        // Try to find each setting\n        var settings = keys.ToDictionary(\n            key => key,\n            key => appSettings.InternalGetPath(key).Result!\n        );\n\n        return l.Return(settings, $\"{settings.Count}\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/Edit/Load.Settings/LoadSettingsProviderParameters.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Cms.Load.Settings;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class LoadSettingsProviderParameters\n{\n    public required IContextOfApp ContextOfApp { get; init; }\n\n    public  required List<IContentType> ContentTypes { get; init; }\n\n    public required List<string> InputTypes { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/HistoryControllerReal.cs",
    "content": "﻿using ToSic.Eav.Persistence.Versions;\nusing ToSic.Eav.WebApi.Sys.Cms;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HistoryControllerReal(GenWorkDb<WorkEntityVersioning> versioning)\n    : ServiceBase(\"Api.CmsHistoryRl\", connect: [versioning]), IHistoryController\n{\n    public const string LogSuffix = \"Hist\";\n\n    public List<ItemHistory> Get(int appId, ItemIdentifier item)\n        => versioning.New(appId: appId).VersionHistory(item.EntityId);\n\n\n    public bool Restore(int appId, int transactionId, ItemIdentifier item)\n    {\n        versioning.New(appId: appId).VersionRestore(item.EntityId, transactionId);\n        return true;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/HyperlinkBackend.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Data.Sys.ValueConverter;\nusing ToSic.Sxc.Adam.Sys;\nusing ToSic.Sxc.Adam.Sys.Manager;\nusing ToSic.Sxc.Adam.Sys.Security;\nusing ToSic.Sxc.Adam.Sys.Work;\nusing ToSic.Sxc.Backend.Adam;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HyperlinkBackend(\n    LazySvc<AdamContext> adamCtxLazy,\n    ISxcCurrentContextService ctxService,\n    Generator<MultiPermissionsApp, MultiPermissionsApp.Options> appPermissions,\n    Generator<IAdamItemDtoMaker, AdamItemDtoMakerOptions> adamDtoMaker,\n    IValueConverter valueConverter)\n    : ServiceBase(\"Bck.HypLnk\", connect: [adamCtxLazy, appPermissions, ctxService, adamDtoMaker, valueConverter])\n{\n    public LinkInfoDto LookupHyperlink(int appId, string hyperlink, string? contentType, Guid guid, string? field)\n    {\n        try\n        {\n            // nothing to resolve\n            if (string.IsNullOrEmpty(hyperlink))\n                return new() { Value = hyperlink };\n\n            var context = ctxService.GetExistingAppOrSet(appId);\n            // different security checks depending on the link-type\n            var lookupPage = hyperlink.Trim().StartsWith(ValueConverterBase.PrefixPage, StringComparison.OrdinalIgnoreCase);\n\n            // look it up first, because we need to know if the result is in ADAM or not (different security scenario)\n            var conv = valueConverter;\n            var resolved = conv.ToValue(hyperlink, guid);\n\n            if (lookupPage)\n            {\n                // page link - only resolve if the user has edit-permissions\n                // only people who have some full edit permissions may actually look up pages\n                var permCheckPage = appPermissions.New(new() { SiteContext = context, App = context.AppReaderRequired });\n                var userMay= permCheckPage.UserMayOnAll(GrantSets.WritePublished);\n                return new() {Value = userMay ? resolved : hyperlink};\n            }\n\n            // for file, we need guid & field - otherwise return the original unmodified\n            if (guid == default || string.IsNullOrEmpty(field) || string.IsNullOrEmpty(contentType))\n                return new() { Value = hyperlink };\n\n            var isOutsideOfAdam = !AdamSecurity.PathIsInItemAdam(guid, field, resolved);\n\n            // file-check, more abilities to allow\n            // this will already do a ensure-or-throw inside it if outside of adam\n            var adamCtx = adamCtxLazy.Value;\n            adamCtx.Init(context, contentType!, field!, guid, isOutsideOfAdam);\n            if (adamCtx.Security.UserIsRestrictedAndAccessingItemOutsideOfFolder(resolved, out var exp))\n                throw exp;\n            if (adamCtx.Security.UserNotPermittedOnField(GrantSets.ReadSomething, out exp))\n                throw exp;\n                \n            // now try to find the item, use this to get the id\n            var parts = new LinkParts(hyperlink);\n\n            // link was not able to match,\n            if (!parts.IsMatch || parts.Id == 0) \n                return new() { Value = hyperlink };\n\n            // Note: kind of temporary solution, will fail if TFileId isn't int!\n            var file = adamCtx.AdamManager.AdamFs.GetFile(AdamAssetIdentifier.Create(parts.Id));\n            var dtoMaker = adamDtoMaker.New(new() { AdamContext = adamCtx });\n            // if everything worked till now, it's ok to return the result\n            var adam = dtoMaker.Create(file);\n            return new()\n            {\n                Adam = adam,\n                Value = adam.Url!\n            };\n        }\n        catch\n        {\n            return new() { Value = hyperlink };\n        }\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/List/ContentGroupControllerReal.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.ImportExport.Json.V1;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Blocks.Sys.Work;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentGroupControllerReal(\n    GenWorkDb<WorkFieldList> workFieldList,\n    GenWorkPlus<WorkBlocks> appBlocks,\n    LazySvc<IPagePublishing> publishing,\n    ISxcCurrentContextService ctxService,\n    LazySvc<ListControllerReal> listController)\n    : ServiceBase(\"Api.CntGrpRl\", connect: [workFieldList, appBlocks, ctxService, publishing, listController]),\n        IContentGroupController\n{\n    #region Constructor / di\n\n    public const string LogSuffix = \"CntGrp\";\n\n\n    public ISxcCurrentContextService CtxService { get; } = ctxService;\n\n\n    [field: AllowNull, MaybeNull]\n    private IContextOfBlock Context => field ??= CtxService.BlockContextRequired();\n\n    private IAppWorkCtxPlus AppCtx => _appCtx.Get(() => appBlocks.CtxSvc.ContextPlus(Context.AppReaderRequired))!;\n    private readonly GetOnce<IAppWorkCtxPlus> _appCtx = new();\n    #endregion\n\n    public EntityInListDto? Header(Guid guid)\n    {\n        Log.A($\"header for:{guid}\");\n        //var cg = CmsManager.Read.Blocks.GetBlockConfig(guid);\n        var cg = appBlocks.New(AppCtx).GetBlockConfig(guid);\n\n        // new in v11 - this call might be run on a non-content-block, in which case we return null\n        var ent = (cg as ICanBeEntity)?.Entity;\n        if (ent == null!)\n            return null;\n        if (ent.Type.Name != WorkBlocks.BlockTypeName)\n            return null;\n\n        var header = cg.Header.FirstOrDefault();\n\n        return new()\n        {\n            Index = 0,\n            Id = header?.EntityId ?? 0,\n            Guid = header?.EntityGuid ?? Guid.Empty,\n            Title = header?.GetBestTitle() ?? \"\",\n            Type = header?.Type.NameId ?? cg.View!.HeaderType\n        };\n    }\n        \n\n    public void Replace(Guid guid, string part, int index, int entityId, bool add = false) \n        => listController.Value.Replace(guid, part, index, entityId, add);\n\n\n    /// <summary>\n    /// Special Replace just like list-replace, but with content type name coming from View definition\n    /// </summary>\n    public ReplacementListDto? Replace(Guid guid, string part, int index)\n    {\n        var l = Log.Fn<ReplacementListDto?>($\"target:{guid}, part:{part}, index:{index}\");\n        var typeNameOfField = FindTypeNameOnContentGroup(guid, part);\n        var result = listController.Value.GetListToReorder(guid, part, index, typeNameOfField);\n        return l.Return(result);\n    }\n\n\n    private string? FindTypeNameOnContentGroup(Guid guid, string part)\n    {\n        var l = Log.Fn<string>($\"{guid}, {part}\");\n\n        //var contentGroup = CmsManager.Read.Blocks.GetBlockConfig(guid);\n        var contentGroup = appBlocks.New(AppCtx).GetBlockConfig(guid);\n        if ((contentGroup as ICanBeEntity)?.Entity == null || contentGroup.View == null)\n            return l.ReturnNull(\"Doesn't seem to be a content-group. Cancel.\");\n\n        var typeNameForField = string.Equals(part, ViewParts.ContentLower, OrdinalIgnoreCase)\n            ? contentGroup.View.ContentType\n            : contentGroup.View.HeaderType;\n\n        return l.Return(typeNameForField);\n    }\n\n\n\n\n    public List<EntityInListDto> ItemList(Guid guid, string part)\n    {\n        Log.A($\"item list for:{guid}\");\n        var cg = Context.AppReaderRequired.GetDraftOrPublished(guid)!;\n        var itemList = cg.Children(part);\n        var list = itemList\n            .Select(Context.AppReaderRequired.GetDraftOrKeep)\n            .Select((c, index) => new EntityInListDto\n            {\n                Index = index,\n                Id = c?.EntityId ?? 0,\n                Guid = c?.EntityGuid ?? Guid.Empty,\n                Title = c?.GetBestTitle() ?? \"\",\n                Type = c?.Type.NameId,\n                TypeWip = c?.Type.NameId == null ? null : new JsonType(c)\n            })\n            .ToList();\n\n        return list;\n    }\n\n\n    // TODO: part should be handed in with all the relevant names! atm it's \"content\" in the content-block scenario\n    public bool ItemList(Guid guid, List<EntityInListDto>? list,  string? part = null)\n    {\n        Log.A($\"list for:{guid}, items:{list?.Count}\");\n        if (list == null)\n            throw new ArgumentNullException(nameof(list));\n\n        publishing.Value.DoInsidePublishing(Context, _ =>\n        {\n            var entity = Context.AppReaderRequired.GetDraftOrPublished(guid);\n            var sequence = list\n                .Select(i => i.Index)\n                .ToArray();\n            var fields = part == ViewParts.ContentLower\n                ? ViewParts.ContentPair\n                : [part ?? throw new ArgumentException(@\"Part name cannot be null\", nameof(part))];\n            workFieldList.New(Context.AppReaderRequired)\n                .FieldListReorder(entity!, fields, sequence, Context.Publishing.ForceDraft);\n        });\n\n        return true;\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/List/EntityInListDto.cs",
    "content": "﻿using ToSic.Eav.ImportExport.Json.V1;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\npublic class EntityInListDto\n{\n    public int Index;\n    public int Id;\n    public Guid Guid;\n    public string? Title;\n    public string? Type;\n    public JsonType? TypeWip;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/List/IContentGroupController.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Cms;\n\npublic interface IContentGroupController\n{\n    EntityInListDto? Header(Guid guid);\n    void Replace(Guid guid, string part, int index, int entityId, bool add = false);\n    ReplacementListDto? Replace(Guid guid, string part, int index);\n    List<EntityInListDto> ItemList(Guid guid, string part);\n    bool ItemList(Guid guid, List<EntityInListDto> list, string? part = null);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/List/ListControllerReal.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic partial class ListControllerReal(\n    GenWorkDb<WorkFieldList> workFieldList,\n    GenWorkPlus<WorkEntities> workEntities,\n    ISxcCurrentContextService ctxService,\n    Generator<IPagePublishing> publishing)\n    : ServiceBase(\"Api.LstRl\",\n        connect: [workFieldList, workEntities, publishing, ctxService]), IListController\n{\n    public const string LogSuffix = \"Lst\";\n\n    private IContextOfBlock Context => field ??= ctxService.BlockContextRequired();\n\n\n    public void Move(Guid? parent, string fields, int index, int toIndex) \n    {\n        var l = Log.Fn($\"parent:{parent}, fields:{fields}, index:{index}, toIndex:{toIndex}\");\n        var fList = workFieldList.New(Context.AppReaderRequired);\n        ModifyList(FindOrThrow(parent), fields,\n            (entity, fieldList, versioning) => fList.FieldListMove(entity, fieldList, index, toIndex, versioning));\n        l.Done();\n    }\n\n\n    public void Delete(Guid? parent, string fields, int index) \n    {\n        var l = Log.Fn($\"parent:{parent}, fields:{fields}, index:{index}\");\n        var fList = workFieldList.New(Context.AppReaderRequired);\n        ModifyList(FindOrThrow(parent), fields,\n            (entity, fieldList, versioning) => fList.FieldListRemove(entity, fieldList, index, versioning));\n        l.Done();\n    }\n\n\n\n\n    private void ModifyList(IEntity target, string fields, Action<IEntity, string[], bool> action)\n    {\n        // use dnn versioning - items here are always part of list\n        var context = ctxService.BlockContextRequired();\n        publishing.New().DoInsidePublishing(context, _ =>\n        {\n            // determine versioning\n            var forceDraft = context.Publishing.ForceDraft;\n            // check field list (default to content-block fields)\n            var fieldList = fields is null or ViewParts.ContentLower\n                ? ViewParts.ContentPair\n                : fields.CsvToArrayWithoutEmpty();\n            action.Invoke(target, fieldList, forceDraft);\n        });\n    }\n\n    private IEntity FindOrThrow(Guid? parent)\n    {\n        var block = ctxService.BlockRequired();\n        var target = parent == null\n            ? (block.Configuration as ICanBeEntity)?.Entity\n            : block.Context.AppReaderRequired.List.GetOne(parent.Value);\n\n        return target == null\n            ? throw new($\"Can't find parent {parent}\")\n            : block.Context.AppReaderRequired.GetDraftOrKeep(target);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/List/ListControllerReal_Replace.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Cms;\n\npartial class ListControllerReal\n{\n\n    public void Replace(Guid guid, string part, int index, int entityId, bool add)\n    {\n        var isContentPair = ViewParts.ContentLower.EqualsInsensitive(part);\n\n        var l = Log.Fn($\"target:{guid}, {nameof(part)}:{part}, {nameof(isContentPair)}: {isContentPair}, {nameof(index)}:{index}, {nameof(entityId)}:{entityId}, {nameof(add)}: {add}\");\n\n        // use dnn versioning - this is always part of page\n        publishing.New().DoInsidePublishing(Context, InternalSave);\n        l.Done();\n        return;\n\n        void InternalSave(VersioningActionInfo _)\n        {\n            var entity = Context.AppReaderRequired.GetDraftOrPublished(guid)\n                         ?? throw l.Done( new Exception($\"Can't find item '{guid}'\"));\n\n            // Make sure we have the correct casing for the field names\n            part = entity.Type[part]!.Name;\n\n            var fList = workFieldList.New(Context.AppReaderRequired);\n\n            var forceDraft = Context.Publishing.ForceDraft;\n            if (add)\n            {\n                var fields = isContentPair ? ViewParts.ContentPair : [part];\n                var values = isContentPair ? [entityId, null] : new int?[] { entityId };\n                fList.FieldListAdd(entity, fields, index, values, forceDraft, false);\n            }\n            else\n                fList.FieldListReplaceIfModified(entity, [part], index, [entityId],\n                    forceDraft);\n        }\n    }\n\n\n    internal ReplacementListDto? GetListToReorder(Guid guid, string part, int index, string? typeName)\n    {\n        var l = Log.Fn<ReplacementListDto>($\"{nameof(typeName)}:{typeName}, {nameof(part)}:{part}, {nameof(index)}:{index}\");\n\n        var (existingItemsInField, typeNameOfField) = FindItemAndFieldTypeName(guid, part);\n\n        typeName ??= typeNameOfField;\n\n        // if no type was defined in this set, then return an empty list as there is nothing to choose from\n        if (string.IsNullOrEmpty(typeName))\n            return l.ReturnNull(\"no type name, so no data\");\n\n        var ct = Context.AppReaderRequired.GetContentType(typeName);\n\n        var listTemp = workEntities.New(Context.AppReaderRequired)\n            .Get(typeName)\n            .ToList();\n\n        var preferDraft = listTemp\n            .Select(Context.AppReaderRequired.GetDraftOrKeep)\n            .GroupBy(e => e!.EntityId)\n            .Select(g => g.OrderBy(e => e!.RepositoryId).Last())\n            .ToList();\n\n        var results = preferDraft.ToDictionary(\n            p => p!.EntityId,\n            p => p!.GetBestTitle() ?? \"\"\n        );\n\n        // if list is empty or shorter than index (would happen in an add-to-end-request) return null\n        var selectedId = existingItemsInField.Count > index\n            ? existingItemsInField[index]?.EntityId\n            : null;\n\n        var result = new ReplacementListDto { SelectedId = selectedId, Items = results, ContentTypeName = ct.NameId };\n        return l.Return(result);\n    }\n\n\n    private (List<IEntity> items, string typeName) FindItemAndFieldTypeName(Guid guid, string part)\n    {\n        var l = Log.Fn<(List<IEntity>, string)>($\"guid:{guid},part:{part}\");\n        var parent = Context.AppReaderRequired.GetDraftOrPublished(guid);\n        if (parent == null)\n            throw l.Done(new Exception($\"No item found for {guid}\"));\n        if (!parent.Attributes.ContainsKey(part))\n            throw l.Done(new Exception($\"Could not find field {part} in item {guid}\"));\n        var itemList = parent\n            .Children(part)\n            .Select(Context.AppReaderRequired.GetDraftOrKeep)\n            .Where(e => e != null)\n            .Cast<IEntity>()\n            .ToList();\n\n        // find attribute-type-name\n        var attribute = parent.Type[part];\n        if (attribute == null)\n            throw l.Done(new Exception($\"Attribute definition for '{part}' not found on the item {guid}\"));\n        var typeNameForField = attribute.EntityFieldItemTypePrimary();\n        return l.ReturnAsOk((itemList, typeNameForField));\n    }\n\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Cms/List/ReplacementListDto.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Cms;\n\npublic class ReplacementListDto\n{\n    public int? SelectedId { get; set; }\n    public required Dictionary<int, string> Items { get; set; }\n    public required string ContentTypeName { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/ContentBlocks/ContentBlockBackend.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Backend.InPage;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockEditor;\nusing ToSic.Sxc.Blocks.Sys.Work;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sxc.Render.Sys;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Render.Sys.RenderBlock;\nusing ToSic.Sxc.Sys.Render.PageFeatures;\nusing ToSic.Sxc.Web.Sys.Url;\nusing ToSic.Sys.Security.Permissions;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.ContentBlocks;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentBlockBackend(\n    GenWorkPlus<WorkViews> workViews,\n    Generator<MultiPermissionsApp, MultiPermissionsApp.Options> multiPermissionsApp,\n    IPagePublishing publishing,\n    GenWorkDb<WorkBlocksMod> workBlocksMod,\n    ISxcCurrentContextService ctxService,\n    LazySvc<IBlockResourceExtractor> optimizerLazy,\n    LazySvc<BlockEditorSelector> blockEditorSelectorLazy,\n    AppWorkContextService appWorkCtxService,\n    Generator<BlockOfEntity> entityBlockGenerator,\n    Generator<IBlockBuilder> blockBuilderGenerator)\n    : ServiceBase(\"Bck.FldLst\",\n        connect: [workViews, multiPermissionsApp, publishing, workBlocksMod, ctxService, optimizerLazy, blockEditorSelectorLazy, appWorkCtxService, entityBlockGenerator, blockBuilderGenerator])\n{\n\n    private const bool DebugDetails = true;\n\n    public IRenderResult NewBlockAndRender(int parentId, string field, int index, string app = \"\", Guid? guid = null)\n    {\n        var block = ctxService.BlockRequired();\n        var appWorkCtxDb = appWorkCtxService.CtxWithDb(block.App);\n        var entityId = workBlocksMod.New(appWorkCtxDb).NewBlockReference(parentId, field, index, app, guid);\n\n        // now return a rendered instance\n        var newContentBlock = entityBlockGenerator.New().GetBlockOfEntity(block, null, entityId);\n        var builder = blockBuilderGenerator.New().Setup(newContentBlock);\n        return builder.Run(true, specs: new());\n    }\n\n    public void AddItem(int? index = null)\n    {\n        Log.A($\"add order:{index}\");\n\n        var block = ctxService.BlockRequired();\n        var appWorCtxDb = appWorkCtxService.CtxWithDb(block.App);\n\n        // use dnn versioning - this is always part of page\n        publishing.DoInsidePublishing(block.Context, _ \n            => workBlocksMod.New(appWorCtxDb).AddEmptyItem(block.Configuration, index, block.Context.Publishing.ForceDraft));\n    }\n\n        \n    public bool PublishPart(string part, int index)\n    {\n        Log.A($\"try to publish #{index} on '{part}'\");\n        var block = ctxService.BlockRequired();\n        multiPermissionsApp.ThrowIfNotAllowedInApp(block.Context, GrantSets.WritePublished);\n        return blockEditorSelectorLazy.Value\n            .GetEditor(block)\n            .Publish(part, index);\n    }\n\n    public AjaxRenderDto RenderForAjax(int templateId, string lang, string root, string edition)\n    {\n        var l = Log.Fn<AjaxRenderDto>($\"{nameof(templateId)}: {templateId}; {nameof(lang)}: {lang}; {nameof(root)}: {root}; {nameof(edition)}: {edition}\");\n        l.A(\"1. Get Render result\");\n        var result = RenderToResult(templateId, lang, edition);\n\n        l.A(\"2.1. Build Resources\");\n        var resources = new List<AjaxResourceDto>();\n        var ver = EavSystemInfo.VersionWithStartUpBuild;\n        if (result.Features?.Contains(SxcPageFeatures.TurnOn) == true)\n            resources.Add(new()\n            {\n                Url = UrlHelpers.QuickAddUrlParameter(root.SuffixSlash() + SxcPageFeatures.TurnOn.UrlInDist, \"v\", ver)\n            });\n\n        l.A(\"2.2. Add JS & CSS which were stripped before\");\n        resources.AddRange(result.Assets\n                               ?.Select(asset => new AjaxResourceDto\n                               {\n                                   // Note: Url can be empty if it has contents\n                                   Url = string.IsNullOrWhiteSpace(asset.Url)\n                                       ? null\n                                       : UrlHelpers.QuickAddUrlParameter(asset.Url!, \"v\", ver),\n                                   Type = asset.IsJs ? \"js\" : \"css\",\n                                   Contents = asset.Content,\n                                   Attributes = asset.HtmlAttributes,\n                               })\n                           ?? []\n        );\n\n        l.A(\"3. Add manual resources (fancybox etc.)\");\n        // First get all the parts out of HTML, as the configuration is still stored as plain HTML\n        var mergedFeatures  = string.Join(\"\\n\", result.FeaturesFromResources?.Select(mc => mc.Html) ?? []);\n\n        l.A(\"4.1. Process optimizers\");\n        var renderResult = optimizerLazy.Value.Process(mergedFeatures, new(extractAll: true));\n        var rest = renderResult.Html;\n        if (!string.IsNullOrWhiteSpace(rest)) \n            l.A(\"Warning: Rest after extraction should be empty - not handled ATM\");\n\n        l.A(\"4.2. Add more resources based on processed\");\n        resources.AddRange(renderResult.Assets\n            .Select(asset => new AjaxResourceDto\n            {\n                Url = asset.Url,\n                Type = asset.IsJs ? \"js\" : \"css\",\n                Attributes = asset.HtmlAttributes,\n            })\n        );\n\n        if (DebugDetails)\n        {\n            l.A(\"5. Debug details\");\n            foreach (var ajaxResourceDto in resources)\n            {\n                l.A($\"Url: {ajaxResourceDto.Url}\");\n            }\n        }\n\n        // Undo Dnn CDF ~/ prefix which is added in the process in the background while rendering,\n        // to fix a CDF issue where paths with a space need \"~/\" to work and not be replaced with %20 \n        // and contain spaces: https://github.com/2sic/2sxc/issues/1566\n        // This is hacky, since we're first patching it and here unpatching it again\n        // but it's really difficult to get the other place to know that we're in the ajax call.\n        resources = resources\n            .Select(res => res with { Url = res.Url != null ? res.Url.TrimStart('~') : res.Url })\n            .ToList();\n\n        return l.ReturnAsOk(new()\n        {\n            Html = result.Html,\n            Resources = resources\n        });\n    }\n\n    private IRenderResult RenderToResult(int templateId, string lang, string edition)\n    {\n        var l = Log.Fn<IRenderResult>($\"{nameof(templateId)}:{templateId}, {nameof(lang)}:{lang}\");\n\n        var block = ctxService.BlockRequired();\n        // if a preview templateId was specified, swap to that\n        if (templateId > 0)\n        {\n            var appWorkCtxPlus = appWorkCtxService.ContextPlus(block.Context.AppReaderRequired);\n            var template = workViews.New(appWorkCtxPlus).Get(templateId);\n            template.Edition = edition;\n            block = ctxService.SwapBlockView(template);\n        }\n\n        var builder = blockBuilderGenerator.New().Setup(block);\n        var result = builder.Run(true, specs: new());\n        return l.ReturnAsOk(result);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Context/IWebApiContextBuilder.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Context;\n\n/// <summary>\n/// Helper object which will determine the current context based on headers, url-parameters etc.\n/// Will be slightly different depending on the platform.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IWebApiContextBuilder\n{\n    ISxcCurrentContextService PrepareContextResolverForApiRequest();\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Context/NetCoreWebApiContextHelper.cs",
    "content": "﻿#if NETCOREAPP\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Sxc.Backend.Adam;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Code.Sys;\nusing ToSic.Sxc.Code.Sys.CodeRunHelpers;\nusing ToSic.Sxc.Sys.ExecutionContext;\nusing IApp = ToSic.Sxc.Apps.IApp;\n\nnamespace ToSic.Sxc.Backend.Context;\ninternal class NetCoreWebApiContextHelper: CodeHelperBase\n{\n    private readonly ControllerBase _owner;\n    private readonly ICanGetService _helper;\n\n    public NetCoreWebApiContextHelper(ControllerBase owner, ICanGetService helper) : base(\"Oqt.ApiHlp\")\n    {\n        if (owner is IHasLog ownerWithLog)\n            this.LinkLog(ownerWithLog.Log);\n        _owner = owner;\n        _helper = helper;\n    }\n\n    #region Initialize\n\n    internal new IExecutionContext? ExCtxOrNull => base.ExCtxOrNull;\n\n    /// <summary>\n    /// This will make sure that any services requiring the context can get it.\n    /// It must usually be called from the base class which expects to use this.\n    /// </summary>\n    public void InitializeBlockContext(ActionExecutingContext context)\n    {\n        if (_blockContextInitialized) return;\n        _blockContextInitialized = true;\n        var getBlock = _helper.GetService<IWebApiContextBuilder>();\n        CtxService = getBlock.PrepareContextResolverForApiRequest();\n        BlockOptional = CtxService.BlockOrNull();\n    }\n\n    private bool _blockContextInitialized;\n\n    private ISxcCurrentContextService CtxService { get; set; } = null!;\n    internal IBlock? BlockOptional { get; private set; }\n\n    public void OnActionExecutingEnd(ActionExecutingContext context)\n    {\n        // base.OnActionExecuting(context);\n        InitializeBlockContext(context);\n\n        // Use the ServiceProvider of the current request to build DynamicCodeRoot\n        // Note that BlockOptional was already retrieved in the base class\n        var exCtx = context.HttpContext.RequestServices\n            .Build<IExecutionContextFactory>()\n            .New(new()\n            {\n                OwnerOrNull = _owner,\n                BlockOrNull = BlockOptional,\n                ParentLog = Log,\n                CompatibilityFallback = CompatibilityLevels.CompatibilityLevel12,\n            });\n        ConnectToRoot(exCtx);\n\n        AdamCode = exCtx.GetService<AdamCode>();\n\n        // In case SxcBlock was null, there is no instance, but we may still need the app\n        if (ExCtx.GetApp() == null! /* realistic case */)\n        {\n            Log.A(\"DynCode.App is null\");\n            TryToAttachAppFromUrlParams(context);\n        }\n\n        // Ensure the Api knows what path it's on, in case it will\n        // create instances of .cs files\n        if (context.HttpContext.Items.TryGetValue(SourceCodeConstants.SharedCodeRootPathKeyInCache, out var createInstancePath)\n            && _owner is IGetCodePath withCodePath)\n            withCodePath.CreateInstancePath = (createInstancePath as string)!;\n    }\n\n\n    private void TryToAttachAppFromUrlParams(ActionExecutingContext context) => Log.Do(() =>\n    {\n        var found = false;\n        try\n        {\n            // Handed in from the App-API Transformer\n            context.HttpContext.Items.TryGetValue(SxcWebApiConstants.HttpContextKeyForAppFolder,\n                out var routeAppPathObj);\n            if (routeAppPathObj == null) return \"\";\n            var routeAppPath = routeAppPathObj.ToString();\n\n            var appId = CtxService.SetAppOrNull(routeAppPath)\n                            ?.AppReaderRequired.AppId\n                        ?? Eav.Sys.EavConstants.NullId;\n\n            if (appId != Eav.Sys.EavConstants.NullId)\n            {\n                // Look up if page publishing is enabled - if module context is not available, always false\n                base.Log.A($\"AppId: {appId}\");\n                var app = LoadAppOnly(appId, CtxService.Site().Site);\n                ((IExCtxAttachApp)ExCtx).AttachApp(app);\n                found = true;\n            }\n        }\n        catch\n        {\n            /* ignore */\n        }\n\n        return found.ToString();\n    });\n\n    /// <summary>\n    /// Only load the app in case we don't have a module context\n    /// </summary>\n    /// <param name=\"appId\"></param>\n    /// <param name=\"site\"></param>\n    /// <returns></returns>\n    private IApp LoadAppOnly(int appId, ISite site)\n    {\n        var l = Log.Fn<IApp>($\"{appId}\");\n        var app = _helper.GetService<Apps.App>();\n        app.Init(site, new AppIdentityPure(site.ZoneId, appId), new());\n        return l.Return(app);\n    }\n\n\n    #endregion\n\n    #region Context Maker\n\n    public void SetupResponseMaker() => _helper.GetService<IResponseMaker>().Init(_owner);\n\n    #endregion\n\n    #region Adam\n\n    public AdamCode AdamCode { get; private set; } = null!;\n\n    public Sxc.Adam.IFile SaveInAdam(NoParamOrder npo = default,\n        Stream? stream = null,\n        string? fileName = null,\n        string? contentType = null,\n        Guid? guid = null,\n        string? field = null,\n        string subFolder = \"\") =>\n        AdamCode.SaveInAdam(\n            stream: stream,\n            fileName: fileName,\n            contentType: contentType,\n            guid: guid,\n            field: field,\n            subFolder: subFolder);\n\n    #endregion\n\n}\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Context/UiContextBuilderBase.cs",
    "content": "﻿using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.Cms;\nusing ToSic.Eav.WebApi.Sys.Languages;\nusing ToSic.Sxc.Apps.Sys.Assets;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Services;\nusing ToSic.Sys.Capabilities.Features;\nusing static ToSic.Sys.Capabilities.Features.BuiltInFeatures;\n\nnamespace ToSic.Sxc.Backend.Context;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class UiContextBuilderBase(UiContextBuilderBase.Dependencies services)\n    : ServiceBase<UiContextBuilderBase.Dependencies>(services, SxcLogName + \".UiCtx\"), IUiContextBuilder\n{\n    #region Dependencies \n\n    public record Dependencies(\n        IContextOfSite SiteCtx,\n        LazySvc<ISysFeaturesService> Features,\n        LazySvc<IUiData> UiDataLazy,\n        LazySvc<LanguagesBackend> LanguagesBackend,\n        IAppPathsMicroSvc AppPaths,\n        LazySvc<GlobalPaths> GlobalPaths,\n        IAppsCatalog AppsCatalog,\n        LazySvc<IUserService> UsersSvc\n    ) : DependenciesRecord(connect: [SiteCtx, Features, UiDataLazy, AppPaths, LanguagesBackend, GlobalPaths, AppsCatalog, UsersSvc]);\n\n    #endregion\n\n    #region Constructor / DI\n\n    protected int ZoneId => Services.SiteCtx.Site.ZoneId;\n    protected IAppSpecs? AppSpecsOrNull;\n    private IAppReader? _appReaderOrNull;\n\n    #endregion\n\n    public IUiContextBuilder InitApp(IAppReader? appReaderOrNull)\n    {\n        AppSpecsOrNull = appReaderOrNull?.Specs;\n        _appReaderOrNull = appReaderOrNull;\n        return this;\n    }\n\n    /// <inheritdoc />\n    public ContextDto Get(Ctx flags, CtxEnable enableFlags)\n    {\n        var ctx = new ContextDto();\n        // logic for activating each part\n        // 1. either that switch is on\n        // 2. or the null-check: all is on\n        // 3. This also means if the switch is off, it's off\n        if (flags.HasFlag(Ctx.AppBasic) | flags.HasFlag(Ctx.AppAdvanced))\n            ctx.App = GetApp(flags);\n        if (enableFlags != CtxEnable.None) ctx.Enable = GetEnable(enableFlags);\n        if (flags.HasFlag(Ctx.Language)) ctx.Language = GetLanguage();\n        if (flags.HasFlag(Ctx.Page)) ctx.Page = GetPage();\n        if (flags.HasFlag(Ctx.Site)) ctx.Site = GetSite(flags);\n        if (flags.HasFlag(Ctx.System)) ctx.System = GetSystem(flags);\n        if (flags.HasFlag(Ctx.User)) ctx.User = GetUser(flags);\n        if (flags.HasFlag(Ctx.Features) || flags.HasFlag(Ctx.FeaturesForSystemTypes))\n            ctx.Features = GetFeatures(flags);\n        return ctx;\n    }\n\n    protected virtual ContextLanguageDto? GetLanguage()\n    {\n        if (ZoneId == 0)\n            return null;\n        var site = Services.SiteCtx.Site;\n\n        var converted = Services.LanguagesBackend.Value.GetLanguagesOfApp(_appReaderOrNull);\n\n        return new()\n        {\n            Current = site.CurrentCultureCode,\n            Primary = converted.Any() ? site.DefaultCultureCode : site.CurrentCultureCode, // in special case when no languages are available, use the current culture to fix translation issue in UI\n            List = converted, \n        };\n    }\n\n    protected virtual ContextResourceWithApp GetSystem(Ctx flags)\n    {\n        var result = new ContextResourceWithApp\n        {\n            Url = \"/\"\n        };\n        // Stop now if we don't need advanced infos\n        if (!flags.HasFlag(Ctx.AppAdvanced))\n            return result;\n\n        // Otherwise also add the global app id\n        result.PrimaryApp = result.DefaultApp = new(1, 1);\n        return result;\n    }\n\n    protected virtual ContextResourceWithApp GetSite(Ctx flags)\n    {\n        var result = new ContextResourceWithApp\n        {\n            Id = Services.SiteCtx.Site.Id,\n            Url = \"//\" + Services.SiteCtx.Site.UrlRoot + \"/\",\n        };\n        // Stop now if we don't need advanced infos\n        if (!flags.HasFlag(Ctx.AppAdvanced)) return result;\n\n        // Otherwise also add the global appId\n        var zoneId = Services.SiteCtx.Site.ZoneId;\n        result.DefaultApp = (AppIdentity)Services.AppsCatalog.DefaultAppIdentity(zoneId);\n        result.PrimaryApp = (AppIdentity)Services.AppsCatalog.PrimaryAppIdentity(zoneId);\n        return result;\n    }\n\n    protected virtual WebResourceDto GetPage() =>\n        new()\n        {\n            Id = EavConstants.NullId,\n        };\n\n    protected virtual ContextEnableDto GetEnable(CtxEnable ctx)\n    {\n        var isRealApp = AppSpecsOrNull != null && ! AppSpecsOrNull.IsContentApp();\n        var user = Services.SiteCtx.User;\n        var dto = new ContextEnableDto\n        {\n            DebugMode = user.IsSystemAdmin ||\n                        Services.Features.Value.IsEnabled(EditUiAllowDebugModeForEditors)\n        };\n        if (ctx.HasFlag(CtxEnable.AppPermissions))\n            dto.AppPermissions = isRealApp;\n        if (ctx.HasFlag(CtxEnable.CodeEditor))\n            dto.CodeEditor = user.IsSystemAdmin;\n        if (ctx.HasFlag(CtxEnable.Query))\n            dto.Query = isRealApp && user.IsSystemAdmin;\n        if (ctx.HasFlag(CtxEnable.FormulaSave))\n            dto.FormulaSave = user.IsSystemAdmin;\n        if (ctx.HasFlag(CtxEnable.OverrideEditRestrictions))\n            dto.OverrideEditRestrictions = user.IsSystemAdmin;\n        return dto;\n    }\n\n    protected virtual string GetGettingStartedUrl() => EavConstants.UrlNotInitialized;\n\n    protected virtual ContextAppDto? GetApp(Ctx flags)\n    {\n        if (_appReaderOrNull == null)\n            return null;\n        var appReader = _appReaderOrNull;\n        var appSpecs = appReader.Specs;\n        var paths = Services.AppPaths.Get(appReader, Services.SiteCtx.Site);\n        var result = new ContextAppDto\n        {\n            Id = appSpecs.AppId,\n            Name = appSpecs.Name,\n            Folder = appSpecs.Folder,\n            Url = paths?.Path,\n            SharedUrl = paths?.PathShared\n        };\n\n        // Stop now if we don't need edit or advanced\n        if (!flags.HasFlag(Ctx.AppEdit) && !flags.HasFlag(Ctx.AppAdvanced))\n            return result;\n\n        result.IsGlobalApp = appSpecs.IsGlobalSettingsApp();\n        result.IsSiteApp = appSpecs.IsSiteSettingsApp();\n        // only check content if not global, as that has the same id\n        if (!result.IsGlobalApp)\n            result.IsContentApp = appSpecs.IsContentApp();\n\n        // Stop now if we don't need advanced infos\n        if (!flags.HasFlag(Ctx.AppAdvanced))\n            return result;\n\n        result.GettingStartedUrl = GetGettingStartedUrl();\n        result.Identifier = appSpecs.NameId;\n            \n        // #SiteApp v13\n        result.SettingsScope = appSpecs.IsGlobalSettingsApp()\n            ? \"Global\" \n            : appSpecs.IsSiteSettingsApp()\n                ? \"Site\" \n                : \"App\";\n\n        result.Permissions = new() { Count = appReader.Specs.Metadata.Permissions.Count() };\n\n        result.IsShared = appReader.IsShared();\n        result.IsInherited = appReader.IsInherited();\n\n        result.Icon = AppAssetThumbnail.GetUrl(appReader, paths!, Services.GlobalPaths);\n        return result;\n    }\n\n    protected virtual ContextUserDto GetUser(Ctx flags)\n    {\n        var user = Services.SiteCtx.User;\n        var userDto = new ContextUserDto\n        {\n            Email = user.Email,\n            Id = user.Id,\n            Guid = user.Guid,\n            IsSystemAdmin = user.IsSystemAdmin,\n            IsAnonymous = user.IsAnonymous,\n            IsSiteAdmin = user.IsSiteAdmin,\n            IsContentEditor = user.IsContentEditor,\n            IsContentAdmin = user.IsContentAdmin,\n            Name = user.Name,\n            Username = user.Username,\n            Roles = flags.HasFlag(Ctx.UserRoles) ? Services.UsersSvc.Value.GetCurrentUser().Roles.Select(r => r.Name).ToListOpt() : [],\n        };\n        return userDto;\n    }\n\n    /// <summary>\n    /// Features provided must be virtual, so that applications can override this.\n    /// </summary>\n    /// <returns></returns>\n    protected virtual IList<FeatureDto> GetFeatures(Ctx flags)\n        => Services.UiDataLazy.Value.FeaturesDto(Services.SiteCtx.Permissions.IsContentAdmin, flags.HasFlag(Ctx.FeaturesForSystemTypes));\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Context/UiContextBuilderUnknown.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Context;\n\ninternal sealed class UiContextBuilderUnknown: UiContextBuilderBase, IIsUnknown\n{\n    public UiContextBuilderUnknown(Dependencies services, WarnUseOfUnknown<UiContextBuilderBase> _) : base(services)\n    {\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Context/WebApiContextBuilderUnknown.cs",
    "content": "﻿#pragma warning disable CS9113 // Parameter is unread.\n\nnamespace ToSic.Sxc.Backend.Context;\n\ninternal class WebApiContextBuilderUnknown(WarnUseOfUnknown<WebApiContextBuilderUnknown> _) : IWebApiContextBuilder\n{\n    public ISxcCurrentContextService PrepareContextResolverForApiRequest()\n    {\n        throw new NotImplementedException();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/CustomApiHelpers.cs",
    "content": "﻿using System.Net;\nusing System.Net.Http.Headers;\nusing System.Text;\nusing System.Xml;\nusing System.Xml.Schema;\n\nnamespace ToSic.Sxc.Backend;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class CustomApiHelpers\n{\n    public static string FileParamsInitialCheck(NoParamOrder npo, bool? download, string virtualPath,\n        string fileDownloadName, object contents)\n    {\n        // Check initial conflicting values\n        CheckInitialConflictingValues(virtualPath, contents);\n\n        return CheckForceDownload(download, virtualPath, fileDownloadName);\n    }\n\n    /**\n         * check initial conflicting value\n         */\n    public static void CheckInitialConflictingValues(string virtualPath, object contents)\n    {\n        var contentCount = (contents != null ? 1 : 0) + (virtualPath != null ? 1 : 0);\n        if (contentCount == 0)\n            throw new ArgumentException(\"None of the provided parameters give content for the file to return.\");\n        if (contentCount > 1)\n            throw new ArgumentException(\n                $\"Multiple file setting properties like '{nameof(contents)}' or '{nameof(virtualPath)}' have a value - only one can be provided.\");\n    }\n\n    public static string CheckForceDownload(bool? download, string virtualPath, string? fileDownloadName)\n    {\n        // Set reallyForceDownload based on forceDownload and file name\n        var reallyForceDownload = download == true || !string.IsNullOrWhiteSpace(fileDownloadName);\n\n        // check if we should force a download, but maybe fileDownloadName is empty\n        if (reallyForceDownload && string.IsNullOrWhiteSpace(fileDownloadName))\n        {\n            // try to guess name based on virtualPath name\n            fileDownloadName = !string.IsNullOrWhiteSpace(virtualPath)\n                ? Path.GetFileName(virtualPath)\n                : null;\n            if (string.IsNullOrWhiteSpace(fileDownloadName))\n                throw new HttpExceptionAbstraction(HttpStatusCode.NotFound,\n                    $\"Can't force download without a {nameof(fileDownloadName)} or a real {nameof(virtualPath)}\",\n                    \"Not Found\");\n        }\n\n        return fileDownloadName!;\n    }\n\n    /*\n     * for \"Content-Disposition: inline\" fileDownloadName should be null\n     */\n    public static string? EnsureFileDownloadNameIsNullForInline(bool? download, string fileDownloadName)\n    {\n        return download == true ? fileDownloadName : null;\n    }\n\n    public static string XmlContentTypeFromContent(bool isValidXml, string contentType)\n    {\n        return isValidXml ? \"text/xml\" : contentType;\n    }\n\n    public static bool IsValidXml(string xml)\n    {\n        var stringReader = new StringReader(xml);\n        var disposable = XmlReader.Create(stringReader, _settings);\n        return IsMinimallyValidXml(disposable);\n    }\n\n    public static bool IsValidXml(Stream stream)\n    {\n        var disposable = XmlReader.Create(stream, _settings);\n        var isValidXml = IsMinimallyValidXml(disposable);\n        stream.Position = 0; // stream was used for validation, so prepare it for new use\n        return isValidXml;\n    }\n\n    public static bool IsValidXml(byte[] body)\n    {\n        // load the data into a memory stream\n        using var stream = new MemoryStream(body);\n        return IsValidXml(stream);\n    }\n\n    public static bool IsMinimallyValidXml(XmlReader disposable)\n    {\n        using var xmlReader = disposable;\n        try\n        {\n            while (xmlReader.Read())\n            {\n                ; // Intentionally left blank.\n            }\n            return true;\n        }\n        catch (XmlException)\n        {\n            return false;\n        }\n    }\n\n    private static readonly XmlReaderSettings _settings = new()\n    {\n        CheckCharacters = true,\n        ConformanceLevel = ConformanceLevel.Document,\n        DtdProcessing = DtdProcessing.Ignore,\n        IgnoreComments = true,\n        IgnoreProcessingInstructions = true,\n        IgnoreWhitespace = true,\n        ValidationFlags = XmlSchemaValidationFlags.None,\n        ValidationType = ValidationType.None,\n    };\n\n    public static Encoding GetEncoding(XmlDocument xmlDocument)\n    {\n        var xmlDeclaration = xmlDocument.ChildNodes.OfType<XmlDeclaration>().FirstOrDefault();\n        return (xmlDeclaration?.Encoding == null)\n            ? Encoding.UTF8\n            : Encoding.GetEncoding(xmlDeclaration.Encoding);\n    }\n\n    public static Encoding GetEncoding(string xmlString)\n    {\n        if (!IsValidXml(xmlString)) return Encoding.UTF8;\n        var xmlDocument = new XmlDocument();\n        xmlDocument.LoadXml(xmlString);\n        return GetEncoding(xmlDocument);\n    }\n\n    public static Encoding GetEncoding(Stream stream)\n    {\n        using var reader = new StreamReader(stream, detectEncodingFromByteOrderMarks: true);\n        reader.ReadToEnd();\n        stream.Position = 0;\n        return reader.CurrentEncoding; // the reader detects the encoding!\n    }\n\n    public static Encoding GetEncoding(byte[] charBody)\n    {\n        using var memoryStream = new MemoryStream(charBody);\n        return GetEncoding(memoryStream);\n    }\n\n    public static MediaTypeHeaderValue PrepareMediaTypeHeaderValue(string contentType, Encoding encoding)\n    {\n        return new(contentType)\n        {\n            CharSet = encoding.WebName // do not use HeaderName or BodyName because it is used for mail agents\n        };\n    }\n\n    public static ContentDispositionHeaderValue PrepareContentDispositionHeaderValue(bool? download, string fileDownloadName)\n    {\n        if (string.IsNullOrWhiteSpace(fileDownloadName))\n            return new(\"inline\");\n        return download != true\n            ? new(\"inline\")\n            {\n                FileName = fileDownloadName\n            }\n            : new ContentDispositionHeaderValue(\"attachment\")\n            {\n                FileName = fileDownloadName\n            };\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/ImportExport/AppStateSyncRestore.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.ImportExport.Integration;\nusing ToSic.Eav.ImportExport.Sys.ImportHelpers;\nusing ToSic.Eav.ImportExport.Sys.XmlImport;\nusing ToSic.Eav.ImportExport.Sys.Zip;\nusing ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.Security;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Capabilities.SysFeatures;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Backend.ImportExport;\n\n/// <summary>\n/// This object will ensure that an app is reset to the state it was in when the app.xml was last exported\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppStateSyncRestore(\n    LazySvc<XmlImportWithFiles> xmlImportWithFilesLazy,\n    ImpExpHelpers impExpHelpers,\n    WorkAppsRemove workAppsRemove,\n    ISite site,\n    IUser user,\n    IImportExportEnvironment env,\n    ZipImport zipImport,\n    ISysFeaturesService features,\n    IAppPathsMicroSvc appPathSvc)\n    : ServiceBase(\"Bck.Export\",\n        connect: [xmlImportWithFilesLazy, impExpHelpers, workAppsRemove, site, user, env, zipImport, features, appPathSvc]),\n        ILowCodeAction<AppStateSyncRestore.Parameters, ImportResultDto>\n{\n    public record Parameters(int ZoneId, int AppId, string DefaultLanguage, bool WithSiteFiles);\n\n    public async Task<ActionData<ImportResultDto>> Run(LowCodeActionContext context, ActionData<Parameters> ad)\n    {\n        var parameters = ad.Data;\n        var zoneId = parameters.ZoneId;\n        var appId = parameters.AppId;\n        var l = Log.Fn<ImportResultDto>($\"Reset App {zoneId}/{appId}\");\n        var result = new ImportResultDto();\n\n        SecurityHelpers.ThrowIfNotSiteAdmin(user, Log);\n\n        if (features.IsEnabled(BuiltInFeatures.AppStateSyncRestoreDisabled))\n            throw new FeaturesRefusingException(BuiltInFeatures.AppStateSyncRestoreDisabled.NameId,\n                \"App Sync Restore Disabled is active, probably as a protective measure.\");\n\n        // Ensure feature available...\n        ExportApp.SyncWithSiteFilesVerifyFeaturesOrThrow(features, parameters.WithSiteFiles);\n\n        var contextZoneId = site.ZoneId;\n        var appRead = impExpHelpers.GetAppAndCheckZoneSwitchPermissions(zoneId, appId, user, contextZoneId);\n        var appPaths = appPathSvc.Get(appRead, site);\n\n        // migrate old .data/app.xml to App_Data\n        ZipImport.MigrateOldAppDataFile(appPaths.PhysicalPath);\n\n        //// 1. Verify the file exists before we flush\n        //var path = Path.Combine(currentApp.PhysicalPath, Eav.Constants.AppDataProtectedFolder);\n        //if (!Directory.Exists(path))\n        //{\n        //    result.Success = false;\n        //    result.Messages.Add(new Message($\"Error: Path to {Eav.Constants.AppDataFile} not found on hard disk\", Message.MessageTypes.Error));\n        //    return result;\n        //}\n\n        var appDataFolder = Path.Combine(appPaths.PhysicalPath, FolderConstants.DataFolderProtected);\n        var filePath = Path.Combine(appDataFolder, FolderConstants.AppDataFile);\n        if (!File.Exists(filePath))\n        {\n            result.Success = false;\n            result.Messages.Add(new($\"Can't find the {FolderConstants.AppDataFile} in the folder\", Message.MessageTypes.Error));\n            return new(result);\n        }\n\n        // 2. Now we can delete the app before we prepare the import\n        workAppsRemove.RemoveAppInSiteAndEav(zoneId, appId, false);\n\n        // 3. Optional reset SiteFiles\n        if (parameters.WithSiteFiles)\n        {\n            var sourcePath = Path.Combine(appPaths.PhysicalPath, FolderConstants.DataFolderProtected);\n\n            // Copy app global template files persisted in /App_Data/2sexyGlobal/ back to app [globalTemplatesRoot]\n            var globalTemplatesStateFolder = Path.Combine(appDataFolder, FolderConstants.ZipFolderForGlobalAppStuff);\n            if (Directory.Exists(globalTemplatesStateFolder))\n            {\n                zipImport.Init(zoneId, appId, allowCode: true);\n                var discard = new List<Message>();\n                zipImport.CopyAppGlobalFiles(discard, appId, sourcePath, deleteGlobalTemplates: true, overwriteFiles: true);\n            }\n\n            // Copy portal files persisted in /App_Data/SiteFiles/ back to site\n            env.TransferFilesToSite(Path.Combine(sourcePath, FolderConstants.ZipFolderForSiteFiles), string.Empty);\n        }\n\n        // 4. Now import the App.xml\n        var allowSystemChanges = user.IsSystemAdmin;\n        var xmlImport = xmlImportWithFilesLazy.Value.Init(parameters.DefaultLanguage, allowSystemChanges);\n        var imp = new ImportXmlReader(filePath, xmlImport, Log);\n        result.Success = xmlImport.ImportXml(zoneId, appId, parentAppId: null /* not sure if we never have a parent here */, imp.XmlDoc);\n        result.Messages.AddRange(xmlImport.Messages);\n        return new(l.Return(result));\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/ImportExport/AppStateSyncSave.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Data.Processing;\nusing ISite = ToSic.Eav.Context.ISite;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.ImportExport.Sys.Zip;\nusing ToSic.Eav.WebApi.Sys.Security;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Backend.ImportExport;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppStateSyncSave(\n    ZipExport export,\n    ISite site,\n    IUser user,\n    Generator<ImpExpHelpers> impExpHelpers,\n    ISysFeaturesService features,\n    IAppPathsMicroSvc appPathSvc)\n    : ServiceBase(\"Bck.Export\", connect: [export, site, user, features, impExpHelpers, appPathSvc]),\n        ILowCodeAction<AppExportSpecs, bool>\n{\n\n    public async Task<ActionData<bool>> Run(LowCodeActionContext context, ActionData<AppExportSpecs> data)\n    {\n        var specs = data.Data;\n        var l = Log.Fn<bool>(specs.Dump());\n        SecurityHelpers.ThrowIfNotSiteAdmin(user, Log); // must happen inside here, as it's opened as a new browser window, so not all headers exist\n\n        if (features.IsEnabled(BuiltInFeatures.AppStateSyncSaveDisabled))\n            throw new FeaturesRefusingException(BuiltInFeatures.AppStateSyncSaveDisabled.NameId,\n                \"App Sync Save Disabled is active, probably as a protective measure.\");\n\n        // Ensure feature available...\n        ExportApp.SyncWithSiteFilesVerifyFeaturesOrThrow(features, specs.WithSiteFiles);\n\n        var contextZoneId = site.ZoneId;\n        var appRead = impExpHelpers.New().GetAppAndCheckZoneSwitchPermissions(specs.ZoneId, specs.AppId, user, contextZoneId);\n        var appPaths = appPathSvc.Get(appRead, site);\n\n        var zipExport = export.Init(specs.ZoneId, specs.AppId, appRead.Specs.Folder, appPaths.PhysicalPath, appPaths.PhysicalPathShared);\n        zipExport.ExportForSourceControl(specs);\n\n        return new(l.ReturnTrue());\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/ImportExport/ExportApp.cs",
    "content": "﻿using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.Context.Sys.ZoneMapper;\nusing ToSic.Eav.Data.Sys.Ancestors;\nusing ISite = ToSic.Eav.Context.ISite;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.ImportExport.Sys.Zip;\nusing ToSic.Eav.WebApi.Sys;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Eav.WebApi.Sys.Security;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Capabilities.SysFeatures;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Backend.ImportExport;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExportApp(\n    IZoneMapper zoneMapper,\n    ZipExport export,\n    AppWorkContextService appWorkCtxSvc,\n    GenWorkPlus<WorkViews> workViews,\n    GenWorkPlus<WorkEntities> workEntities,\n    ISite site,\n    IUser user,\n    Generator<ImpExpHelpers> impExpHelpers,\n    IAppPathsMicroSvc appPathSvc)\n    : ServiceBase(\"Bck.Export\",\n        connect: [workEntities, appWorkCtxSvc, workViews, zoneMapper, export, site, user, impExpHelpers, appPathSvc])\n{\n    public AppExportInfoDto GetAppInfo(int zoneId, int appId)\n    {\n        var l = Log.Fn<AppExportInfoDto>($\"get app info for app:{appId} and zone:{zoneId}\");\n        var contextZoneId = site.ZoneId;\n        var appReader = impExpHelpers.New().GetAppAndCheckZoneSwitchPermissions(zoneId, appId, user, contextZoneId);\n        var appPaths = appPathSvc.Get(appReader, site);\n        var specs = appReader.Specs;\n        var zipExport = export.Init(zoneId, appId, specs.Folder, appPaths.PhysicalPath, appPaths.PhysicalPathShared);\n        var cultCount = zoneMapper.CulturesEnabledWithState(site).Count;\n\n        var appCtx = appWorkCtxSvc.ContextPlus(appReader);\n        var appEntities = workEntities.New(appCtx);\n        var appViews = workViews.New(appCtx);\n\n        var appHasCustomParent = appReader.HasCustomParentApp();\n\n        return l.Return(new()\n        {\n            Name = specs.Name,\n            Guid = specs.NameId,\n            Version = specs.VersionSafe(),\n            EntitiesCount = appEntities.All().Count(e => !e.HasAncestor()),\n            LanguagesCount = cultCount,\n            TemplatesCount = appViews.GetAll().Count(),\n            HasRazorTemplates = appViews.GetRazor().Any(),\n            HasTokenTemplates = appViews.GetToken().Any(),\n            FilesCount = zipExport.AppFileManager.AllFiles().Count() // PortalFilesCount\n                         + (appHasCustomParent ? 0 : zipExport.AppFileManagerGlobal.AllFiles().Count()), // GlobalFilesCount\n            TransferableFilesCount = zipExport.AppFileManager.GetAllTransferableFiles().Count() // TransferablePortalFilesCount\n                                     + (appHasCustomParent ? 0 : zipExport.AppFileManagerGlobal.GetAllTransferableFiles().Count()), // TransferableGlobalFilesCount\n        });\n    }\n\n    internal static void SyncWithSiteFilesVerifyFeaturesOrThrow(ISysFeaturesService features, bool withSiteFiles)\n    {\n        if (!withSiteFiles) return;\n        features.ThrowIfNotEnabled(\"Requires features enabled to sync with site files \",\n            BuiltInFeatures.AppSyncWithSiteFiles.Guid);\n    }\n\n    public FileToUploadToClient Export(AppExportSpecs specs)\n    {\n        var l = Log.Fn<FileToUploadToClient>(specs.Dump());\n\n        SecurityHelpers.ThrowIfNotSiteAdmin(user, Log); // must happen inside here, as it's opened as a new browser window, so not all headers exist\n\n        var contextZoneId = site.ZoneId;\n        var appRead = impExpHelpers.New().GetAppAndCheckZoneSwitchPermissions(specs.ZoneId, specs.AppId, user, contextZoneId);\n        var appPaths = appPathSvc.Get(appRead, site);\n\n        var zipExport = export.Init(specs.ZoneId, specs.AppId, appRead.Specs.Folder, appPaths.PhysicalPath, appPaths.PhysicalPathShared);\n        var addOnWhenContainingContent = specs.IncludeContentGroups\n            ? \"_withPageContent_\" + DateTime.Now.ToString(\"yyyy-MM-ddTHHmm\")\n            : \"\";\n\n        var fileName =\n            $\"2sxcApp_{appRead.Specs.ToFileNameWithVersion()}{addOnWhenContainingContent}.zip\";\n        l.A($\"file name:{fileName}\");\n\n        using var fileStream = zipExport.ExportApp(specs);\n        var fileBytes = fileStream.ToArray();\n        l.A(\"will stream so many bytes:\" + fileBytes.Length);\n\n        return l.ReturnAsOk(new()\n        {\n            FileName = fileName,\n            ContentType = MimeTypeConstants.FallbackType,\n            FileBytes = fileBytes\n        });\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/ImportExport/ExportContent.cs",
    "content": "﻿using ToSic.Eav.Apps.AppReader.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.ImportExport.Sys.XmlExport;\nusing ToSic.Eav.WebApi.Sys.Security;\nusing ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Backend.ImportExport;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExportContent(\n    XmlExporter xmlExporter,\n    GenWorkPlus<WorkViews> workViews,\n    GenWorkPlus<WorkEntities> workEntities,\n    ISite site,\n    IUser user,\n    Generator<ImpExpHelpers> impExpHelpers,\n    IResponseMaker responseMaker)\n    : ServiceBase(\"Bck.Export\",\n        connect: [xmlExporter, workViews, workEntities, site, user, impExpHelpers, responseMaker])\n{\n\n    public ExportPartsOverviewDto PreExportSummary(int zoneId, int appId, string scope)\n    {\n        Log.A($\"get content info for z#{zoneId}, a#{appId}, scope:{scope} super?:{user.IsSystemAdmin}\");\n        var contextZoneId = site.ZoneId;\n        var currentApp = impExpHelpers.New().GetAppAndCheckZoneSwitchPermissions(zoneId, appId, user, contextZoneId);\n\n        var appCtx = workEntities.CtxSvc.ContextPlus(currentApp);\n        var contentTypes = currentApp.ContentTypes.OfScope(scope);\n        var entities = workEntities.New(appCtx).All();\n        var templates = workViews.New(appCtx).GetAll();\n\n        return new()\n        {\n            ContentTypes = contentTypes.Select(c => new ExportPartsContentTypesDto\n            {\n                Id = c.Id,\n                Name = c.Name,\n                StaticName = c.NameId,\n                Templates = templates.Where(t => t.ContentType == c.NameId)\n                    .Select(t => new IdNameDto\n                    {\n                        Id = t.Id,\n                        Name = t.Name\n                    }),\n                Entities = entities\n                    .Where(e => e.Type.Id == c.Id)\n                    .Select(e => new ExportPartsEntitiesDto\n                    {\n                        Title = e.GetBestTitle(),\n                        Id = e.EntityId\n                    })\n            }),\n            TemplatesWithoutContentTypes = templates\n                .Where(t => string.IsNullOrEmpty(t.ContentType))\n                .Select(t => new IdNameDto\n                {\n                    Id = t.Id,\n                    Name = t.Name\n                })\n        };\n    }\n\n\n    public THttpResponseType Export(int zoneId, int appId, string contentTypeIdsString, string entityIdsString, string templateIdsString)\n    {\n        var l = Log.Fn<THttpResponseType>($\"export content z#{zoneId}, a#{appId}, ids:{entityIdsString}, templId:{templateIdsString}\");\n        SecurityHelpers.ThrowIfNotSiteAdmin(user, Log); // must happen inside here, as it's opened as a new browser window, so not all headers exist\n\n        var currentApp = impExpHelpers.New().GetAppAndCheckZoneSwitchPermissions(zoneId, appId, user, site.ZoneId);\n\n        var fileName = $\"2sxcContentExport_{currentApp.Specs.ToFileNameWithVersion()}.xml\";\n        var fileXml = xmlExporter.Init(new AppExportSpecs(zoneId, appId), currentApp, false,\n            contentTypeIdsString?.Split(';') ?? [],\n            entityIdsString?.Split(';') ?? []\n        ).GenerateNiceXml();\n\n        var result = responseMaker.File(fileXml, fileName, \"text/xml\");\n        return l.Return(result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/ImportExport/ImpExpHelpers.cs",
    "content": "﻿using ToSic.Sys.Users;\n\nnamespace ToSic.Sxc.Backend.ImportExport;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ImpExpHelpers(IAppReaderFactory appReadFac) : ServiceBase(\"Sxc.ImExHl\", connect: [appReadFac])\n{\n    /// <summary>\n    /// Get an app - but only allow zone change if super-user\n    /// </summary>\n    /// <returns></returns>\n    internal IAppReader GetAppAndCheckZoneSwitchPermissions(int zoneId, int appId, IUser user, int contextZoneId)\n    {\n        var l = Log.Fn<IAppReader>($\"superuser: {user.IsSystemAdmin}\");\n        if (!user.IsSystemAdmin && zoneId != contextZoneId)\n        {\n            l.ReturnNull(\"error\");\n            throw HttpException.PermissionDenied(\"Tried to access app from another zone. Requires SuperUser permissions.\");\n        }\n\n        var app = appReadFac.Get(new AppIdentity(zoneId, appId));\n        return l.Return(app);\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/ImportExport/ImportContent.cs",
    "content": "﻿using System.Xml.Linq;\nusing ToSic.Eav.Apps.Sys.Caching;\nusing ToSic.Eav.Data.Sys.Entities.Sources;\nusing ToSic.Eav.Identity;\nusing ToSic.Eav.ImportExport.Integration;\nusing ToSic.Eav.ImportExport.Json.Sys;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.ImportExport.Sys.XmlImport;\nusing ToSic.Eav.ImportExport.Sys.Zip;\nusing ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Eav.Serialization.Sys;\nusing ToSic.Eav.WebApi.Sys.Helpers.Validation;\nusing ToSic.Sys.Capabilities.Features;\nusing ToSic.Sys.Configuration;\nusing ToSic.Sys.Users;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.ImportExport;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ImportContent(\n    IEnvironmentLogger envLogger,\n    LazySvc<ImportService> importerLazy,\n    LazySvc<XmlImportWithFiles> xmlImportWithFilesLazy,\n    ZipImport zipImport,\n    Generator<JsonSerializer> jsonSerializerGenerator,\n    IGlobalConfiguration globalConfiguration,\n    IAppReaderFactory appReaders,\n    LazySvc<IUser> userLazy,\n    AppCachePurger appCachePurger,\n    LazySvc<ISysFeaturesService> features,\n    GenWorkDb<WorkEntitySave> workEntSave)\n    : ServiceBase(\"Bck.Export\",\n        connect:\n        [\n            envLogger, importerLazy, xmlImportWithFilesLazy, zipImport, jsonSerializerGenerator, globalConfiguration,\n            appReaders, appCachePurger, userLazy, features, workEntSave\n        ])\n{\n\n    protected readonly AppCachePurger AppCachePurger = appCachePurger;\n\n    public ImportResultDto Import(int zoneId, int appId, string fileName, Stream stream, string defaultLanguage)\n    {\n        var l = Log.Fn<ImportResultDto>();\n        var result = new ImportResultDto();\n\n        var allowSystemChanges = userLazy.Value.IsSystemAdmin;\n        if (fileName.EndsWith(\".zip\"))\n        {   // ZIP\n            try\n            {\n                zipImport.Init(zoneId, appId, userLazy.Value.IsSystemAdmin);\n                var temporaryDirectory = Path.Combine(globalConfiguration.TemporaryFolder(), Guid.NewGuid().GuidCompress().Substring(0, 8));\n\n                result.Success = zipImport.ImportZip(stream, temporaryDirectory);\n                result.Messages.AddRange(zipImport.Messages);\n            }\n            catch (Exception ex)\n            {\n                l.Ex(ex);\n                envLogger.LogException(ex);\n            }\n        }\n        else\n        {\n            // XML\n            using var fileStreamReader = new StreamReader(stream);\n            var xmlImport = xmlImportWithFilesLazy.Value.Init(defaultLanguage, allowSystemChanges);\n            var xmlDocument = XDocument.Parse(fileStreamReader.ReadToEnd());\n            result.Success = xmlImport.ImportXml(zoneId, appId, parentAppId: null /* not sure if we never have a parent here */, xmlDocument);\n            result.Messages.AddRange(xmlImport.Messages);\n        }\n        return l.Return(result);\n    }\n\n\n    public ImportResultDto ImportJsonFiles(int zoneId, int appId, List<FileUploadDto> files, string defaultLanguage)\n    {\n        var l = Log.Fn<ImportResultDto>($\"{zoneId}, {appId}, {defaultLanguage}\");\n        try\n        {\n            // 0. Verify it's json etc.\n            if (files.Any(file => !Json.IsValidJson(file.Contents)))\n                throw l.Ex(new ArgumentException(\"a file is not json\"));\n\n            // 1. Create content types\n            var serializer = jsonSerializerGenerator.New().SetApp(appReaders.Get(new AppIdentity(zoneId, appId)));\n\n            // 1.1 Deserialize json files\n            var packages = files.ToDictionary(file => file.Name, file => serializer.UnpackAndTestGenericJsonV1(file.Contents));\n            l.A($\"Packages: {packages.Count}\");\n\n            // 1.2. Build content types\n            var types = new List<IContentType>();\n                \n            var isEnabled = features.Value.IsEnabled(BuiltInFeatures.DataExportImportBundles);\n            l.A($\"Is bundle packages import feature enabled: {isEnabled}\");\n\n            foreach (var package in packages)\n            {\n                l.A($\"import content-types from package: {package.Key}\");\n\n                // bundle json\n                if (package.Value.Bundles.SafeAny())\n                {\n                    if (isEnabled)\n                        types.AddRange(serializer.GetContentTypesFromBundles(package.Value).Select(set => set.ContentType));\n                    else\n                        throw l.Ex(new NotSupportedException(\"Bundle packages import feature is not enabled.\"));\n                }\n\n                // single json\n                if (package.Value.ContentType != null)\n                    types.Add(serializer.ConvertContentType(package.Value).ContentType);\n            }\n\n            if (types.Any(t => t == null))\n                throw l.Ex(new NullReferenceException(\"One ContentType is null, something is wrong\"));\n\n            // 1.3 Import the type\n            var import = importerLazy.Value.Init(zoneId, appId, true, true);\n            if (types.Any())\n            {\n                import.ImportIntoDb(types, []);\n\n                l.A($\"Purging {zoneId}/{appId}\");\n                AppCachePurger.Purge(zoneId, appId);\n            }\n\n            // are there any entities from bundles for import?\n            if (packages.All(p => p.Value.Bundles?.Any(b => b.Entities.SafeAny()) != true))\n                return l.Return(new(true), \"ok (types only)\");\n\n            // 2. Create Entities\n\n            // 2.1 Reset serializer to use the new app\n            var appState = appReaders.Get(new AppIdentity(zoneId, appId));\n            serializer = jsonSerializerGenerator.New().SetApp(appState);\n            // Since we're importing directly into this app, we prefer local content-types\n            serializer.PreferLocalAppTypes = true;\n            l.A(\"Load items\");\n\n            // 2.2. Build content types\n            var entities = new List<IEntity>();\n            DirectEntitiesSource.Using(relationships =>\n            {\n                foreach (var package in packages)\n                {\n                    l.A($\"import entities from package: {package.Key}\");\n                    if (package.Value.Bundles.SafeNone())\n                        continue;\n                    // bundle json\n                    var entitiesFromBundles = serializer.GetEntitiesFromBundles(package.Value, relationships.Source);\n                    l.A($\"entities from bundles: {entitiesFromBundles.Count}\");\n                    entities.AddRange(entitiesFromBundles);\n                    relationships.List.AddRange(entitiesFromBundles);\n                }\n                return \"dummy\";\n            });\n\n            if (entities.Any(t => t == null))\n                throw new NullReferenceException(\"One Entity is null, something is wrong\");\n\n            // 2.3 Import the entities\n            l.A($\"Import entity {entities.Count} items\");\n            if (entities.Any()) \n                workEntSave.New(appState).Import(entities);\n\n            // 3. possibly show messages / issues\n            return l.Return(new(true), \"ok (with entities)\");\n        }\n        catch (Exception ex)\n        {\n            l.Ex(ex);\n            envLogger.LogException(ex);\n            return l.Return(new ImportResultDto(false, ex.Message, Message.MessageTypes.Error), \"error\");\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/InPage/AjaxPreviewHelperWIP.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.InPage;\n\n// 2025-06-23 2dm - as of now doesn't seem in use, and probably has not been for a long time.\n\n///// <summary>\n///// This helps the ajax preview to ensure js/css are also loaded in the preview.\n///// - v0.1 for 2sxc 12.05 will just rebuild the necessary tags and add them to the HTML\n///// - v0.2 should later on include the relevant assets so that the JS in the can add them as best possible\n///// </summary>\n//[ShowApiWhenReleased(ShowApiMode.Never)]\n//public class AjaxPreviewHelperWIP\n//{\n//    // 2025-06-23 2dm - as of now doesn't seem in use, and probbly has not been for a long time.\n//    public string ReconstructHtml(IRenderResult renderResult, string root)\n//    {\n//        // 0. Skip basics like jQuery, $2sxc, editApi and editUI as they are always available in edit mode\n\n//        // 0.1 Get Version etc.\n//        root = root.SuffixSlash(); // important because DNN historically has a slash in the constant, Oqtane does not\n//        var ver = EavSystemInfo.VersionWithStartUpBuild; // Settings.Version.ToString();\n//        var addOn = \"\";\n\n//        // 1. Check if the features includes turnOn\n//        if (renderResult.Features.Contains(SxcPageFeatures.TurnOn)) \n//            addOn += Js(ver, root + SxcPageFeatures.TurnOn.UrlInDist);\n\n//        // 2. Add JS & CSS which was stripped before\n//        renderResult.Assets.ToList().ForEach(a => addOn += \"\\n\" + (a.IsJs ? Js(ver, a.Url) : Css(a.Url)));\n\n//        renderResult.FeaturesFromSettings.ToList().ForEach(f => addOn += \"\\n\" + f.Html);\n\n//        var html = renderResult.Html;\n//        if (!string.IsNullOrEmpty(html) && !string.IsNullOrEmpty(addOn))\n//        {\n//            // Must insert before the last closing div\n//            var lastDiv = html.LastIndexOf(\"</div>\", StringComparison.InvariantCultureIgnoreCase);\n//            var result = html.Substring(0, lastDiv)\n//                         + \"\\n<!-- resources added for ajax -->\"\n//                         + addOn\n//                         + \"\\n\"\n//                         + \"</div>\";\n//            html = result;\n//        }\n\n//        return html; \n//    }\n\n//    private static string Js(string version, string path)\n//    {\n//        var url = $\"{path}{(path.IndexOf('?') > 0 ? '&' : '?')}v={version}\";\n//        return Tag.Script().Src(url).Type(\"text/javascript\").ToString();\n//    }\n\n//    private static string Css(string path)\n//        => Tag.Link().Href(path).Type(\"text/css\").Rel(\"stylesheet\").ToString();\n\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/InPage/AjaxRenderDto.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.InPage;\n\npublic class AjaxRenderDto\n{\n    public required string? Html { get; init; }\n\n    public required IEnumerable<AjaxResourceDto> Resources { get; init; }\n}\n\npublic record AjaxResourceDto\n{\n    public string? Url { get; init; }\n\n    /// <summary>\n    /// \"js\" or \"css\"\n    /// </summary>\n    public string Type { get; init; } = \"js\";\n\n    public string? Contents { get; init; }\n\n    public IDictionary<string, string>? Attributes { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/InPage/AppViewPickerBackend.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Sxc.Apps.Sys.Ui;\nusing ToSic.Sxc.Blocks.Sys.BlockEditor;\nusing ToSic.Sxc.Blocks.Sys.Work;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Backend.InPage;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppViewPickerBackend(\n    Generator<MultiPermissionsApp, MultiPermissionsApp.Options> multiPermissionsApp,\n    ISxcCurrentContextService ctxService,\n    LazySvc<BlockEditorSelector> blockEditorSelectorLazy,\n    GenWorkPlus<WorkViews> workViews,\n    GenWorkPlus<WorkBlockViewsGet> workBlockViews,\n    AppWorkContextService appWorkCtxService,\n    GenWorkDb<WorkEntityPublish> workPublish)\n    : ServiceBase(\"Bck.ViwApp\", connect: [multiPermissionsApp, ctxService, blockEditorSelectorLazy, workViews, workBlockViews, appWorkCtxService, workPublish])\n{\n    public void SetAppId(int? appId)\n        => blockEditorSelectorLazy.Value\n            .GetEditor(ctxService.BlockRequired())\n            .SetAppId(appId);\n\n    public IEnumerable<TemplateUiInfo> Templates()\n    {\n        var block = ctxService.BlockRequired();\n        return block?.AppOrNull == null\n            ? []\n            : workBlockViews.New(appWorkCtxService.ContextPlus(block.Context.AppReaderRequired))\n                .GetCompatibleViews(block);\n    }\n\n    public IEnumerable<ContentTypeUiInfo> ContentTypes()\n    {\n        var block = ctxService.BlockRequired();\n        return block?.AppOrNull == null\n            ? []\n            : workViews.New(appWorkCtxService.ContextPlus(block.Context.AppReaderRequired))\n                .GetContentTypesWithStatus(block.App.Path ?? \"\", block.App.PathShared ?? \"\");\n    }\n\n    public Guid? SaveTemplateId(int templateId, bool forceCreateContentGroup)\n    {\n        var l = Log.Fn<Guid?>($\"{templateId}, {forceCreateContentGroup}\");\n        var block = ctxService.BlockRequired();\n        multiPermissionsApp.ThrowIfNotAllowedInApp(block.Context, GrantSets.WriteSomething);\n        var result = blockEditorSelectorLazy.Value.GetEditor(block)\n            .SaveTemplateId(templateId, forceCreateContentGroup);\n        return l.ReturnAsOk(result);\n    }\n\n    public bool Publish(int id)\n    {\n        var l = Log.Fn<bool>($\"{id}\");\n        var block = ctxService.BlockRequired();\n        ApiForBlockHelpers.ThrowIfNotAllowedInApp(multiPermissionsApp, block.Context, GrantSets.WritePublished);\n        workPublish.New(appWorkCtxService.Context(block.Context.AppReaderRequired)).Publish(id);\n        return l.ReturnTrue(\"ok\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SaveHelpers/ContentGroupList.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.BlockEditor;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Blocks.Sys.Work;\nusing ToSic.Sys.Utils;\nusing static System.StringComparison;\n\nnamespace ToSic.Sxc.Backend.SaveHelpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ContentGroupList(\n    GenWorkPlus<WorkBlocks> blocks,\n    LazySvc<BlockEditorSelector> blockEditorSelectorLazy,\n    GenWorkDb<WorkFieldList> workFieldList)\n    : ServiceBase(\"Api.GrpPrc\", connect: [blocks, workFieldList, blockEditorSelectorLazy])\n{\n    #region Constructor / DI\n\n    public ContentGroupList Init(IAppIdentity appIdentity)\n    {\n        _appIdentity = appIdentity;\n        AppCtx = blocks.CtxSvc.Context(appIdentity);\n        return this;\n    }\n\n    private IAppIdentity _appIdentity = null!;\n    private IAppWorkCtx AppCtx { get; set; } = null!;\n    #endregion\n\n    internal bool IfChangesAffectListUpdateIt(IBlock? block, List<BundleWithHeader<IEntity>> items, Dictionary<Guid, int> ids)\n    {\n        var l = Log.Fn<bool>();\n        var groupItems = items\n            .Where(i => i.Header.Parent != null)\n            .GroupBy(i => i.Header.Parent!.Value.ToString() + i.Header.IndexSafeOrFallback() + i.Header.AddSafe)\n            .ToList();\n\n        // if it's new, it has to be added to a group\n        // only add if the header wants it, AND we started with ID unknown\n        return groupItems.Any()\n            ? l.Return(PostSaveUpdateIdsInParent(block, ids, groupItems), \"post save ids\")\n            : l.Return(true, \"no additional group processing necessary\");\n    }\n\n    private bool PostSaveUpdateIdsInParent(IBlock? block, Dictionary<Guid, int> postSaveIds, IEnumerable<IGrouping<string, BundleWithHeader<IEntity>>> pairsOrSingleItems)\n    {\n        var l = Log.Fn<bool>($\"{_appIdentity.AppId}\");\n\n        // If no content block given, skip all this\n        if (block == null)\n            return l.ReturnTrue(\"no block, nothing to update\");\n\n\n        foreach (var bundle in pairsOrSingleItems)\n        {\n            l.A(\"processing:\" + bundle.Key);\n\n            if (bundle.First().Header.Parent == null)\n                continue;\n\n            var parent = AppCtx.AppReader.GetDraftOrPublished(bundle.First().Header.GetParentEntityOrError())!;\n            var targetIsContentBlock = parent.Type.Name == WorkBlocks.BlockTypeName;\n                \n            var primaryItem = targetIsContentBlock\n                ? FindContentItem(bundle)\n                : bundle.First();\n            var primaryId = GetIdFromGuidOrError(postSaveIds, primaryItem.Entity.EntityGuid);\n\n            var ids = targetIsContentBlock\n                ? [primaryId, FindPresentationItem(postSaveIds, bundle)]\n                : new[] {primaryId as int?};\n\n            var index = primaryItem.Header.IndexSafeOrFallback();\n            // fix https://github.com/2sic/2sxc/issues/2846 - Bug: Adding an item to a list doesn't seem to respect the position\n            // This is used on new content item (+)\n            var indexNullAddToEnd = primaryItem.Header.Index == null;\n            var willAdd = primaryItem.Header.AddSafe;\n\n            l.A($\"will add: {willAdd}; Group.Add:{primaryItem.Header.Add}; EntityId:{primaryItem.Entity.EntityId}\");\n\n            var fieldPair = targetIsContentBlock\n                ? ViewParts.PickFieldPair(primaryItem.Header.Field!)\n                : [primaryItem.Header.Field!];\n\n            var fieldList = workFieldList.New(AppCtx.AppReader);\n            if (willAdd) // this cannot be auto-detected, it must be specified\n            {\n\n                // handle edge case on app with empty list, when index=1, but it should be index=0 (indexNullAddToEnd=true have the same effect)\n                // fix https://github.com/2sic/2sxc/issues/2943 \n                if (!parent.Children(fieldPair.First()).Any() && !targetIsContentBlock)\n                    indexNullAddToEnd = true;\n                    \n                fieldList.FieldListAdd(parent, fieldPair, index, ids, block.Context.Publishing.ForceDraft, indexNullAddToEnd, targetIsContentBlock);\n            }\n            else\n                fieldList.FieldListReplaceIfModified(parent, fieldPair, index, ids, block.Context.Publishing.ForceDraft);\n\n        }\n\n        // update-module-title\n        blockEditorSelectorLazy.Value.GetEditor(block).UpdateTitle();\n        return l.ReturnTrue(\"ok\");\n    }\n\n    private static BundleWithHeader<T> FindContentItem<T>(IGrouping<string, BundleWithHeader<T>> bundle)\n    {\n        var primaryItem =\n            bundle.FirstOrDefault(e => e.Header.Field.EqualsInsensitive(ViewParts.Content))\n            ?? bundle.FirstOrDefault(e => e.Header.Field.EqualsInsensitive(ViewParts.FieldHeader));\n        if (primaryItem == null)\n            throw new(\"unexpected group-entity assignment, cannot figure it out\");\n        return primaryItem;\n    }\n\n    /// <summary>\n    /// Get saved entity (to get its ID)\n    /// </summary>\n    private static int GetIdFromGuidOrError(IReadOnlyDictionary<Guid, int> postSaveIds, Guid guid)\n    {\n        if (!postSaveIds.TryGetValue(guid, out var id))\n            throw new(\"Saved entity not found - not able to update BlockConfiguration\");\n\n        return id;\n    }\n\n    private int? FindPresentationItem(IReadOnlyDictionary<Guid, int> postSaveIds, IGrouping<string, BundleWithHeader<IEntity>> bundle)\n    {\n        var l = Log.Fn<int?>();\n        int? presentationId = null;\n        var presItem =\n            bundle.FirstOrDefault(e => string.Equals(e.Header.Field, ViewParts.Presentation, OrdinalIgnoreCase))\n            ?? bundle.FirstOrDefault(e =>\n                string.Equals(e.Header.Field, ViewParts.ListPresentation, OrdinalIgnoreCase));\n\n        if (presItem == null)\n            return l.ReturnNull(\"no presentation\");\n        // use null if it shouldn't have one\n        if (presItem.Header.IsEmpty)\n            return l.ReturnNull(\"header is empty\");\n\n        if (postSaveIds.TryGetValue(presItem.Entity.EntityGuid, out var id))\n            presentationId = id;\n\n        return l.Return(presentationId, \"found\");\n    }\n\n    internal ContentGroupList ConvertGroup(List<ItemIdentifier> identifiers)\n    {\n        var l = Log.Fn<ContentGroupList>();\n        foreach (var identifier in identifiers.Where(identifier => identifier != null))\n            identifier.IsContentBlockMode = DetectContentBlockMode(identifier);\n        return l.Return(this);\n    }\n\n    internal List<ItemIdentifier> ConvertListIndexToId(List<ItemIdentifier> identifiers)\n    {\n        var l = Log.Fn<List<ItemIdentifier>>();\n        var newItems = new List<ItemIdentifier>();\n        var appBlocks = blocks.New(AppCtx);\n        foreach (var identifier in identifiers)\n        {\n            // Case one, it's a Content-Group - in this case the content-type name comes from View configuration\n            if (identifier.IsContentBlockMode)\n            {\n                if (!identifier.Parent.HasValue) continue;\n\n                //var contentGroup = CmsManager.Read.Blocks.GetBlockConfig(identifier.GetParentEntityOrError());\n                var contentGroup = appBlocks.GetBlockConfig(identifier.GetParentEntityOrError());\n                var contentTypeName = contentGroup.View?.GetTypeStaticName(identifier.Field!) ?? \"\";\n\n                // if there is no content-type for this, then skip it (don't deliver anything)\n                if (contentTypeName == \"\")\n                    continue;\n\n                identifier.ContentTypeName = contentTypeName;\n                ConvertListIndexToEntityIds(identifier, contentGroup);\n                newItems.Add(identifier);\n                continue;\n            }\n\n            // Case #2 it's an entity inside a field of another entity\n            // Added in v11.01\n            if (identifier is { Parent: not null, Field: not null })\n            {\n                // look up type\n                var target = AppCtx.AppReader.List.GetOne(identifier.Parent.Value)!;\n                var field = target.Type[identifier.Field]!;\n                identifier.ContentTypeName = field.EntityFieldItemTypePrimary();\n                newItems.Add(identifier);\n                continue;\n            }\n\n            // Default case - just a normal identifier\n            newItems.Add(identifier);\n        }\n\n        return l.Return(newItems, $\"{newItems.Count}\");\n    }\n\n\n    /// <summary>\n    /// Check if the save will affect a ContentBlock.\n    /// If it's a simple entity-edit or edit of item inside a normal field list, it returns false\n    /// </summary>\n    /// <returns></returns>\n    private bool DetectContentBlockMode(ItemIdentifier identifier)\n    {\n        var l = Log.Fn<bool>();\n        if (!identifier.Parent.HasValue)\n            return l.ReturnFalse(\"no parent\");\n\n        // get the entity and determine if it's a content-block. If yes, that should affect the differences in load/save\n        var entity = AppCtx.AppReader.List.GetOne(identifier.Parent.Value)!;\n        return l.Return(entity.Type.Name == WorkBlocks.BlockTypeName, \"type name should match\");\n    }\n\n\n    private bool ConvertListIndexToEntityIds(ItemIdentifier identifier, BlockConfiguration blockConfiguration)\n    {\n        var l = Log.Fn<bool>();\n        var part = blockConfiguration[identifier.Field!];\n        if (!identifier.AddSafe) // not in add-mode\n        {\n            var idx = identifier.IndexSafeOrFallback(part.Count - 1);\n            if (idx >= 0 && part.Count > idx && // has as many items as desired\n                part[idx] != null) // and the slot has something\n                identifier.EntityId = part[idx].EntityId;\n        }\n\n        // tell the UI that it should not actually use this data yet, keep it locked\n        if (!identifier.Field!.ToLowerInvariant().Contains(ViewParts.PresentationLower))\n            return l.ReturnFalse(\"no presentation\");\n\n        // the following steps are only for presentation items\n        identifier.IsEmptyAllowed = true;\n\n        if (identifier.EntityId != 0)\n            return l.ReturnFalse(\"id != 0\");\n\n        identifier.IsEmpty = true;\n\n        identifier.DuplicateEntity = identifier.Field.ToLowerInvariant() == ViewParts.PresentationLower\n            ? blockConfiguration.View!.PresentationItem?.EntityId\n            : blockConfiguration.View!.HeaderPresentationItem?.EntityId;\n\n        return l.ReturnTrue(\"ok\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SaveHelpers/DataValidatorContentTypeDataStore.cs",
    "content": "﻿using System.Net;\nusing ToSic.Eav.Data.ContentTypes;\nusing ToSic.Eav.Data.Processing;\nusing ToSic.Eav.Metadata;\nusing ToSic.Eav.Models;\nusing ToSic.Sys.Utils.Assemblies;\nusing static ToSic.Eav.WebApi.Sys.Helpers.Validation.ValidatorBase;\n\nnamespace ToSic.Sxc.Backend.SaveHelpers;\n\n[PrivateApi]\npublic class DataValidatorContentTypeDataStore(IServiceProvider sp) : ServiceBase(\"Val.DtStor\")\n{\n\n    /// <summary>\n    /// Check if entity was able to deserialize, and if it has attributes.\n    /// In rare cases, no-attributes are allowed, but this requires metadata decorators to allow it.\n    /// </summary>\n    /// <param name=\"index\"></param>\n    /// <param name=\"ent\"></param>\n    /// <returns></returns>\n    internal async Task<Result> PreEdit(int index, IEntity ent) =>\n        await Shared(index, ent, DataProcessingEvents.PreEdit);\n\n    /// <summary>\n    /// Check if entity was able to deserialize, and if it has attributes.\n    /// In rare cases, no-attributes are allowed, but this requires metadata decorators to allow it.\n    /// </summary>\n    /// <param name=\"index\"></param>\n    /// <param name=\"ent\"></param>\n    /// <returns></returns>\n    internal async Task<Result> PreSave(int index, IEntity ent)\n    {\n        var l = Log.Fn<Result>();\n\n        // Check if Save is disabled because of content-type metadata (new v21)\n        // This should prevent entities from being put in the DB, where the UI was only meant for some other configuration\n        var sharedWork = await Shared(index, ent, DataProcessingEvents.PreSave);\n\n        // Preprocessor exists, and supports pre-saving, so execute it\n        if (sharedWork.Exception != null)\n            return l.Return(sharedWork, \"error from shared\");\n\n        // If we have a decorator, check if it forbids saving.\n        // For example for Debug-Settings which should never hit the backend\n        if (sharedWork.Decorator?.SaveIsDisabled == true)\n            return l.Return(new(sharedWork.Entity, sharedWork.Decorator, BuildExceptionIfHasIssues($\"Save is disabled for content-type {ent.Type.Name} (index: {index})\", l)), \"save disabled!\");\n\n        return l.Return(sharedWork);\n\n    }\n\n    /// <summary>\n    /// Shared code\n    /// </summary>\n    /// <param name=\"index\"></param>\n    /// <param name=\"ent\"></param>\n    /// <param name=\"action\"></param>\n    /// <returns></returns>\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n    private async Task<Result> Shared(int index, IEntity ent, string action)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n    {\n        var l = Log.Fn<Result>($\"action: {action}\");\n\n        // Check if Save is disabled because of content-type metadata (new v21)\n        // This should prevent entities from being put in the DB, where the UI was only meant for some other configuration\n        var ct = ent.Type;\n        var decorator = ct.GetMetadataModel<DataStorageDecorator>();\n\n        if (decorator == null)\n            return l.Return(new (ent, decorator), \"no decorator\");\n\n        if (string.IsNullOrEmpty(decorator.DataProcessingHandler))\n            return l.Return(new (ent, decorator), \"no data processing handler\");\n\n\n        // generate an object of the specified type name\n        var dataProcessingType = AssemblyHandling.GetTypeOrNull(decorator.DataProcessingHandler);\n\n        if (dataProcessingType == null)\n            return l.Return(AsError(\"not found\"), \"data type results in null\");\n\n        // Check if the type is ok, before instantiating it, to avoid security issues with instantiating random types.\n        // It must be a data processor, otherwise it is not valid for this purpose.\n        if (!typeof(IDataProcessor).IsAssignableFrom(dataProcessingType))\n            return l.Return(AsError(\"is not a valid data processor\"), $\"not assignable from {nameof(IDataProcessor)}\");\n\n        // Re-verify it's a dataProcessor and not null\n        var probablyProcessor = sp.GetService(dataProcessingType);\n        if (probablyProcessor is not IDataProcessor dataProcessor)\n            return l.Return(AsError(\"could not be instantiated\"), \"Instantiated type null or wrong type\");\n\n        // Preprocessor exists, and supports pre-save and post-save, so execute it\n        var result = await dataProcessor.Process(action, new() { Data = ent });\n        var exception = HttpExceptionAbstraction.FromPossibleException(result.Exceptions.FirstOrDefault(), HttpStatusCode.Forbidden);\n        return l.Return(new(result.Data, decorator, exception, dataProcessor), $\"action: {action}, {(exception != null ? \"with exception\" : \"\")}\");\n\n\n        Result AsError(string msg) =>\n            new(ent, decorator, BuildExceptionIfHasIssues(\n                $\"Data processing handler '{decorator.DataProcessingHandler}' {msg} for content-type {ct.Name} (id: {ct.Id})\", l));\n    }\n\n    public record Result(\n        IEntity? Entity,\n        DataStorageDecorator? Decorator,\n        HttpExceptionAbstraction? Exception = null,\n        IDataProcessor? Processor = null\n    );\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SaveHelpers/SaveDataPackageValidator.cs",
    "content": "﻿using ToSic.Eav.ImportExport.Json.V1;\nusing ToSic.Eav.WebApi.Sys.Helpers.Validation;\n\nnamespace ToSic.Sxc.Backend.SaveHelpers;\n\n/// <summary>\n/// Check for any major discrepancies in the edit-save package,\n/// especially missing headers or inconsistent group assignments.\n/// </summary>\n/// <param name=\"parentLog\"></param>\ninternal class SaveDataPackageValidator(ILog parentLog) : ValidatorBase(parentLog, \"Val.PackOk\")\n{\n    /// <summary>\n    /// The package format for loading and saving are the same, but we want to make sure\n    /// that the save package doesn't contain unexpected trash (which would indicate the UI was broken)\n    /// or that invalid combinations get back here\n    /// </summary>\n    /// <returns></returns>\n    internal HttpExceptionAbstraction? ContainsOnlyExpectedNodes(EditSaveDto package)\n    {\n        var l = Log.Fn<HttpExceptionAbstraction?>();\n\n        // check that items are mostly intact\n        if (package.Items == null! || package.Items.Count == 0)\n            Add(\"package didn't contain items, unexpected!\");\n        else\n        {\n            // do various validity tests on items\n            VerifyAllGroupAssignmentsValid(package.Items);\n            ValidateEachItemInBundle(package.Items);\n        }\n\n        var preparedException = BuildExceptionIfHasIssues(Errors, l, \"ContainsOnlyExpectedNodes() done\");\n        return l.Return(preparedException);\n    }\n\n    /// <summary>\n    /// Do various validity checks on each item\n    /// </summary>\n    private void ValidateEachItemInBundle(IList<BundleWithHeader<JsonEntity>> list)\n    {\n        var l = Log.Fn($\"{list.Count}\");\n        foreach (var item in list)\n        {\n            if (item.Header == null! /* paranoid */ || item.Entity == null!)\n                Add($\"item {list.IndexOf(item)} header or entity is missing\");\n            else if (item.Header.Guid != item.Entity.Guid) // check this first (because .Group may not exist)\n            {\n                if (!item.Header.IsContentBlockMode)\n                    Add($\"item {list.IndexOf(item)} has guid mismatch on header/entity, and doesn't have a group\");\n                else if (!item.Header.IsEmpty)\n                    Add($\"item {list.IndexOf(item)} header / entity guid miss match\");\n                // otherwise we're fine\n            }\n        }\n        l.Done();\n    }\n\n    /// <summary>\n    /// ensure all want to save to the same assignment type - either all in group or none!\n    /// </summary>\n    private void VerifyAllGroupAssignmentsValid(IReadOnlyCollection<BundleWithHeader<JsonEntity>> list)\n    {\n        var l = Log.Fn($\"{list.Count}\");\n        var groupAssignments = list\n            .Select(i => i.Header.ContentBlockAppId)\n            .Where(g => g != null)\n            .ToList();\n        if (groupAssignments.Count == 0)\n        {\n            l.Done(\"none of the items is part of a list/group\");\n            return;\n        }\n\n        if (groupAssignments.Count != list.Count)\n            Add($\"Items in package with group: {groupAssignments} \" +\n                $\"- should be 0 or {list.Count} (items in list) \" +\n                \"- must stop, never expect items to come from different sources\");\n        else\n        {\n            var firstInnerContentAppId = groupAssignments.First();\n            if (list.Any(i => i.Header.ContentBlockAppId != firstInnerContentAppId))\n                Add(\"not all items have the same Group.ContentBlockAppId - this is required when using groups\");\n        }\n\n        l.Done(\"done\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SaveHelpers/SaveDataUpdateValidator.cs",
    "content": "﻿using ToSic.Eav.WebApi.Sys.Helpers.Validation;\n\nnamespace ToSic.Sxc.Backend.SaveHelpers;\n\n/// <summary>\n/// Perform special validation checks on update, such as ensuring that we're updating the correct target item etc.\n/// </summary>\n/// <param name=\"parentLog\"></param>\ninternal class SaveDataUpdateValidator(ILog parentLog) : ValidatorBase(parentLog, \"Val.UpdOk\")\n{\n    internal (int? ResetId, HttpExceptionAbstraction? Exception) IfUpdateValidateAndCorrectIds(WorkEntities workEntities, int count, IEntity newEntity)\n    {\n        var l = Log.Fn<(int?, HttpExceptionAbstraction?)>();\n        var previousEntity = workEntities.Get(newEntity.EntityId)\n                             ?? workEntities.Get(newEntity.EntityGuid);\n\n        int? resetId = default;\n        if (previousEntity == null)\n            return l.Return((null, null), \"no previous entity found\");\n\n\n        l.A(\"found previous entity, will check types/ids/attributes\");\n        CompareTypes(count, previousEntity, newEntity);\n\n        // for saving, ensure we are using the DB entity-ID \n        if (newEntity.EntityId == 0)\n        {\n            l.A(\"found existing entity - will set the ID to that to overwrite\");\n            resetId = previousEntity.EntityId;\n        }\n\n        CompareIdentities(count, previousEntity, newEntity);\n        CompareAttributes(count, previousEntity, newEntity);\n\n        var exception = BuildExceptionIfHasIssues(Errors, l, \"EntityIsOk() done\");\n\n        return l.Return((resetId, exception), \"ok\");\n    }\n\n\n    private void CompareTypes(int count, IEntity originalEntity, IEntity newEntity)\n    {\n        var l = Log.Fn($\"ids:{newEntity.Type.NameId}/{originalEntity.Type.NameId}\");\n        if (originalEntity.Type.NameId != newEntity.Type.NameId)\n            Add($\"entity type mismatch on {count}\");\n        l.Done();\n    }\n\n    private void CompareIdentities(int count, IEntity originalEntity, IEntity newEntity)\n    {\n        var l = Log.Fn($\"ids:{newEntity.EntityId}/{originalEntity.EntityId}\");\n        if (originalEntity.EntityId != newEntity.EntityId)\n            Add($\"entity ID mismatch on {count} - {newEntity.EntityId}/{originalEntity.EntityId}\");\n\n        l.A($\"Guids:{newEntity.EntityGuid}/{originalEntity.EntityGuid}\");\n        if (originalEntity.EntityGuid != newEntity.EntityGuid)\n            Add($\"entity GUID mismatch on {count} - {newEntity.EntityGuid}/{originalEntity.EntityGuid}\");\n        l.Done();\n    }\n\n    private void CompareAttributes(int count, IEntity original, IEntity ent)\n    {\n        var l = Log.Fn();\n        if (original.Attributes.Count != ent.Attributes.Count)\n            Add($\"entity {count} has different amount \" +\n                $\"of attributes {ent.Attributes.Count} \" +\n                $\"than the original {original.Attributes.Count}\");\n        else\n            foreach (var origAttr in original.Attributes)\n            {\n                var newAttr = ent.Attributes.FirstOrDefault(a => a.Key == origAttr.Key);\n                if (newAttr.Equals(default(KeyValuePair<string, IAttribute>)))\n                    Add($\"attribute {origAttr.Key} not found in save\");\n                else if (origAttr.Value.Type != newAttr.Value.Type)\n                    Add($\"found different type on attribute {origAttr.Key} \" +\n                        $\"- '{origAttr.Value.Type}'/'{newAttr.Value.Type}'\");\n            }\n\n        l.Done();\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SaveHelpers/SaveDataValidator.cs",
    "content": "﻿using ToSic.Eav.Metadata.Sys;\nusing ToSic.Eav.WebApi.Sys.Helpers.Validation;\n\nnamespace ToSic.Sxc.Backend.SaveHelpers;\n\ninternal class SaveDataValidator(ILog parentLog) : ValidatorBase(parentLog, \"Val.EntOk\")\n{\n    /// <summary>\n    /// Check if entity was able to deserialize, and if it has attributes.\n    /// In rare cases, no-attributes are allowed, but this requires metadata decorators to allow it.\n    /// </summary>\n    /// <param name=\"index\"></param>\n    /// <param name=\"newEntity\"></param>\n    /// <returns></returns>\n    internal HttpExceptionAbstraction? EntityNotNullAndAttributeCountOk(int index, IEntity? newEntity)\n    {\n        var l = Log.Fn<HttpExceptionAbstraction?>();\n        if (newEntity == null)\n        {\n            var preparedException = BuildExceptionIfHasIssues($\"entity {index} couldn't deserialize\", l);\n            return l.Return(preparedException, \"newEntity is null\");\n        }\n\n        // New #2595 allow saving empty metadata decorator entities\n        var preparedException2 = (newEntity.Attributes.Count == 0 && !newEntity.Type.Metadata.HasType(KnownDecorators.SaveEmptyDecoratorId))\n            ? BuildExceptionIfHasIssues($\"entity {index} doesn't have attributes (or they are invalid)\", l, \"EntityIsOk() done\")\n            : null;\n\n        return l.Return(preparedException2, \"second test\");\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SaveHelpers/SavePermissionDataHelper.cs",
    "content": "﻿using ToSic.Eav.Data.Sys.Entities;\n\nnamespace ToSic.Sxc.Backend.SaveHelpers;\n\n/// <summary>\n/// Extension Methods to Init with slightly different parameters\n/// </summary>\ninternal class SavePermissionDataHelper(ILog parentLog): HelperBase(parentLog, \"Sav.TypExt\")\n{\n    /// <summary>\n    /// Important: this can only run after init, because AppState isn't available before\n    /// </summary>\n    internal List<string> ExtractTypeNamesFromItems(IAppReader parent, IEnumerable<ItemIdentifier> items)\n    {\n        var l = Log.Fn<List<string>>();\n        var allData = parent.List;\n\n        l.A($\"items in full list: {allData.Count}\");\n\n        // build list of type names\n        var typeNames = items\n            .Select(item =>\n            {\n                var itemTypeName = item.ContentTypeName;\n                var useItemTypeName = !string.IsNullOrEmpty(itemTypeName) || item.EntityId == 0;\n                l.A($\"item: {item.EntityId}, useItemTypeName: {useItemTypeName}, itemTypeName: {itemTypeName}\");\n\n                if (useItemTypeName)\n                    return itemTypeName!;\n\n                var entityFromRepo = allData.FindRepoId(item.EntityId)!;\n                //if (entityFromRepo == null)\n                //{\n                //    l.A($\"Entity not found in repo: {item.EntityId}\");\n\n                //    var entityFromId = allData.One(item.EntityId);\n\n                //    if (entityFromId == null)\n                //    {\n                //        l.A($\"Entity not found in data: {item.EntityId}\");\n                //    }\n\n                //    throw new ArgumentException($\"Can't find this entity so can't find the content-type name\");\n                //}\n                return entityFromRepo.Type.NameId;\n            })\n            .ToList();\n\n        return l.Return(typeNames, l.Try(() => string.Join(\",\", typeNames)));\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SaveHelpers/SaveSecurityCheck.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Eav.WebApi.Sys.Security;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Backend.SaveHelpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SaveSecurity(Generator<MultiPermissionsTypes, MultiPermissionsTypes.Options> multiPermissionsTypesGen)\n    : ServiceBase(\"Api.SavSec\", connect: [multiPermissionsTypesGen])\n{\n\n    public IMultiPermissionCheck DoPreSaveSecurityCheck(IContextOfApp context, IEnumerable<BundleWithHeader> items)\n    {\n        var list = items.ToListOpt();\n        var l = Log.Fn<IMultiPermissionCheck>($\"{list.Count} items\");\n\n        var appReader = context.AppReaderRequired;\n        var permCheck = multiPermissionsTypesGen.New(new()\n        {\n            SiteContext = context,\n            App = appReader,\n            ContentTypes = new SavePermissionDataHelper(Log).ExtractTypeNamesFromItems(\n                appReader,\n                list.Select(i => i.Header).ToList()\n            )\n        });\n        \n        if (!permCheck.EnsureAll(GrantSets.WriteSomething, out var error))\n            throw HttpException.PermissionDenied(error);\n        \n        if (!permCheck.UserCanWriteAndPublicFormsEnabled(out _, out error))\n            throw HttpException.PermissionDenied(error);\n\n        return l.Return(permCheck, \"passed security checks\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SaveHelpers/SxcPagePublishing.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Cms.Publishing.Sys;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Backend.SaveHelpers;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcPagePublishing(ContentGroupList contentGroupList, IPagePublishing pagePublishing, IAppsCatalog appsCatalog)\n    : ServiceBase(\"Sxc.PgPubl\", connect: [contentGroupList, pagePublishing, appsCatalog])\n{\n\n    internal Dictionary<Guid, int> SaveInPagePublishing(\n        IContextOfApp context,\n        IBlock? blockOrNull,\n        int appId,\n        List<BundleWithHeader<IEntity>> items,\n        bool partOfPage,\n        Func<bool, Dictionary<Guid, int>> internalSaveMethod,\n        IMultiPermissionCheck permCheck\n    )\n    {\n        var l = Log.Fn<Dictionary<Guid, int>>();\n        var allowWriteLive = permCheck.UserMayOnAll(GrantSets.WritePublished);\n        var forceDraft = !allowWriteLive;\n        l.A($\"allowWrite: {allowWriteLive} forceDraft: {forceDraft}\");\n\n        // list of saved IDs\n        Dictionary<Guid, int>? postSaveIds = null;\n\n        // The internal call which will be used further down\n        var appIdentity = appsCatalog.AppIdentity(appId);\n        var groupList = contentGroupList.Init(appIdentity);\n\n\n        // use dnn versioning if partOfPage\n        if (partOfPage)\n        {\n            l.A(\"partOfPage - save with publishing\");\n            pagePublishing.DoInsidePublishing(context, _ => postSaveIds = SaveAndSaveGroupsInnerCall(internalSaveMethod, forceDraft));\n        }\n        else\n        {\n            l.A(\"partOfPage false, save without publishing\");\n            postSaveIds = SaveAndSaveGroupsInnerCall(internalSaveMethod, forceDraft);\n        }\n\n        var logIds = l.Try(() => string.Join(\",\", postSaveIds!.Select(psi => $\"{psi.Key}({psi.Value})\")));\n        return l.Return(postSaveIds!, $\"post save IDs: {logIds}\");\n\n        Dictionary<Guid, int> SaveAndSaveGroupsInnerCall(Func<bool, Dictionary<Guid, int>> call, bool forceSaveAsDraft)\n        {\n            var ids = call.Invoke(forceSaveAsDraft);\n            // now assign all content-groups as needed\n            groupList.IfChangesAffectListUpdateIt(blockOrNull, items, ids);\n            return ids;\n        }\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/SxcWebApiConstants.cs",
    "content": "﻿namespace ToSic.Sxc.Backend;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SxcWebApiConstants\n{\n    //public const string HeaderInstanceId = \"moduleid\";\n    public const string HeaderContentBlockId = \"ContentBlockId\";\n\n    public const string HeaderContentBlockList = \"BlockIds\";\n\n    // QueryStringKeys\n    //public const string PageId = \"pageid\";\n    //public const string ModuleId = \"moduleid\";\n\n    /// <summary>\n    /// Key for the App Folder to add in the middleware, so the Controller can find it's App\n    /// </summary>\n    public const string HttpContextKeyForAppFolder = \"SxcAppFolderName\";\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Sys/Insights/InsightsAppCodeBuild.cs",
    "content": "﻿using ToSic.Eav.Sys.Insights;\nusing ToSic.Razor.Blade;\n\nnamespace ToSic.Sxc.Backend.Sys;\n\ninternal class InsightsAppCodeBuild() : InsightsProvider(new() { Name = Link })\n{\n    public static string Link = \"AppCodeBuild\";\n\n    public override string HtmlBody()\n    {\n        if (AppId == null)\n            return \"please add appid to the url parameters\";\n\n        var msg = \"\";\n        msg += Tags.Nl2Br(\"Some Statistics\\n\"\n                          + \"\\n\"\n                          + \"\\n\"\n        );\n\n        if (Parameters.TryGetValue(\"toggle\", out var strToggle) && strToggle?.ToString() == \"true\")\n        {\n            msg += Tags.Nl2Br(\"Toggle: \" + strToggle);\n        }\n\n        msg += \"Type: \" + Parameters[\"type\"];\n\n\n        msg += Linker.LinkTo(view: Specs.Name, label: \"Run\", appId: AppId.Value, more: \"type=run\");\n\n        return msg;\n\n\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Sys/Insights/InsightsAppCodeOverview.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.State;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.Sys.Insights;\nusing ToSic.Eav.Sys.Insights.HtmlHelpers;\n\nnamespace ToSic.Sxc.Backend.Sys;\n\ninternal class InsightsAppCodeOverview(IAppReaderFactory appReaders, IAppStateCacheService appStates, IAppsCatalog appsCatalog)\n    : InsightsProvider(new() { Name = Link, HelpCategory = FolderConstants.AppCodeFolder }, connect: [appReaders, appStates, appsCatalog])\n{\n    public static string Link => \"AppCodeOverview\";\n\n    public override string HtmlBody()\n    {\n        var msg = \"\";\n        msg += \"<table id='table'>\"\n               + InsightsHtmlTable.HeadFields([\"Zone ↕\", \"App ↕\", \"Name\", \"Is Loaded\", \"Build App Code\"])\n               + \"<tbody>\";\n\n        var zones = appsCatalog.Zones\n            .OrderBy(z => z.Key);\n\n\n        foreach (var zone in zones)\n        {\n            var apps = zone.Value\n                .Apps\n                .Select(a =>\n                {\n                    var appIdentity = new AppIdentity(zone.Value.ZoneId, a.Key);\n                    var inCache = appStates.IsCached(appIdentity);\n                    var appState = inCache ? appReaders.Get(appIdentity) : null;\n                    return new\n                    {\n                        Id = a.Key,\n                        Guid = a.Value,\n                        InCache = inCache,\n                        Name = inCache\n                            ? appState?.Specs.Name ?? \"unknown, app-infos not json\"\n                            : \"not-loaded\",\n                        Reader = appState\n                    };\n                })\n                .OrderBy(a => a.Id);\n\n\n            msg = apps.Aggregate(msg, (current, app)\n                => current\n                   + InsightsHtmlTable.RowFields([\n                       zone.Key.ToString(),\n                       app.Id.ToString(),\n                       app.Name,\n                       app.InCache ? \"yes\" : \"no\",\n                       AppStateExtensions.AppGuidIsAPreset(app.Guid)\n                           ? \"\"\n                           : Linker.LinkTo(view: InsightsAppCodeBuild.Link, label: \"Build\",\n                               appId: app.Id)\n                   ])\n            );\n        }\n        msg += \"</tbody>\"\n               + \"</table>\"\n               + InsightsHtmlParts.JsTableSort();\n        return msg;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Sys/Insights/InsightsLightSpeed.cs",
    "content": "﻿using ToSic.Eav.Apps.Assets.Sys;\nusing ToSic.Eav.Sys.Insights;\nusing ToSic.Eav.Sys.Insights.HtmlHelpers;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sys.Utils;\nusing static ToSic.Razor.Blade.Tag;\n\nnamespace ToSic.Sxc.Backend.Sys;\n\ninternal class InsightsLightSpeed(LightSpeedStats lightSpeedStats, IAppReaderFactory appReader)\n    : InsightsProvider(new() { Name = Link, Teaser = \"Show LightSpeed Caching Statistics\", HelpCategory = \"Performance\" }, connect: [lightSpeedStats, appReader])\n{\n    public static string Link = \"LightSpeedStats\";\n\n    public override string HtmlBody()\n    {\n        var msg = H1(\"LightSpeed Stats\").ToString();\n        try\n        {\n            var countStats = lightSpeedStats.GetStats();\n            //var sizeStats = lightSpeedStats.Size;\n            msg += P($\"Apps in Cache: {countStats.Count}\");\n            msg += \"<table id='table'>\"\n                   + InsightsHtmlTable.HeadFields([\"#\", \"ZoneId\", \"AppId\", \"Name\", \"Items in Cache\", \"Ca. Memory Use\", \"Uncompressed\", \"Compressed\", \"Expanded\", \"Grand-Total\", \"Mem-Saved\", \"NameId\"])\n                   + \"<tbody>\";\n            var count = 0;\n            var totalItems = 0;\n            var totalMemory = 0L;\n            foreach (var cacheItem in countStats)\n            {\n                var appSpecs = (cacheItem.Key != 0)\n                    ? appReader.Get(cacheItem.Key).Specs\n                    : null;\n\n                var stats = cacheItem.Value;\n                msg += InsightsHtmlTable.RowFields([\n                    ++count,\n                    // ZoneId, AppId, Name\n                    SpecialField.Right(appSpecs?.ZoneId ?? 0),\n                    SpecialField.Right(cacheItem.Key),\n                    appSpecs?.Name ?? \"unknown\",\n\n                    // Count, Size, Uncompressed, Compressed\n                    SpecialField.Right(stats.Count),\n                    SpecialField.Right(new SizeInfo(stats.MemoryUse).ToString(\"N\")),\n                    SpecialField.Right(new SizeInfo(stats.Uncompressed).ToString(\"N\")),\n                    SpecialField.Right(new SizeInfo(stats.Compressed).ToString(\"N\")),\n                    SpecialField.Right(new SizeInfo(stats.Expanded).ToString(\"N\")),\n                    SpecialField.Right(new SizeInfo(stats.GrandTotal).ToString(\"N\")),\n                    SpecialField.Right(new SizeInfo(stats.GrandTotal - stats.Compressed).ToString(\"N\")),\n\n                    appSpecs?.NameId ?? \"unknown\"\n                ]);\n                totalItems += stats.Count;\n                totalMemory += stats.MemoryUse;\n            }\n            msg += \"</tbody>\";\n            msg += \"<tfoot>\";\n            msg += InsightsHtmlTable.RowFields([\n                B(\"Total:\"),\n                \"\",\n                \"\",\n                \"\",\n                SpecialField.Right(B($\"{totalItems}\")),\n                SpecialField.Right(B(ByteToKByte(totalMemory))),\n                \"\"\n            ]);\n\n            msg += \"</tfoot>\";\n            msg += \"</table>\";\n            msg += \"\\n\\n\";\n            msg += InsightsHtmlParts.JsTableSort();\n        }\n        catch\n        {\n            // ignored\n        }\n        return msg;\n    }\n\n    private string ByteToKByte(long bytes)\n    {\n        const int kb = 1024;\n        if (bytes < kb) return bytes + \" b\";\n\n        const int mb = kb * kb;\n        if (bytes < 10 * mb)\n            return ((double)bytes / kb).ToAposString() + \" kb\";\n\n        return ((double)bytes / mb).ToAposString() + \" mb\";\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Sys/InstallControllerReal.cs",
    "content": "﻿using System.Text;\nusing ToSic.Eav.Apps.Sys.AppStack;\nusing ToSic.Eav.Data.Sys.PropertyLookup;\nusing ToSic.Eav.Data.Sys.PropertyStack;\nusing ToSic.Eav.Models;\nusing ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Eav.WebApi.Sys.Install;\nusing ToSic.Sxc.Apps.Sys.Installation;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Context;\nusing ToSic.Sxc.Sys.Integration.Installation;\nusing ToSic.Sys.Capabilities.Features;\nusing IFeaturesService = ToSic.Sxc.Services.IFeaturesService;\nusing Services_ServiceBase = ToSic.Sys.Services.ServiceBase;\n\nnamespace ToSic.Sxc.Backend.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class InstallControllerReal(\n    LazySvc<IContextOfSite> context,\n    LazySvc<IEnvironmentInstaller> envInstallerLazy,\n    LazySvc<IPlatformAppInstaller> platformAppInstaller,\n    LazySvc<ImportFromRemote> impFromRemoteLazy,\n    IResponseMaker responseMaker,\n    LazySvc<IFeaturesService> featureService,\n    LazySvc<AppsBackend> appsBackend,\n    LazySvc<AppDataStackService> appSettingsStack)\n    : Services_ServiceBase($\"{EavLogs.WebApi}.{LogSuffix}Rl\",\n        connect:\n        [\n            context, envInstallerLazy, platformAppInstaller, impFromRemoteLazy, responseMaker, featureService,\n            appSettingsStack, appsBackend\n        ])\n{\n    public const string LogSuffix = \"Install\";\n\n    #region System Installation\n\n    /// <summary>\n    /// Finish system installation which had somehow been interrupted\n    /// </summary>\n    /// <returns></returns>\n    public bool Resume() => envInstallerLazy.Value.ResumeAbortedUpgrade();\n\n    #endregion\n\n    #region App / Content Package Installation\n\n    public InstallAppsDto InstallSettings(bool isContentApp, IModule module)\n    {\n        // Get Remote Install URL\n        var site = context.Value.Site;\n        var url = platformAppInstaller.Value\n            .GetAutoInstallPackagesUiUrl(site, module, isContentApp);\n\n        // Get list of already installed Apps\n        var appsOfThisSite = appsBackend.Value.Apps()\n            .Select(a => new AppDtoLight\n            {\n                name = a.Name,\n                guid = a.Guid,\n                version = a.Version,\n            })\n            .ToListOpt();\n\n        // Get list of allow/forbid rules for the App installer\n        var settingsSources = appSettingsStack.Value\n            .InitForPrimaryAppOfZone(site.ZoneId)\n            .GetStack(AppStackConstants.Settings);\n        var stack = new PropertyStack().Init(AppStackConstants.RootNameSettings, settingsSources);\n\n        var rules = stack.InternalGetPath(new PropReqSpecs(\"SiteSetup.AutoInstallApps\", PropReqSpecs.EmptyDimensions, true, Log), new());\n        var ruleEntities = rules.Result as IEnumerable<IEntity>;    // note: Result is null if nothing found...\n        var rulesFinal = ruleEntities?\n            .Select(e => e.ToModel<SiteSetupAutoInstallAppsRule>(skipTypeCheck: true)!.GetRuleDto())\n            .ToListOpt();\n\n        if (!featureService.Value.IsEnabled(BuiltInFeatures.AppAutoInstallerConfigurable.NameId))\n        {\n            Log.A(\"will not add installer rules as the feature is not enabled\");\n            rulesFinal = [];\n        }\n\n        return new()\n        {\n            remoteUrl = url,\n            installedApps = appsOfThisSite,\n            rules = rulesFinal,\n        };\n    }\n\n    /// <summary>\n    /// Before this was GET Installer/InstallPackage\n    /// </summary>\n    /// <param name=\"packageUrl\"></param>\n    /// <param name=\"container\"></param>\n    /// <param name=\"newName\"></param>\n    /// <returns></returns>\n    public THttpResponseType RemotePackage(string packageUrl, IModule container, string? newName = null)\n    {\n        var l = Log.Fn<THttpResponseType>();\n\n        var isApp = !container.IsContent;\n\n        Log.A($\"install package:'{packageUrl}', {nameof(newName)}:'{newName}'\");\n\n        var block = container.BlockIdentifier;\n        var (success, messages) = impFromRemoteLazy.Value\n            .InstallPackage(block.ZoneId, block.AppId, isApp, packageUrl, newName);\n\n        Log.A($\"install completed with success:{success}\");\n\n        return success \n            ? l.ReturnAsOk(responseMaker.Ok()) \n            : l.Return(responseMaker.InternalServerError(MessageBuilder(messages)), \"error\");\n    }\n\n    private static string MessageBuilder(List<Message> messages)\n    {\n        var err = new StringBuilder();\n        foreach (var m in messages) err.AppendFormat(\"{0}\", m.Text);\n        return err.ToString();\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Sys/SiteSetupAutoInstallAppsRule.cs",
    "content": "﻿using ToSic.Eav.Models;\nusing ToSic.Eav.WebApi.Sys.Install;\n\nnamespace ToSic.Sxc.Backend.Sys;\n\n[ModelSpecs(ContentType = ContentTypeNameId)]\ninternal record SiteSetupAutoInstallAppsRule : ModelFromEntityBasic\n{\n    public const string ContentTypeNameId = \"833baa25-899b-4242-ade7-323a319bcf71\";\n    public const string ContentTypeName = \"⚙️SiteSetupAutoInstallApps\";\n\n    public const string TargetGuid = \"guid\";\n    public const string TargetAll = \"all\";\n    public const string TargetUrl = \"url\";\n    public const string ModeForbidden = \"f\";\n    public const string ModeAllow = \"a\";\n    public const string ModeOptional = \"o\";\n    public const string ModeRequired = \"r\";\n\n    public string Target => GetThis(TargetGuid);\n\n    public string Mode => GetThis(ModeAllow);\n\n    public string AppGuid => GetThis(\"\");\n\n    public string Url => GetThis(\"\");\n\n    public AppInstallRuleDto GetRuleDto() => new()\n    {\n        name = Title,\n        appGuid = AppGuid,\n        mode = Mode,\n        target = Target,\n        url = Url,\n    };\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Usage/Dto/ContentTypeDto.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Usage.Dto;\n\npublic class ContentTypeDto: IdentifierDto\n{\n    public string Name;\n    public string StaticName;\n\n    public ContentTypeDto(IContentType type)\n    {\n        Id = type.Id;\n        Name = type.Name;\n        StaticName = type.NameId;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Usage/Dto/EntityDto.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Usage.Dto;\n\npublic class EntityDto: IdentifierDto\n{\n    public string? Title;\n    public ContentTypeDto Type;\n\n    public EntityDto(IEntity entity)\n    {\n        Id = entity.EntityId;\n        Guid = entity.EntityGuid;\n        Title = entity.GetBestTitle();\n        Type = new(entity.Type);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Usage/Dto/EntityInRelationDto.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Usage.Dto;\n\nclass EntityInRelationDto(IEntity entity, string relationship, string key) : EntityDto(entity)\n{\n    public string Relationship = relationship;\n    public string Key = key;\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Usage/EntityBackend.cs",
    "content": "﻿// 2026-02-26 2dm - seems to be a partial implementation of relationships - never implemented, moving to SysData\n\n//using ToSic.Eav.Apps.Sys.Permissions;\n//using ToSic.Sys.Security.Permissions;\n\n//namespace ToSic.Sxc.Backend.Usage;\n\n//[ShowApiWhenReleased(ShowApiMode.Never)]\n//public class EntityBackend(\n//    ISxcCurrentContextService ctxService,\n//    Generator<MultiPermissionsApp, MultiPermissionsApp.Options> appPermissions)\n//    : ServiceBase(\"Bck.Entity\", connect: [ctxService, appPermissions])\n//{\n//    // New feature in 11.03 - Usage Statistics\n\n//    public object? Usage(int appId, Guid guid)\n//    {\n//        var context = ctxService.GetExistingAppOrSet(appId);\n//        var permCheck = appPermissions.New(new(context, context.AppReaderRequired));\n//        if (!permCheck.EnsureAll(GrantSets.ReadSomething, out var error))\n//            throw HttpException.PermissionDenied(error);\n\n//        var item = context.AppReaderRequired.List.GetOne(guid);\n//        // Note: this isn't proper yet, it's all relationships in the app, not just of this entity\n//        //var relationships = item.Relationships.AllRelationships;\n\n//        // var result = relationships.Select(r => new EntityInRelationDto(r.))\n//        // todo: don't forget Metadata relationships\n//        return null;\n//    }\n\n//}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Usage/UsageBackend.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Permissions;\nusing ToSic.Sxc.Blocks.Sys;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sxc.Blocks.Sys.Work;\nusing ToSic.Sys.Security.Permissions;\n\nnamespace ToSic.Sxc.Backend.Usage;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class UsageBackend(\n    GenWorkPlus<WorkBlocks> appBlocks,\n    GenWorkPlus<WorkViews> workViews,\n    Generator<MultiPermissionsApp, MultiPermissionsApp.Options> appPermissions,\n    ISxcCurrentContextService ctxService)\n    : ServiceBase(\"Bck.Usage\", connect: [appPermissions, ctxService, workViews, appBlocks])\n{\n    public IEnumerable<ViewDto> ViewUsage(int appId, Guid guid, Func<ICollection<IView>, ICollection<BlockConfiguration>, IEnumerable<ViewDto>> finalBuilder)\n    {\n        var l = Log.Fn<IEnumerable<ViewDto>>($\"{appId}, {guid}\");\n        var context = ctxService.GetExistingAppOrSet(appId);\n\n        // extra security to only allow zone change if host user\n        var permCheck = appPermissions.New(new() { SiteContext = context, App = context.AppReaderRequired });\n        if (!permCheck.EnsureAll(GrantSets.ReadSomething, out var error))\n            throw HttpException.PermissionDenied(error);\n\n        var appWorkCtxPlus = appBlocks.CtxSvc.ContextPlus(appId);\n        var appViews = workViews.New(appWorkCtxPlus);\n        // treat view as a list - in case future code will want to analyze many views together\n        var views = new List<IView> { appViews.Get(guid) };\n\n        var blocks = appBlocks.New(appWorkCtxPlus).AllWithView();\n\n        l.A($\"Found {blocks.Count} content blocks\");\n\n        var result = finalBuilder(views, blocks);\n\n        return l.ReturnAsOk(result);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Views/AppPolymorphism.cs",
    "content": "﻿using ToSic.Eav.DataSource;\nusing ToSic.Eav.DataSource.VisualQuery;\nusing ToSic.Eav.Models;\nusing ToSic.Sxc.Polymorphism.Sys;\n\nnamespace ToSic.Sxc.Backend.Views;\n\n[PrivateApi]\n[VisualQuery(\n    NiceName = \"App Polymorphism Configuration\",\n    NameId = \"a495b51f-44e7-4335-81db-b8a7e33120f0\",\n    NameIds = [\"System.Polymorphism\"], // Internal name for the system, used in some entity-pickers. Can change at any time.\n    Type = DataSourceType.System,\n    Audience = Audience.System,\n    DataConfidentiality = DataConfidentiality.Confidential,\n    UiHint = \"Current Apps Polymorphism\")]\n// ReSharper disable once UnusedMember.Global\npublic class AppPolymorphism : CustomDataSource\n{\n    public AppPolymorphism(Dependencies services, IAppReaderFactory appReaders)\n        : base(services, logName: \"Sxc.PolyMo\", connect: [appReaders])\n    {\n        ProvideOut(() => AppConfig(appReaders));\n    }\n\n\n    private IEnumerable<IEntity> AppConfig(IAppReaderFactory appReaders)\n    {\n        var l = Log.Fn<IEnumerable<IEntity>>($\"App: {AppId}\");\n\n        var poly = appReaders.Get(AppId).List\n            .FirstModel<PolymorphismConfiguration>(nullHandling: ModelNullHandling.PreferModel)!;\n\n        var data = DataFactory\n            .SpawnNew(new() { AutoId = false })\n            .Create(new Dictionary<string, object?>\n            {\n                { nameof(poly.Resolver), poly.Resolver },\n                { \"TypeName\", PolymorphismConfiguration.ContentTypeName },\n            }, id: poly.Id);\n\n        return l.Return([data], $\"{poly}\");\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Views/ViewContentTypeDto.cs",
    "content": "﻿namespace ToSic.Sxc.Backend.Views;\n\npublic class ViewContentTypeDto\n{\n    public required string StaticName { get; set; }\n    public required int Id { get; set; }\n    public required string Name { get; set; }\n    public required int DemoId { get; set; }\n    public required string DemoTitle { get; set; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Views/ViewDetailsDto.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.WebApi.Sys.Security;\n\nnamespace ToSic.Sxc.Backend.Views;\n\npublic class ViewDetailsDto\n{\n    public required int Id { get; init; }\n    public required string Name { get; init; }\n    public required ViewContentTypeDto ContentType { get; init; }\n    public required ViewContentTypeDto PresentationType { get; init; }\n    public required ViewContentTypeDto ListContentType { get; init; }\n    public required ViewContentTypeDto ListPresentationType { get; init; }\n    public required string TemplatePath { get; init; }\n    public required bool IsHidden { get; init; }\n    public required string ViewNameInUrl { get; init; }\n    public required Guid Guid { get; init; }\n    public required bool List { get; init; }\n    public required bool HasQuery { get; init; }\n    public required int Used { get; init; }\n\n    public required bool IsShared { get; init; }\n\n    public required EditInfoDto EditInfo { get; init; }\n\n\n    public required IEnumerable<EavLightEntityReference>? Metadata { get; init; }\n\n    public required HasPermissionsDto Permissions { get; init; }\n\n    [JsonPropertyName(\"lightSpeed\")]\n    public required AppMetadataDto? Lightspeed { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Views/ViewsBackend.cs",
    "content": "﻿using ToSic.Eav.Data.Sys;\nusing ToSic.Eav.Data.Sys.ContentTypes;\nusing ToSic.Eav.DataFormats.EavLight;\nusing ToSic.Eav.Models;\nusing ToSic.Eav.Serialization.Sys.Options;\nusing ToSic.Sxc.Backend.ImportExport;\nusing ToSic.Sxc.Web.Sys.LightSpeed;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Views;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ViewsBackend(\n    GenWorkBasic<WorkViewsMod> workViewsMod,\n    GenWorkPlus<WorkViews> workViews,\n    IContextOfSite context,\n    LazySvc<IConvertToEavLight> convertToEavLight,\n    Generator<ImpExpHelpers> impExpHelpers)\n    : ServiceBase(\"Bck.Views\", connect: [workViewsMod, convertToEavLight, impExpHelpers, workViews, context])\n{\n    public IEnumerable<ViewDetailsDto> GetAll(int appId)\n    {\n        var l = Log.Fn<IEnumerable<ViewDetailsDto>>($\"get all a#{appId}\");\n\n        var appViews = workViews.New(appId);\n        var contentTypes = appViews.AppWorkCtx.AppReader.ContentTypes.OfScope(ScopeConstants.Default).ToList();\n\n        var viewList = appViews.GetAll().ToList();\n        Log.A($\"attribute list count:{contentTypes.Count}, template count:{viewList.Count}\");\n        var ser = convertToEavLight.Value as ConvertToEavLight;\n\n        var views = viewList\n            .Select(view =>\n            {\n                var lightspeed = view.Metadata\n                    .FirstModel<LightSpeedDecorator>()\n                    .NullOrGetWith(ls => new AppMetadataDto\n                        {\n                            Id = ls.Id,\n                            Title = ls.Title,\n                            IsEnabled = ls.IsEnabledNullable != false,\n                        });\n\n                return new ViewDetailsDto\n                {\n                    Id = view.Id, Name = view.Name,\n                    ContentType = TypeSpecs(contentTypes, view.ContentType, view.ContentItem),\n                    PresentationType = TypeSpecs(contentTypes, view.PresentationType, view.PresentationItem),\n                    ListContentType = TypeSpecs(contentTypes, view.HeaderType, view.HeaderItem),\n                    ListPresentationType = TypeSpecs(contentTypes, view.HeaderPresentationType, view.HeaderPresentationItem),\n                    TemplatePath = view.Path,\n                    IsHidden = view.IsHidden,\n                    ViewNameInUrl = view.UrlIdentifier,\n                    Guid = view.Guid,\n                    List = view.UseForList,\n                    HasQuery = view.QueryRaw != null,\n                    Used = view.Entity.Parents().Count(),\n                    IsShared = view.IsShared,\n                    EditInfo = new(view.Entity),\n                    Metadata = ser?.SubConverter.CreateListOfSubEntities(view.Metadata, SubEntitySerialization.NeverSerializeChildren()),\n                    Permissions = new() { Count = view.Entity.Metadata.Permissions.Count() },\n                    Lightspeed = lightspeed,\n                };\n            })\n            .ToList();\n        return l.Return(views, $\"{views.Count}\");\n    }\n\n\n    /// <summary>\n    /// Helper to prepare a quick-info about 1 content type\n    /// </summary>\n    /// <param name=\"allCTs\"></param>\n    /// <param name=\"staticName\"></param>\n    /// <param name=\"maybeEntity\"></param>\n    /// <returns></returns>\n    private static ViewContentTypeDto TypeSpecs(IEnumerable<IContentType> allCTs, string staticName, IEntity? maybeEntity)\n    {\n        var found = allCTs.FirstOrDefault(ct => ct.NameId == staticName);\n        return new()\n        {\n            StaticName = staticName, Id = found?.Id ?? 0, Name = found == null ? \"no content type\" : found.Name,\n            DemoId = maybeEntity?.EntityId ?? 0,\n            DemoTitle = maybeEntity?.GetBestTitle() ?? \"\"\n        };\n    }\n\n    public bool Delete(int appId, int id)\n    {\n        // todo: extra security to only allow zone change if host user\n        Log.A($\"delete a{appId}, t:{id}\");\n        var app = impExpHelpers.New().GetAppAndCheckZoneSwitchPermissions(context.Site.ZoneId, appId, context.User, context.Site.ZoneId);\n        workViewsMod.New(app).DeleteView(id);\n        return true;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Backend/Views/ViewsExportImport.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Data.Sys.Entities;\nusing ToSic.Eav.DataSource.Query.Sys;\nusing ToSic.Eav.Environment.Sys.ServerPaths;\nusing ToSic.Eav.ImportExport.Integration;\nusing ToSic.Eav.ImportExport.Json.Sys;\nusing ToSic.Eav.ImportExport.Json.V1;\nusing ToSic.Eav.ImportExport.Sys;\nusing ToSic.Eav.ImportExport.Sys.Xml;\nusing ToSic.Eav.Persistence.Sys.Logging;\nusing ToSic.Eav.Serialization.Sys;\nusing ToSic.Eav.WebApi.Sys.Helpers.Validation;\nusing ToSic.Eav.WebApi.Sys.Security;\nusing ToSic.Sxc.Apps.Sys;\nusing ToSic.Sxc.Apps.Sys.Paths;\nusing ToSic.Sxc.Backend.ImportExport;\nusing ToSic.Sxc.Blocks.Sys.Views;\nusing ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.Backend.Views;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ViewsExportImport(\n    GenWorkDb<WorkEntitySave> workEntSave,\n    IServerPaths serverPaths,\n    IEnvironmentLogger envLogger,\n    LazySvc<JsonSerializer> jsonSerializerLazy,\n    IContextOfSite context,\n    AppIconHelpers appIconHelpers,\n    Generator<ImpExpHelpers> impExpHelpers,\n    IResponseMaker responseMaker,\n    Generator<QueryDefinitionFactory> qDefBuilder,\n    IAppPathsMicroSvc appPathSvc)\n    : ServiceBase(\"Bck.Views\",\n        connect:\n        [\n            workEntSave, serverPaths, envLogger, jsonSerializerLazy, appIconHelpers, impExpHelpers, responseMaker,\n            qDefBuilder, appPathSvc\n        ])\n{\n    public THttpResponseType DownloadViewAsJson(int appId, int viewId)\n    {\n        var logCall = Log.Fn<THttpResponseType>($\"{appId}, {viewId}\");\n        SecurityHelpers.ThrowIfNotSiteAdmin(context.User, Log);\n        var appReader = impExpHelpers.New().GetAppAndCheckZoneSwitchPermissions(context.Site.ZoneId, appId, context.User, context.Site.ZoneId);\n        var bundle = new BundleEntityWithAssets\n        {\n            Entity = appReader.List.GetOne(viewId)!.IfOfType(Settings.TemplateContentType)!\n        };\n\n        var appPaths = appPathSvc.Get(appReader, context.Site);\n\n        // Attach files\n        var view = new View(bundle.Entity!, [context.Site.CurrentCultureCode], qDefBuilder);\n\n        if (!string.IsNullOrEmpty(view.Path))\n        {\n            bundle = TryAddAsset(bundle, appPaths.ViewPath(view, PathTypes.PhysRelative), view.Path);\n            var webPath = appIconHelpers.IconPathOrNull(appPaths, view, PathTypes.PhysRelative)?.ForwardSlash();\n            if(webPath != null)\n            {\n                var relativePath = webPath.Replace(appPaths.RelativePath.ForwardSlash(), \"\").TrimPrefixSlash();\n                bundle = TryAddAsset(bundle, webPath, relativePath);\n            }\n        }\n\n        var serializer = jsonSerializerLazy.Value.SetApp(appReader);\n        var serialized = serializer.Serialize(bundle, 0);\n\n        return logCall.ReturnAsOk(responseMaker.File(serialized,\n            (\"View\" + \".\" + bundle.Entity.GetBestTitle() + ImpExpConstants.Extension(ImpExpConstants.Files.json))\n            .RemoveNonFilenameCharacters()));\n    }\n\n    private BundleEntityWithAssets TryAddAsset(BundleEntityWithAssets bundle, string webPath, string relativePath)\n    {\n        if (string.IsNullOrEmpty(webPath))\n            return bundle;\n        var realPath = serverPaths.FullAppPath(webPath);\n        var jsonAssetMan = new JsonAssets();\n        var asset1 = jsonAssetMan.Get(realPath, relativePath, JsonAsset.StorageApp);\n        bundle = bundle with\n        {\n            Assets = bundle.Assets.Append(asset1).ToListOpt()\n        };\n        return bundle;\n    }\n\n        \n\n    public ImportResultDto ImportView(int zoneId, int appId, List<FileUploadDto> files, string defaultLanguage)\n    {\n        var l = Log.Fn<ImportResultDto>($\"{zoneId}, {appId}, {defaultLanguage}\");\n\n        try\n        {\n            // 0.1 Check permissions, get the app, \n            var appRead = impExpHelpers.New().GetAppAndCheckZoneSwitchPermissions(context.Site.ZoneId, appId, context.User, context.Site.ZoneId);\n            var appPaths = appPathSvc.Get(appRead, context.Site);\n\n            // 0.2 Verify it's json etc.\n            if (files.Any(file => !Json.IsValidJson(file.Contents)))\n                throw new ArgumentException(\"a file is not json\");\n\n            // 1. create the views\n            var serializer = jsonSerializerLazy.Value.SetApp(appRead);\n\n            var bundles = files.Select(f => serializer.DeserializeEntityWithAssets(f.Contents)).ToList();\n\n            if (bundles.Any(t => t == null!))\n                throw new NullReferenceException(\"At least one file returned a null-item, something is wrong\");\n\n            // 1.1 Verify these are view-entities\n            if (!bundles.All(v => v.Entity.Type.Is(Settings.TemplateContentType)))\n                throw new(\"At least one of the uploaded items is not a view configuration. \" +\n                          \"Expected all to be \" + Settings.TemplateContentType);\n\n            // 2. Import the views\n            // todo: construction of this should go into init\n            workEntSave.New(appRead).Import(bundles.Select(v => v.Entity).ToList());\n\n            // 3. Import the attachments\n            var assets = bundles.SelectMany(b => b.Assets);\n            var assetMan = new JsonAssets();\n            foreach (var asset in assets)\n                assetMan.Create(GetRealPath(appPaths, asset), asset);\n\n            // 3. possibly show messages / issues\n            return l.ReturnAsOk(new(true));\n        }\n        catch (Exception ex)\n        {\n            envLogger.LogException(ex);\n            return l.Return(new(false, ex.Message, Message.MessageTypes.Error), \"error\");\n        }\n    }\n\n    private string? GetRealPath(IAppPaths app, JsonAsset asset)\n    {\n        if (!string.IsNullOrEmpty(asset.Storage) && asset.Storage != JsonAsset.StorageApp)\n            return null;\n        var root = app.PhysicalPathSwitch(false);\n        return Path.Combine(root, asset.Folder!, asset.Name);\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using ToSic.Eav.Apps;\nglobal using ToSic.Eav.Apps.Sys.Work;\nglobal using ToSic.Eav.Context;\nglobal using ToSic.Eav.Data;\nglobal using ToSic.Eav.WebApi.Sys.Context;\nglobal using ToSic.Eav.WebApi.Sys.Dto;\nglobal using ToSic.Eav.WebApi.Sys.Helpers.Http;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Documentation;\nglobal using ToSic.Sys.Data;\nglobal using ToSic.Sys.Logging;\nglobal using ToSic.Sys.Services;\nglobal using ToSic.Sxc.Apps.Sys.Work;\nglobal using ToSic.Sxc.Context.Sys;\nglobal using ToSic.Sys.Performance;\nglobal using static ToSic.Sxc.Sys.SxcLogging;\n\n\n#if NETFRAMEWORK\nglobal using THttpResponseType = System.Net.Http.HttpResponseMessage;\n#else\nglobal using THttpResponseType = Microsoft.AspNetCore.Mvc.IActionResult;\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/ImportExport.Package.Sys/PackageIndexFile.cs",
    "content": "﻿using System.Text.Json.Serialization;\n\nnamespace ToSic.Sxc.ImportExport.Package.Sys;\n\n/// <summary>\n/// This is for a file which contains the index of a set of files, and also the lock/hashes,\n/// </summary>\npublic record PackageIndexFile\n{\n    /// <summary>\n    /// File name for an extension index/lock file inside an Extension's App_Data folder.\n    /// </summary>\n    /// <remarks>\n    /// Should have a generic name which will also be usable for non-extension packages in the future.\n    /// But we can't use `package.lock.json` because it looks too similar to `package-lock.json` used by npm.\n    /// </remarks>\n    public const string LockFileName = \"package-index.json\";\n\n    [JsonPropertyOrder(1)]\n#pragma warning disable CA1822\n    public string Comments => \"This file contains the list of files in a package with their hashes to check if files were changed.\";\n#pragma warning restore CA1822\n\n    [JsonPropertyOrder(2)]\n    public required string Version { get; init; }\n\n    [JsonPropertyOrder(3)]\n    public required List<PackageIndexFileEntry> Files { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/ImportExport.Package.Sys/PackageIndexFileEntry.cs",
    "content": "﻿namespace ToSic.Sxc.ImportExport.Package.Sys;\n\npublic record PackageIndexFileEntry\n{\n    public required string File { get; init; }\n\n    public required string Hash { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/ImportExport.Package.Sys/PackageInstallAbout.cs",
    "content": "namespace ToSic.Sxc.ImportExport.Package.Sys;\n\npublic record PackageInstallAbout\n{\n    public required string Title { get; init; }\n\n    public required string Description { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/ImportExport.Package.Sys/PackageInstallExtension.cs",
    "content": "namespace ToSic.Sxc.ImportExport.Package.Sys;\n\n/// <summary>\n/// Definition of a single extension within the package.\n/// </summary>\n/// <param name=\"Name\">Extension name - usually a lower-case folder name</param>\n/// <param name=\"DefinitionFile\">Path to the extension definition file</param>\n/// <param name=\"IndexFile\">Path to the index file</param>\n/// <param name=\"IndexFileHash\">Hash of the index file for verification</param>\npublic record PackageInstallExtension(\n    string Name,\n    string DefinitionFile,\n    string IndexFile,\n    string IndexFileHash\n);"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/ImportExport.Package.Sys/PackageInstallFile.cs",
    "content": "using System.Text.Json.Serialization;\n\nnamespace ToSic.Sxc.ImportExport.Package.Sys;\n\n/// <summary>\n/// This is a package definition structure.\n/// This file should be placed in the root of any ZIP exported in future,\n/// so that importing systems can quickly determine if it's compatible and other aspects.\n/// </summary>\n/// <remarks>\n/// It should be extended with additional information about version compatibility, platforms, etc.\n/// </remarks>\npublic record PackageInstallFile\n{\n    /// <summary>\n    /// The name in the root of the package ZIP file where this definition is stored.\n    /// Note that upon import, this file should never be imported.\n    /// </summary>\n    public const string FileName = \"package-install.json\";\n\n    /// <inheritdoc cref=\"PackageInstallHeader\"/>\n    public PackageInstallHeader Header { get; init; } = new();\n\n    public required PackageInstallAbout About { get; init; }\n\n    /// <summary>\n    /// List of extensions in this package.\n    /// </summary>\n    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]\n    public List<PackageInstallExtension>? Extensions { get; init; }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/ImportExport.Package.Sys/PackageInstallHeader.cs",
    "content": "namespace ToSic.Sxc.ImportExport.Package.Sys;\n\n/// <summary>\n/// Header / compatibility information about the package.\n/// </summary>\npublic record PackageInstallHeader\n{\n    private const string CurrentPackageFormatVersion = \"00.00.01\";\n\n    public string PackageVersion { get; init; } = CurrentPackageFormatVersion;\n\n    public PackageTypes PackageType { get; init; } = PackageTypes.App;\n\n\n}\npublic enum PackageTypes\n{\n    /// <summary>\n    /// An App package - contains an application with optional extensions.\n    /// </summary>\n    App,\n\n    /// <summary>\n    /// An AppExtension package - things to be installed into an existing app.\n    /// </summary>\n    AppExtension,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Dnn.WebApi\")]\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Mvc\")]\n\n[assembly: InternalsVisibleTo(\"ToSic.Sxc.Oqtane.Server\")]\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/Properties/launchSettings.json",
    "content": "{\n  \"profiles\": {\n    \"ToSic.Sxc.WebApi\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"environmentVariables\": {\n        \"ASPNETCORE_ENVIRONMENT\": \"Development\"\n      },\n      \"applicationUrl\": \"http://localhost:51714\"\n    }\n  }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/StartupSxcWebApi.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing ToSic.Eav.Sys.Insights;\nusing ToSic.Eav.WebApi.Sys.Admin;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Apps.Sys.EditAssets;\nusing ToSic.Sxc.Backend.Adam;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Backend.Admin.AppFiles;\nusing ToSic.Sxc.Backend.Admin.Query;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Backend.AppStack;\nusing ToSic.Sxc.Backend.Cms;\nusing ToSic.Sxc.Backend.Cms.Load.Activities;\nusing ToSic.Sxc.Backend.Cms.Load.Settings;\nusing ToSic.Sxc.Backend.ContentBlocks;\nusing ToSic.Sxc.Backend.Context;\nusing ToSic.Sxc.Backend.ImportExport;\nusing ToSic.Sxc.Backend.InPage;\nusing ToSic.Sxc.Backend.SaveHelpers;\nusing ToSic.Sxc.Backend.Sys;\nusing ToSic.Sxc.Backend.Usage;\nusing ToSic.Sxc.Backend.Views;\nusing ToSic.Sxc.Render.Sys.Output;\nusing ToSic.Sxc.Render.Sys.ResourceExtractor;\nusing ToSic.Sxc.WebApi.Sys;\nusing ToSic.Sxc.WebApi.Sys.ExternalLinks;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.Backend;\n\n[InternalApi_DoNotUse_MayChangeWithoutNotice]\npublic static class StartupSxcWebApi\n{\n    public static IServiceCollection AddSxcWebApi(this IServiceCollection services)\n    {\n        // WIP - objects which are not really final\n        services.TryAddTransient<ExternalLinksService>();\n\n        // These are usually replaced by the target platform\n        services.TryAddTransient<IBlockResourceExtractor, BlockResourceExtractorUnknown>();\n            \n        // Real Controllers\n\n        // Backends\n        services.TryAddTransient<AppsBackend>();\n        services.TryAddTransient<ExtensionExportService>();\n        services.TryAddTransient<ExtensionReaderBackend>();\n        services.TryAddTransient<ExtensionWriterBackend>();\n        services.TryAddTransient<ExtensionInstallBackend>();\n        services.TryAddTransient<ExtensionDownloadBackend>();\n        // commented out, already registered in Eav.Apps.Persistence\n        //services.TryAddTransient<ExtensionManifestService>();\n        services.TryAddTransient<ExtensionInspectBackend>();\n        services.TryAddTransient<ExtensionDeleteBackend>();\n        //services.TryAddTransient<EntityBackend>();\n\n        services.TryAddTransient<EditLoadBackend>();\n        services.TryAddTransient<EditLoadActivityAddContentTypes>();\n        services.TryAddTransient<EditLoadActivityAddNecessaryInputTypes>();\n        services.TryAddTransient<EditLoadActivityAddContext>();\n        services.TryAddTransient<EditLoadActivityAddRequiredFeatures>();\n        services.TryAddTransient<EditLoadActivityAddPrefetch>();\n        services.TryAddTransient<EditLoadActivitySettingsHelper>();\n        services.TryAddTransient<EditLoadActivityCleanupRequest>();\n        services.TryAddTransient<EditLoadActivityConvertRequest>();\n\n\n        services.TryAddTransient<EditSaveBackend>();\n        services.TryAddTransient<SaveSecurity>();\n        services.TryAddTransient<AppViewPickerBackend>();\n        services.TryAddTransient<ContentBlockBackend>();\n        services.TryAddTransient<UsageBackend>();\n\n        // Internal API helpers\n        services.TryAddTransient<AppContent>();\n        services.TryAddTransient<SxcPagePublishing>();\n        services.TryAddTransient<ExportApp>();\n        services.TryAddTransient<ImportApp>();\n        services.TryAddTransient<ImportContent>();\n        services.TryAddTransient<ExportContent>();\n        services.TryAddTransient<AppStateSyncSave>();   // new separate in v21.06\n        services.TryAddTransient<AppStateSyncRestore>();\n        services.TryAddTransient<AppStackBackend>();\n        services.TryAddTransient<AppFolderLookupForWebApi>();\n        services.TryAddTransient<ViewsExportImport>();\n\n        // Small WebApi Helpers\n        services.TryAddTransient<ContentGroupList>();\n\n        // js context / UI\n        services.TryAddTransient<IUiContextBuilder, UiContextBuilderUnknown>();\n        services.TryAddTransient<UiContextBuilderBase.Dependencies>();\n            \n        // Helpers\n        services.TryAddTransient<ImpExpHelpers>();\n\n        // Adam shared code across the APIs\n        services.TryAddTransient<AdamCode>();\n\n        // New v13 - try to reduce Dnn/Oqtane code to the max, by creating ControllerReal objects which do everything\n        services.TryAddTransient(typeof(AdamControllerReal<>));\n        services.TryAddTransient<AppFilesControllerReal>();\n        services.TryAddTransient<IAppExplorerControllerDependency, AppFilesControllerReal>();\n        services.TryAddTransient<QueryControllerReal>();\n        services.TryAddTransient<AppControllerReal>();\n        services.TryAddTransient<AppPartsControllerReal>();\n        services.TryAddTransient<DialogControllerReal>();\n        services.TryAddTransient<TypeControllerReal>();\n        services.TryAddTransient<ViewControllerReal>();\n        services.TryAddTransient<AppDataControllerReal>();\n        services.TryAddTransient<AppQueryControllerReal>();\n        services.TryAddTransient<CacheControllerReal>();\n        services.TryAddTransient<ContentGroupControllerReal>();\n        services.TryAddTransient<EditControllerReal>();\n        services.TryAddTransient<HistoryControllerReal>();\n        services.TryAddTransient<ListControllerReal>();\n        services.TryAddTransient<InstallControllerReal>();\n        services.TryAddTransient<BlockControllerReal>();\n        services.TryAddTransient<CodeControllerReal>();\n        services.TryAddTransient<DataControllerReal>();\n\n        services.TryAddTransient<AssetTemplates>();\n\n        // Odata v21\n        services.TryAddTransient<AppQueryODataHelper>();\n\n        // SaveData PreSave\n        services.TryAddTransient<DataValidatorContentTypeDataStore>();\n\n        services.AddLoadSettingsProviders();\n\n        services.AddSxcInsights();\n\n        services.AddFallbacks();\n\n        return services;\n    }\n\n    public static IServiceCollection AddLoadSettingsProviders(this IServiceCollection services)\n    {\n        services.AddTransient<ILoadSettingsProvider, LoadSettingsForGpsDefaults>();\n        services.AddTransient<ILoadSettingsProvider, LoadSettingsForContentType>();\n        services.AddTransient<ILoadSettingsProvider, LoadSettingsApiKeys>();\n        services.AddTransient<ILoadSettingsProvider, LoadSettingsForWysiwygDefaults>(); // new v21\n        services.AddTransient<ILoadSettingsContentTypesProvider, LoadSettingsForPickerSources>();\n        return services;\n    }\n\n    public static IServiceCollection AddAdamWebApi<TFolder, TFile>(this IServiceCollection services)\n    {\n        // Adam Controllers etc.\n        services.TryAddTransient(typeof(HyperlinkBackend));\n        services.TryAddTransient(typeof(AdamItemDtoMaker<,>));\n        services.TryAddTransient(typeof(AdamItemDtoMaker<,>.Dependencies));\n\n        // Default `int` implementation, the platform must specify a different type before this if it needs another identity type\n        services.TryAddTransient<IAdamItemDtoMaker, AdamItemDtoMaker<TFolder, TFile>>();\n\n        // Prefetch helper so it can be used in the Edit CMS Load\n        services.TryAddTransient<IAdamPrefetchHelper, AdamPrefetchHelper>();\n\n        return services;\n    }\n\n    public static IServiceCollection AddSxcInsights(this IServiceCollection services)\n    {\n        services.AddTransient<IInsightsProvider, InsightsAppCodeOverview>();\n        services.AddTransient<IInsightsProvider, InsightsAppCodeBuild>();\n        services.AddTransient<IInsightsProvider, InsightsLightSpeed>();\n        return services;\n    }\n\n    public static IServiceCollection AddFallbacks(this IServiceCollection services)\n    {\n        services.TryAddTransient<IWebApiContextBuilder, WebApiContextBuilderUnknown>();\n        return services;\n    }\n        \n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/ToSic.Sxc.WebApi.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForRealCode-Nullable.props\" />\n\n  <Import Project=\"../../SharedImports/CsProj.Props/CreateXDocsOnRelease.props\" />\n\n  <PropertyGroup>\n    <AssemblyName>ToSic.Sxc.WebApi</AssemblyName>\n  </PropertyGroup>\n\n  <Import Project=\"../../SharedImports/CsProj.Props/Reference/RazorBlade.props\" />\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps\\ToSic.Eav.Apps.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Apps.Persistence\\ToSic.Eav.Apps.Persistence.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.Insights\\ToSic.Eav.Insights.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Eav.WebApi\\ToSic.Eav.WebApi.csproj\" />\n    <ProjectReference Include=\"..\\..\\..\\..\\eav-server\\ToSic.Sys.Core\\ToSic.Sys.Core.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Apps\\ToSic.Sxc.Apps.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Blocks\\ToSic.Sxc.Blocks.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code.Generate\\ToSic.Sxc.Code.Generate.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code.HotBuild\\ToSic.Sxc.Code.HotBuild.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Code\\ToSic.Sxc.Code.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.LightSpeed\\ToSic.Sxc.LightSpeed.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Render\\ToSic.Sxc.Render.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Services\\ToSic.Sxc.Services.csproj\" />\n    <ProjectReference Include=\"..\\ToSic.Sxc.Web\\ToSic.Sxc.Web.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net472'\">\n    <Reference Include=\"System.Net.Http\" />\n    <PackageReference Include=\"Microsoft.AspNet.WebApi.WebHost\" Version=\"5.2.3\">\n      <ExcludeAssets>runtime</ExcludeAssets>\n    </PackageReference>\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.IO.Compression\" />\n    <Reference Include=\"System.IO.Compression.FileSystem\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <PackageReference Include=\"Microsoft.CSharp\" Version=\"4.7.0\" />\n    <FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/ToSic.Sxc.WebApi.csproj.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=admin_005Cappfiles/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=attributes/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=backend_005Cadmin_005Cappfiles/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=backend_005Ccms_005Cblock/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=backend_005Ccms_005Cedit/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=backend_005Ccms_005Clist/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=backend_005Csys_005Cinsights/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cms_005Cedit/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=cms_005Ceditui/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=jsonformatter/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=query/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=save/@EntryIndexedValue\">False</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=sys_005Cinsights/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=webapi_005Cjsonformatter/@EntryIndexedValue\">True</s:Boolean>\n\t<s:Boolean x:Key=\"/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=webapi_005Csecureendpoint/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/IDynamicWebApi.cs",
    "content": "﻿using ToSic.Sxc.Adam;\n\n// ReSharper disable UnusedMember.Global\n\nnamespace ToSic.Sxc.WebApi;\n\n/// <summary>\n/// This interface extends WebAPIs with File-Save helpers.\n/// It's important, because if 2sxc also runs on other CMS platforms, then the Dnn Context won't be available, so it's in a separate interface.\n/// </summary>\n[PrivateApi(\"Was public till v17, but now the docs are all objects directly\")]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic interface IDynamicWebApi\n{\n    /// <summary>\n    /// Save a file from a stream (usually an upload from the browser) into an adam-field of an item.\n    /// Read more about this in the [WebAPI docs for SaveInAdam](xref:NetCode.WebApi.DotNet.SaveInAdam)\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"stream\">the stream</param>\n    /// <param name=\"fileName\">file name to save to</param>\n    /// <param name=\"contentType\">content-type of the target item (important for security checks)</param>\n    /// <param name=\"guid\"></param>\n    /// <param name=\"field\"></param>\n    /// <param name=\"subFolder\"></param>\n    /// <returns></returns>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    IFile SaveInAdam(NoParamOrder npo = default,\n        Stream? stream = null,\n        string? fileName = null,\n        string? contentType = null,\n        Guid? guid = null,\n        string? field = null,\n        string subFolder = \"\");\n\n\n    /// <summary>\n    /// Create a File-result to stream to the client\n    ///\n    ///\n    /// Typical use: `return File(download: true, contentType: \"text/xml\", contents: ...);`\n    /// </summary>\n    /// <param name=\"npo\">see [](xref:NetCode.Conventions.NamedParameters)</param>\n    /// <param name=\"download\">If a download should be enforced (otherwise the file may just be displayed - like an image)</param>\n    /// <param name=\"virtualPath\">Path in the website to get the file from. Provide _either_ virtualPath or contents</param>\n    /// <param name=\"contentType\">Mime Content-type. Will try to auto-detect from virtualPath or fileDownloadName if not provided.</param>\n    /// <param name=\"fileDownloadName\">Download name. If provided, it will try to force download/save on the browser. </param>\n    /// <param name=\"contents\">Content of the result - a string, byte[] or stream to include.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// Added in 2sxc 12.05\n    /// </remarks>\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    dynamic File(NoParamOrder npo = default,\n        // Important: the second parameter should _not_ be a string, otherwise the signature looks the same as the built-in File(...) method\n        bool? download = null,\n        // important: this is the virtualPath, but it should not have the same name, to not confuse the compiler with same sounding param names\n        string? virtualPath = null,\n        string? contentType = null,\n        string? fileDownloadName = null,\n        object? contents = null\n    );\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/JsonFormatter/Casing.cs",
    "content": "﻿namespace ToSic.Sxc.WebApi;\n\n/// <summary>\n/// Determines what casing to use when converting data to JSON.\n/// This is for the <see cref=\"JsonFormatterAttribute\"/>.\n/// Can be used as flags, so you can say `Casing = Casing.CamelCase` or `Casing = Casing.ObjectPascal | Casing.DictionaryCamel`\n/// </summary>\n[PublicApi]\n[Flags]\npublic enum Casing\n{\n    /// <summary>\n    /// No casing configuration set.\n    /// Will preserve casing as it is, usually Pascal case (old behavior for 2sxc Apis).\n    /// </summary>\n    [PrivateApi(\"Hidden for now, as it doesn't matter to external users\")]\n    [ShowApiWhenReleased(ShowApiMode.Never)]\n    Unspecified = 0,\n\n    /// <summary>\n    /// Set casing to use camelCase for everything.\n    /// This is how most JavaScript code expects the data.\n    /// The opposite would be <see cref=\"Preserve\"/>.\n    /// </summary>\n    Camel = 1 << 0,\n\n    /// <summary>\n    /// Set casing to use original name for everything - usually PascalCase as is common in C#.\n    /// This is how conversion would have worked before v15, as the C# objects all use CamelCase internally.\n    /// The opposite would be <see cref=\"Camel\"/>\n    /// </summary>\n    Preserve = 1 << 2,\n\n    /// <summary>\n    /// Set casing of Dictionaries to be camelCase.\n    /// For example, Entity properties such as `Birthday` = `birthday`, `FirstName` = `firstName`.\n    /// This would be Camel case.\n    /// </summary>\n    DictionaryCamel = 1 << 9,\n\n    /// <summary>\n    /// Set casing of Dictionaries to be PascalCase.\n    /// For example, Entity properties such as `Birthday` = `Birthday`, `FirstName` = `firstName`.\n    /// This would be Camel case.\n    /// </summary>\n    DictionaryPreserve = 1 << 10,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/JsonFormatter/EntityFormat.cs",
    "content": "﻿using ToSic.Eav.DataFormats.EavLight;\n\nnamespace ToSic.Sxc.WebApi;\n\n/// <summary>\n/// Formats to use for automatic Entity to JSON conversion.\n/// This is for the <see cref=\"JsonFormatterAttribute\"/>.\n/// As of now it only has `None` and `Light`, in future we plan to extend this with other formats.\n/// Default is usually `Light`.\n/// </summary>\n[PublicApi]\npublic enum EntityFormat\n{\n    /// <summary>\n    /// Do not auto-convert into any specific format.\n    /// If <see cref=\"IEntity\"/> objects are in the result, will result in an error.\n    /// </summary>\n    None,\n\n    /// <summary>\n    /// Format <see cref=\"IEntity\"/> objects as <see cref=\"EavLightEntity\"/>.\n    /// This results in single-language objects with name/value pairs like a JavaScript object.\n    /// </summary>\n    Light,\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/JsonFormatter/JsonCasingOverrideHelper.cs",
    "content": "using ToSic.Sys.Utils;\n\nnamespace ToSic.Sxc.WebApi;\n\n/// <summary>\n/// Shared helpers for request-level JSON casing overrides.\n/// Framework-specific code should pass query key/value pairs into this utility.\n/// </summary>\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static class JsonCasingOverrideHelper\n{\n    internal const string CasingQueryKey = \"$casing\";\n    private const string CamelValue = \"camel\";\n\n    /// <summary>\n    /// Parse casing override from query parameters.\n    /// Currently, supports only `$casing=camel`.\n    /// </summary>\n    internal static bool TryParseCasingOverride(IEnumerable<KeyValuePair<string, string>>? queryNameValuePairs, out Casing casing)\n    {\n        casing = Casing.Unspecified;\n        if (queryNameValuePairs == null)\n            return false;\n\n        var casingQueryValue = queryNameValuePairs\n            .FirstOrDefault(pair => pair.Key.EqualsInsensitive(CasingQueryKey))\n            .Value;\n\n        if (!casingQueryValue.EqualsInsensitive(CamelValue))\n            return false;\n\n        casing = Casing.Camel;\n        return true;\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/JsonFormatter/JsonFormatterAttribute.cs",
    "content": "﻿namespace ToSic.Sxc.WebApi;\n\n/// <summary>\n/// Mark a WebApi to use the modern Json Formatter based on System.Text.Json.\n/// Without this, older WebApi Controllers use the Newtonsoft JSON Formatter.\n/// Also provides additional configuration to make certain work easier. \n/// </summary>\n/// <remarks>\n/// * new in v15.08\n/// </remarks>\n[PublicApi]\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]\npublic class JsonFormatterAttribute : Attribute\n{\n    /// <summary>\n    /// Specify how <see cref=\"IEntity\"/> objects in the result should be formatted.\n    /// Default is <see cref=\"WebApi.EntityFormat.Light\"/>.\n    /// </summary>\n    public EntityFormat EntityFormat { get; set; } = EntityFormat.Light;\n\n    /// <summary>\n    /// Specify how resulting objects should be cased.\n    /// Default is <see cref=\"WebApi.Casing.Camel\"/>.\n    /// Will affect both normal object properties as well as Dictionary keys.\n    /// </summary>\n    public Casing Casing { get; set; } = Casing.Camel;\n\n    [PrivateApi(\"Hide constructor, not important for docs\")]\n    public JsonFormatterAttribute() { }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/JsonFormatter/JsonFormatterHelpers.cs",
    "content": "﻿using System.Text.Json;\n\nnamespace ToSic.Sxc.WebApi;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\ninternal static class JsonFormatterHelpers\n{\n\n    public static void SetCasing(this JsonSerializerOptions jsonSerializerOptions, Casing casing)\n    {\n        // this preserves casing (old behavior for 2sxc Apis)\n        if (casing == Casing.Unspecified)\n            return;\n\n        var objectPreserve = casing.HasFlag(Casing.Preserve);\n        jsonSerializerOptions.PropertyNamingPolicy = objectPreserve ? null : JsonNamingPolicy.CamelCase;\n\n        var dicPreserve = (objectPreserve && !casing.HasFlag(Casing.DictionaryCamel))\n                          || casing.HasFlag(Casing.DictionaryPreserve);\n        jsonSerializerOptions.DictionaryKeyPolicy = dicPreserve ? null : JsonNamingPolicy.CamelCase;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/SecureEndpoint/SecureEndpointAttributeNetCore.cs",
    "content": "﻿#if NETCOREAPP\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Text;\nusing System.Text.Json;\nusing ToSic.Sys.Security.Encryption;\nusing JsonOptions = ToSic.Eav.Serialization.Sys.Json.JsonOptions;\n\nnamespace ToSic.Sxc.WebApi;\n\n[PrivateApi]\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]\npublic class SecureEndpointAttribute : ActionFilterAttribute\n{\n    [PrivateApi]\n    public SecureEndpointAttribute()\n    {\n        Order = -3002;\n    }\n\n    [PrivateApi]\n    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)\n    {\n        var request = context.HttpContext.Request;\n\n        if (request.Method != HttpMethods.Post || request.ContentType != SecureEndpointShared.MediaJson)\n        {\n            await base.OnActionExecutionAsync(context, next);\n            return;\n        }\n\n        var jsonString = await GetRequestContentStream(request);\n        if (string.IsNullOrEmpty(jsonString))\n        {\n            context.Result = new BadRequestObjectResult(SecureEndpointShared.ErrorIfBodyIsEmpty);\n            return;\n        }\n\n        var encryptedData = SecureEndpointShared.TestAndGetEncryptedData(jsonString);\n        if (encryptedData == null)\n            return;\n\n        // Currently, only POST payloads can be encrypted. \n        // Try to determine the POST parameter dynamically by finding a parameter \n        // that has the FromBody attribute on it or a parameter that is not a value type.\n        // We need the final type because we will deserialize the decrypted data into it.\n        var parameter = context.ActionDescriptor.Parameters\n            .FirstOrDefault(p => p.BindingInfo?.BindingSource == BindingSource.Body || !p.ParameterType.IsValueType);\n        if (parameter == null)\n        {\n            context.Result = new BadRequestObjectResult(\"No parameter found for action.\");\n            return;\n        }\n\n        try\n        {\n            // Decrypt data\n            var decryptedData = Decrypt(context.HttpContext.RequestServices, encryptedData);\n\n            // Validate that decrypted data is valid JSON\n            var formData = JsonSerializer.Deserialize(decryptedData, parameter.ParameterType,\n                JsonOptions.SafeJsonForHtmlAttributes);\n\n            // Replace the request content with the deserialized object\n            context.ActionArguments[parameter.Name] = formData;\n\n            SetRequestContentStream(request, decryptedData);\n        }\n        catch (JsonException)\n        {\n            // Handle invalid JSON format\n            context.Result = new BadRequestObjectResult(\"Exception in decryption.\");\n            return;\n        }\n\n        await base.OnActionExecutionAsync(context, next);\n    }\n\n    /// <summary>\n    /// Reads the request content stream as a string.\n    /// </summary>\n    /// <param name=\"request\"></param>\n    /// <returns></returns>\n    private static async Task<string> GetRequestContentStream(HttpRequest request)\n    {\n        request.EnableBuffering();\n        using var reader = new StreamReader(request.Body, Encoding.UTF8, leaveOpen: true);\n        var content = await reader.ReadToEndAsync();\n        request.Body.Position = 0;\n        return content;\n    }\n\n\n    /// <summary>\n    /// Replaces the request content with a new stream containing the specified JSON string.\n    /// </summary>\n    /// <param name=\"request\">The HTTP request message.</param>\n    /// <param name=\"jsonString\">The JSON string to set as the request content.</param>\n    private void SetRequestContentStream(HttpRequest request, string jsonString)\n    {\n        var newStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));\n        request.Body = newStream;\n        request.Body.Position = 0;\n        request.ContentType = SecureEndpointShared.MediaJson;\n    }\n\n    /// <summary>\n    /// Decrypts the specified encrypted data.\n    /// </summary>\n    /// <param name=\"serviceProvider\"></param>\n    /// <param name=\"encryptedData\"></param>\n    /// <returns></returns>\n    private static string Decrypt(IServiceProvider serviceProvider, EncryptedData encryptedData)\n    {\n        var cryptoService = serviceProvider.GetRequiredService<AesHybridCryptographyService>();\n        return cryptoService.Decrypt(encryptedData);\n    }\n}\n#endif\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/SecureEndpoint/SecureEndpointAttributeNetFull.cs",
    "content": "﻿#if NETFRAMEWORK\nusing System.Net;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Text;\nusing System.Text.Json;\nusing System.Web.Http;\nusing System.Web.Http.Controllers;\nusing System.Web.Http.Dependencies;\nusing System.Web.Http.Filters;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sys.Security.Encryption;\n\nnamespace ToSic.Sxc.WebApi;\n\n/// <summary>\n/// Attribute for WebApi controllers, which automatically decrypts encrypted POST payloads for Web API endpoints.\n/// Use this attribute on controller or methods to automatically decrypt incoming POST requests.\n/// \n/// It will intercepts POST requests with JSON content, checks for encrypted data,\n/// and if present, decrypts the payload using the <see cref=\"AesHybridCryptographyService\"/>.\n/// It then deserializes the decrypted data into the expected parameter type and replaces the action arguments.\n/// If the payload is not encrypted, the request content remains unchanged.\n///\n/// See [](xref:Abyss.Security.EncryptBody.Index) for more information.\n/// </summary>\n/// <remarks>\n/// * Introduced in version 19.00.\n/// </remarks>\n[PublicApi]\n[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]\npublic class SecureEndpointAttribute : ActionFilterAttribute\n{\n    [PrivateApi]\n    public override void OnActionExecuting(HttpActionContext filterContext)\n    {\n        var request = filterContext.Request;\n\n        if (request.Method != HttpMethod.Post || request.Content.Headers.ContentType.MediaType != SecureEndpointShared.MediaJson)\n        {\n            base.OnActionExecuting(filterContext);\n            return;\n        }\n\n        var jsonString = GetRequestContentStream(request);\n        if (string.IsNullOrEmpty(jsonString))\n        {\n            filterContext.Response = request.CreateErrorResponse(HttpStatusCode.BadRequest, SecureEndpointShared.ErrorIfBodyIsEmpty);\n            return;\n        }\n\n        var encryptedData = SecureEndpointShared.TestAndGetEncryptedData(jsonString);\n        if (encryptedData == null)\n            return;\n\n        // Currently, only POST payloads can be encrypted. \n        // Try to determine the POST parameter dynamically by finding a parameter \n        // that has the FromBody attribute on it or a parameter that is not a value type.\n        // We need the final type because we will deserialize the decrypted data into it.\n        var parameter = filterContext.ActionDescriptor.GetParameters()\n            .FirstOrDefault(p => p.GetCustomAttributes<FromBodyAttribute>().Any() || !p.ParameterType.IsValueType);\n        if (parameter == null)\n        {\n            filterContext.Response = request.CreateErrorResponse(HttpStatusCode.BadRequest, \"No parameter found for action.\");\n            return;\n        }\n\n        try\n        {\n            // Decrypt data\n            var decryptedData = Decrypt(filterContext.Request.GetDependencyScope(), encryptedData);\n\n            // Validate that decrypted data is valid JSON\n            var formData = JsonSerializer.Deserialize(decryptedData, parameter.ParameterType,\n                options: JsonOptions.SafeJsonForHtmlAttributes);\n\n            // Replace the request content with the deserialized object\n            filterContext.ActionArguments[parameter.ParameterName] = formData;\n\n            SetRequestContentStream(request, decryptedData);\n        }\n        catch (JsonException)\n        {\n            // Handle invalid JSON format\n            filterContext.Response = request.CreateErrorResponse(HttpStatusCode.BadRequest, \"Exception in decryption.\");\n        }\n    }\n\n\n    /// <summary>\n    /// Reads the request content stream as a string.\n    /// </summary>\n    /// <param name=\"request\"></param>\n    /// <returns></returns>\n    private static string GetRequestContentStream(HttpRequestMessage request)\n    {\n        var stream = request.Content.ReadAsStreamAsync().Result;\n        stream.Position = 0;\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    /// <summary>\n    /// Replaces the request content with a new stream containing the specified JSON string.\n    /// </summary>\n    /// <param name=\"request\">The HTTP request message.</param>\n    /// <param name=\"jsonString\">The JSON string to set as the request content.</param>\n    private static void SetRequestContentStream(HttpRequestMessage request, string jsonString)\n    {\n\n        request.Content = new StreamContent(new MemoryStream(Encoding.UTF8.GetBytes(jsonString)));\n        request.Content.Headers.ContentType = new(SecureEndpointShared.MediaJson);\n        //filterContext.Request.Content = new ObjectContent(parameter.ParameterType, formData, parameter.Configuration.Formatters.JsonFormatter);\n    }\n\n    /// <summary>\n    /// Decrypts the specified encrypted data.\n    /// </summary>\n    /// <param name=\"dependencyScope\"></param>\n    /// <param name=\"encryptedData\"></param>\n    /// <returns></returns>\n    private static string Decrypt(IDependencyScope dependencyScope, EncryptedData encryptedData)\n    {\n        var cryptoService = (AesHybridCryptographyService)dependencyScope.GetService(typeof(AesHybridCryptographyService));\n        return cryptoService.Decrypt(encryptedData);\n    }\n}\n#endif\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi/SecureEndpoint/SecureEndpointShared.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Sys.Security.Encryption;\n\nnamespace ToSic.Sxc.WebApi;\n\ninternal class SecureEndpointShared\n{\n    public const string MediaJson = \"application/json\";\n\n    public const string ErrorIfBodyIsEmpty = \"Request content is empty. Endpoint uses the SecureEndpoint, which expects data in the POST body.\";\n\n    public static EncryptedData? TestAndGetEncryptedData(string jsonString)\n    {\n        // Deserializes the JSON string to an EncryptedData object and performs a \"EncryptedData\" check.\n        // If encrypted data is missing, sets the request content stream to the original JSON string and returns.\n        var maybeEncrypted = JsonSerializer.Deserialize<EncryptedDataRaw>(jsonString, options: JsonOptions.SafeJsonForHtmlAttributes);\n        if (maybeEncrypted == null || (maybeEncrypted.Version == 1 && (maybeEncrypted.Data is null || maybeEncrypted.Key is null || maybeEncrypted.Iv is null)))\n            return null;\n\n        var encryptedData = new EncryptedData\n        {\n            Data = maybeEncrypted.Data ?? throw new JsonException(\"Encrypted data is missing.\"),\n            Key = maybeEncrypted.Key ?? throw new JsonException(\"Encryption key is missing.\"),\n            Iv = maybeEncrypted.Iv ?? throw new JsonException(\"Initialization vector (IV) is missing.\"),\n            Version = maybeEncrypted.Version\n        };\n        return encryptedData;\n    }\n\n}\n\n\n/// <remarks>\n/// If the data is encrypted, it would need to be required. But because we're test-deserializing this to do duck-checking, it cannot be required.\n/// See also <see cref=\"EncryptedData\"/>\n/// </remarks>\npublic class EncryptedDataRaw\n{\n    public int Version { get; init; } = 1;\n\n    public string? Data { get; init; }\n\n    public string? Key { get; init; }\n\n    public string? Iv { get; init; }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/ActionFilters/HttpResponseExceptionFilter.cs",
    "content": "﻿#if NETCOREAPP\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Filters;\n\nnamespace ToSic.Sxc.WebApi.Sys.ActionFilters;\n/// <summary>\n/// TODO: @STV pls document what this is for\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter\n{\n    public int Order { get; } = int.MaxValue - 10;\n\n    public void OnActionExecuting(ActionExecutingContext context) { }\n\n    public void OnActionExecuted(ActionExecutedContext context)\n    {\n        if (context.Exception is HttpExceptionAbstraction exception)\n        {\n            context.Result = new ObjectResult(exception.Status)\n            {\n                StatusCode = exception.Status,\n                Value = exception.Message,\n            };\n            context.ExceptionHandled = true;\n        }\n        else if (context.Exception is { } anyException)\n        {\n            context.Result = new ObjectResult(500)\n            {\n                StatusCode = 400,\n                Value = anyException,\n            };\n            context.ExceptionHandled = true;\n        }   \n    }\n}\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/ActionFilters/JsonConverterFactoryHelpers.cs",
    "content": "﻿using System.Text.Json;\nusing ToSic.Eav.Serialization.Sys.Json;\nusing ToSic.Eav.WebApi.Sys.Helpers.Json;\n\nnamespace ToSic.Sxc.WebApi.Sys.ActionFilters;\ninternal class JsonConverterFactoryHelpers\n{\n    internal static TFormatter CreateNewFormatterFactory<TFormatter>(\n        IServiceProvider sp,\n        JsonFormatterAttribute? jsonFormatterAttribute,\n        Func<Casing> getFallbackCasing,\n        Func<JsonSerializerOptions, TFormatter> factory)\n    {\n        // Build Eav to Json converters for api v15\n        // Important: Get the factory from the request-scoped service provider\n        // This ensures it gets fresh IConvertToEavLight with the current request's culture from IZoneCultureResolver\n        var eavJsonConverterFactory = NewEavJsonConverterFactoryOrNull(jsonFormatterAttribute?.EntityFormat, sp);\n\n        var jsonSerializerOptions = JsonOptions.UnsafeJsonWithoutEncodingHtmlOptionsFactory(eavJsonConverterFactory);\n\n        jsonSerializerOptions.SetCasing(jsonFormatterAttribute?.Casing ?? getFallbackCasing());\n\n        return factory(jsonSerializerOptions);\n    }\n\n    /// <summary>\n    /// Retrieves an instance of <see cref=\"entityFormat\"/> based on the specified entity format.\n    /// </summary>\n    /// <param name=\"entityFormat\">The desired entity format. </param>\n    /// <param name=\"serviceProvider\">The service provider used to resolve the factory and its dependencies.</param>\n    /// <returns>An instance of <see cref=\"ToSic.Eav.WebApi.Sys.Helpers\"/> if the entity format is <see langword=\"null\"/> or <see\n    /// cref=\"ToSic.Eav.WebApi.Sys.Helpers\"/>; otherwise, <see langword=\"null\"/>.</returns>\n    public static EavJsonConverterFactory? NewEavJsonConverterFactoryOrNull(EntityFormat? entityFormat, IServiceProvider serviceProvider) =>\n        entityFormat switch\n        {\n            // Build the factory from the request-scoped service provider\n            // This is the key change - it ensures the factory and all its dependencies\n            // (including IConvertToEavLight and IZoneCultureResolver) are request-scoped\n            null or EntityFormat.Light => serviceProvider.Build<EavJsonConverterFactory>(),\n            EntityFormat.None or _ => null,\n        };\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/ActionFilters/OptionalBodyFilter.cs",
    "content": "﻿#if NETCOREAPP\nusing Microsoft.AspNetCore.Mvc.Controllers;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\n\nnamespace ToSic.Sxc.WebApi.Sys.ActionFilters;\n/// <summary>\n/// TODO: @STV pls document what this is for\n/// </summary>\n/// <remarks>\n/// inspired by https://github.com/pranavkm/OptionalBodyBinding\n/// </remarks>\n\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class OptionalBodyFilter : ActionFilterAttribute\n{\n    public OptionalBodyFilter()\n    {\n        // Run before the ModelStateInvalidFilter\n        Order = -2001;\n    }\n\n    public override void OnActionExecuting(ActionExecutingContext context)\n    {\n        var controllerActionDescriptor = (ControllerActionDescriptor)context.ActionDescriptor;\n        var methodParameters = controllerActionDescriptor.MethodInfo.GetParameters();\n        for (var i = 0; i < context.ActionDescriptor.Parameters.Count; i++)\n        {\n            var parameter = context.ActionDescriptor.Parameters[i];\n            if (parameter.BindingInfo?.BindingSource != BindingSource.Body)\n                continue;\n\n            if (methodParameters[i].HasDefaultValue)\n                continue;\n\n            context.ActionArguments.TryGetValue(parameter.Name, out var boundValue);\n            if (boundValue != null)\n                continue;\n\n            // This should be equivalent of global setting\n            // options.AllowEmptyInputInBodyModelBinding = true;\n            context.ModelState.MarkFieldSkipped(parameter.Name);\n            break;\n        }\n    }\n}\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/ActionFilters/SystemTextJsonBodyModelBinder.cs",
    "content": "﻿#if NETCOREAPP\nusing System.Buffers;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Formatters;\nusing Microsoft.AspNetCore.Mvc.Infrastructure;\nusing Microsoft.AspNetCore.Mvc.ModelBinding.Binders;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.ObjectPool;\nusing Microsoft.Extensions.Options;\nusing ToSic.Eav.Serialization.Sys.Json;\n\nnamespace ToSic.Sxc.WebApi.Sys.ActionFilters;\n\npublic class SystemTextJsonBodyModelBinder(\n    ILoggerFactory loggerFactory,\n    ArrayPool<char> charPool,\n    IHttpRequestStreamReaderFactory readerFactory,\n    ObjectPoolProvider objectPoolProvider,\n    IOptions<MvcOptions> mvcOptions)\n    : BodyModelBinder(GetInputFormatters(loggerFactory, charPool, objectPoolProvider, mvcOptions), readerFactory)\n{\n    private static IInputFormatter[] GetInputFormatters(\n        ILoggerFactory loggerFactory,\n        // ReSharper disable UnusedParameter.Local\n        ArrayPool<char> charPool,\n        ObjectPoolProvider objectPoolProvider,\n        IOptions<MvcOptions> mvcOptions)\n        // ReSharper restore UnusedParameter.Local\n    {\n        return\n        [\n            new SystemTextJsonInputFormatter(SxcJsonOptions, loggerFactory.CreateLogger<SystemTextJsonInputFormatter>())\n        ];\n    }\n\n    [field: AllowNull, MaybeNull]\n    public static Microsoft.AspNetCore.Mvc.JsonOptions SxcJsonOptions\n    {\n        get\n        {\n            if (field != null)\n                return field;\n            field = new();\n            field.JsonSerializerOptions.SetUnsafeJsonSerializerOptions();\n            return field;\n        }\n    }\n}\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/ActionFilters/SystemTextJsonFormatterAttribute.cs",
    "content": "﻿#if NETCOREAPP\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.ApplicationModels;\nusing Microsoft.AspNetCore.Mvc.Controllers;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing Microsoft.AspNetCore.Mvc.Formatters;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\nusing JsonOptions = ToSic.Eav.Serialization.Sys.Json.JsonOptions;\n\n\nnamespace ToSic.Sxc.WebApi.Sys.ActionFilters;\n\n/// <summary>\n/// Make sure .net controllers behave the same in terms of JSON serialization like Newtonsoft\n/// </summary>\n// https://blogs.taiga.nl/martijn/2020/05/28/system-text-json-and-newtonsoft-json-side-by-side-in-asp-net-core/\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class SystemTextJsonFormatterAttribute : ActionFilterAttribute, IControllerModelConvention, IActionModelConvention\n{\n    public SystemTextJsonFormatterAttribute()\n    {\n        Order = -3001;\n    }\n\n    public void Apply(ControllerModel controller)\n    {\n        foreach (var action in controller.Actions)\n            Apply(action);\n    }\n\n    public void Apply(ActionModel action)\n    {\n        // Set the model binder to NewtonsoftJsonBodyModelBinder for parameters that are bound to the request body.\n        var parameters = action.Parameters\n            .Where(p => p.BindingInfo?.BindingSource == BindingSource.Body);\n        foreach (var p in parameters)\n            p.BindingInfo!.BinderType = typeof(SystemTextJsonBodyModelBinder);\n    }\n\n    public override void OnActionExecuted(ActionExecutedContext context)\n    {\n        if (context.Result is ObjectResult objectResult)\n        {\n            // we need to use System.Text.Json, but generated per request\n            // because of DI dependencies for EavJsonConvertors in new generated JsonOptions\n            objectResult.Formatters.Insert(0, SystemTextJsonMediaTypeFormatterFactory(context));\n\n            // Oqtane 3.2.0 and older had NewtonsoftJsonOutputFormatter that we need to remove for our endpoints\n            var newtonsoftJsonOutputFormatterType = Type.GetType(\"NewtonsoftJsonOutputFormatter\");\n            if (newtonsoftJsonOutputFormatterType != null)\n                objectResult.Formatters.RemoveType(newtonsoftJsonOutputFormatterType);\n        }\n        else\n        {\n            base.OnActionExecuted(context);\n        }\n    }\n\n    private static SystemTextJsonOutputFormatter SystemTextJsonMediaTypeFormatterFactory(ActionExecutedContext context)\n    {\n        var jsonFormatterAttribute \n            = GetCustomAttributes(((ControllerActionDescriptor)context.ActionDescriptor).MethodInfo)\n                  .OfType<JsonFormatterAttribute>()\n                  .FirstOrDefault()\n              ?? GetCustomAttributes(context.Controller.GetType())\n                  .OfType<JsonFormatterAttribute>()\n                  .FirstOrDefault();\n\n        var effectiveJsonFormatterAttribute = ApplyQueryStringCasingOverride(context, jsonFormatterAttribute);\n\n        // creating JsonConverter, JsonOptions and SystemTextJsonOutputFormatter per request\n        // instead of using global, static, singleton version because this is for API only\n        return JsonConverterFactoryHelpers.CreateNewFormatterFactory(\n            context.HttpContext.RequestServices,\n            effectiveJsonFormatterAttribute,\n            () => Casing.Unspecified,\n            jsonSerializerOptions => new SystemTextJsonOutputFormatter(jsonSerializerOptions)\n        );\n    }\n\n    /// <summary>\n    /// Allows request-level casing override using `?$casing=camel` without touching global JSON options.\n    /// </summary>\n    private static JsonFormatterAttribute? ApplyQueryStringCasingOverride(ActionExecutedContext context, JsonFormatterAttribute? currentAttribute)\n    {\n        if (!TryGetQueryStringCasingOverride(context, out var requestedCasing))\n            return currentAttribute;\n\n        return new()\n        {\n            EntityFormat = currentAttribute?.EntityFormat ?? EntityFormat.Light,\n            Casing = requestedCasing\n        };\n    }\n\n    /// <summary>\n    /// Returns true only for supported casing overrides; unsupported values are ignored.\n    /// </summary>\n    private static bool TryGetQueryStringCasingOverride(ActionExecutedContext context, out Casing casing)\n        => JsonCasingOverrideHelper.TryParseCasingOverride(\n            context.HttpContext?.Request?.Query?\n                .Select(pair => new KeyValuePair<string, string>(pair.Key, pair.Value.ToString())),\n            out casing);\n\n\n    //private static SystemTextJsonOutputFormatter SystemTextJsonMediaTypeFormatterFactory(ActionExecutedContext context)\n    //{\n    //    var jsonFormatterAttribute \n    //        = GetCustomAttributes(((ControllerActionDescriptor)context.ActionDescriptor).MethodInfo)\n    //              .OfType<JsonFormatterAttribute>()\n    //              .FirstOrDefault()\n    //          ?? GetCustomAttributes(context.Controller.GetType())\n    //              .OfType<JsonFormatterAttribute>()\n    //              .FirstOrDefault();\n\n    //    // creating JsonConverter, JsonOptions and SystemTextJsonOutputFormatter per request\n    //    // instead of using global, static, singleton version because this is for API only\n    //    var eavJsonConverterFactory = JsonConverterFactoryHelpers.NewEavJsonConverterFactoryOrNull(\n    //        jsonFormatterAttribute?.EntityFormat,\n    //        context.HttpContext.RequestServices\n    //    );\n\n    //    var jsonSerializerOptions = JsonOptions.UnsafeJsonWithoutEncodingHtmlOptionsFactory(eavJsonConverterFactory);\n\n    //    jsonSerializerOptions.SetCasing(jsonFormatterAttribute?.Casing ?? Casing.Unspecified);\n\n    //    return new(jsonSerializerOptions);\n    //}\n\n}\n\n#endif\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/AppFolderLookupForWebApi.cs",
    "content": "﻿using ToSic.Sxc.Blocks.Sys;\n\nnamespace ToSic.Sxc.WebApi.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class AppFolderLookupForWebApi(ISxcCurrentContextService ctxService) : ServiceBase(\"AppFld\")\n{\n    /// <summary>\n    /// This is necessary for special calls where the _ctxResolve may not yet be complete...\n    /// Important: not sure if this is actually needed, I believe the ctxResolver is always initialized on all web-api requests...?\n    /// </summary>\n    /// <param name=\"block\"></param>\n    /// <returns></returns>\n    public AppFolderLookupForWebApi Init(IBlock block)\n    {\n        ctxService.AttachBlock(block);\n        return this;\n    }\n\n    public string GetAppFolder()\n    {\n        var ctx = ctxService.AppNameRouteBlock(\"\");\n        return ctx.AppReaderRequired.Specs.Folder;\n    }\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/ExternalLinks/ExternalLinksService.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Context.Sys.ZoneCulture;\nusing ToSic.Eav.Sys;\nusing ToSic.Sys.Capabilities.Fingerprints;\nusing ToSic.Sys.Capabilities.Platform;\n\nnamespace ToSic.Sxc.WebApi.Sys.ExternalLinks;\n\n/// <summary>\n/// Service to generate links to getting started, app-details and more.\n/// </summary>\n[PrivateApi]\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class ExternalLinksService(SystemFingerprint fingerprint, IPlatformInfo platformInfo)\n{\n    /// <summary>\n    /// Link to a page in the 2sxc.org destination such as getting started, app-home, etc.\n    /// </summary>\n    /// <returns>a link</returns>\n    public string LinkToDestination(ExternalSxcDestinations destination, ISite site, int moduleId, IAppSpecs? appSpecsOrNull, bool isContentApp)\n    {\n        var destinationPart = \"\";\n        if (destination == ExternalSxcDestinations.AutoConfigure)\n            destinationPart =\n                $\"&destination=autoconfigure{(isContentApp ? KnownAppsConstants.ContentAppAutoConfigureId : KnownAppsConstants.AppAutoConfigureId)}\";\n        else if (destination == ExternalSxcDestinations.Features) \n            destinationPart = \"&destination=features\";\n\n        // ReSharper disable once StringLiteralTypo\n        var link = \"//gettingstarted.2sxc.org/router.aspx?\"\n                   + $\"Platform={platformInfo.Name}\"\n                   // note: Version ToString max 3, as Oqtane only has 3 version numbers, otherwise error\n                   + $\"&SysVersion={platformInfo.Version.ToString(3)}\"\n                   + $\"&SxcVersion={EavSystemInfo.VersionString}\"\n                   + destinationPart\n                   + \"&ModuleId=\" + moduleId\n                   + \"&SiteId=\" + site?.Id\n                   + \"&ZoneID=\" + site?.ZoneId\n                   + \"&DefaultLanguage=\" + site?.DefaultCultureCode\n                   + \"&CurrentLanguage=\" + site?.SafeCurrentCultureCode()\n                   + \"&SysGuid=\" + platformInfo.Identity\n            ;\n\n        link += \"&AppId=\" + (isContentApp ? \"Default\" : appSpecsOrNull?.NameId ?? \"\");\n            \n        // Add AppStaticName and Version if _not_ the primary content-app\n        if (appSpecsOrNull?.Configuration != null)\n            link += $\"&AppVersion={appSpecsOrNull.Configuration.Version}\"\n                    + $\"&AppOriginalId={appSpecsOrNull.Configuration.OriginalId}\";\n\n        link += \"&fp=\" + System.Net.WebUtility.UrlEncode(fingerprint.GetFingerprint())?.ToLowerInvariant();\n        return link;\n    }\n\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/ExternalLinks/ExternalSxcDestinations.cs",
    "content": "﻿namespace ToSic.Sxc.WebApi.Sys.ExternalLinks;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic enum ExternalSxcDestinations\n{\n    AutoConfigure,\n    GettingStarted,\n    Features\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi/WebApi.Sys/NetCoreControllersHelper.cs",
    "content": "﻿#if !NETFRAMEWORK\nusing Microsoft.AspNetCore.Http.Extensions;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.Controllers;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing ToSic.Sxc.Sys.ExecutionContext;\n\nnamespace ToSic.Sxc.WebApi.Sys;\n\n[ShowApiWhenReleased(ShowApiMode.Never)]\npublic class NetCoreControllersHelper(ControllerBase parent) : ICanGetService\n{\n    public ControllerBase Parent { get; } = parent;\n    public ILog? LogOrNull { get; } = (parent as IHasLog)?.Log;\n\n    private ILogCall? _actionTimerWrap; // it is used across events to track action execution total time\n\n    public IServiceProvider ServiceProvider => _serviceProvider ?? throw new($\"{nameof(ServiceProvider)} is only available after calling {nameof(OnActionExecuting)}\");\n    private IServiceProvider? _serviceProvider;\n\n\n    public void OnActionExecuting(ActionExecutingContext context, string historyLogGroup)\n    {\n        // Create a log entry with timing\n        _actionTimerWrap = LogOrNull.Fn($\"action executing url: {context.HttpContext.Request.GetDisplayUrl()}\", timer: true);\n\n        // Get the ServiceProvider of the current request\n        _serviceProvider = context.HttpContext.RequestServices;\n\n        // Add to Log History\n        if (LogOrNull != null)\n            GetService<ILogStore>().Add(historyLogGroup, LogOrNull);\n    }\n\n    public void OnActionExecuted(ActionExecutedContext context)\n    {\n        if (context.ActionDescriptor is ControllerActionDescriptor actionDescriptor)\n        {\n            // If the api endpoint method return type is \"void\" or \"Task\", Web API will return HTTP response with status code 204 (No Content).\n            // This changes aspnetcore default behavior in Oqtane that returns HTTP 200 OK, with no body so it is same as in ASP.NET MVC2 in DNN. \n            // This is helpful for jQuery Ajax issue that on HTTP 200 OK with empty body throws json parse error.\n            // https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/action-results#void\n            // https://github.com/dotnet/aspnetcore/issues/16944\n            // https://github.com/2sic/2sxc/issues/2555\n            var returnType = actionDescriptor.MethodInfo.ReturnType;\n            if (returnType == typeof(void) || returnType == typeof(Task))\n            {\n                if (context.HttpContext.Response.StatusCode == 200)\n                    context.HttpContext.Response.StatusCode = 204; // NoContent (instead of HTTP 200 OK)\n            }\n        }\n\n        _actionTimerWrap.Done(\"ok\");\n        _actionTimerWrap = null; // just to mark that Action Delegate is not in use any more, so GC can collect it\n    }\n\n    public TService GetService<TService>() where TService : class => ServiceProvider.Build<TService>(LogOrNull);\n}\n\n#endif "
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExportExtensionTestAccessors.cs",
    "content": "using ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Backend.App;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Test accessor methods for ExtensionExportService to isolate test usage from production code references.\n/// These are pure pass-through forwarders with no logic.\n/// </summary>\ninternal static class ExportExtensionTestAccessors\n{\n    /// <summary>\n    /// Test accessor for Export method.\n    /// </summary>\n    public static FileToUploadToClient ExportTac(this ExtensionExportService exportExtension, int zoneId, int appId, string name)\n        => exportExtension.Export(appId: appId, name: name);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExportExtensionTestContext.cs",
    "content": "using System.Text;\nusing System.Text.Json;\nusing Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Sys;\nusing ToSic.Eav.WebApi.Sys.ImportExport;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing static ToSic.Sxc.ImportExport.Package.Sys.PackageIndexFile;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Test context for ExtensionExportService tests providing setup/teardown and test extension creation\n/// </summary>\ninternal sealed class ExportExtensionTestContext : IDisposable\n{\n    #region Properties\n\n    public string TempRoot { get; }\n    public ExtensionExportService ExportBackend { get; }\n\n    #endregion\n\n    #region Constructor / Factory\n\n    private readonly ServiceProvider _sp;\n\n    private ExportExtensionTestContext(string tempRoot, ServiceProvider sp, ExtensionExportService exportBackend)\n    {\n        TempRoot = tempRoot;\n        _sp = sp;\n        ExportBackend = exportBackend;\n    }\n\n    public static ExportExtensionTestContext Create()\n    {\n        var tempRoot = Path.Combine(Path.GetTempPath(), \"2sxc-export-tests\", Guid.NewGuid().ToString(\"N\"));\n        Directory.CreateDirectory(tempRoot);\n\n        var services = new ServiceCollection();\n        services.AddSingleton<IAppReaderFactory, FakeAppReaderFactory>();\n        services.AddSingleton<IJsonService, SimpleJsonService>();\n            \n        var sp = services.BuildServiceProvider() \n            ?? throw new InvalidOperationException(\"Failed to build service provider\");\n\n        var appReadersLazy = new LazySvc<IAppReaderFactory>(sp);\n        var contentExportLazy = new LazySvc<ContentExportApi>(sp);\n\n        var site = new FakeSite(tempRoot);\n        var appPathSvc = new FakeAppPathsMicroSvc(tempRoot);\n\n        // Create manifest service\n        var manifestService = new ExtensionManifestService();\n\n        var exportBackend = new ExtensionExportService(\n            appReadersLazy, \n            site, \n            appPathSvc, \n            contentExportLazy,\n            manifestService);\n\n        return new ExportExtensionTestContext(tempRoot, sp, exportBackend);\n    }\n\n    #endregion\n\n    #region Setup Helpers\n\n    /// <summary>\n    /// Setup a test extension with given manifest\n    /// </summary>\n    public void SetupExtension(string name, ExtensionManifest manifest)\n    {\n        var extDir = Path.Combine(TempRoot, FolderConstants.AppExtensionsFolder, name);\n        var dataDir = Path.Combine(extDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n\n        var jsonPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n\n        // Sanitize JsonElements (Undefined -> null) then serialize directly\n        var sanitized = manifest with\n        {\n            DataBundles = SanitizeJsonElement(manifest.DataBundles),\n            //InputTypeAssets = SanitizeJsonElement(manifest.InputTypeAssets),\n            InputFieldAssets = SanitizeJsonElement(manifest.InputFieldAssets),\n            Releases = SanitizeJsonElement(manifest.Releases),\n        };\n\n        var json = JsonSerializer.Serialize(sanitized, new JsonSerializerOptions { WriteIndented = true });\n        File.WriteAllText(jsonPath, json, new UTF8Encoding(false));\n    }\n\n    public void SetExtensionsBundled(string name, string bundledCommaSeparated)\n    {\n        var jsonPath = Path.Combine(TempRoot, FolderConstants.AppExtensionsFolder, name,\n            FolderConstants.DataFolderProtected, FolderConstants.AppExtensionJsonFile);\n        var json = File.ReadAllText(jsonPath);\n\n        using var doc = JsonDocument.Parse(json);\n        var root = doc.RootElement.ValueKind == JsonValueKind.Object\n            ? doc.RootElement\n            : throw new InvalidOperationException(\"extension.json root must be an object\");\n\n        var dict = root\n            .EnumerateObject()\n            .ToDictionary(p => p.Name, p => p.Value.Clone(), StringComparer.Ordinal);\n\n        using var bundledDoc = JsonDocument.Parse(JsonSerializer.Serialize(bundledCommaSeparated));\n        dict[\"extensionsBundled\"] = bundledDoc.RootElement.Clone();\n\n        var newJson = JsonSerializer.Serialize(dict, new JsonSerializerOptions\n        {\n            WriteIndented = true,\n        });\n\n        File.WriteAllText(jsonPath, newJson, new UTF8Encoding(false));\n    }\n\n    public void WriteInstalledLockFile(string name, string lockJson)\n    {\n        var lockPath = Path.Combine(TempRoot, FolderConstants.AppExtensionsFolder, name,\n            FolderConstants.DataFolderProtected, LockFileName);\n        Directory.CreateDirectory(Path.GetDirectoryName(lockPath)!);\n        File.WriteAllText(lockPath, lockJson, new UTF8Encoding(false));\n    }\n\n    private static readonly JsonElement JsonNullElement = JsonDocument.Parse(\"null\").RootElement.Clone();\n    private static JsonElement SanitizeJsonElement(JsonElement el) => el.ValueKind == JsonValueKind.Undefined ? JsonNullElement : el;\n\n    /// <summary>\n    /// Create extension files in dist folder\n    /// </summary>\n    public void CreateExtensionFiles(string name, params (string fileName, string content)[] files)\n    {\n        var extDir = Path.Combine(TempRoot, FolderConstants.AppExtensionsFolder, name);\n        var distDir = Path.Combine(extDir, \"dist\");\n        Directory.CreateDirectory(distDir);\n\n        foreach (var (fileName, content) in files)\n        {\n            File.WriteAllText(Path.Combine(distDir, fileName), content);\n        }\n    }\n\n    /// <summary>\n    /// Create AppCode files for extension\n    /// </summary>\n    public void CreateAppCodeFiles(string name, params (string fileName, string content)[] files)\n    {\n        var appCodePath = Path.Combine(TempRoot, FolderConstants.AppCodeFolder, FolderConstants.AppExtensionsFolder, name);\n        Directory.CreateDirectory(appCodePath);\n\n        foreach (var (fileName, content) in files)\n        {\n            File.WriteAllText(Path.Combine(appCodePath, fileName), content);\n        }\n    }\n\n    #endregion\n\n    #region Disposal\n\n    public void Dispose()\n    {\n        try { _sp.Dispose(); } catch { /* Ignore */ }\n        try { Directory.Delete(TempRoot, recursive: true); } catch { /* Ignore */ }\n    }\n\n    #endregion\n\n    #region Fake Implementations\n\n    private class FakeAppReaderFactory : IAppReaderFactory\n    {\n        public IAppReader Get(int appId) => null!;\n        public IAppReader Get(IAppIdentity appIdentity) => null!;\n        public IAppReader GetSystemPreset() => null!;\n        public IAppIdentityPure AppIdentity(int appId) => new AppIdentity(1, appId) as IAppIdentityPure ?? throw new();\n        public IAppReader GetZonePrimary(int zoneId) => throw new NotImplementedException();\n        public IAppReader? TryGet(IAppIdentity appIdentity) => null;\n        public IAppReader? ToReader(IAppStateCache? state) => null;\n        public IAppReader? TryGetSystemPreset(bool nullIfNotLoaded) => null;\n        public IAppReader GetOrKeep(IAppIdentity appIdOrReader) => throw new NotImplementedException();\n    }\n\n    private class FakeAppPathsMicroSvc(string root) : IAppPathsMicroSvc\n    {\n        public IAppPaths Get(IAppReader appReader) => new FakeAppPaths(root);\n        public IAppPaths Get(IAppReader appReader, ISite? siteOrNull) => new FakeAppPaths(root);\n    }\n\n    private class FakeAppPaths(string physicalPath) : IAppPaths\n    {\n        public string Path => \"/\";\n        public string PhysicalPath { get; } = physicalPath;\n        public string PathShared => \"/\";\n        public string PhysicalPathShared { get; } = physicalPath;\n        public string RelativePath => \"/\";\n        public string RelativePathShared => \"/\";\n    }\n\n    private class SimpleJsonService : IJsonService\n    {\n        private static readonly JsonSerializerOptions Options = new() \n        { \n            PropertyNamingPolicy = null,\n            WriteIndented = false \n        };\n\n        public string ToJson(object item) => JsonSerializer.Serialize(item, Options);\n        public string ToJson(object item, int indentation) => JsonSerializer.Serialize(item, \n            new JsonSerializerOptions(Options) { WriteIndented = indentation > 0 });\n        public T? To<T>(string json) => JsonSerializer.Deserialize<T>(json, Options);\n        public object? ToObject(string json) => JsonSerializer.Deserialize<object>(json, Options);\n        public ITyped? ToTyped(string json, NoParamOrder npo = default, string? fallback = default, bool? propsRequired = default) \n            => null;\n        public IEnumerable<ITyped>? ToTypedList(string json, NoParamOrder npo = default, string? fallback = default, bool? propsRequired = default) \n            => null;\n    }\n\n    private class FakeSite(string appsRootPhysicalFull) : ISite\n    {\n        public ISite Init(int siteId, ILog? parentLogOrNull) => this;\n        public int Id { get; } = 1;\n        public string Name { get; } = \"Test\";\n        public string AppsRootPhysical { get; } = appsRootPhysicalFull;\n        public string AppsRootPhysicalFull { get; } = appsRootPhysicalFull;\n        public string AppAssetsLinkTemplate { get; } = \"/app/{appFolder}\";\n        public string ContentPath { get; } = \"/\";\n        public string Url { get; } = \"/\";\n        public string UrlRoot { get; } = \"/\";\n        public string CurrentCultureCode { get; } = \"en-us\";\n        public string DefaultCultureCode { get; } = \"en-us\";\n        public int ZoneId { get; } = 1;\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExportExtensionTestHelpers.cs",
    "content": "using System.IO.Compression;\nusing System.Text.Json;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Helper methods for ExtensionExportService tests\n/// </summary>\ninternal static class ExportExtensionTestHelpers\n{\n    /// <summary>\n    /// Extract and parse json file from ZIP\n    /// </summary>\n    public static Dictionary<string, object> GetJsonFileFromZip(ZipArchive zip, string jsonFile)\n    {\n        var jsonEntry = zip.Entries.FirstOrDefault(e => e.FullName.EndsWith(jsonFile, StringComparison.OrdinalIgnoreCase))\n                        ?? throw new InvalidOperationException($\"{jsonFile} not found in zip archive\");\n        using var jsonStream = jsonEntry.Open();\n        var dict = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonStream);\n        return dict ?? throw new InvalidOperationException($\"Failed to deserialize '{jsonEntry.FullName}'\");\n    }\n\n    /// <summary>\n    /// Get a JsonElement value as JsonElement\n    /// </summary>\n    public static JsonElement GetElement(this Dictionary<string, object> dict, string key)\n        => (JsonElement)dict[key];\n\n    /// <summary>\n    /// Get a JsonElement value as boolean\n    /// </summary>\n    public static bool GetBool(this Dictionary<string, object> dict, string key)\n            => GetElement(dict, key).GetBoolean();\n\n    /// <summary>\n    /// Get a JsonElement value as string\n    /// </summary>\n    public static string? GetString(this Dictionary<string, object> dict, string key)\n        => GetElement(dict, key).GetString();\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExportExtensionTests.cs",
    "content": "using System.IO.Compression;\nusing System.Text.Json;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing static ToSic.Eav.Sys.FolderConstants;\nusing static ToSic.Sxc.ImportExport.Package.Sys.PackageIndexFile;\nusing static ToSic.Sxc.ImportExport.Package.Sys.PackageInstallFile;\nusing static ToSic.Sxc.WebApi.Tests.Extensions.ExportExtensionTestHelpers;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Unit tests for ExtensionExportService service\n/// </summary>\npublic class ExportExtensionTests\n{\n    #region Basic Export Tests\n\n    [Fact]\n    public void Export_BasicExtension_CreatesZipStructure()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        const string version = \"1.0.0\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = version, IsInstalled = false, AppCodeInside = false, DataInside = false });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        Assert.NotNull(result);\n        Assert.NotEmpty(result.FileBytes);\n        Assert.Contains(result.ContentType, new[] { \"application/zip\", \"application/octet-stream\" });\n        Assert.Contains($\"app-extension-{extName}-v{version}.zip\", result.FileName);\n    }\n\n    [Fact]\n    public void Export_VerifyZipContainsExtensionJson()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\" });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"/{DataFolderProtected}/{AppExtensionJsonFile}\", StringComparison.OrdinalIgnoreCase));\n    }\n\n    [Fact]\n    public void Export_VerifyZipContainsLockJson()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\" });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"/{DataFolderProtected}/{LockFileName}\", StringComparison.OrdinalIgnoreCase));\n    }\n\n    #endregion\n\n    #region Bundled Extensions Tests\n\n    [Fact]\n    public void Export_IncludesBundledExtensions_AndListsAllInPackageInstall()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n\n        const string extName = \"primary-ext\";\n        ctx.SetupExtension(extName, new ExtensionManifest\n        {\n            Version = \"1.0.0\",\n            IsInstalled = false,\n            AppCodeInside = false,\n            DataInside = false,\n        });\n        ctx.SetExtensionsBundled(extName, \"bundle-a,bundle-b\");\n        ctx.CreateExtensionFiles(extName, (\"primary.txt\", \"primary\"));\n\n        ctx.SetupExtension(\"bundle-a\", new ExtensionManifest\n        {\n            Version = \"2.0.0\",\n            IsInstalled = false,\n            AppCodeInside = false,\n            DataInside = false,\n        });\n        ctx.CreateExtensionFiles(\"bundle-a\", (\"a.txt\", \"a\"));\n\n        ctx.SetupExtension(\"bundle-b\", new ExtensionManifest\n        {\n            Version = \"3.0.0\",\n            IsInstalled = true,\n            AppCodeInside = false,\n            DataInside = false,\n        });\n        ctx.CreateExtensionFiles(\"bundle-b\", (\"b.txt\", \"b\"));\n\n        // Simulate previous installation lock file which should be included unchanged\n        const string installedLock = \"{\\n  \\\"version\\\": \\\"3.0.0\\\",\\n  \\\"files\\\": []\\n}\";\n        ctx.WriteInstalledLockFile(\"bundle-b\", installedLock);\n\n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n\n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n\n        // Verify files from all 3 extensions are present\n        Assert.Contains(zip.Entries, e => e.FullName.Equals($\"{AppExtensionsFolder}/{extName}/dist/primary.txt\", StringComparison.OrdinalIgnoreCase));\n        Assert.Contains(zip.Entries, e => e.FullName.Equals($\"{AppExtensionsFolder}/bundle-a/dist/a.txt\", StringComparison.OrdinalIgnoreCase));\n        Assert.Contains(zip.Entries, e => e.FullName.Equals($\"{AppExtensionsFolder}/bundle-b/dist/b.txt\", StringComparison.OrdinalIgnoreCase));\n\n        // Verify extension.json exists for each\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"{AppExtensionsFolder}/{extName}/{DataFolderProtected}/{AppExtensionJsonFile}\", StringComparison.OrdinalIgnoreCase));\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"{AppExtensionsFolder}/bundle-a/{DataFolderProtected}/{AppExtensionJsonFile}\", StringComparison.OrdinalIgnoreCase));\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"{AppExtensionsFolder}/bundle-b/{DataFolderProtected}/{AppExtensionJsonFile}\", StringComparison.OrdinalIgnoreCase));\n\n        // Verify lock file exists for each\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"{AppExtensionsFolder}/{extName}/{DataFolderProtected}/{LockFileName}\", StringComparison.OrdinalIgnoreCase));\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"{AppExtensionsFolder}/bundle-a/{DataFolderProtected}/{LockFileName}\", StringComparison.OrdinalIgnoreCase));\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"{AppExtensionsFolder}/bundle-b/{DataFolderProtected}/{LockFileName}\", StringComparison.OrdinalIgnoreCase));\n\n        // Verify installed lock json preserved\n        var bundleBLockEntry = zip.Entries.Single(e => e.FullName.EndsWith($\"{AppExtensionsFolder}/bundle-b/{DataFolderProtected}/{LockFileName}\", StringComparison.OrdinalIgnoreCase));\n        using (var lockStream = bundleBLockEntry.Open())\n        using (var reader = new StreamReader(lockStream))\n        {\n            var lockText = reader.ReadToEnd();\n            Assert.Contains(\"\\\"version\\\": \\\"3.0.0\\\"\", lockText);\n            Assert.Contains(\"\\\"files\\\": []\", lockText);\n        }\n\n        // Verify package-install.json lists all extensions\n        var package = GetJsonFileFromZip(zip, FileName);\n        Assert.True(package.ContainsKey(\"extensions\"));\n        var exts = package.GetElement(\"extensions\");\n        Assert.Equal(JsonValueKind.Array, exts.ValueKind);\n        var names = exts.EnumerateArray().Select(e => e.GetProperty(\"name\").GetString()).ToList();\n        Assert.Contains(extName, names);\n        Assert.Contains(\"bundle-a\", names);\n        Assert.Contains(\"bundle-b\", names);\n        Assert.Equal(3, names.Count);\n    }\n\n    [Fact]\n    public void Export_SkipsMissingBundledExtensions()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n\n        const string extName = \"primary-ext\";\n        ctx.SetupExtension(extName, new ExtensionManifest\n        {\n            Version = \"1.0.0\",\n            IsInstalled = false,\n            AppCodeInside = false,\n            DataInside = false,\n        });\n\n        // One missing, one present\n        ctx.SetExtensionsBundled(extName, \"text-ext2,bundle-a\");\n\n        ctx.SetupExtension(\"bundle-a\", new ExtensionManifest\n        {\n            Version = \"2.0.0\",\n            IsInstalled = false,\n            AppCodeInside = false,\n            DataInside = false,\n        });\n\n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n\n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n\n        // Present bundled extension should be included\n        Assert.Contains(zip.Entries, e => e.FullName.EndsWith($\"{AppExtensionsFolder}/bundle-a/{DataFolderProtected}/{AppExtensionJsonFile}\", StringComparison.OrdinalIgnoreCase));\n\n        // Missing bundled extension should not appear anywhere\n        Assert.DoesNotContain(zip.Entries, e => e.FullName.Contains($\"{AppExtensionsFolder}/text-ext2/\", StringComparison.OrdinalIgnoreCase));\n\n        // package-install.json should only list primary + existing bundled\n        var package = GetJsonFileFromZip(zip, FileName);\n        var exts = package.GetElement(\"extensions\");\n        var names = exts.EnumerateArray().Select(e => e.GetProperty(\"name\").GetString()).ToList();\n        Assert.Contains(extName, names);\n        Assert.Contains(\"bundle-a\", names);\n        Assert.DoesNotContain(\"text-ext2\", names);\n        Assert.Equal(2, names.Count);\n    }\n\n    #endregion\n\n    #region Error Handling Tests\n\n    [Fact]\n    public void Export_ThrowsWhenExtensionNotFound()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        Assert.Throws<DirectoryNotFoundException>(() =>\n            ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: \"nonexistent\"));\n    }\n\n    [Fact]\n    public void Export_ThrowsWhenExtensionJsonMissing()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"incomplete\";\n        var extDir = Path.Combine(ctx.TempRoot, AppExtensionsFolder, extName);\n        Directory.CreateDirectory(extDir);\n        \n        Assert.Throws<FileNotFoundException>(() =>\n            ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName));\n    }\n\n    #endregion\n\n    #region Installation Status Tracking\n\n    [Fact]\n    public void Export_SetsIsInstalledToTrue_WhenFalse()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\", IsInstalled = false });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n\n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        var config = GetJsonFileFromZip(zip, $\"/{DataFolderProtected}/{AppExtensionJsonFile}\");\n        Assert.True(config.ContainsKey(\"isInstalled\"));\n        Assert.True(config.GetBool(\"isInstalled\"));\n    }\n\n    [Fact]\n    public void Export_SetsIsInstalledToTrue_WhenMissing()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\" });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        var config = GetJsonFileFromZip(zip, $\"/{DataFolderProtected}/{AppExtensionJsonFile}\");\n        Assert.True(config.ContainsKey(\"isInstalled\"));\n        Assert.True(config.GetBool(\"isInstalled\"));\n    }\n\n    [Fact]\n    public void Export_DoesNotModifyOriginalExtensionJson()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\", IsInstalled = false });\n        \n        var originalPath = Path.Combine(ctx.TempRoot, AppExtensionsFolder, extName, \n            DataFolderProtected, AppExtensionJsonFile);\n        var originalContent = File.ReadAllText(originalPath);\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        var afterExportContent = File.ReadAllText(originalPath);\n        Assert.Equal(originalContent, afterExportContent);\n        \n        var originalConfig = JsonSerializer.Deserialize<Dictionary<string, object>>(originalContent);\n        Assert.NotNull(originalConfig);\n        Assert.False(originalConfig.GetBool(\"isInstalled\"));\n    }\n\n    #endregion\n\n    #region Conditional AppCode Inclusion\n\n    [Fact]\n    public void Export_IncludesAppCode_WhenHasAppCodeTrue()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"with-appcode\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\", AppCodeInside = true });\n        ctx.CreateAppCodeFiles(extName, \n            (\"Helper.cs\", \"// test helper\"),\n            (\"Service.cs\", \"// test service\"));\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        \n        Assert.Contains(zip.Entries, e => e.FullName.Contains($\"AppCode/Extensions/{extName}/Helper.cs\", StringComparison.InvariantCultureIgnoreCase));\n        Assert.Contains(zip.Entries, e => e.FullName.Contains($\"AppCode/Extensions/{extName}/Service.cs\", StringComparison.InvariantCultureIgnoreCase));\n    }\n\n    [Fact]\n    public void Export_ExcludesAppCode_WhenHasAppCodeFalse()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"without-appcode\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\", AppCodeInside = false });\n        ctx.CreateAppCodeFiles(extName, (\"Helper.cs\", \"// should not be included\"));\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        \n        Assert.DoesNotContain(zip.Entries, e => e.FullName.Contains(\"AppCode/\"));\n    }\n\n    [Fact]\n    public void Export_ExcludesAppCode_WhenPropertyMissing()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"no-appcode-property\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\" });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        \n        Assert.DoesNotContain(zip.Entries, e => e.FullName.Contains(\"AppCode/\"));\n    }\n\n    #endregion\n\n    #region Extension Integrity Verification (Lock File)\n\n    [Fact]\n    public void Export_LockFileHasCorrectVersion()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        const string version = \"2.4.7\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = version });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        \n        var lockData = GetJsonFileFromZip(zip, $\"/{DataFolderProtected}/{LockFileName}\");\n        Assert.True(lockData.ContainsKey(\"version\"));\n        Assert.Equal(version, lockData.GetString(\"version\"));\n    }\n\n    [Fact]\n    public void Export_LockFileContainsFilesArray()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\" });\n        \n        var extDir = Path.Combine(ctx.TempRoot, AppExtensionsFolder, extName);\n        File.WriteAllText(Path.Combine(extDir, \"readme.txt\"), \"test\");\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n\n        var lockData = GetJsonFileFromZip(zip, $\"/{DataFolderProtected}/{LockFileName}\");\n        Assert.True(lockData.ContainsKey(\"files\"));\n        var filesElem = lockData.GetElement(\"files\");\n        Assert.True(filesElem.ValueKind == JsonValueKind.Array);\n        Assert.True(filesElem.GetArrayLength() > 0);\n    }\n\n    [Fact]\n    public void Export_LockFileEntryHasFileAndHash()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\" });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n\n        var lockEntry = zip.Entries.First(e => e.FullName.EndsWith($\"/{DataFolderProtected}/{LockFileName}\"));\n        using var lockStream = lockEntry.Open();\n        using var reader = new StreamReader(lockStream);\n        var lockJson = reader.ReadToEnd();\n        \n        Assert.Contains(\"\\\"file\\\":\", lockJson);\n        Assert.Contains(\"\\\"hash\\\":\", lockJson);\n        \n        var lockData = JsonSerializer.Deserialize<Dictionary<string, object>>(lockJson);\n        var filesElem = lockData!.GetElement(\"files\");\n        var firstFile = filesElem[0];\n        var hash = firstFile.GetProperty(\"hash\").GetString();\n        Assert.NotNull(hash);\n        Assert.Equal(64, hash.Length);\n        Assert.Matches(\"^[a-f0-9]{64}$\", hash);\n    }\n\n    #endregion\n\n    #region ZIP Structure Tests\n\n    [Fact]\n    public void Export_ExtensionFilesIncluded()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\" });\n        ctx.CreateExtensionFiles(extName,\n            (\"script.js\", \"console.log('test');\"),\n            (\"styles.css\", \".test { color: red; }\"));\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        \n        Assert.Contains(zip.Entries, e => e.FullName.Contains(\"/dist/script.js\"));\n        Assert.Contains(zip.Entries, e => e.FullName.Contains(\"/dist/styles.css\"));\n    }\n\n    [Fact]\n    public void Export_FilePathsStartWithExtensions()\n    {\n        using var ctx = ExportExtensionTestContext.Create();\n        \n        const string extName = \"test-extension\";\n        ctx.SetupExtension(extName, new ExtensionManifest { Version = \"1.0.0\" });\n        \n        var result = ctx.ExportBackend.ExportTac(zoneId: 1, appId: 42, name: extName);\n        \n        using var zipStream = new MemoryStream(result.FileBytes);\n        using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);\n        \n        foreach (var entry in zip.Entries.Where(e => !string.IsNullOrEmpty(e.Name)))\n        {\n            if (!entry.FullName.Equals(FileName, StringComparison.OrdinalIgnoreCase)\n                && !entry.FullName.StartsWith(DataFolderProtected))\n                Assert.StartsWith($\"{AppExtensionsFolder}/\", entry.FullName);\n        }\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExtensionBackendTestAccessors.cs",
    "content": "﻿using ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Backend.App;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\ninternal static class ExtensionBackendTestAccessors\n{\n    public static ExtensionsResultDto GetExtensionsTac(this ExtensionReaderBackend reader, int appId)\n        => reader.GetExtensions(appId: appId);\n\n    public static bool SaveExtensionTac(this ExtensionWriterBackend writer, int zoneId, int appId, string name, ExtensionManifest manifest)\n        => writer.SaveConfiguration(appId: appId, name: name, manifest: manifest);\n\n    public static bool InstallExtensionZipTac(this ExtensionInstallBackend zip, int zoneId, int appId, Stream zipStream,\n        bool overwrite = false, string? originalZipFileName = null, string editions = null!)\n        => zip.InstallExtensionZip(zoneId, appId: appId, zipStream: zipStream, overwrite: overwrite, originalZipFileName: originalZipFileName, editions: editions);\n}"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExtensionInstallBackendTest.cs",
    "content": "using System.IO.Compression;\nusing System.Text;\nusing ToSic.Sys.Security.Encryption;\nusing static ToSic.Eav.Sys.FolderConstants;\nusing static ToSic.Sxc.ImportExport.Package.Sys.PackageIndexFile;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Unit tests for ExtensionInstallBackend focusing on ZIP install scenarios\n/// </summary>\npublic class ExtensionInstallBackendTest\n{\n    private const int TestZoneId = 1;\n    private const int TestAppId = 42;\n    private const string TestVersion = \"1.0.0\";\n\n    [Fact]\n    public void InstallZip_Simple_Works()\n    {\n        // Arrange\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string extensionName = \"color-picker\";\n\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            // Create proper extensions/color-picker/ structure\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{extensionName}\\\", \\\"enabled\\\": true, \\\"isInstalled\\\": true }}\");\n            }\n\n            var distFile = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/dist/script.js\");\n            using (var stream = distFile.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write(\"console.log('ok');\");\n            }\n\n            // Create lock file\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{LockFileName}\");\n            using (var stream = lockJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                var lockData = new\n                {\n                    version = TestVersion,\n                    files = new[]\n                    {\n                        new\n                        {\n                            file = $\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{AppExtensionJsonFile}\",\n                            hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{extensionName}\\\", \\\"enabled\\\": true, \\\"isInstalled\\\": true }}\")\n                        },\n                        new\n                        {\n                            file = $\"{AppExtensionsFolder}/{extensionName}/dist/script.js\",\n                            hash = Sha256.Hash(\"console.log('ok');\")\n                        }\n                    }\n                };\n                writer.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms.Position = 0;\n\n        // Act\n        var ok = ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: $\"{extensionName}.zip\");\n\n        // Assert\n        Assert.True(ok);\n\n        var result = ctx.Reader.GetExtensionsTac(TestAppId);\n        Assert.Contains(result.Extensions, e => e.Folder == extensionName);\n        var cfg = result.Extensions.First(e => e.Folder == extensionName).Configuration;\n        Assert.NotNull(cfg);\n    }\n\n    [Fact]\n    public void InstallZip_BlocksTraversal()\n    {\n        // Arrange\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string extensionName = \"bad\";\n\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            // Create proper structure but with path traversal attempt\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{extensionName}\\\", \\\"isInstalled\\\": true }}\");\n            }\n\n            // Try to create a file outside the extension folder\n            var badFile = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/../../outside.txt\");\n            using (var stream = badFile.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write(\"nope\");\n            }\n\n            // Create lock file (it should fail validation due to the traversal)\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{LockFileName}\");\n            using (var stream = lockJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                var lockData = new\n                {\n                    version = TestVersion,\n                    files = new[]\n                    {\n                        new\n                        {\n                            file = $\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{AppExtensionJsonFile}\",\n                            hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{extensionName}\\\", \\\"isInstalled\\\": true }}\")\n                        },\n                        new\n                        {\n                            file = $\"{AppExtensionsFolder}/{extensionName}/../../outside.txt\",\n                            hash = Sha256.Hash(\"nope\")\n                        }\n                    }\n                };\n                writer.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms.Position = 0;\n\n        // Act\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: $\"{extensionName}.zip\"));\n    }\n\n    [Fact]\n    public void InstallZip_Overwrite_Behavior()\n    {\n        // Arrange\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string extensionName = \"dup\";\n\n        // Create a properly structured extension ZIP\n        using var ms1 = new MemoryStream();\n        using (var zip = new ZipArchive(ms1, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            // Create extensions/dup/ structure\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{extensionName}\\\", \\\"isInstalled\\\": true }}\");\n            }\n\n            // Create a simple file to include\n            var distFile = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/dist/main.js\");\n            using (var stream = distFile.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"console.log('{extensionName}');\");\n            }\n\n            // Add another placeholder asset to ensure multi-file lock scenarios\n            var placeholder = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/readme.txt\");\n            using (var stream = placeholder.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{extensionName} extension placeholder\");\n            }\n\n            // Create lock file with file hashes (must include all installed files except the lock itself)\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{LockFileName}\");\n            using (var stream = lockJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                var lockData = new\n                {\n                    version = TestVersion,\n                    files = new[]\n                    {\n                        new\n                        {\n                            file = $\"{AppExtensionsFolder}/{extensionName}/{DataFolderProtected}/{AppExtensionJsonFile}\",\n                            hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{extensionName}\\\", \\\"isInstalled\\\": true }}\")\n                        },\n                        new\n                        {\n                            file = $\"{AppExtensionsFolder}/{extensionName}/dist/main.js\",\n                            hash = Sha256.Hash($\"console.log('{extensionName}');\")\n                        },\n                        new\n                        {\n                            file = $\"{AppExtensionsFolder}/{extensionName}/readme.txt\",\n                            hash = Sha256.Hash($\"{extensionName} extension placeholder\")\n                        }\n                    }\n                };\n                writer.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms1.Position = 0;\n\n        // Act - First install\n        var ok1 = ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms1, overwrite: false, originalZipFileName: $\"{extensionName}.zip\");\n\n        // Assert - First install succeeds\n        Assert.True(ok1);\n\n        // Act - Try installing again without overwrite should fail\n        using var ms2 = new MemoryStream(ms1.ToArray());\n        ms2.Position = 0;\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms2, overwrite: false, originalZipFileName: $\"{extensionName}.zip\"));\n\n        // Act - With overwrite should succeed\n        using var ms3 = new MemoryStream(ms1.ToArray());\n        ms3.Position = 0;\n        var ok3 = ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms3, overwrite: true, originalZipFileName: $\"{extensionName}.zip\");\n\n        // Assert - Third install with overwrite succeeds\n        Assert.True(ok3);\n    }\n\n    // Additional tests covering validation and lock/hash failure modes\n\n    [Fact]\n    public void InstallZip_MissingTopLevelExtensionsFolder_Fails()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            var entry = zip.CreateEntry($\"notextensions/foo/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = entry.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write(\"{ \\\"id\\\":\\\"foo\\\", \\\"isInstalled\\\": true }\");\n            }\n        }\n        ms.Position = 0;\n\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"missing-extensions.zip\"));\n    }\n\n    [Fact]\n    public void InstallZip_MissingLockFile_Fails()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"no-lock\";\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\");\n            }\n\n            // Intentionally do not add lock file\n            var extra = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/dist/extra.js\");\n            using (var s2 = extra.Open())\n            {\n                using var w2 = new StreamWriter(s2, new UTF8Encoding(false));\n                w2.Write(\"console.log('x');\");\n            }\n        }\n        ms.Position = 0;\n\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"no-lock.zip\"));\n    }\n\n    [Fact]\n    public void InstallZip_InvalidExtensionJson_Fails()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"invalid-json\";\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                // Missing isInstalled true\n                writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"enabled\\\": true }}\");\n            }\n\n            // Provide a lock file so validation still checks extension.json\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{LockFileName}\");\n            using (var lstream = lockJson.Open())\n            {\n                using var lw = new StreamWriter(lstream, new UTF8Encoding(false));\n                var lockData = new { version = TestVersion, files = new[] { new { file = $\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash(\"{}\") } } };\n                lw.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms.Position = 0;\n\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"invalid-json.zip\"));\n    }\n\n    [Fact]\n    public void InstallZip_MissingFilesListedInLock_Fails()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"missing-file\";\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            // Only include extension.json but lock lists another file\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\");\n            }\n\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{LockFileName}\");\n            using (var lstream = lockJson.Open())\n            {\n                using var lw = new StreamWriter(lstream, new UTF8Encoding(false));\n                var lockData = new\n                {\n                    version = TestVersion,\n                    files = new[]\n                    {\n                        new { file = $\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\") },\n                        new { file = $\"{AppExtensionsFolder}/{folder}/dist/missing.js\", hash = Sha256.Hash(\"console.log('x');\") }\n                    }\n                };\n                lw.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms.Position = 0;\n\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"missing-file.zip\"));\n    }\n\n    [Fact]\n    public void InstallZip_UnexpectedExtraFiles_Fails()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"extra-file\";\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            // extension.json\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\");\n            }\n\n            // an extra file not listed in lock\n            var extra = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/dist/extra.js\");\n            using (var s2 = extra.Open())\n            {\n                using var w2 = new StreamWriter(s2, new UTF8Encoding(false));\n                w2.Write(\"console.log('extra');\");\n            }\n\n            // lock only lists the extension.json\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{LockFileName}\");\n            using (var lstream = lockJson.Open())\n            {\n                using var lw = new StreamWriter(lstream, new UTF8Encoding(false));\n                var lockData = new { version = TestVersion, files = new[] { new { file = $\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\") } } };\n                lw.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms.Position = 0;\n\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"extra-file.zip\"));\n    }\n\n    [Fact]\n    public void InstallZip_HashMismatch_Fails()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"bad-hash\";\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\");\n            }\n\n            var file = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/dist/main.js\");\n            using (var s = file.Open())\n            using (var w = new StreamWriter(s, new UTF8Encoding(false)))\n            {\n                w.Write(\"console.log('real');\");\n            }\n\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{LockFileName}\");\n            using (var lstream = lockJson.Open())\n            {\n                using var lw = new StreamWriter(lstream, new UTF8Encoding(false));\n                // Intentionally put wrong hash for main.js\n                var lockData = new\n                {\n                    version = TestVersion,\n                    files = new[]\n                    {\n                        new { file = $\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\") },\n                        new { file = $\"{AppExtensionsFolder}/{folder}/dist/main.js\", hash = \"0000000000000000000000000000000000000000000000000000000000000000\" }\n                    }\n                };\n                lw.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms.Position = 0;\n\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"bad-hash.zip\"));\n    }\n\n    [Fact]\n    public void InstallZip_WithAppCodeFiles()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"with-appcode\";\n\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\");\n            }\n\n            var jsFile = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/dist/script.js\");\n            using (var stream = jsFile.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write(\"console.log('ac');\");\n            }\n\n            var codeFile = zip.CreateEntry($\"AppCode/Extensions/{folder}/Helper.cs\");\n            using (var stream = codeFile.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write(\"public class Helper { public static string Hi() => \\\"hi\\\"; }\");\n            }\n\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{LockFileName}\");\n            using (var stream = lockJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                var lockData = new\n                {\n                    version = TestVersion,\n                    files = new[]\n                    {\n                        new { file = $\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\") },\n                        new { file = $\"{AppExtensionsFolder}/{folder}/dist/script.js\", hash = Sha256.Hash(\"console.log('ac');\") },\n                        new { file = $\"AppCode/Extensions/{folder}/Helper.cs\", hash = Sha256.Hash(\"public class Helper { public static string Hi() => \\\"hi\\\"; }\") }\n                    }\n                };\n                writer.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms.Position = 0;\n\n        var ok = ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"with-appcode.zip\");\n        Assert.True(ok);\n        var result = ctx.Reader.GetExtensionsTac(TestAppId);\n        Assert.Contains(result.Extensions, e => e.Folder == folder);\n    }\n\n    [Fact]\n    public void InstallZip_MultipleExtensions()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string a = \"ext-a\";\n        const string b = \"ext-b\";\n\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            void Add(string folder)\n            {\n                var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n                using (var stream = extensionJson.Open())\n                {\n                    using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                    writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\");\n                }\n                var asset = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/dist/asset.js\");\n                using (var s = asset.Open())\n                {\n                    using var w = new StreamWriter(s, new UTF8Encoding(false));\n                    w.Write($\"console.log('{folder}');\");\n                }\n                var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{LockFileName}\");\n                using (var ls = lockJson.Open())\n                {\n                    using var lw = new StreamWriter(ls, new UTF8Encoding(false));\n                    var lockData = new\n                    {\n                        version = TestVersion,\n                        files = new[]\n                        {\n                            new { file = $\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\") },\n                            new { file = $\"{AppExtensionsFolder}/{folder}/dist/asset.js\", hash = Sha256.Hash($\"console.log('{folder}');\") }\n                        }\n                    };\n                    lw.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n                }\n            }\n\n            Add(a);\n            Add(b);\n        }\n        ms.Position = 0;\n\n        var ok = ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"multi.zip\");\n        Assert.True(ok);\n\n        var result = ctx.Reader.GetExtensionsTac(TestAppId);\n        Assert.Contains(result.Extensions, e => e.Folder == a);\n        Assert.Contains(result.Extensions, e => e.Folder == b);\n    }\n\n    [Fact]\n    public void InstallZip_MultipleExtensions_OneInvalid_FailsAndNoneInstalled()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string good = \"ext-good\";\n        const string bad = \"ext-bad\";\n\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            // Good extension\n            var gJson = zip.CreateEntry($\"{AppExtensionsFolder}/{good}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var s = gJson.Open())\n            {\n                using var w = new StreamWriter(s, new UTF8Encoding(false));\n                w.Write($\"{{ \\\"id\\\":\\\"{good}\\\", \\\"isInstalled\\\": true }}\");\n            }\n            var gScript = zip.CreateEntry($\"{AppExtensionsFolder}/{good}/dist/a.js\");\n            using (var s = gScript.Open())\n            {\n                using var w = new StreamWriter(s, new UTF8Encoding(false));\n                w.Write(\"console.log('g');\");\n            }\n            var gLock = zip.CreateEntry($\"{AppExtensionsFolder}/{good}/{DataFolderProtected}/{LockFileName}\");\n            using (var s = gLock.Open())\n            {\n                using var w = new StreamWriter(s, new UTF8Encoding(false));\n                var lockData = new { version = TestVersion, files = new[] { new { file = $\"{AppExtensionsFolder}/{good}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{good}\\\", \\\"isInstalled\\\": true }}\") }, new { file = $\"{AppExtensionsFolder}/{good}/dist/a.js\", hash = Sha256.Hash(\"console.log('g');\") } } };\n                w.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n\n            // Bad extension (missing lock file)\n            var bJson = zip.CreateEntry($\"{AppExtensionsFolder}/{bad}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var s = bJson.Open())\n            {\n                using var w = new StreamWriter(s, new UTF8Encoding(false));\n                w.Write($\"{{ \\\"id\\\":\\\"{bad}\\\", \\\"isInstalled\\\": true }}\");\n            }\n        }\n        ms.Position = 0;\n\n        Assert.Throws<InvalidOperationException>(() =>\n            ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"multi-invalid.zip\"));\n\n        var result = ctx.Reader.GetExtensionsTac(TestAppId);\n        Assert.DoesNotContain(result.Extensions, e => e.Folder == good);\n        Assert.DoesNotContain(result.Extensions, e => e.Folder == bad);\n    }\n\n    [Fact]\n    public void InstallZip_LockFileCopiedAndReadOnly()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"lockfile\";\n\n        using var ms = new MemoryStream();\n        using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n        {\n            var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n            using (var stream = extensionJson.Open())\n            {\n                using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\");\n            }\n            var asset = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/dist/x.js\");\n            using (var s = asset.Open())\n            {\n                using var w = new StreamWriter(s, new UTF8Encoding(false));\n                w.Write(\"console.log('x');\");\n            }\n            var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{LockFileName}\");\n            using (var s = lockJson.Open())\n            {\n                using var w = new StreamWriter(s, new UTF8Encoding(false));\n                var lockData = new { version = TestVersion, files = new[] { new { file = $\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\") }, new { file = $\"{AppExtensionsFolder}/{folder}/dist/x.js\", hash = Sha256.Hash(\"console.log('x');\") } } };\n                w.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n            }\n        }\n        ms.Position = 0;\n\n        var ok = ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: ms, overwrite: false, originalZipFileName: \"lockfile.zip\");\n        Assert.True(ok);\n\n        var lockPath = Path.Combine(ctx.TempRoot, AppExtensionsFolder, folder, DataFolderProtected, LockFileName);\n        Assert.True(File.Exists(lockPath));\n        Assert.True(File.GetAttributes(lockPath).HasFlag(FileAttributes.ReadOnly));\n    }\n\n    [Fact]\n    public void InstallZip_Overwrite_ReplacesPreviousFileContent()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"replace\";\n\n        MemoryStream MakeZip(string jsContent)\n        {\n            var ms = new MemoryStream();\n            using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))\n            {\n                var extensionJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\");\n                using (var stream = extensionJson.Open())\n                {\n                    using var writer = new StreamWriter(stream, new UTF8Encoding(false));\n                    writer.Write($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\");\n                }\n                var asset = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/dist/main.js\");\n                using (var s = asset.Open())\n                {\n                    using var w = new StreamWriter(s, new UTF8Encoding(false));\n                    w.Write(jsContent);\n                }\n                var lockJson = zip.CreateEntry($\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{LockFileName}\");\n                using (var s = lockJson.Open())\n                {\n                    using var w = new StreamWriter(s, new UTF8Encoding(false));\n                    var lockData = new { version = TestVersion, files = new[] { new { file = $\"{AppExtensionsFolder}/{folder}/{DataFolderProtected}/{AppExtensionJsonFile}\", hash = Sha256.Hash($\"{{ \\\"id\\\":\\\"{folder}\\\", \\\"isInstalled\\\": true }}\") }, new { file = $\"{AppExtensionsFolder}/{folder}/dist/main.js\", hash = Sha256.Hash(jsContent) } } };\n                    w.Write(ctx.JsonSvc.ToJson(lockData, indentation: 2));\n                }\n            }\n            ms.Position = 0;\n            return ms;\n        }\n\n        var first = MakeZip(\"console.log('v1');\");\n        var ok1 = ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: first, overwrite: false, originalZipFileName: \"replace-v1.zip\");\n        Assert.True(ok1);\n\n        var filePath = Path.Combine(ctx.TempRoot, AppExtensionsFolder, folder, \"dist\", \"main.js\");\n        Assert.True(File.Exists(filePath));\n        Assert.Equal(\"console.log('v1');\", File.ReadAllText(filePath));\n\n        var second = MakeZip(\"console.log('v2');\");\n        var ok2 = ctx.Zip.InstallExtensionZipTac(zoneId: TestZoneId, appId: TestAppId, zipStream: second, overwrite: true, originalZipFileName: \"replace-v2.zip\");\n        Assert.True(ok2);\n        Assert.Equal(\"console.log('v2');\", File.ReadAllText(filePath));\n    }\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExtensionManifestServiceTestAccessors.cs",
    "content": "using ToSic.Eav.Apps.Sys.FileSystemState;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Test accessor methods for ExtensionManifestService.\n/// Provides logic-free pass-through methods to keep production API usage analysis clean.\n/// </summary>\ninternal static class ExtensionManifestServiceTestAccessors\n{\n    /// <summary>\n    /// Test accessor for LoadManifest method.\n    /// </summary>\n    public static ExtensionManifest? LoadManifestTac(this ExtensionManifestService service, FileInfo manifestFile)\n        => service.LoadManifest(manifestFile: manifestFile);\n\n    /// <summary>\n    /// Test accessor for GetManifestFile method.\n    /// </summary>\n    public static FileInfo GetManifestFileTac(this ExtensionManifestService service, DirectoryInfo extensionFolder)\n        => service.GetManifestFile(extensionFolder: extensionFolder);\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExtensionManifestServiceTests.cs",
    "content": "using System.Text;\nusing System.Text.Json;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Sys;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Unit tests for ExtensionManifestService serialization behavior\n/// </summary>\npublic class ExtensionManifestServiceTests : IDisposable\n{\n    private readonly string _tempDir;\n    private readonly ExtensionManifestService _service;\n\n    public ExtensionManifestServiceTests()\n    {\n        _tempDir = Path.Combine(Path.GetTempPath(), \"extension-manifest-tests\", Guid.NewGuid().ToString(\"N\"));\n        Directory.CreateDirectory(_tempDir);\n        _service = new ExtensionManifestService();\n    }\n\n    public void Dispose()\n    {\n        try { Directory.Delete(_tempDir, recursive: true); } catch { /* Ignore cleanup errors */ }\n    }\n\n    #region JsonElement Serialization Tests\n\n    [Fact]\n    public void LoadManifest_JsonElements_CanBeSerializedWithoutError()\n    {\n        // Arrange\n        var manifestDir = Path.Combine(_tempDir, \"test-extension\");\n        var dataDir = Path.Combine(manifestDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n\n        var manifestPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        var manifestJson = @\"{\n            \"\"name\"\": \"\"string-font-icon\"\",\n            \"\"inputFieldAssets\"\": {\n                \"\"default\"\": \"\"index.js\"\"\n            },\n            \"\"version\"\": \"\"1.0.0\"\",\n            \"\"dataBundles\"\": [\"\"bundle-guid-1\"\", \"\"bundle-guid-2\"\"],\n            \"\"releases\"\": [\n                {\n                    \"\"version\"\": \"\"1.0.0\"\",\n                    \"\"breaking\"\": false,\n                    \"\"notes\"\": \"\"Initial release\"\"\n                }\n            ]\n        }\";\n        File.WriteAllText(manifestPath, manifestJson, new UTF8Encoding(false));\n\n        // Act\n        var manifest = _service.LoadManifestTac(new FileInfo(manifestPath));\n        \n        // Assert - should not throw when serializing\n        Assert.NotNull(manifest);\n        var exception = Record.Exception(() =>\n        {\n            var serialized = JsonSerializer.Serialize(manifest, new JsonSerializerOptions { WriteIndented = true });\n            Assert.NotEmpty(serialized);\n        });\n        \n        Assert.Null(exception);\n    }\n\n    [Fact]\n    public void LoadManifest_ComplexJsonElements_PreserveStructure()\n    {\n        // Arrange\n        var manifestDir = Path.Combine(_tempDir, \"complex-extension\");\n        var dataDir = Path.Combine(manifestDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n\n        var manifestPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        var manifestJson = @\"{\n            // Comment to verify comment-tolerant parsing\n            \"\"name\"\": \"\"string-wysiwyg\"\",\n            \"\"inputFieldAssets\"\": [\n                \"\"styles.css\"\",\n                \"\"editor.js\"\",\n                \"\"config.json\"\"\n            ],\n            \"\"version\"\": \"\"2.5.1\"\",\n            \"\"editionsSupported\"\": true,\n            \"\"dataBundles\"\": [\n                {\n                    \"\"guid\"\": \"\"abc-123\"\",\n                    \"\"name\"\": \"\"Template Data\"\",\n                    \"\"type\"\": \"\"ContentType\"\"\n                }\n            ],\n            \"\"releases\"\": [\n                {\n                    \"\"version\"\": \"\"2.5.1\"\",\n                    \"\"breaking\"\": true,\n                    \"\"notes\"\": \"\"Major refactor\"\"\n                },\n                {\n                    \"\"version\"\": \"\"2.0.0\"\",\n                    \"\"breaking\"\": false,\n                    \"\"notes\"\": \"\"Stable release\"\"\n                }\n            ]\n        }\";\n        File.WriteAllText(manifestPath, manifestJson, new UTF8Encoding(false));\n\n        // Act\n        var manifest = _service.LoadManifestTac(new FileInfo(manifestPath));\n        \n        // Assert\n        Assert.NotNull(manifest);\n        Assert.Equal(\"string-wysiwyg\", manifest.Name);\n        Assert.Equal(\"2.5.1\", manifest.Version);\n        Assert.True(manifest.EditionsSupported);\n        \n        // Verify JsonElements can be accessed and re-serialized\n        var serialized = JsonSerializer.Serialize(manifest);\n        Assert.Contains(\"string-wysiwyg\", serialized);\n        Assert.Contains(\"2.5.1\", serialized);\n    }\n\n    [Fact]\n    public void LoadManifest_MultipleLoads_ProduceIndependentManifests()\n    {\n        // Arrange\n        var manifestDir = Path.Combine(_tempDir, \"multi-load-test\");\n        var dataDir = Path.Combine(manifestDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n\n        var manifestPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        var manifestJson = @\"{\n            \"\"name\"\": \"\"string-test\"\",\n            \"\"version\"\": \"\"1.0.0\"\",\n            \"\"inputFieldAssets\"\": { \"\"js\"\": \"\"main.js\"\" }\n        }\";\n        File.WriteAllText(manifestPath, manifestJson, new UTF8Encoding(false));\n\n        // Act - load the same manifest twice\n        var manifest1 = _service.LoadManifestTac(new FileInfo(manifestPath));\n        var manifest2 = _service.LoadManifestTac(new FileInfo(manifestPath));\n        \n        // Assert - both should serialize independently without errors\n        Assert.NotNull(manifest1);\n        Assert.NotNull(manifest2);\n        \n        var json1 = JsonSerializer.Serialize(manifest1);\n        var json2 = JsonSerializer.Serialize(manifest2);\n        \n        Assert.NotEmpty(json1);\n        Assert.NotEmpty(json2);\n        Assert.Contains(\"string-test\", json1);\n        Assert.Contains(\"string-test\", json2);\n    }\n\n    [Fact]\n    public void LoadManifest_EmptyJsonElements_HandleCorrectly()\n    {\n        // Arrange\n        var manifestDir = Path.Combine(_tempDir, \"minimal-extension\");\n        var dataDir = Path.Combine(manifestDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n\n        var manifestPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        var manifestJson = @\"{\n            \"\"name\"\": \"\"string-minimal\"\",\n            \"\"version\"\": \"\"1.0.0\"\"\n        }\";\n        File.WriteAllText(manifestPath, manifestJson, new UTF8Encoding(false));\n\n        // Act\n        var manifest = _service.LoadManifestTac(new FileInfo(manifestPath));\n        \n        // Assert - should handle undefined/missing JsonElements\n        Assert.NotNull(manifest);\n        var serialized = JsonSerializer.Serialize(manifest);\n        Assert.NotEmpty(serialized);\n    }\n\n    #endregion\n\n    #region Load Basic Tests\n\n    [Fact]\n    public void LoadManifest_ValidFile_ReturnsManifest()\n    {\n        // Arrange\n        var manifestDir = Path.Combine(_tempDir, \"valid-extension\");\n        var dataDir = Path.Combine(manifestDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n\n        var manifestPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        var manifestJson = @\"{\n            \"\"name\"\": \"\"string-font-icon\"\",\n            \"\"version\"\": \"\"1.2.3\"\",\n            \"\"editionsSupported\"\": true\n        }\";\n        File.WriteAllText(manifestPath, manifestJson, new UTF8Encoding(false));\n\n        // Act\n        var result = _service.LoadManifestTac(new FileInfo(manifestPath));\n\n        // Assert\n        Assert.NotNull(result);\n        Assert.Equal(\"string-font-icon\", result.Name);\n        Assert.Equal(\"1.2.3\", result.Version);\n        Assert.True(result.EditionsSupported);\n    }\n\n    [Fact]\n    public void LoadManifest_EmptyFile_ReturnsNull()\n    {\n        // Arrange\n        var manifestDir = Path.Combine(_tempDir, \"empty-extension\");\n        var dataDir = Path.Combine(manifestDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n\n        var manifestPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        File.WriteAllText(manifestPath, \"\", new UTF8Encoding(false));\n\n        // Act\n        var result = _service.LoadManifestTac(new FileInfo(manifestPath));\n\n        // Assert\n        Assert.Null(result);\n    }\n\n    [Fact]\n    public void LoadManifest_InvalidJson_ReturnsNull()\n    {\n        // Arrange\n        var manifestDir = Path.Combine(_tempDir, \"invalid-extension\");\n        var dataDir = Path.Combine(manifestDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n\n        var manifestPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        File.WriteAllText(manifestPath, \"{ invalid json }\", new UTF8Encoding(false));\n\n        // Act\n        var result = _service.LoadManifestTac(new FileInfo(manifestPath));\n\n        // Assert\n        Assert.Null(result);\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExtensionsBackendTestContext.cs",
    "content": "using Microsoft.Extensions.DependencyInjection;\nusing System.Text.Json;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Eav.Apps.Sys.Caching;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Apps.Sys.Loaders;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\nusing ToSic.Sys.Configuration;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Test context for ExtensionsBackend tests providing setup/teardown and test extension creation\n/// </summary>\ninternal sealed class ExtensionsBackendTestContext : IDisposable\n{\n    #region Properties\n\n    public string TempRoot { get; }\n    public ExtensionReaderBackend Reader { get; }\n    public ExtensionWriterBackend Writer { get; }\n    public ExtensionInstallBackend Zip { get; }\n    public IJsonService JsonSvc { get; }\n\n    #endregion\n\n    #region Constructor / Factory\n\n    private readonly ServiceProvider _sp;\n\n    private ExtensionsBackendTestContext(string tempRoot, ServiceProvider sp, ExtensionReaderBackend reader, ExtensionWriterBackend writer, ExtensionInstallBackend zip, IJsonService jsonSvc)\n    {\n        TempRoot = tempRoot;\n        _sp = sp;\n        Reader = reader;\n        Writer = writer;\n        Zip = zip;\n        JsonSvc = jsonSvc;\n    }\n\n    public static ExtensionsBackendTestContext Create()\n    {\n        var tempRoot = Path.Combine(Path.GetTempPath(), \"2sxc-ext-tests\", Guid.NewGuid().ToString(\"N\"));\n        Directory.CreateDirectory(tempRoot);\n\n        // Create site & path services first so they can be registered\n        var site = new FakeSite(tempRoot);\n        var appPathSvc = new FakeAppPathsMicroSvc(tempRoot);\n\n        var services = new ServiceCollection();\n        services.AddSingleton<IAppReaderFactory, FakeAppReaderFactory>();\n        services.AddSingleton<IJsonService, SimpleJsonService>();\n        services.AddSingleton<IGlobalConfiguration, FakeGlobalConfiguration>();\n        services.AddSingleton<ISite>(site);\n        services.AddSingleton<IAppPathsMicroSvc>(appPathSvc);\n        services.AddSingleton<IAppsCatalog, FakeAppsCatalog>();\n\n        // Register LazySvc wrappers for basic services using factory overloads (DI will provide sp when resolving)\n        services.AddSingleton(sp => new LazySvc<IAppReaderFactory>(sp));\n        services.AddSingleton(sp => new LazySvc<IJsonService>(sp));\n        services.AddSingleton<AppsCacheSwitch>(sp => new FakeAppsCacheSwitch());\n        services.AddSingleton<AppCachePurger>(sp => new AppCachePurger(sp.GetRequiredService<IAppsCatalog>(), sp.GetRequiredService<AppsCacheSwitch>()));\n        services.AddSingleton(sp => new LazySvc<AppCachePurger>(sp));\n        services.AddSingleton<IEnumerable<IFileGenerator>>(_ => []);\n        services.AddSingleton(sp => new LazySvc<IEnumerable<IFileGenerator>>(sp));\n        services.AddSingleton<IAppJsonConfigurationService, FakeAppJsonConfigurationService>();\n        services.AddSingleton(sp => new LazySvc<IAppJsonConfigurationService>(sp));\n\n        // Register backend dependencies explicitly so they can be resolved by LazySvc later\n        services.AddTransient<ExtensionManifestService>();\n        services.AddSingleton(sp => new LazySvc<ExtensionInspectBackend>(sp));\n        services.AddTransient<ExtensionInspectBackend>();\n        services.AddSingleton<FileSaver>();\n        services.AddSingleton<CodeControllerReal>(sp => new CodeControllerReal(\n            sp.GetRequiredService<FileSaver>(),\n            sp.GetRequiredService<LazySvc<IEnumerable<IFileGenerator>>>(),\n            sp.GetRequiredService<LazySvc<IAppJsonConfigurationService>>(),\n            sp.GetRequiredService<LazySvc<IAppReaderFactory>>()));\n        services.AddSingleton(sp => new LazySvc<CodeControllerReal>(sp));\n        \n        services.AddSingleton<ExtensionReaderBackend>(sp => new ExtensionReaderBackend(\n            sp.GetRequiredService<LazySvc<IAppReaderFactory>>(),\n            sp.GetRequiredService<ISite>(),\n            sp.GetRequiredService<IAppPathsMicroSvc>(),\n            sp.GetRequiredService<LazySvc<IJsonService>>(),\n            sp.GetRequiredService<ExtensionManifestService>(),\n            sp.GetRequiredService<LazySvc<CodeControllerReal>>()));\n\n        services.AddSingleton<ExtensionWriterBackend>(sp => new ExtensionWriterBackend(\n            sp.GetRequiredService<LazySvc<IAppReaderFactory>>(),\n            sp.GetRequiredService<ISite>(),\n            sp.GetRequiredService<IAppPathsMicroSvc>()));\n\n        services.AddSingleton<ExtensionInstallBackend>(sp => new ExtensionInstallBackend(\n            sp.GetRequiredService<LazySvc<IAppReaderFactory>>(),\n            sp.GetRequiredService<ISite>(),\n            sp.GetRequiredService<IAppPathsMicroSvc>(),\n            sp.GetRequiredService<IGlobalConfiguration>(),\n            sp.GetRequiredService<ExtensionManifestService>(),\n            sp.GetRequiredService<LazySvc<ExtensionInspectBackend>>(),\n            sp.GetRequiredService<LazySvc<CodeControllerReal>>(),\n            sp.GetRequiredService<LazySvc<AppCachePurger>>()));\n\n        var sp = services.BuildServiceProvider() \n            ?? throw new InvalidOperationException(\"Failed to build service provider\");\n\n        // Configure global folder as previous tests relied on it for path resolution helpers\n        var globalConfig = sp.GetRequiredService<IGlobalConfiguration>();\n        globalConfig.GlobalFolder(tempRoot);\n\n        // Resolve backends\n        var reader = sp.GetRequiredService<ExtensionReaderBackend>();\n        var writer = sp.GetRequiredService<ExtensionWriterBackend>();\n        var zip = sp.GetRequiredService<ExtensionInstallBackend>();\n\n        var jsonSvc = sp.GetRequiredService<IJsonService>();\n\n        return new ExtensionsBackendTestContext(tempRoot, sp, reader, writer, zip, jsonSvc);\n    }\n\n    #endregion\n    \n    #region Disposal\n\n    public void Dispose()\n    {\n        try { _sp.Dispose(); } catch { /* Ignore */ }\n        try { Directory.Delete(TempRoot, recursive: true); } catch { /* Ignore */ }\n    }\n\n    #endregion\n\n    #region Fake Implementations\n\n    private class FakeAppReaderFactory : IAppReaderFactory\n    {\n        public IAppReader Get(int appId)\n            => null!; // not used by our fake path svc\n        public IAppReader Get(IAppIdentity appIdentity)\n            => null!;\n        public IAppReader GetSystemPreset()\n            => null!;\n        public IAppIdentityPure AppIdentity(int appId)\n            => new AppIdentityPure(1, appId);\n        public IAppReader GetZonePrimary(int zoneId)\n            => throw new NotImplementedException();\n        public IAppReader? TryGet(IAppIdentity appIdentity)\n            => null;\n        public IAppReader? ToReader(IAppStateCache? state)\n            => null;\n        public IAppReader? TryGetSystemPreset(bool nullIfNotLoaded)\n            => null;\n        public IAppReader GetOrKeep(IAppIdentity appIdOrReader)\n            => throw new NotImplementedException();\n    }\n\n    private class FakeAppPathsMicroSvc(string root) : IAppPathsMicroSvc\n    {\n        public IAppPaths Get(IAppReader appReader)\n            => new FakeAppPaths(root);\n        public IAppPaths Get(IAppReader appReader, ISite? siteOrNull)\n            => new FakeAppPaths(root);\n    }\n\n    private class FakeAppPaths(string physicalPath) : IAppPaths\n    {\n        public string Path => \"/\";\n        public string PhysicalPath { get; } = physicalPath;\n        public string PathShared => \"/\";\n        public string PhysicalPathShared { get; } = physicalPath;\n        public string RelativePath => \"/\";\n        public string RelativePathShared => \"/\";\n    }\n\n    private class SimpleJsonService : IJsonService\n    {\n        private static readonly JsonSerializerOptions Options = new()\n        {\n            PropertyNamingPolicy = null,\n            WriteIndented = true\n        };\n\n        public string ToJson(object item) => item switch\n        {\n            string s => s,\n            JsonElement je => je.GetRawText(),\n            _ => JsonSerializer.Serialize(item, Options)\n        };\n        public string ToJson(object item, int indentation)\n            => JsonSerializer.Serialize(item, new JsonSerializerOptions(Options) { WriteIndented = indentation > 0 });\n        public T? To<T>(string json)\n            => JsonSerializer.Deserialize<T>(json, Options);\n        public object? ToObject(string json)\n        {\n            try\n            {\n                using var doc = JsonDocument.Parse(json);\n                return doc.RootElement.Clone();\n            }\n            catch\n            {\n                return null;\n            }\n        }\n        public ITyped ToTyped(string json, NoParamOrder noParamOrder = default, string? fallback = default, bool? propsRequired = default)\n            => throw new NotImplementedException();\n        public IEnumerable<ITyped> ToTypedList(string json, NoParamOrder noParamOrder = default, string? fallback = default, bool? propsRequired = default)\n            => throw new NotImplementedException();\n    }\n\n    private class FakeSite(string appsRootPhysicalFull) : ISite\n    {\n        public ISite Init(int siteId, ILog? parentLogOrNull) => this;\n\n        public int Id { get; } = 1;\n        public string Name { get; } = \"Test\";\n        public string AppsRootPhysical { get; } = appsRootPhysicalFull;\n        public string AppsRootPhysicalFull { get; } = appsRootPhysicalFull;\n        public string AppAssetsLinkTemplate { get; } = \"/app/{appFolder}\";\n        public string ContentPath { get; } = \"/\";\n        public string Url { get; } = \"/\";\n        public string UrlRoot { get; } = \"/\";\n        public string CurrentCultureCode { get; } = \"en-us\";\n        public string DefaultCultureCode { get; } = \"en-us\";\n        public int ZoneId { get; } = 1;\n    }\n\n    private class FakeGlobalConfiguration : IGlobalConfiguration\n    {\n        private readonly Dictionary<string, string?> _values = new();\n\n        public FakeGlobalConfiguration()\n        {\n            var tempFolder =\n                // Create a unique temp folder for this test run\n                Path.Combine(Path.GetTempPath(), \"2sxc-test-temp\", Guid.NewGuid().ToString(\"N\"));\n            Directory.CreateDirectory(tempFolder);\n        }\n\n        public string? GetThis(string? key = null)\n            => _values.TryGetValue(key!, out var value) ? value : null;\n\n        public string? GetThisOrSet(Func<string> generator, string? key = null)\n        {\n            if (!_values.TryGetValue(key!, out var value))\n            {\n                value = generator();\n                _values[key!] = value;\n            }\n            return value;\n        }\n\n        public string GetThisErrorOnNull(string? key = null)\n            => GetThis(key) ?? throw new InvalidOperationException($\"Config key '{key}' is null\");\n\n        public string? SetThis(string? value, string? key = null)\n        {\n            _values[key!] = value;\n            return value;\n        }\n    }\n\n    private class FakeAppJsonConfigurationService : IAppJsonConfigurationService\n    {\n        public void MoveAppJsonTemplateFromOldToNewLocation()\n        {\n        }\n\n        public AppJsonConfiguration? GetAppJson(int appId, bool useShared)\n            => null;\n\n        public string AppJsonCacheKey(int appId, bool useShared)\n            => string.Empty;\n\n        public ICollection<string> ExcludeSearchPatterns(string sourceFolder, int appId, bool useShared)\n            => Array.Empty<string>();\n    }\n\n    private class FakeAppsCatalog : IAppsCatalog\n    {\n        public IReadOnlyDictionary<int, string> Apps(int zoneId)\n            => new Dictionary<int, string>();\n\n        public IReadOnlyDictionary<int, Zone> Zones\n            => new Dictionary<int, Zone>();\n\n        public Zone Zone(int zoneId)\n            => new Zone(zoneId, 1, 2, new Dictionary<int, string>(), []);\n\n        public IAppIdentityPure DefaultAppIdentity(int zoneId)\n            => new AppIdentityPure(zoneId, 1);\n\n        public IAppIdentityPure PrimaryAppIdentity(int zoneId)\n            => new AppIdentityPure(zoneId, 2);\n\n        public IAppIdentityPure AppIdentity(int appId)\n            => new AppIdentityPure(1, appId);\n\n        public string AppNameId(IAppIdentity appIdentity)\n            => Guid.NewGuid().ToString();\n    }\n\n    private class FakeAppsCacheSwitch : AppsCacheSwitch\n    {\n        private readonly FakeAppsCacheSwitchable _fakeValue = new();\n\n        public FakeAppsCacheSwitch() : base(null!, null!, null!, null!)\n        {\n            // Use reflection to inject the fake value into the private _value field\n            var field = typeof(AppsCacheSwitch).GetField(\"_value\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);\n            if (field != null)\n            {\n                var getOnce = field.GetValue(this);\n                var resetMethod = getOnce?.GetType().GetMethod(\"Reset\", [typeof(IAppsCacheSwitchable)]);\n                resetMethod?.Invoke(getOnce, [_fakeValue]);\n            }\n        }\n    }\n\n    private class FakeAppsCacheSwitchable : IAppsCacheSwitchable\n    {\n        // IAppsCache methods\n        public void Purge(IAppIdentity app) { }\n        public void PurgeZones() { }\n        public IAppStateCache Get(IAppIdentity app, IAppLoaderTools tools) => null!;\n        IReadOnlyDictionary<int, Zone> IAppsCache.Zones(IAppLoaderTools tools) => new Dictionary<int, Zone>();\n        int IAppsCache.ZoneIdOfApp(int appId, IAppLoaderTools tools) => 1;\n        public bool Has(IAppIdentity app) => false;\n        void IAppsCache.Update(IAppIdentity app, IEnumerable<int> entities, ILog log, IAppLoaderTools tools) { }\n        public void Add(IAppStateCache appState) { }\n        public void Load(IAppIdentity app, string primaryLanguage, IAppLoaderTools tools) { }\n        \n        // ISwitchableService methods\n        public bool IsViable() => true;\n        public int Priority { get; } = 0;\n        public string NameId { get; } = \"Fake\";\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExtensionsBackendTests.cs",
    "content": "using ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Backend.App;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Unit tests for extension read/write backends covering read and write operations\n/// </summary>\npublic class ExtensionsBackendTests\n{\n    #region Constants\n\n    private const int TestZoneId = 1;\n    private const int TestAppId = 42;\n    private const string TestVersion = \"1.0.0\";\n\n    #endregion\n\n    #region Save and Read Tests\n\n    [Fact]\n    public void SaveThenRead_Roundtrip_Works()\n    {\n        // Arrange\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string extensionName = \"test\";\n        var manifest = new ExtensionManifest\n        {\n            Version = TestVersion,\n            IsInstalled = true\n        };\n\n        // Ensure extension folder exists before saving\n        var fooFolder = Path.Combine(ctx.TempRoot, FolderConstants.AppExtensionsFolder, extensionName);\n        Directory.CreateDirectory(fooFolder);\n\n        // Act\n        var saved = ctx.Writer.SaveExtensionTac(zoneId: TestZoneId, appId: TestAppId, name: extensionName, manifest: manifest);\n\n        // Assert\n        Assert.True(saved);\n\n        // Create another extension folder without a config file for comparison\n        var barFolder = Path.Combine(ctx.TempRoot, FolderConstants.AppExtensionsFolder, \"bar\");\n        Directory.CreateDirectory(barFolder);\n\n        var result = ctx.Reader.GetExtensionsTac(TestAppId);\n        Assert.NotNull(result);\n        Assert.NotNull(result.Extensions);\n\n        var foo = result.Extensions.FirstOrDefault(e => e.Folder == extensionName);\n        Assert.NotNull(foo);\n        Assert.NotNull(foo.Configuration);\n        Assert.Empty(foo.Icon);\n\n        var expectedJson = ExtensionManifestSerializer.Serialize(manifest);\n        var actualJson = ctx.JsonSvc.ToJson(foo.Configuration);\n        Assert.Equal(expectedJson, actualJson);\n\n        var bar = result.Extensions.FirstOrDefault(e => e.Folder == \"bar\");\n        Assert.NotNull(bar);\n        Assert.NotNull(bar.Configuration);\n        Assert.Empty(bar.Icon);\n    }\n\n    [Fact]\n    public void SaveThenRead_WithSampleSimpleExtension_Config_Works()\n    {\n        using var ctx = ExtensionsBackendTestContext.Create();\n        const string folder = \"test\";\n        var folderPath = Path.Combine(ctx.TempRoot, FolderConstants.AppExtensionsFolder, folder);\n        Directory.CreateDirectory(folderPath);\n\n        var manifest = new ExtensionManifest\n        {\n            Version = \"00.00.03\",\n            IsInstalled = false,\n            //InputTypeInside = \"empty-app-hello-world-simple\",\n            Name = \"empty-app-hello-world-simple\",\n            EditionsSupported = false\n        };\n\n        var saved = ctx.Writer.SaveExtensionTac(zoneId: TestZoneId, appId: TestAppId, name: folder, manifest: manifest);\n        Assert.True(saved);\n\n        var result = ctx.Reader.GetExtensionsTac(TestAppId);\n        Assert.NotNull(result);\n        var item = result.Extensions.FirstOrDefault(e => e.Folder == folder);\n        Assert.NotNull(item);\n        Assert.NotNull(item.Configuration);\n        Assert.Empty(item.Icon);\n\n        var expected = ExtensionManifestSerializer.Serialize(manifest);\n        var actual = ctx.JsonSvc.ToJson(item.Configuration);\n        Assert.Equal(expected, actual);\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExtensionsReaderEditionsTests.cs",
    "content": "using ToSic.Eav.Sys;\n// ReSharper disable once CheckNamespace\n\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Unit tests for ExtensionReaderBackend editions detection\n/// </summary>\npublic class ExtensionsReaderEditionsTests\n{\n    #region Basic Editions Tests\n\n    [Fact]\n    public void GetExtensions_NoEditions_WhenEditionsSupportedFalse()\n    {\n        using var ctx = ExtensionsReaderTestContext.Create();\n        \n        const string extName = \"no-editions-ext\";\n        ctx.SetupExtension(extName, new \n        { \n            version = \"1.0.0\",\n            inputTypeInside = \"string-test\",\n            editionsSupported = false\n        });\n        \n        var result = ctx.ReaderBackend.GetExtensionsTac(appId: 42);\n        \n        Assert.NotNull(result);\n        var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n        Assert.Single(extensions);\n        var ext = extensions.First();\n        Assert.Equal(extName, ext.Folder);\n        Assert.Equal(string.Empty, ext.Edition);\n    }\n\n    [Fact]\n    public void GetExtensions_NoEditions_WhenEditionsSupportedMissing()\n    {\n        using var ctx = ExtensionsReaderTestContext.Create();\n        \n        const string extName = \"no-flag-ext\";\n        ctx.SetupExtension(extName, new \n        { \n            version = \"1.0.0\",\n            inputTypeInside = \"string-test\"\n        });\n        \n        var result = ctx.ReaderBackend.GetExtensionsTac(appId: 42);\n        \n        var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n        Assert.Single(extensions);\n        Assert.Equal(string.Empty, extensions[0].Edition);\n    }\n\n    [Fact]\n    public void GetExtensions_DetectsEdition_WhenEditionFolderExists()\n    {\n        using var ctx = ExtensionsReaderTestContext.Create();\n        \n        const string extName = \"multi-edition\";\n        const string inputType = \"string-font-icon\";\n        \n        // Primary extension\n        ctx.SetupExtension(extName, new \n        { \n            version = \"1.0.0\",\n            inputTypeInside = inputType,\n            editionsSupported = true\n        });\n        \n        // Staging edition\n        ctx.SetupEdition(\"staging\", extName, new\n        {\n            version = \"1.0.0-staging\",\n            inputTypeInside = inputType,\n            editionName = \"Staging\"\n        });\n        \n        var result = ctx.ReaderBackend.GetExtensionsTac(appId: 42);\n        \n        var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n        Assert.Equal(2, extensions.Count);\n\n        var root = extensions.Single(e => e.Edition == string.Empty);\n        Assert.Equal(extName, root.Folder);\n\n        var stagingEdition = extensions.Single(e => e.Edition == \"staging\");\n        Assert.Equal(extName, stagingEdition.Folder);\n        Assert.NotNull(stagingEdition.Configuration);\n    }\n\n    [Fact]\n    public void GetExtensions_DetectsMultipleEditions()\n    {\n        using var ctx = ExtensionsReaderTestContext.Create();\n        \n        const string extName = \"multi-edition\";\n        const string inputType = \"string-dropdown\";\n        \n        ctx.SetupExtension(extName, new \n        { \n            version = \"1.0.0\",\n            inputTypeInside = inputType,\n            editionsSupported = true\n        });\n        \n        ctx.SetupEdition(\"staging\", extName, new\n        {\n            version = \"1.0.0-staging\",\n            inputTypeInside = inputType\n        });\n        \n        ctx.SetupEdition(\"live\", extName, new\n        {\n            version = \"1.0.0\",\n            inputTypeInside = inputType\n        });\n        \n        ctx.SetupEdition(\"dev\", extName, new\n        {\n            version = \"1.0.0-dev\",\n            inputTypeInside = inputType\n        });\n        \n        var result = ctx.ReaderBackend.GetExtensionsTac(appId: 42);\n        \n        var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n        Assert.Equal(4, extensions.Count);\n\n        Assert.Contains(extensions, e => e.Edition == string.Empty);\n        Assert.Contains(extensions, e => e.Edition == \"staging\");\n        Assert.Contains(extensions, e => e.Edition == \"live\");\n        Assert.Contains(extensions, e => e.Edition == \"dev\");\n    }\n\n    [Fact]\n    public void GetExtensions_ReturnsIconUrlsPerEdition()\n    {\n        using var ctx = ExtensionsReaderTestContext.Create();\n\n        const string extName = \"icon-ext\";\n        const string inputType = \"string-icon\";\n\n        ctx.SetupExtension(extName, new\n        {\n            version = \"1.0.0\",\n            inputTypeInside = inputType,\n            editionsSupported = true\n        });\n\n        var primaryIcon = Path.Combine(ctx.TempRoot, FolderConstants.AppExtensionsFolder, extName, \"icon.png\");\n        File.WriteAllText(primaryIcon, \"icon-primary\");\n\n        ctx.SetupEdition(\"staging\", extName, new\n        {\n            version = \"1.0.0-staging\",\n            inputTypeInside = inputType\n        });\n\n        var stagingIcon = Path.Combine(ctx.TempRoot, \"staging\", FolderConstants.AppExtensionsFolder, extName, \"icon.png\");\n        File.WriteAllText(stagingIcon, \"icon-staging\");\n\n        var result = ctx.ReaderBackend.GetExtensionsTac(appId: 42);\n\n        var primary = result.Extensions.Single(e => e.Folder == extName && e.Edition == string.Empty);\n        Assert.Equal(\"/extensions/icon-ext/icon.png\", primary.Icon.ToLowerInvariant());\n\n        var staging = result.Extensions.Single(e => e.Folder == extName && e.Edition == \"staging\");\n        Assert.Equal(\"/staging/extensions/icon-ext/icon.png\", staging.Icon.ToLowerInvariant());\n    }\n\n    #endregion\n\n    #region Edition Validation Tests\n\n    //[Fact]\n    //public void GetExtensions_SkipsEdition_WhenInputTypeMismatch()\n    //{\n    //    using var ctx = ExtensionsReaderTestContext.Create();\n        \n    //    const string extName = \"mismatch-test\";\n        \n    //    ctx.SetupExtension(extName, new \n    //    { \n    //        version = \"1.0.0\",\n    //        inputTypeInside = \"string-font-icon\",\n    //        editionsSupported = true\n    //    });\n        \n    //    // Edition with different inputType - should be skipped\n    //    ctx.SetupEdition(\"staging\", extName, new\n    //    {\n    //        version = \"1.0.0\",\n    //        inputTypeInside = \"string-different\"\n    //    });\n        \n    //    var result = ctx.ReaderBackend.GetExtensions(appId: 42);\n        \n    //    var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n    //    Assert.Single(extensions);\n    //    Assert.Equal(string.Empty, extensions[0].Edition);\n    //}\n\n    //[Fact]\n    //public void GetExtensions_SkipsEdition_WhenManifestMissing()\n    //{\n    //    using var ctx = ExtensionsReaderTestContext.Create();\n        \n    //    const string extName = \"no-manifest-edition\";\n        \n    //    ctx.SetupExtension(extName, new \n    //    { \n    //        version = \"1.0.0\",\n    //        inputTypeInside = \"string-test\",\n    //        editionsSupported = true\n    //    });\n        \n    //    // Create edition folder without manifest\n    //    ctx.CreateEditionFolderOnly(\"staging\", extName);\n        \n    //    var result = ctx.ReaderBackend.GetExtensions(appId: 42);\n        \n    //    var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n    //    Assert.Single(extensions);\n    //    Assert.Equal(string.Empty, extensions[0].Edition);\n    //}\n\n    //[Fact]\n    //public void GetExtensions_SkipsEdition_WhenInputTypeInvalid()\n    //{\n    //    using var ctx = ExtensionsReaderTestContext.Create();\n        \n    //    const string extName = \"invalid-input-type\";\n        \n    //    ctx.SetupExtension(extName, new \n    //    { \n    //        version = \"1.0.0\",\n    //        inputTypeInside = \"string-test\",\n    //        editionsSupported = true\n    //    });\n        \n    //    // Edition with empty inputTypeInside\n    //    ctx.SetupEdition(\"staging\", extName, new\n    //    {\n    //        version = \"1.0.0\",\n    //        inputTypeInside = \"\"\n    //    });\n        \n    //    var result = ctx.ReaderBackend.GetExtensions(appId: 42);\n        \n    //    var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n    //    Assert.Single(extensions);\n    //    Assert.Equal(string.Empty, extensions[0].Edition);\n    //}\n\n    #endregion\n\n    #region Edition Configuration Tests\n\n    [Fact]\n    public void GetExtensions_EditionConfiguration_PreservesAllProperties()\n    {\n        using var ctx = ExtensionsReaderTestContext.Create();\n        const string extName = \"config-test\";\n        const string inputType = \"string-test\";\n        ctx.SetupExtension(extName, new\n        {\n            version = \"1.0.0\",\n            inputTypeInside = inputType,\n            editionsSupported = true\n        });\n        ctx.SetupEdition(\"staging\", extName, new\n        {\n            version = \"1.0.1-staging\",\n            inputTypeInside = inputType,\n            customProp = \"test-value\",\n            nestedObj = new { key = \"value\" }\n        });\n        var result = ctx.ReaderBackend.GetExtensionsTac(appId: 42);\n        var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n        var stagingEdition = extensions.Single(e => e.Edition == \"staging\");\n        var config = stagingEdition.Configuration;\n        Assert.NotNull(config);\n\n        // Configuration is now ExtensionManifest - check properties directly\n        Assert.Equal(\"1.0.1-staging\", config.Version);\n        \n        // Note: customProp and nestedObj won't be in ExtensionManifest as it only has defined properties\n        // If tests need arbitrary JSON properties, the manifest needs JsonElement fields or we need different test data\n    }\n\n    #endregion\n\n    #region Extensions Folder Filtering Tests\n\n    [Fact]\n    public void GetExtensions_DoesNotTreatExtensionsFolderAsEdition()\n    {\n        using var ctx = ExtensionsReaderTestContext.Create();\n        \n        const string extName = \"filter-test\";\n        \n        ctx.SetupExtension(extName, new \n        { \n            version = \"1.0.0\",\n            inputTypeInside = \"string-test\",\n            editionsSupported = true\n        });\n        \n        var result = ctx.ReaderBackend.GetExtensionsTac(appId: 42);\n        \n        var extensions = result.Extensions.Where(e => e.Folder == extName).ToList();\n        Assert.Single(extensions);\n\n        // Should not have an entry treating the extensions folder as an edition\n        Assert.DoesNotContain(extensions, e => e.Edition.Equals(\"extensions\", StringComparison.OrdinalIgnoreCase));\n    }\n\n    #endregion\n\n    #region Multiple Extensions with Editions\n\n    [Fact]\n    public void GetExtensions_HandlesMultipleExtensionsWithDifferentEditionSetups()\n    {\n        using var ctx = ExtensionsReaderTestContext.Create();\n        \n        // Extension 1: with editions\n        ctx.SetupExtension(\"ext-with-editions\", new \n        { \n            version = \"1.0.0\",\n            inputTypeInside = \"string-font-icon\",\n            editionsSupported = true\n        });\n        ctx.SetupEdition(\"staging\", \"ext-with-editions\", new\n        {\n            version = \"1.0.0\",\n            inputTypeInside = \"string-font-icon\"\n        });\n        \n        // Extension 2: without editions\n        ctx.SetupExtension(\"ext-without-editions\", new \n        { \n            version = \"2.0.0\",\n            inputTypeInside = \"string-dropdown\",\n            editionsSupported = false\n        });\n        \n        var result = ctx.ReaderBackend.GetExtensionsTac(appId: 42);\n        \n        Assert.Equal(3, result.Extensions.Count);\n\n        var extWithEditions = result.Extensions.Where(e => e.Folder == \"ext-with-editions\").ToList();\n        Assert.Equal(2, extWithEditions.Count);\n        Assert.Contains(extWithEditions, e => e.Edition == string.Empty);\n        Assert.Contains(extWithEditions, e => e.Edition == \"staging\");\n        \n        var extWithoutEditions = result.Extensions.Where(e => e.Folder == \"ext-without-editions\").ToList();\n        Assert.Single(extWithoutEditions);\n        Assert.Equal(string.Empty, extWithoutEditions[0].Edition);\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/Extensions/ExtensionsReaderTestContext.cs",
    "content": "using System.Text;\nusing System.Text.Json;\nusing Microsoft.Extensions.DependencyInjection;\nusing ToSic.Eav.Apps.Sys;\nusing ToSic.Eav.Apps.Sys.AppJson;\nusing ToSic.Eav.Apps.Sys.FileSystemState;\nusing ToSic.Eav.Apps.Sys.Paths;\nusing ToSic.Eav.Sys;\nusing ToSic.Sxc.Backend.Admin;\nusing ToSic.Sxc.Backend.App;\nusing ToSic.Sxc.Code.Generate.Sys;\nusing ToSic.Sxc.Data;\nusing ToSic.Sxc.Services;\n\n// ReSharper disable once CheckNamespace\nnamespace ToSic.Sxc.WebApi.Tests.Extensions;\n\n/// <summary>\n/// Test context for ExtensionReaderBackend tests\n/// </summary>\ninternal sealed class ExtensionsReaderTestContext : IDisposable\n{\n    #region Properties\n\n    public string TempRoot { get; }\n    public ExtensionReaderBackend ReaderBackend { get; }\n\n    #endregion\n\n    #region Constructor / Factory\n\n    private readonly ServiceProvider _sp;\n    private readonly FakeAppJsonConfigurationService _appJsonService;\n\n    private ExtensionsReaderTestContext(string tempRoot, ServiceProvider sp, ExtensionReaderBackend readerBackend, FakeAppJsonConfigurationService appJsonService)\n    {\n        TempRoot = tempRoot;\n        _sp = sp;\n        ReaderBackend = readerBackend;\n        _appJsonService = appJsonService;\n    }\n\n    public static ExtensionsReaderTestContext Create()\n    {\n        var tempRoot = Path.Combine(Path.GetTempPath(), \"2sxc-extensions-reader-tests\", Guid.NewGuid().ToString(\"N\"));\n        Directory.CreateDirectory(tempRoot);\n\n        var site = new FakeSite(tempRoot);\n        var appPathSvc = new FakeAppPathsMicroSvc(tempRoot);\n\n        var services = new ServiceCollection();\n        services.AddSingleton<IAppReaderFactory, FakeAppReaderFactory>();\n        services.AddSingleton<IJsonService, SimpleJsonService>();\n        services.AddTransient<ExtensionManifestService>();\n        services.AddSingleton<ISite>(site);\n        services.AddSingleton<IAppPathsMicroSvc>(appPathSvc);\n        services.AddSingleton(sp => new LazySvc<IAppReaderFactory>(sp));\n        services.AddSingleton<IEnumerable<IFileGenerator>>(_ => []);\n        services.AddSingleton(sp => new LazySvc<IEnumerable<IFileGenerator>>(sp));\n        services.AddSingleton<FakeAppJsonConfigurationService>(_ => new FakeAppJsonConfigurationService(tempRoot));\n        services.AddSingleton<IAppJsonConfigurationService>(sp => sp.GetRequiredService<FakeAppJsonConfigurationService>());\n        services.AddSingleton(sp => new LazySvc<IAppJsonConfigurationService>(sp));\n        services.AddSingleton<FileSaver>();\n        services.AddSingleton<CodeControllerReal>(sp => new CodeControllerReal(\n            sp.GetRequiredService<FileSaver>(),\n            sp.GetRequiredService<LazySvc<IEnumerable<IFileGenerator>>>(),\n            sp.GetRequiredService<LazySvc<IAppJsonConfigurationService>>(),\n            sp.GetRequiredService<LazySvc<IAppReaderFactory>>()));\n        services.AddSingleton(sp => new LazySvc<CodeControllerReal>(sp));\n            \n        var sp = services.BuildServiceProvider() \n            ?? throw new InvalidOperationException(\"Failed to build service provider\");\n\n        var appReadersLazy = new LazySvc<IAppReaderFactory>(sp);\n        var jsonLazy = new LazySvc<IJsonService>(sp);\n        var manifestHelper = sp.GetRequiredService<ExtensionManifestService>();\n        var codeLazy = sp.GetRequiredService<LazySvc<CodeControllerReal>>();\n\n        var readerBackend = new ExtensionReaderBackend(\n            appReadersLazy, \n            sp.GetRequiredService<ISite>(), \n            sp.GetRequiredService<IAppPathsMicroSvc>(), \n            jsonLazy,\n            manifestHelper,\n            codeLazy);\n\n        var appJsonService = sp.GetRequiredService<FakeAppJsonConfigurationService>();\n\n        return new ExtensionsReaderTestContext(tempRoot, sp, readerBackend, appJsonService);\n    }\n\n    #endregion\n\n    #region Setup Helpers\n\n    /// <summary>\n    /// Setup a test extension with given configuration in the primary extensions folder\n    /// </summary>\n    public void SetupExtension(string name, object config)\n    {\n        _appJsonService.EnsureEdition(string.Empty);\n\n        var extDir = Path.Combine(TempRoot, FolderConstants.AppExtensionsFolder, name);\n        var dataDir = Path.Combine(extDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n            \n        var jsonPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        var json = config is ExtensionManifest manifest \n            ? ExtensionManifestSerializer.Serialize(manifest, new JsonSerializerOptions { WriteIndented = true })\n            : JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true });\n        File.WriteAllText(jsonPath, json, new UTF8Encoding(false));\n    }\n\n    /// <summary>\n    /// Setup an edition of an extension with given configuration\n    /// </summary>\n    public void SetupEdition(string editionName, string extensionName, object config)\n    {\n        _appJsonService.EnsureEdition(editionName);\n\n        var editionExtDir = Path.Combine(TempRoot, editionName, FolderConstants.AppExtensionsFolder, extensionName);\n        var dataDir = Path.Combine(editionExtDir, FolderConstants.DataFolderProtected);\n        Directory.CreateDirectory(dataDir);\n            \n        var jsonPath = Path.Combine(dataDir, FolderConstants.AppExtensionJsonFile);\n        var json = config is ExtensionManifest manifest \n            ? ExtensionManifestSerializer.Serialize(manifest, new JsonSerializerOptions { WriteIndented = true })\n            : JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true });\n        File.WriteAllText(jsonPath, json, new UTF8Encoding(false));\n    }\n\n    /// <summary>\n    /// Create an edition folder structure without manifest (for negative testing)\n    /// </summary>\n    public void CreateEditionFolderOnly(string editionName, string extensionName)\n    {\n        _appJsonService.EnsureEdition(editionName);\n\n        var editionExtDir = Path.Combine(TempRoot, editionName, FolderConstants.AppExtensionsFolder, extensionName);\n        Directory.CreateDirectory(editionExtDir);\n    }\n\n    #endregion\n\n    #region Disposal\n\n    public void Dispose()\n    {\n        try { _sp.Dispose(); } catch { /* Ignore */ }\n        try { Directory.Delete(TempRoot, recursive: true); } catch { /* Ignore */ }\n    }\n\n    #endregion\n\n    #region Fake Implementations\n\n    private class FakeAppReaderFactory : IAppReaderFactory\n    {\n        public IAppReader Get(int appId)\n            => null!;\n        public IAppReader Get(IAppIdentity appIdentity)\n            => null!;\n        public IAppReader GetSystemPreset()\n            => null!;\n        public IAppIdentityPure AppIdentity(int appId)\n            => new AppIdentity(1, appId) as IAppIdentityPure ?? throw new();\n        public IAppReader GetZonePrimary(int zoneId)\n            => throw new NotImplementedException();\n        public IAppReader? TryGet(IAppIdentity appIdentity)\n            => null;\n        public IAppReader? ToReader(IAppStateCache? state)\n            => null;\n        public IAppReader? TryGetSystemPreset(bool nullIfNotLoaded)\n            => null;\n        public IAppReader GetOrKeep(IAppIdentity appIdOrReader)\n            => throw new NotImplementedException();\n    }\n\n    private class FakeAppPathsMicroSvc(string root) : IAppPathsMicroSvc\n    {\n        public IAppPaths Get(IAppReader appReader)\n            => new FakeAppPaths(root);\n        public IAppPaths Get(IAppReader appReader, ISite? siteOrNull)\n            => new FakeAppPaths(root);\n    }\n\n    private class FakeAppPaths(string physicalPath) : IAppPaths\n    {\n        public string Path => \"/\";\n        public string PhysicalPath { get; } = physicalPath;\n        public string PathShared => \"/\";\n        public string PhysicalPathShared { get; } = physicalPath;\n        public string RelativePath => \"/\";\n        public string RelativePathShared => \"/\";\n    }\n\n    private class SimpleJsonService : IJsonService\n    {\n        private static readonly JsonSerializerOptions Options = new() \n        { \n            PropertyNamingPolicy = null,\n            WriteIndented = false \n        };\n\n        public string ToJson(object item)\n            => JsonSerializer.Serialize(item, Options);\n        public string ToJson(object item, int indentation)\n            => JsonSerializer.Serialize(item, new JsonSerializerOptions(Options) { WriteIndented = indentation > 0 });\n        public T? To<T>(string json)\n            => JsonSerializer.Deserialize<T>(json, Options);\n        public object? ToObject(string json)\n            => JsonSerializer.Deserialize<object>(json, Options);\n        public ITyped? ToTyped(string json, NoParamOrder noParamOrder = default, string? fallback = default, bool? propsRequired = default) \n            => null;\n        public IEnumerable<ITyped>? ToTypedList(string json, NoParamOrder noParamOrder = default, string? fallback = default, bool? propsRequired = default) \n            => null;\n    }\n\n    private class FakeAppJsonConfigurationService : IAppJsonConfigurationService\n    {\n        private readonly string _appRoot;\n        private readonly AppJsonConfiguration _configuration;\n        private readonly object _lock = new();\n\n        public FakeAppJsonConfigurationService(string appRoot)\n        {\n            _appRoot = appRoot;\n            _configuration = new AppJsonConfiguration\n            {\n                IsConfigured = true,\n                Editions =\n                {\n                    [string.Empty] = new AppJsonConfiguration.EditionInfo\n                    {\n                        Description = \"Root edition shared by all variants.\",\n                        IsDefault = true\n                    }\n                }\n            };\n            PersistConfiguration();\n        }\n\n        public void MoveAppJsonTemplateFromOldToNewLocation()\n        {\n        }\n\n        public AppJsonConfiguration? GetAppJson(int appId, bool useShared) => _configuration;\n\n        public string AppJsonCacheKey(int appId, bool useShared) => string.Empty;\n\n        public ICollection<string> ExcludeSearchPatterns(string sourceFolder, int appId, bool useShared)\n            => Array.Empty<string>();\n\n        public void EnsureEdition(string editionName)\n        {\n            if (editionName == null)\n                return;\n\n            lock (_lock)\n            {\n                if (_configuration.Editions.ContainsKey(editionName))\n                    return;\n\n                _configuration.Editions[editionName] = new AppJsonConfiguration.EditionInfo();\n                PersistConfiguration();\n            }\n        }\n\n        private void PersistConfiguration()\n        {\n            var appData = Path.Combine(_appRoot, FolderConstants.DataFolderProtected);\n            Directory.CreateDirectory(appData);\n            var appJsonPath = Path.Combine(appData, FolderConstants.AppJsonFile);\n            var json = JsonSerializer.Serialize(_configuration, new JsonSerializerOptions { WriteIndented = true });\n            File.WriteAllText(appJsonPath, json, new UTF8Encoding(false));\n        }\n    }\n\n    private class FakeSite(string appsRootPhysicalFull) : ISite\n    {\n        public ISite Init(int siteId, ILog? parentLogOrNull)\n            => this;\n        public int Id { get; } = 1;\n        public string Name { get; } = \"Test\";\n        public string AppsRootPhysical { get; } = appsRootPhysicalFull;\n        public string AppsRootPhysicalFull { get; } = appsRootPhysicalFull;\n        public string AppAssetsLinkTemplate { get; } = \"/app/{appFolder}\";\n        public string ContentPath { get; } = \"/\";\n        public string Url { get; } = \"/\";\n        public string UrlRoot { get; } = \"/\";\n        public string CurrentCultureCode { get; } = \"en-us\";\n        public string DefaultCultureCode { get; } = \"en-us\";\n        public int ZoneId { get; } = 1;\n    }\n\n    #endregion\n}\n"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/GlobalUsings.cs",
    "content": "// Global using directives\n\nglobal using System;\nglobal using System.Collections.Generic;\nglobal using System.Diagnostics.CodeAnalysis;\nglobal using System.Linq;\nglobal using ToSic.Eav.Apps;\nglobal using ToSic.Eav.Context;\nglobal using ToSic.Sys.Coding;\nglobal using ToSic.Sys.DI;\nglobal using ToSic.Sys.Logging;\n\n\n#if NETFRAMEWORK\nglobal using THttpResponseType = System.Net.Http.HttpResponseMessage;\n#else\nglobal using THttpResponseType = Microsoft.AspNetCore.Mvc.IActionResult;\n#endif\n\n#if NETCOREAPP\nglobal using Microsoft.AspNetCore.Mvc;\n#endif"
  },
  {
    "path": "Src/Sxc/ToSic.Sxc.WebApi.Tests/ToSic.Sxc.WebApi.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <Import Project=\"../../SharedImports/CsProj.Props/AllImportsForTestCode.props\" />\n\n  <PropertyGroup>\n    <RootNamespace>Tests.ToSic.ToSxc.WebApi</RootNamespace>\n    <AssemblyName>2sxc.WebApi.Tests</AssemblyName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ToSic.Sxc.WebApi\\ToSic.Sxc.WebApi.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net472'\">\n\t  <Reference Include=\"System.IO.Compression\" />\n\t  <Reference Include=\"System.IO.Compression.FileSystem\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Src/nuget.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <config>\n    <add key=\"repositoryPath\" value=\"./packages\" />\n    <add key=\"globalPackagesFolder\" value=\"./packages\" />\n  </config>\n  <settings>\n    <repositoryPath>./packages</repositoryPath>\n  </settings>\n  <packageRestore>\n    <add key=\"enabled\" value=\"True\" />\n    <add key=\"automatic\" value=\"True\" />\n  </packageRestore>\n  <solution>\n    <add key=\"disableSourceControlIntegration\" value=\"true\" />\n  </solution>\n</configuration>\n"
  },
  {
    "path": "contributing.md",
    "content": "# Contributing to 2sxc\n\n2sxc is a sophisticated system using C#, TypeScript, Angular and more.\nWe're always looking for help, so if you're interested in contributing:\n\nPlease check out the docs on <https://go.2sxc.org/contribute>.\n"
  },
  {
    "path": "readme.md",
    "content": "<img src=\"https://docs.2sxc.org/assets/logos/vcurrent/500.png\" width=\"200px\" align=\"right\">\n\n# 2sxc for Dnn and Oqtane\n\n## CMS, Dynamic Data, Dynamic Code & App Engine\n\n> you can't use DNN  or Oqtane without 2sxc 😉\n\n2sxc helps web designers and developers prepare great looking, animated and sexy content and applications in DNN (DotNetNuke) and Oqtane.\nIn works in .net Framework and .net Core.\n\nVisit [2sxc.org](https://2sxc.org/) for more information.\n\nVisit [docs.2sxc.org](https://docs.2sxc.org) for API docs.\n\nVisit [DNN & Razor Tutorials](https://2sxc.org/dnn-tutorials/) for tutorials.\n\nVisit [2sxc Blogs](https://2sxc.org/en/blog) for news, updates, articles.\n\n## Contents of this Repo\n\n1. 2sxc Core - containing the main 2sxc code (not dependant on DNN)\n1. 2sxc Dnn - containing everything which connects 2sxc to DNN\n1. 2sxc Oqtane - everything which implements 2sxc for Oqtane\n1. 2sxc Razor - contains the razor engine and also connects to DNN\n1. 2sxc WebApi - contains the WebApi - also as part of the DNN infrastructure\n1. 2sxc - the root project - containing installation / bundling and dependency injection for runtime\n\n## More Git Repos\n\nThis is just one repo of 2sxc - the full software also has another ca. 3 for\n\n1. [EAV-server](https://github.com/2sic/eav-server) the dynamic data layer\n1. [EAV-UI](https://github.com/2sic/eav-ui) Angular 12 UI layer for EAV data\n1. [2sxc-UI](https://github.com/2sic/2sxc-ui) In-page editing system and JS APIs\n\n## System Requirements for 2sxc\n\n1. DNN 9.6.1+ with .net Framework 4.8\n1. Oqtane 5.1+ with .net 8 or Oqtane 6 with .net 9\n\nOlder Versions\n\n* DNN: 2sxc 8 to 13 all work on DNN 7.4.2 - 9.10 or even later\n* Oqtane: see [compatibility list](https://r.2sxc.org/oqtane-install)\n"
  }
]